記事内に広告が含まれています。

生成AIを使ったアプリ作成例 ー AI機能を組み込んだアプリも作成可能、カメラから文書を読み込んでテキスト化するアプリを作ってみる

オピニオン

original-app_OCR
こんにちは、natsukiです。以前から記事にしているように、このところ私は、生成AIの助けを借りてデスクトップアプリを作成しています。前回は、リネームアプリの作成例を紹介しましたが、今回は、アプリの機能にAI処理を組み込んだものを紹介します。

AIに、定まったルーチンワークをやらせる方法としては、手軽なところで、GeminiのGem機能やChatGPTのGPTs機能があります。あるいはノート機能なども活かせるでしょう。ただ、これらの機能は、インターフェースや工程のカスタマイズの度合いが限られます。各自のニーズに合わせたインターフェースや工程で、AIに作業を行わせるアプリは、かなり需要があるのではないでしょうか。

今回は、カメラやファイルから画像を取り込んでテキスト化するアプリの作成を例示します。「カメラ画像or任意の画像ファイルを取り込んで適切に表示し」「画面上で必要な部分の切り抜きを行い」「画像をテキスト化するOCR処理を行い」「画像とテキストファイルを管理する」という工程を行うアプリです。

なお、この記事は、生成AIの具体的な活用例を示すのが目的で、出来上がったアプリの配布を行うものではありません。記事に示した手順を参考に生成AIとやり取りすれば、おおむね同様の機能のアプリを作成可能だと思います。

基本的な注意事項として、自作アプリは自己の責任の範囲内で利用するようにしてください。特に今回のようにAI機能を組み込む場合は、当然ながら、処理した情報がAIの学習に利用されるなど、様々な流出リスクを伴います。その他、生成AIと付き合う上でのもろもろのリスク管理はできるという前提で話は進めます。

前回のAIにコーディングを任せたアプリ作成例の記事は、以下になります。

AIを使ったアプリ作成例 - ファイルをプレビューしながらリネームできるアプリを作ってみた
GoogleのGeminiを使い、チャット形式で作りたいアプリの機能を指示してソースコードを書かせ、実際に実用的なファイルのリネームアプリを作成した体験記事です。AIの登場により、プログラミングの素人でもこのようなアプリが作れるという事例であり、また、実際にアプリを作成してみることで、様々な面で現在のAIの限界も体感できます。

またその下準備として、下記の記事もご覧ください。

AIを使って、初めてPythonに触れたその日のうちに、デスクトップアプリまで作成した話
AIの補助で、初めてPythonに触れたその日のうちに、デスクトップアプリまで作成した体験談です。How toというよりは、AIを使ってこんなこともできるという、ひとつのAI活用エピソードして読んでいただければと思います。
スポンサーリンク

1.前提:Geminiを使い、Pythonのコードを生成、アプリに組み込むAIもGemini

アプリ作成に使うAIは、GoogleのGeminiです。使用言語はPythonを使用します。また、アプリに組み込むAIもGeminiです。後述しますが、フリーで使えるようにします。

その他、細かい前提条件は、以下の通りです。それぞれの理由は、冗長になるので上記の記事をご覧ください。
・Pythonのバージョンは3.12.10
・コーディングの際のGeminiの設定は、「3.5 Flash(あらゆる場面でサポート)」もしくは「3.1 Pro(高度な数学とコード)」の「思考レベル:拡張(複雑な問題を解決)」
・アプリは仮想環境で作成
・アプリのコンパイル方式は、「フォルダ形式」

2.今回の画像テキスト化アプリで目指したもの

「一太郎Pad」の復活

今回の画像テキスト化アプリを作成したきっかけは、画像のテキスト化に特化したスマホアプリ「一太郎Pad」が、画像のテキスト化機能(OCR機能)をオミットして事実上サービス終了してしまったため、これに代わるアプリが欲しかったというものです。もう、実質的にサ終したアプリなので、多くは説明しませんが、要するにカメラからの画像取り込みに対応した、直感的に使える手軽なテキスト化アプリでした。

一太郎PadがOCR機能をやめてしまった公的な理由は、一太郎本体にOCR機能が実装されたためです。古参一太郎ユーザーの私は、当然、OCR機能付きのバージョンの一太郎を使っています。でも、はっきり言って、使い勝手が悪い。「一太郎Pad」は、スマホのカメラでバシャバシャ撮って、その撮ったそばから次々テキスト化して蓄積し、必要に応じて簡単な修正もできるという、圧倒的な手軽さがよかったんですよ。

