ChatGPT による内部資料活用アプリ

# はじめに
ChatGPT は実に様々なところで応用が拡大しています。特に膨大な情報から必要な情報を取り出すなど、これまで多くの時間を要していた作業が大幅に簡略化できることは、大きなブレークスルーになると思います。この能力を個人や組織が保持している様々な資料に対して活用するニーズも高まっているのではないでしょうか。そこで、そのようなユースケースに対応するシンプルなサンプルアプリを作成しましたので、本記事ご紹介しようと思います。
* [Azure OpenAI Documents Search App - Document Insight Warehouse](https://github.com/hatasaki/oai-document-insight-warehouse)

なお、本記事ではこのアプリのセットアップの詳細については説明しませんので、そちらについては上記のリポジトリを参照して下さい。（不明点あれば気軽に Issue にあげて下さい！）

# アプリの概要
Azure OpenAI Documents Search App - Document Insight Warehouse は、保存されている資料から ChatGPT でインサイトを取得してデータベースに蓄積しておき、利用時にはそのインサイトに基づき必要な特にすぐに必要な資料を探し出して詳細な分析の実施も手助けしてくれるアプリです。
<img width="1200" alt="DIWH SystemDiagram" src="https://github.com/hatasaki/oai-document-insight-warehouse/raw/main/img/DIWHsystemdiagram.png">
ChatGPT に対して保持する全ての資料を渡して分析することは、ChatGPT で一度に利用できるデータ量（トークン）の上限があり難しいため、どのように必要な情報だけに絞って ChatGPT に渡すか？という課題は、いわゆるプロンプトエンジニアリングにおいてもひときわ重要な部分です。このアプリでは、ちょうどデータウェアハウスのように、資料のインサイトをあらかじめ作成しておくことで、そのインサイトを利用して特に関連する資料だけに絞って ChatGPT で詳細分析が可能となります。ドキュメントのインサイトのいわゆるウェアハウスを作る Document Insight Warehouse というコンセプトです。

# アプリの動作
本アプリの大きな処理の流れは下記になります。括弧内は活用する Azure サービスです。

* トリガー処理
    * OneDrive から blob に資料をコピー (Logic Apps)
    * blob 資料からテキストを抽出して CosmosDB に保存 例：PDFからテキストに変換する (Functions, Form Recognizer)
    * ChatGPT によって　CosmosDB の資料テキストからインサイトを抽出 (Functions, OpenAI) (Functions, OpenAI)
* Document Insight Warehouse データベース
    * ChatGPT によって作成されたインサイトとともに資料情報を DB に格納 (Cosmos DB)
* フロントエンド処理
    * シングルページアプリの資料活用ポータルにユーザーがアクセス (Static Web Apps)
    * 資料検索 API を使用してキーワードでドキュメントを検索 (Functions)
    * 資料クエリ API で選択した資料を ChatGPT で詳細分析 (Functions, OpenAI)

以下にそれぞれの動作を画面イメージとともに紹介していきます。

## トリガー処理
トリガー処理は、イベントの発生を契機に動作する処理になります。データウェアハウスで言えば、バッチ処理部分に相当します。

### OneDrive から blob に資料をコピー (Logic Apps)
OneDrive など、普段資料を保存しているサービスと本アプリを連携するための処理です。OneDrive に保存に資料を保存すると、それをトリガーとして blob にコピーします。OneDrive だけでなく、SharePoint や Teams、そのほか Logic Apps が連携する様々なファイルサービスも利用できます。ただし、直接 blob にファイルを保存できる場合は、この処理は不要です。
下図は OneDrive のフォルダにファイルの保存イメージです。４つの pdf ファイルを保存しています。それぞれ私が以前に執筆した[学会発表内容](https://ipsj.ixsq.nii.ac.jp/ej/?action=repository_uri&item_id=169510&file_id=1&file_no=1)などです。
![onedrive.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255074/fb0048b3-16e3-ee5d-25e3-f0acd13b10a3.png)

### blob 資料からテキストを抽出して CosmosDB に保存 (Functions, Form Recognizer)
blob に資料がコピーされると、資料の形式を Form Recognizer で認識してテキストを抽出して CosmosDB に保存します。資料のテキスト全文が抽出できますので、これにより直接資料ファイルを参照せずに CosmosDB から参照可能となります。ただし、膨大なテキストを含む資料の場合、この後の処理で ChatGPT に全文を渡して処理するためにトークン制限によるエラーとなる可能性があります。なお、Form Recognizer のフリープランを用いた場合、pdf は最初の２ページのみが読み取られますので、トークン制限を考慮するとちょうど良いかもしれません。
下図が抽出されたテキストが CosmosDB のアイテムとして保存されているイメージです。content プロパティに抽出したテキストが保存されています。id プロパティがファイル名です。
![cosmosdb_content.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255074/b0c19ebd-8900-e9e1-a4e5-98c056ba08d8.png)

### ChatGPT によって　CosmosDB の資料テキストからインサイトを抽出 (Functions, OpenAI)
CosmosDB に保存された資料テキストから、事前定義されたシステムメッセージで ChatGPT によって資料のインサイトを抽出して CosmosDB の資料情報に追加します。事前定義済みのシステムメッセージは環境変数により Azure Functions に設定可能であり、いつでもカスタマイズできます。今回の例では次のメッセージが設定されており、ChatGPT で資料のタイトルと３つのポイントを抽出するようにしています。
```「タイトルを抽出し'Title: <タイトル>'で出力。日本語で3つの各観点とそのまとめを'point<n>:<まとめ>'で出力」```
抽出したインサイトは下記のように、CosmosDB のアイテムの openai プロパティに保存されます。
```
"openai": "Title: Linux 稼動中パッチ方式の開発\n\npoint1: Linuxのオープン・ソース・ソフトウェアは、バグやセキュリティホールに対する迅速な対応が可能でシステムの安全性を高く保つことが期待できる。\npoint2: カーネル更新には頻繁に発行される修正パッチの速やかな適用が不可欠だが、カーネルに対するパッチ適用にはシステムリブートを伴うため、頻繁な実施はシステムのダウンタイム増大を招くことになる。\npoint3: 稼動中パッチ方式では、実行中のカーネルに動的にオブジェクトを追加し、古いコードが提供する機能を呼び出したときに新しいコードを呼び出すようにすることで、ダウンタイムを増大せずにカーネル更新を実現する。稼動中パッチ方式のプロトタイプにより、原理的な動作確認が行われ、本方式の有効性が確認された。"
```

## Document Insight Warehouse データベース
### ChatGPT によって作成されたインサイトとともに資料情報を DB に格納 (Cosmos DB)

Document Insight Warehouse の本体は CosmosDB のデータベースです。トリガー処理で説明した通り、資料に関する必要な情報として、資料のファイル名、テキスト全文、ChatGPT により事前作成されたインサイトは、それぞれ id、context、openai のプロバティに保存されています。これにより、資料ファイルに直接アクセスしなくても、本データベースの内容で資料の活用が可能となります。また、活用時にも資料全文だけでなく、ChatGPT により要約されたインサイトを参照できるため、迅速に必要な資料を探し出すことができます。
下記に CosmosDB のアイテムの例を示します。
```
{
    "id": "doc1.pdf",
    "_rid": "LgxaAOITw4NaAAAAAAAAAA==",
    "_self": "dbs/LgxaAA==/colls/LgxaAOITw4M=/docs/LgxaAOITw4NaAAAAAAAAAA==/",
    "_etag": "\"09009461-0000-2300-0000-645515290000\"",
    "content": "6D-7\n情報処理学会第66回全国大会\nLinux 稼動中パッ チ方式の開発1\n畑崎恵介 株)日立製作所中央研究所\n(\n1.はじめに\nLinuxは低コスト\nのOSとし て急速にシェアを 拡大し ており 、 企業基幹業務における採用のニーズも高ま っている。\nLinuxのよう なオープン・ソース・ソフト ウェアは、ソー スコードと開発形態の透明性から 、 バグ やセキュリテ ィホールに対する迅速な対応が可能でシステムの安 全性を高く保つこと が期待できる。その半面、安全性 確保には頻繁に発行される修正パッチの速やかな適 用が不可欠である。し かし 、 カーネルに対するパッチ 適用にはシステムリブート を伴う ため、頻繁な実施は システムのダウンタイム増大を 招くことになる。 本稿では、ダウンタイムを増大せずにカーネル更新 を実現する、パッチ適用方式を提案する。\n2.パッチ適用における課題\nバグ やセキュリティホールに対処するためのカーネ ル更新には大きく二つ方法がある。一つは実行形式 のカーネルの一部を書き直す形でパッチを適用する\n方法、もう 一つはカーネルのソース自体を修正し て新\n規リビジョンとし てカーネルを作成し 直す方法である。 これら方法は、後者はもちろん前者でも更新後のカ ー ネルを利用するために、一部システムを除いて、シ ステムのリブート が一般的である。リ\nを必要とすること\nブート 中のサービスの中断を防ぐためには、システム を二重化することが考えられる。その場合、片系のリ ブート 中に他方によるサービスの継続が可能である\nが、コスト の上昇や、システムの複雑化等が問題とな る可能性がある。\n上記を踏まえ、ここではリブート 不要のカーネルパ\nッチ適用を実現する 稼動中パッチ方式の実現を課題 とし て取り 組む。\n3.稼動中パッチ方式の概要\n稼動中パッチ方式では、実行中のカーネルに動的\nにオブジェクト を追加し 、 かつ、古いコード が提供す\nる機能を呼び出し\nたときに新し\nいコード を呼び出すよ\nう にする必要がある。\nDevelopment of LINUX Dynamic Patch Application Method Keisuke Hatasaki\nHITACHI, Ltd.\n従って、稼動中パッチ方式は、次の項目を実現す ること が不可欠である。\n(a)オブジェクト コード の動的な追加\n(b)新規コード 呼び出しに必要な命令列書き換え のアトミック 性保証\n(c)新旧コード の関係付け\n以下、本稼動中パッチ方式について、上記項目へ の対応方針を示す。\n3.1オブジェクトコードの動的な追加\nカーネルへの動的な新規オブジェクト コード 追加の ために、Linuxのモジュール機能を利用する。モジュ ー ル機能の利用により 動的なパッチ適用の際、実 、\n行中のカーネルに矛盾なく新規オブジェクト コード\nを 追加することができる。パッチをモジュールとして作 成するため、稼動中パッチ方式では関数単位の書き\n換えを行う 。 つまり 、 パッチを当てる箇所を含む関数 を作成し 、 それをカーネルに組み込む。\n稼動中パッチ用モジュールは、次の手順で作成し 、\nカーネルに組み込む。\n(1)パッチを適用すべき 個所を含む古い関数(パッ チ適用先の関数)を元に、パッチを適用し た新\nし い関数を作成。\n(2)モジュールとし\nてカーネルに組み込める形式で、\n新し い関数からオブジェクトファイル(稼動中パ\nッチ用モジュール)を作成。\n(3)作成し た稼動中パッチ用モジュールを、モジュ ール組み込みプログラムであるinsmodを使っ\nてカーネルに組み込み。\nなお、モジュールを組み込む場合、モジュールのオ ブジェクト からモジュール組み込み先カーネル内の グローバル・カーネル・シンボル(変数および関数)に 対する参照を解決するために対象となるシンボルは エク スポート されていなければならない。\n3.2命令列書き換えのアトミック性保証\n稼動中パッチ実現のためには、古い関数を実行す る代わりに、組み込んだモジュール内の新しい関数 を実行するようにする必要がある。古い関数の代わり に新し い関数が実行されるようにするためには、古い\nの先頭部分を書き 換えて、何ら 関数のバイナリコード\nかの方法(分岐命令やト ラップ 命令など )でモジュール 内の新しい関数を呼ぶようにすればよい。ただし 、 こ の書き換えは、少なくとも書き換え対象部分をちょう\n1−53\nどCPUが実行中であった場合や、書き換え中に CPUが対象部分を実行しようとし た場合に不整合が\n生じないようにしなくてはならない。従って、書き はアトミックに行う 必要がある。\n換え\nアトミック 性を確保するためには、例えばCPUの最 小命令語長で分岐処理を実現できる命令へ書き換 える方法や、同期点を用意し て書き換えが完了する までその先に進まないようにする方法など が考えら れ る。\n3.3新旧コードの対応付け\n古い関数が呼ばれた場合に新しい関数を呼び出 すようにするために、古い関数と 新しい関数の対応 付けを管理することが必要である。このため、カーネ ルには、古い関数のアドレスと 新しい関数のアドレス 古い関数への呼び出し があ\nを記録しておく機構と 、\nった場合に新し い関数を呼び出す機構をあらかじめ\n静的に組み込んでおく。こ れらの機構により 、 稼動中 パッチ用モジュールをカーネルに組み込むときに、 指定された古い関数のアドレスを用いて新旧関数の 対応付けを行う\n。\n4.稼動中パッチ方式プロトタイプ\n以上考察に基づき、次のような前提で稼動中パッ チ方式のプロト タイプを作成し た。プロト タイプの目的\nは稼動中パッチ方式の原理的な動作確認である。\n・ i386アーキテクチャで実装する。\n・ 新規コード アトミック 呼び出しに必要な命令列書き換えの 性保証には、int3命令によるソフト ウェア\n割り 込みを利用する(int3命令は1Byte長で、 1cycleでアトミックに書き 換え可能なため)。 SMPによる関数の同時実行を許すが、稼動中パ ッチ適用の同期点は実装しない。従って、稼動 中パッチ適用の前後における新旧関数実行結 果の影響が、グローバルにはないものと する。\n・\nプロト タイプの概要を図1に示す。具体的な手順は 次のよう になる。\n(1)作成し た稼動中パッチ用モジュールをinsmod プログラムによりカーネルに組み込み。\n(2) insmod実行に伴う より\nモジュールの初期化処理に 、 モジュール内の稼動中パッチ登録関数が 呼ばれ、新旧関数の対応表に新し 録。 い関数を登\n(3) (2)と同様にモジュールの初期化処理で、古い 関数のテキスト の先頭にint3命令を挿入\n(4)古い関数が呼ばれたとき、int3命令によってソ フトウェア割り 込み発生。ソフトウェア割り 込み ハンドラは、新旧関数の対応表を参照して古\nい関数からのint3割り 込みであることを検知し\n、\n割り 込みの戻りアドレスであるスタックのインスト ラクションポインタの値を登録されている新し い カーネル関数の先頭アドレスに変更。\n本プロト タイプで、システム稼動中にカーネルパッ チを適用可能なこと が実証でき、本方式の有効性を た。\n確認し\n●ﾓｼﾞｭｰﾙｲﾝｽﾄｰﾙ時\n●実行時\nカーネル\n古い関数\nカーネル\n(3)int3命令に 書き 換え\n(4)ｿﾌﾄｳｪｱ 割り 込み\n古い関数\nxxx\nint3\nint3\nyyy\n(2)新旧関数 の対応表 への登録\nyyy\nzzz\nzzz\nハンド\nラ\nハンド\nラ do_int3()\ndo_int3()\n稼動中パッ チ用 モジュール\n稼動中パッ チ用\nモジュール\n1\n1\n新し い関数 (1)ﾓｼﾞｭｰﾙの 組み込み\n新し い関数\n図1.稼動中パッ チ方式プロト タ イプ の概要\n5. まとめ\nリブート 不要で動的なカーネル更新を実現すること を目的とした稼動中パッチ方式について検討した。 検討結果に基づくプロト タイピングにより 原理的な動 作テスト を行い、本方式の有効性を確認した。本方\n式により 、\nLinuxのオープン・ソース・ソフト\nウェアとし て の透明性と品質の高さという 利点を保ちつつ、ダウン\nタイムを増大し ないカーネル更新が可能になる。\n一方、本方式はプロト タイプ段階であり 、 実際に適 用するにはいくつかの課題がある。今後、本稼動中 パッチ方式の実運用への適用に向け、次のよう\n題に取り 組んでいく。 な課\n・ 稼動中パッチ方式における命令書き換え同期点 の実装。\n・ 実際に配布されているパッチの分析による パッチ適用可否の検証。\n稼動中\n・ 通常のパッチを含めたパッチの依存関係管理の 実現。\n1−54",
    "_lsn": 406,
    "openai": "Title: Linux 稼動中パッチ方式の開発\n\npoint1: Linuxのオープン・ソース・ソフトウェアは、バグやセキュリティホールに対する迅速な対応が可能でシステムの安全性を高く保つことが期待できる。\npoint2: カーネル更新には頻繁に発行される修正パッチの速やかな適用が不可欠だが、カーネルに対するパッチ適用にはシステムリブートを伴うため、頻繁な実施はシステムのダウンタイム増大を招くことになる。\npoint3: 稼動中パッチ方式では、実行中のカーネルに動的にオブジェクトを追加し、古いコードが提供する機能を呼び出したときに新しいコードを呼び出すようにすることで、ダウンタイムを増大せずにカーネル更新を実現する。稼動中パッチ方式のプロトタイプにより、原理的な動作確認が行われ、本方式の有効性が確認された。",
    "_attachments": "attachments/",
    "_ts": 1683297577
}
```

## フロントエンド処理
ユーザが資料を活用するための処理部分です。

### シングルページアプリの資料活用ポータルにユーザーがアクセス (Static Web Apps)
Static Web Apps でシングルページアプリがホスティングされており、ユーザがクライアントからブラウザでアプリの URL にアクセスすると、Azure Active Directory (AzureAD) による認証を要求します。ログインに成功すると、下記のポータル画面が表示されます。
![oaiportal.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255074/15512a23-544d-97da-ca1a-2e40f153b71b.png)

### 資料検索 API を使用してキーワードでドキュメントを検索 (Functions)
ポータルの検索ボックスにキーワードを入力して「検索実行」ボタンをクリックすると、該当するキーワードを含む資料の一覧が表示されます。完全一致検索になっています。検索では、資料テキスト本文だけでなく、ChatGPT が作成したインサイトからも検索できます。また、結果一覧の Summary にも ChatGPT が作成したインサイトが表示されますので、素早く必要な資料を探し出すことができます。
下記は検索結果の例です。より詳細に分析したい場合、表示された資料のうち詳細分析を実施したい資料の右側のチェックボックスにチェックを入れて、右上の「詳細」ボタンをクリックすると、詳細分析画面に移動します。複数の資料を選択して詳細分析を実施することもできます。
![oaisearchresult.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255074/8f279518-2192-b1d8-4e5a-7d80a9914fec.png)

### 資料クエリ API で選択した資料を ChatGPT で詳細分析 (Functions, OpenAI)
ポータルの詳細画面にて、検索結果で選択した資料に対する質問を ChatGPT に渡して資料を詳細分析できます。自由な質問を質問内容ボックスに入力して「質問」ボタンをクリックすることで、ChatGPT により該当資料に基づく質問回答を作成して、画面に結果が表示されます。同じ資料に対して何度も質問を入力し直して実行することが可能です。ChatGPTには、選択した資料のテキスト全文と質問内容が渡されるため、資料内容を詳細に分析できます。資料を複数選択している場合は、全ての資料が ChatGPT に渡されます。ただし、多数の資料を選択すると ChatGPT のトークン上限によりエラーとなる可能性もあるため、注意が必要です。
下記は詳細分析画面で質問を実施した例になります。
![oaiquery.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255074/248dfc53-af6c-dc2f-9509-ad47e7b08f1b.png)

# その他ポイント
* From Recognizer は様々なファイル形式に対応していますので、pdf だけでなく 資料の写真なども利用できます。一方で非対応にファイル形式ではうまく動作しない場合もありますので、対応状況を確認して下さい 
[Azure Form Recognizer レイアウト モデル](https://learn.microsoft.com/ja-jp/azure/applied-ai-services/form-recognizer/concept-layout?view=form-recog-3.0.0#input-requirements)
* OpenAI のモデルによってトークンの上限や分析内容も変化しますので、分析可能なドキュメント規模やインサイトの作成に利用するシステムメッセージのチューニングなどが必要な場合があります
* OpenAI 社の提供する API を利用することも可能です。必要な環境変数の設定に変更して下さい

# さいごに
本記事では、組織や個人が保持する様々な資料を ChatGPT に活用するアプリについてご紹介しました。Document Insight Warehouse をコンセプトに、事前にデータベースに必要な情報を蓄積しておき、必要な資料を素早く探し出して詳細分析できる特徴を備えています。とはいえ、あくまでサンプルアプリであり、実際に活用するにはまだまだ多くの部分で改良が必要と思います。しかし、本アプリが皆様が ChatGPT を活用する際に少しでも参考になればありがたいです。