Slide 1

Slide 1 text

KotlinとCloud Vision APIで 領収書の電子帳簿保存法対応をする 2024年4月26日 Kotlin愛好会 vol.51(Swift愛好会合同) 竹端 尚人

Slide 2

Slide 2 text

自己紹介

Slide 3

Slide 3 text

概要 竹端 尚人 主にバックエンドエンジニア Twitter: @n_takehata ● 2006.04 公務員 ● 2007.12 SES ● 2014.04 株式会社アプリボット(Kotlinを始める) ● 2020.06 株式会社ZOZOテクノロジーズ ● 2020.12 フリーランス(現在) 現在は主に株式会社ヘンリーでの開発に従事

Slide 4

Slide 4 text

登壇、執筆 ● CEDEC 2018、2019登壇 ● Software Design 2019年2月号〜4月号で短期連載 「サーバーサイド開発の品質を向上させる Java→Kotlin 移行のススメ」執筆 ● 2021年4月 書籍「Kotlin サーバーサイドプログラミング 実践開発」出版 ● 2023年4月 Techpitにて「Kotlin入門ガイドー言語思想 から特徴・歴史・使いどころまで、まるっと予備知識がわ かる教科書」執筆

Slide 5

Slide 5 text

宣伝

Slide 6

Slide 6 text

最近力を入れている マネジメントについて書いているnote https://note.com/n_takehata (毎週投稿中)

Slide 7

Slide 7 text

Kotlin Fest 2024にて採択いただきました!

Slide 8

Slide 8 text

アジェンダ 1. 開発の目的 2. KotlinとCloud Vision APIで実装する 3. 今後やりたいこと

Slide 9

Slide 9 text

1. 開発の目的

Slide 10

Slide 10 text

電子帳簿保存法に対応した 領収書管理を楽にするため

Slide 11

Slide 11 text

● 国税関係の帳簿や書類を電子データで保存する際のルー ルを定めた法律 ● 2024年1月から領収書などの電子データ保存が完全義務 化された(施行は2022年1月) ● 電子データには「検索機能の確保」が必要 電子帳簿保存法とは?

Slide 12

Slide 12 text

1. 取引年月日・取引金額・取引先名の条件で検索できること 2. 取引年月日・取引金額の記録項目は、範囲を指定して検索 できること 3. 任意の記録項目を複数組み合わせて検索できること 電子帳簿保存法の検索要件

Slide 13

Slide 13 text

ファイル名に検索要件の情報を 入れることで対応している 例) 20240426_Amazon_1980.pdf ※税理士さんに確認済みの方法

Slide 14

Slide 14 text

※ちなみに売上5,000万円未満の事業者は検索要件への対応不要です ※しかし、どのみちなにかしら領収書の管理は必要なので私は対応しています

Slide 15

Slide 15 text

1. ファイルをダウンロード 2. 日付と金額を確認 3. リネーム これを毎月何ファイルも・・・ (年1でまとめてやっている人はさらに地獄・・・) ただ作業が面倒くさい・・・

Slide 16

Slide 16 text

なので自動化したい

Slide 17

Slide 17 text

PDFから請求日と金額を取得して ファイルをリネームする

Slide 18

Slide 18 text

2. KotlinとCloud Vision APIで実装する

Slide 19

Slide 19 text

● Googleの提供する画像認識サービス ● Google 独自の機械学習モデルを使用して、画像を分析して いる ● 画像から文字を抽出したりすることもできる Cloud Vision APIとは?

Slide 20

Slide 20 text

Cloud Vision APIのセットアップ

Slide 21

Slide 21 text

ChatGTPに聞いた手順(これ見てできました) Google Cloud SDKをセットアップして認証情報を取得する手順は以下の通りです。 1. Google Cloud Consoleにアクセスし、プロジェクトを作成します(既存のプロジェクトを使 用する場合はスキップできます)。 2. プロジェクトを選択し、[APIとサービス] > [ダッシュボード]に移動します。 3. [APIを有効にする] をクリックし、Google Cloud Vision APIを有効にします。 4. [APIとサービス] > [認証情報]に移動し、[認証情報を作成]をクリックします。 5. [サービス アカウント] を選択し、必要な情報を入力してサービス アカウントを作成します。 6. 作成されたサービス アカウントを選択し、[鍵を追加]をクリックして新しい鍵を作成します。 鍵のタイプはJSONにしてください。 7. JSON形式の認証情報ファイルがダウンロードされます。このファイルをGoogle Cloud Vision APIを使用するKotlinコードから参照できる場所に保存します。

Slide 22

Slide 22 text

ダウンロードしたJSONを環境変数に設定する 例) GOOGLE_APPLICATION_CREDENTIALS=/Users/example/credentials.json

Slide 23

Slide 23 text

build.gradle.ktsのdependenciesに以下を追加 implementation("com.google.cloud:google-cloud-vision:3.39.0") implementation("org.apache.pdfbox:pdfbox:2.0.31") ● Cloud Vision APIのSDK ● Apache PDFBoxというPDFを扱うライブラリ

Slide 24

Slide 24 text

Kotlinのコード実装

Slide 25

Slide 25 text

この領収書の情報を使います

Slide 26