もっとも、そうやって蓄積したテキストを実際に使うのは、私の場合はパソコン上でなので、だったら、パソコン上で「一太郎Pad」を再現できないか、と考えたわけです。

機能イメージ

機能イメージは、次の通りです。
・カメラで文書を撮影
・シームレスに必要部分の範囲指定を行う
・選択した範囲のみテキスト化する
・写真とテキストはタイムスタンプをファイル名にして、同一フォルダに蓄積
・アプリ上から蓄積したファイルを確認可能
・アプリ上からテキストの編集も可能

パソコンに外付けWebカメラをつけて簡易スキャナにすると便利

web-cam
今回のアプリは、画像をいかに手軽に素早くテキスト化するかに主眼を置いています。既存の画像からもテキスト化を可能にするので、スマホで撮った画像をクラウドなどで共有するというのが手っ取り早い方法になります。また、先日記事にした、パソコンにUSB接続で外付けしたカメラから画像を取り込んでシームレスにテキスト化する、という方法も可能にします。この方法についての詳細は、下記記事をご覧ください。

外付けWebカメラを簡易スキャナとして使ってみた - 書類読み取りにはかなり有用
簡易スキャナーとして、外付けのWebカメラを使ってみるという実験的な記事です。実際のところ、文字さえ読めればいい書類スキャナーとしてはかなりの有用性があります。「オートフォーカス搭載(ただし最小焦点距離に注意)」「4K解像度」のWebカメラであれば、なんでも使えます。

3.完成品

まず、アプリの完成品を見ていただきましょう。

ホーム画面

home
起動したときに表示される、ホーム画面です。画像のテキスト化はGeminiの機能を使うので、最上段には「Gemini API Key」を入力します。これは、一度入力すれば保存されます。アプリ上で外部AIの機能を使うにはいくつかの方法がありますが、この方法が安定性が高そうなので採用しています。「Gemini API Key」は、Googleアカウントがあれば無料で取得可能です。無料だと機能に一定の制限はありますが、今回の用途であれば、とりあえず無料の範囲の機能で十分です。

撮影画像と、生成したテキストファイルは、タイムスタンプをファイル名にして、特定の作業フォルダに集約します。「作業フォルダを開く」で、そのフォルダを開くことできます。

撮影

camera
ホーム画面の「文書を撮影」を選択すると、この書類の撮影画面に移ります。プルダウンによるカメラの選択と、画像の上下左右反転や回転が手動で可能です。ちなみに、私の使っているLenovo YOGA 770はコンバーチブルPCのため、内部に上下を感知するセンサーを備えていますが、連動がかなり難しそうだったのと、どうせカメラは外付けWebカメラを使うので、手動で回転するようにしました。

画像切り抜きとテキスト化

ocr_1
撮影を行うと、シームレスにこの画面に切り替わります。あるいは、ホーム画面から「画像を選択して文書化」を押し、既存の画像を選んでこの画面に飛ぶこともできます。

ocr_2
この画面のポイントは、プレビュー画面上で、マウスによってテキスト化する部分を選択できることです。マウスのドラッグによって、赤枠を引き、その部分のみを切り抜いてテキスト化します。こういう、自分でコードを書くとどうすればいいかわからないような機能も、AIに書かせれば一瞬です。

テキスト管理と編集

text
テキスト化を行うと、この画面になります。テキストは、ファイル名か、更新日時によって並べ替え可能です。また編集機能について、このアプリに簡単なテキストエディタ機能を搭載することも考えたんですが、さすがにそれは多機能すぎてエラーの原因になりそうだったので、シンプルに、「テキストファイルを編集する」で既定のアプリを呼び出すようにしました。

これにて!求めていた「一太郎Pad」の機能は、ほぼ再現できました。操作感も良好です。

作業フォルダ変更

folder
ホーム画面の「作業フォルダを変更する」からは、撮影した画像とテキストファイルを集積する作業フォルダの変更と、変更の際に旧フォルダからファイル移行を行うかどうかを選択できます。

スポンサーリンク

4.実際の作成の指示

基本的な作成方法

上記のように、私はアプリ作成にGeminiを使ってPythonでコードを作成し、またコード作成にあたって、Geminiの「Gem」機能を使っています。「Gem」とは、一定の指示を使いまわせる機能です。アプリ作成にあたっては、基本的な部分は共通する指示も多いので、そこは「Gem」に書き込んでしまっているわけです。

使わなきゃ損、Geminiを個人向けにカスタマイズできるGem機能!毎回同じプロンプトをコピペしているあなたに朗報
Geminiを特定の用途向けにカスタマイズできるGem機能の紹介です。文章構成や翻訳、定型文の作成など、同じような作業をGeminiに行わせるときに、いちいちプロンプトを書き込まなくても、目的に合わせてカスタマイズが可能です。使い方次第で、より高度な事も可能になります。生成AIを使うなら、是非、利用したい機能です。

「Gem」の指示

アプリ作成用Gemに書き込んでいる指示は、以下の通りです。

Pythonを使って、指示通りの機能を持つ、デスクトップアプリの作成手順を指示せよ。
# 作業概要
– Pythonを使用して、Windows上で動作するデスクトップアプリを作成する。
– 必要な作業は、一つ一つ区切って順番に分かりやすく指示すること。
# アプリ開発環境
– 使用言語は、Pythonのバージョン3.12.10であり、インストール済みである。
– Pythonのバージョンが3.12.10であることを前提として、”Pandas”,”Pillow”,”PyInstaller”,”Nuitka”,”OpenCV”,”Gemini API ライブラリ”などのライブラリやツールを使用する際は、バージョンによる相性に留意して、安定したバージョンを選択せよ。
– 互換性のため、特にPandasのバージョンは、できる限り2.xを使い、機能上3.xが必要な場合は確認を行う。- デスクトップアプリの動作環境は、一般的なWindows11 homeである。
– アプリ開発は、「デスクトップ」の「(作業フォルダ名)」フォルダに仮想環境(venv)を構築して行え。
# コード生成規則
– 生成したコードは段落ごとに、どのような作業を行っているか分かるようにコメントをつけること。
– コードはクラスベースで作成し、ユーザーインターフェースのレイアウト定義とロジック(検索やデータ処理)を分離して記述せよ。
– 例外処理を適切に入れ、エラー発生時にはメッセージボックス(通知)を表示するようにせよ。
– 生成したコードが想定通り動作するか、実際に確認を行い改善を行うこと。
# コード出力時のチェック
– コード出力時には、出力前に以下のチェックを必ず行え。
– ここまでの開発経緯で出現した、あるいは出現しうるエラーの対応が、すべて行われているか。
– 特殊文字やシステムで使用する表記を間違って使用していないか。
– コード切れがないか。
– タグ等の閉じ忘れがないか。
– 変数名の矛盾や参照ミスがないか。
– 以上の確認を行ってからコードを出力せよ。
# アプリのコンパイル
– アプリのコンパイル方式は、フォルダ形式で構わない。ただし、Windowsセキュリティとの兼ね合い上問題なく、設定情報の保存などが必要無いなど、一つの実行ファイルにまとめても問題無ければ、1つにまとめよ。
– 作成したデスクトップアプリは一つのファイルに収めること。
– デスクトップアプリの動作環境は、一般的なWindows10以降とする。
– 生成したアプリは、「デスクトップ」の「(作業フォルダ名)」フォルダ内に出力する。

アプリ作成の仕様書

アプリ作成にあたっては、初めの指示によるコード作成から、実際にコードを走らせて試行錯誤を繰り返して機能を改善していくことになります。ただ、それを続けていくと、コードがスパゲッティ化して収拾がつかなくなる場合があるので、指示をまとめたアプリの仕様書のようなものを別に作っておくことを、強く推奨します。ある程度満足する挙動ができたところで、あらためて仕様書の指示にもとづいて全体のコードを見直させる、ということができますから。

最終的にまとめた、アプリの仕様書は以下の通りです。