Slide 26 text

1. PDFを画像に変換しrequestを作成する

Slide 27

Slide 27 text

val pdfPath = "/Users/example/hogehoge.pdf" try { // PDFを画像に変換 val document = PDDocument.load(File(pdfPath)) val renderer = PDFRenderer(document) val requestBuilder = BatchAnnotateImagesRequest.newBuilder() for (pageIndex in 0 until document.numberOfPages) { val image: BufferedImage = renderer.renderImageWithDPI(pageIndex, 300f) val byteArrayOutputStream = ByteArrayOutputStream() ImageIO.write(image, "png", byteArrayOutputStream) val imageBytes = ByteString.copyFrom(byteArrayOutputStream.toByteArray()) // Vision APIリクエストの構築 val visionImage = Image.newBuilder().setContent(imageBytes).build() val feature = Feature.newBuilder().setType(Feature.Type.DOCUMENT_TEXT_DETECTION).build() val request = AnnotateImageRequest.newBuilder().addFeatures(feature) .setImage(visionImage).build() requestBuilder.addRequests(request) } document.close() ① ② ①Cloud Vision APIは画像ファイルしか受け付けないので、PDFを画像に変換する ②画像に変換したPDFを渡してCloud Vision APIのrequestを作成する

Slide 28

Slide 28 text

2. Cloud Vision APIへrequestを送信

Slide 29

Slide 29 text

val settings = ImageAnnotatorSettings.newBuilder().setCredentialsProvider { GoogleCredentials.getApplicationDefault() } .build() val client = ImageAnnotatorClient.create(settings) val response = client.batchAnnotateImages(requestBuilder.build()) val list = response.responsesList.first().fullTextAnnotation.text.split("\r\n", "\n") client.close() ①Cloud Vision APIのclientを生成 ②requestを送信して分析結果を取得し、各行ごとの値のlistにsplitする ① ②

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

amazon.co.jp 注文番号xxx-xxxxxxx-xxxxxxxの領収書 様 注文日: 2024年4月19日 発行日: 2024年4月22日 Amazon.co.jp 注文番号: xxx-xxxxxxx-xxxxxxx ご請求額:¥1,190 2024年4月22日に発送済み 注文商品 税込価格 1点 USB-C & USB-A 3.1(Gen2) ケーブル(0.5m, ブラック) Popolier 【10Gbpsデータ転送/3A 60W高速充電】 USB3.1 Gen2 ケーブル USB-A to USB-C ケーブル 高耐久PVC素材 Xperia/Galaxy/Huawei/Pixel などのusb type c機器と互換 販売: Popolier-JP (適格請求書発行可) (出品者のプロフィール) \ 780 法人価格 コンディション: 新品 お届け先住所: 竹端 尚人 xxx-xxxx 東京都 日本 配送方法: 通常配送 支払い情報 支払い方法: |Visa | カード番号の一部: xxxx 商品の小計: 配送料・手数料: \ 410 \ 780 請求先住所: 竹端 尚人 150-0013 東京都 日本 クレジットカードへの請求 注文合計:¥1,190 ご請求額:¥1,190 Visa (下4けたがxxxx): 2024年4月22日: ¥ 1,190 注文の状況を確認するには、 注文内容をご覧ください。 利用規約 | プライバシー規約 1996-2020, Amazon.com, Inc. and its affiliates

Slide 32

Slide 32 text

3. responseから請求日と金額を抽出する

Slide 33

Slide 33 text

var date = "" var amount = "" list.forEach { if (it.startsWith("注文日")) { date = LocalDate.parse(it.replace("注文日: ", ""), DateTimeFormatter .ofPattern("yyyy年M月d日")) .format(DateTimeFormatter.ofPattern("yyyyMMdd")) } if (it.startsWith("ご請求額")) { it.replace(Regex(" | "), "").replace(Regex("ご請求額:¥|,"), "") } } ①注文日を抽出し、yyyyMMddのフォーマットに変換 ②請求額を抽出し、ラベルの文字列とカンマを削除 ① ②

Slide 34

Slide 34 text

4. ファイルをリネームする

Slide 35

Slide 35 text

val oldFile = File("/Users/example/hogehoge.pdf") val newFile = File("/Users/example/result/${date}_Amazon_$amount.pdf") Files.copy(oldFile.toPath(), newFile.toPath(), StandardCopyOption.REPLACE_EXISTING) ①抽出した請求日と金額を埋め込み、変更後のファイル名を定義 ②変更前のファイルをコピーし定義した変更後のファイル名で保存 ① ②

Slide 36

Slide 36 text

こういうファイル名にリネームされる 20240419_Amazon_1190.pdf

Slide 37

Slide 37 text

サンプルコード https://github.com/n-takehata/kotlin-cloud-vision-api-example

Slide 38

Slide 38 text

3. 今後やりたいこと

Slide 39

Slide 39 text

● reponseのtextデータを処理して値を取る部分をインター フェース化し、領収書のフォーマット毎の実装を増やす ● 生成AIでテキスト解析し、フォーマット関係なく取得できるよ うにする ● Web UIからPDFをアップロードして動かせるようにする

Slide 40

Slide 40 text

ご清聴ありがとうございました