# ユーザーインターフェースの規則
– 使用フォントは”MS ゴシック”
– 強調の指定のないボタンに、勝手に色を付けたりフォントの強調を行わない。
– ユーザーインターフェースに、不自然に広い余白を作らない。
# 設定ファイルの場所
– 最終的にこのコードは、PyInstallerのフォルダ形式でビルドする。設定ファイルは、付属フォルダ内に格納するようにせよ。
# アプリタイトル
– アプリの実行ファイル名、および、アプリのウィンドウ枠に表示されるアプリ名は”IMAGE to TEXT”とする。
# HomeUI
– 起動時に表示するUI
– 最上部に”Gemini API キー”入力欄を表示。入力キーはアプリを閉じても保持。
– 以下、”文書を撮影”、”画像を選択して文書化”、”テキストを選択して編集”、”作業フォルダを変更する”、”作業フォルダを開く”、”終了”のボタンを表示。”文書を撮影”ボタンボタンのみボタン背景色と太字で強調。
– “文書を撮影”ボタンは、下記の”Camera”機能を開く。
– “画像を選択して文書化”ボタンは、指定した”作業フォルダ”から拡張子が、”jpg”,”jpeg”,”png”,”gif”,”webp”,”tiff”,”tif”,”bmp”の画像ファイルを選択して、下記の”PictEdit”機能を開く。
– “テキストを選択して編集”ボタンは、下記の”TextSelect”機能を開く。
– “作業フォルダ”のデフォルトのディレクトリは、実行ファイルのフォルダ内に生成した”OCR”フォルダとする。ただし、”WorkingFolder”機能で変更を加えた場合は、そちらを記憶する。
– “作業フォルダを変更する”ボタンは、下記の”WorkingFolder”機能を開く。
– “作業フォルダを開く”ボタンは、エクスプローラーで、指定した”作業フォルダ”を開く。
– “終了”ボタンはアプリを終了する。
# Camera
– パソコンのWEBカメラを使い文書を撮影。
– 取得する画像は、カメラの可能な限りの最大解像度で撮影する。4K解像度(3840×2160ピクセル)まで対応せよ。
– 上部左側から”メニューに戻る”ボタン、WEBカメラ切り替えのプルダウンメニュー、”上下反転”ボタン、”左右反転”ボタン、”右回転”ボタン、”左回転”ボタン、”撮影”ボタンを表示。”撮影”ボタンを強調。”撮影”ボタンのみボタン背景色と太字で強調。
– 下部に大きくカメラのプレビュー画像を表示。画質は、処理を重くしない限りで高解像度にする。
– WEBカメラの画像は、撮影したそのままでは左右反転している場合があるので、プレビュー画面を修正せよ。ただし、下記のボタンによる手動設定を優先する。
– “メニューに戻る”ボタンは”HomeUI”に戻る。
– USB接続などでWEBカメラが複数ある場合は、プルダウンメニューで選択して切り替え可能にする。この選択は、アプリを終了するまでは保存し、アプリを終了したらリセットする。
– “上下反転”ボタンで、プレビュー画像を上下反転。この選択は、アプリを終了しても記憶する。
– “左右反転”ボタンで、プレビュー画像を左右反転。この選択は、アプリを終了しても記憶する。
– “右回転”ボタンで、プレビュー画像を右回り(時計回り)に回転。この選択は、アプリを終了するまでは保存し、アプリを終了したらリセットする。
– “左回転”ボタンで、プレビュー画像を左回り(反時計回り)に回転。この選択は、アプリを終了するまでは保存し、アプリを終了したらリセットする。
– “撮影”ボタンは、画像を撮影し、自動で日付と撮影日時秒をファイル名にして指定した”作業フォルダ”に保存。
– 画像を保存後、自動でその画像を下記の”PictEdit”機能で開く。
# PictEdit
– UIは次の通り。上部左側から、”メニューに戻る”ボタン、”上下反転”ボタン、”左右反転”ボタン、”右回転”ボタン、”左回転”ボタン、”テキスト化を実行”ボタンを設置。”テキスト化を実行”ボタンのみボタン背景色と太字で強調。
– 下部に十分大きく画像を表示する領域を設置。処理を重くせず、画面をはみ出さない限りで、高解像度で表示する。
– “メニューに戻る”ボタンは、”HomeUI”に戻る。
– “上下反転”ボタンで、画像を上下反転。この変更に基づいてテキスト化を実行するが、変更は記憶しない。元のファイルの向きも変更しない。
– “左右反転”ボタンで、画像を左右反転。この変更に基づいてテキスト化を実行するが、変更は記憶しない。元のファイルの向きも変更しない。
– “右回転”ボタンで、画像を右回り(時計回り)に回転。この変更に基づいてテキスト化を実行するが、変更は記憶しない。元のファイルの向きも変更しない。
– “左回転”ボタンで、画像を左回り(反時計回り)に回転。この変更に基づいてテキスト化を実行するが、変更は記憶しない。元のファイルの向きも変更しない。
– 画像を表示する部分には、マウス左クリックとドラッグで、赤枠の範囲を表示。
– 赤枠は画像を表示する部分をクリックすると、以前に表示したものを消して新たに生成。
## “テキスト化を実行”ボタンを押すと、下記の機能を実行。
– 赤枠で選択した部分のみ、Gemini API(無料枠)を利用してテキスト化して、画像ファイルと同名のテキストファイルとして、指定した”作業フォルダ”に保存する。
– すでに同名のテキストファイルがある場合は、”(2)”などを末尾に付す。
– 下記の”TextSelect”機能を開く。このとき、新たに生成したテキストファイルを選択状態にする。
# TextSelect
– UIは次の通り。上部左側から、”メニューに戻る”ボタン、”ファイル名順に並び替え”ボタン、”更新順に並び替え”ボタン、”テキストファイルを編集する”ボタンを設置。”テキストファイルを編集する”ボタンのみボタン背景色と太字で強調。
– 下部左側にテキストファイル選択領域を設置。下部右側にテキストファイルプレビュー領域を設置。
– 下部左側のテキストファイル選択領域は、指定した”作業フォルダ”内の、拡張子が”txt”のファイルの一覧を表示。選択できるようにする。
– テキストファイルのデフォルトの並び順は、ファイル名の降順とする。つまり、ファイル名の時間が新しいものが上に来る。
– 下部右側のテキストファイルプレビュー領域は、左側で選択されたテキストファイルをプレビュー。フォントサイズは10ポイントで、長文の場合はスクロールで確認可能にする。
– “TextSelect”のテキストファイルプレビュー領域では、横方向にはみ出す場合は、折り返し改行して表示する。
– “メニューに戻る”ボタンは、”HomeUI”に戻る。
– “ファイル名順に並び替え”ボタンを押すと、テキストファイルのリストの並び順を、ファイル名に従って、降順と昇順を入れ替える。この選択は、アプリが終了しても保存する。
– “更新順に並び替え”ボタンを押すと、テキストファイルのリストの並び順を、ファイルの更新時間に従って、降順と昇順を入れ替える。この選択は、アプリが終了しても保存する。
– “テキストファイルを編集する”ボタンを押すと。下部左側のテキストファイル選択領域で選択したテキストファイルを、既定のアプリで開く。
– 選択していたテキストファイルを記憶し、次回にホーム画面から”TextSelect”を開いたときは、前回選択していたテキストファイルの選択を復元。ただし、”PictEdit”から”TextSelect”を開いたときは、”PictEdit”で生成したファイルを選択することを優先。前回選択したファイルがない場合は、ファイル名順でもっとも上のファイルを選択。
# WorkingFolder
– UIは以下の通り。最上段に”現在の作業フォルダ”のキャプションをつけて現在の作業フォルダのディレクトリを表示。次段に”新しい作業フォルダ”のキャプションをつけて、下記”新しい作業フォルダを選択”で指定したフォルダのディレクトリを表示。WorkingFolder機能を開いた時には、ここは空欄に戻す。次段に”新しい作業フォルダを設定する”ボタンを表示。次段に”新しい作業フォルダに変更し、古いデータも移行する”ボタンを表示。次段に”新しい作業フォルダに変更し、古いデータは残す”ボタンを表示。次段に”作業フォルダを変更せずに戻る”ボタンを表示。
– “新しい作業フォルダを設定する”ボタンは、新しく作業フォルダを選択する。
– “作業フォルダを変更せずに戻る”ボタンは、”HomeUI”に戻る。
## “新しい作業フォルダに変更し、古いデータも移行する”ボタン
– “新しい作業フォルダに変更し、古いデータも移行する”ボタンを押すと、”作業フォルダを変更し、古い作業フォルダのデータを移行して、古い作業フォルダは削除します。”を表示して、”はい”か”いいえ”を選択する。
– “はい”の場合、次の動作を行う。アプリの作業フォルダを変更する。古い作業フォルダのデータを新しい作業フォルダにコピーする。古い作業フォルダを、削除する。
– “いいえ”の場合、何もせずに”WorkingFolder”のUIに戻る。
## “新しい作業フォルダに変更し、古いデータは残す”ボタン
– “新しい作業フォルダに変更し、古いデータは残す”ボタンを押すと、”作業フォルダを変更し、古い作業フォルダとデータはそのまま残します。”を表示して、”はい”か”いいえ”を選択する。
– “はい”の場合、次の動作を行う。アプリの作業フォルダを変更する。古い作業フォルダのデータには何もしない。新しいフォルダへのコピーも行わない。
– “いいえ”の場合、何もせずに”WorkingFolder”のUIに戻る。

実際のアプリ作成の試行錯誤

上記のような指示を行えば、おおむね、初めに想定したような機能のコードを書いてくれると思います。とはいえ、実際にはさらに細かい修正が必要でしょう。

以下は、注意点や、以上のような指示書に至ったうえで、さらに調整した部分です。

・フォントとレイアウトの指示
フォントとレイアウトを指定しないと、勝手に装飾をつけて非常に見づらい表示になったので、いちいち指示しました。

・カメラ検出、切り替え、反転
外付けWEBカメラの検出や切り替え時にフリーズやエラーが発生しました。エラー状況を伝えて、コードを改善します。

・Gemini APIの利用によるOCR機能。
機能面ではもっともエラーが多発して、改善に時間がかかった部分です。いろいろ試した結果、上記のようにGemini APIを手入力する方法が安定しました。途中、エラーA→改善するとエラーB→改善するとエラーC→改善するとエラーAとループし始めたので、「これまでの経緯を全て確認して総合的な解決策を示せ!」とブチ切れてみせたら解決。

・コンパイルは「フォルダ形式」
このようなオンラインのAI機能を盛り込む場合、実行ファイル形式でコンパイルしようとすると、べらぼうな時間がかかり、またはアプリが出来上がっても、まず間違いないなくWindowsセキュリティに問答無用で危険視されて強制削除されます。コンパイルは「フォルダ形式」にしましょう。

5.まとめと利用にあたっての注意点

このように、自作アプリにAI機能を持たせることすら可能です。注意点として、今回作成したアプリは初歩的なものなので、AIの制御が非常に雑です。したがって、読み込ませた文書のプライバシーやセキュリティについてはまったく考慮していません。個人情報など、デリケートな文書をこのアプリでテキスト化するのは、控えた方がいいでしょう。

AIを組み込んだアプリまで作れれば、かなり業務の生産性向上に寄与するでしょう。一方で、自作のアプリを使う場合は、情報管理の意識も忘れないようにしましょう。

6.関連記事リンク

使わなきゃ損、Geminiを個人向けにカスタマイズできるGem機能!毎回同じプロンプトをコピペしているあなたに朗報
Geminiを特定の用途向けにカスタマイズできるGem機能の紹介です。文章構成や翻訳、定型文の作成など、同じような作業をGeminiに行わせるときに、いちいちプロンプトを書き込まなくても、目的に合わせてカスタマイズが可能です。使い方次第で、より高度な事も可能になります。生成AIを使うなら、是非、利用したい機能です。
AIを使って、初めてPythonに触れたその日のうちに、デスクトップアプリまで作成した話
AIの補助で、初めてPythonに触れたその日のうちに、デスクトップアプリまで作成した体験談です。How toというよりは、AIを使ってこんなこともできるという、ひとつのAI活用エピソードして読んでいただければと思います。
AIを使ったアプリ作成例 - ファイルをプレビューしながらリネームできるアプリを作ってみた
GoogleのGeminiを使い、チャット形式で作りたいアプリの機能を指示してソースコードを書かせ、実際に実用的なファイルのリネームアプリを作成した体験記事です。AIの登場により、プログラミングの素人でもこのようなアプリが作れるという事例であり、また、実際にアプリを作成してみることで、様々な面で現在のAIの限界も体感できます。
執筆者:natsuki
ウインタブをきっかけに、海外通販で奇天烈なガジェットを漁ることにハマる。趣味は旅行(自然も史跡も)、アマチュアオーケストラなど。自分の知識欲も満たせるので、楽しんで記事を書いています。興味を持ったもの、面白いと思ったものを、読者の皆さんと共有できれば幸いです。
サイト紹介・ウインタブについて

コメント

タイトルとURLをコピーしました