|
|
@@ -0,0 +1,126 @@
|
|
|
+# Editor Assistant API 実装解説
|
|
|
+
|
|
|
+## 要求仕様
|
|
|
+
|
|
|
+Editor Assistant API は、OpenAI AssistantAPI を使用して、マークダウンエディタの編集をサポートする機能です。主な要件は以下の通りです:
|
|
|
+
|
|
|
+1. **ストリーミング処理**:
|
|
|
+ - OpenAI からの応答をストリーミングで受け取り、Server-Sent Events (SSE) でクライアントにリアルタイムに転送
|
|
|
+ - JSON データを適切なタイミングで解析し、クライアントに送信
|
|
|
+
|
|
|
+2. **データ形式**:
|
|
|
+ - 応答は `EditorAssistantResponseSchema` に準拠した JSON 形式
|
|
|
+ - `contents` 配列内に `{ message: "..." }` と delta 形式の差分情報(`insert`, `delete`, `retain`)を含む
|
|
|
+
|
|
|
+3. **エラーハンドリング**:
|
|
|
+ - 不完全な JSON データの処理時のエラーを適切に処理
|
|
|
+ - リソースリークの防止
|
|
|
+
|
|
|
+4. **効率性**:
|
|
|
+ - メモリ使用量を最小限に抑える
|
|
|
+ - 不要な通信を避け、クライアントへの適切なタイミングでのデータ送信を実現
|
|
|
+
|
|
|
+## 重要なインプット
|
|
|
+
|
|
|
+### 実装時に参照したコード
|
|
|
+
|
|
|
+1. **jsonrepair ライブラリ**:
|
|
|
+ - 壊れた JSON や不完全な JSON を修復するライブラリ
|
|
|
+ - 特に部分的なストリーミング JSON の処理に有効
|
|
|
+
|
|
|
+2. **型定義**:
|
|
|
+ - `message-error.ts`: エラー型と定義
|
|
|
+ - `schema.ts`: エディタアシスタントのメッセージと差分の Zod スキーマ定義
|
|
|
+
|
|
|
+### 今後のリファクタリングに重要なインプット
|
|
|
+
|
|
|
+1. **OpenAI API の仕様変更**:
|
|
|
+ - AssistantAPI のレスポンス形式の変更に注意
|
|
|
+
|
|
|
+2. **jsonrepair のアップデート**:
|
|
|
+ - 新バージョンでの API 変更や最適化手法の変更を確認
|
|
|
+
|
|
|
+3. **パフォーマンス監視**:
|
|
|
+ - メモリ使用量と処理時間のモニタリング
|
|
|
+ - 大規模 JSON 処理時のボトルネック特定
|
|
|
+
|
|
|
+## 実装のポイント
|
|
|
+
|
|
|
+### 1. jsonrepair による JSON 修復
|
|
|
+- ストリーミングされる不完全な JSON データを処理するために jsonrepair を使用
|
|
|
+- 部分的に届く JSON フラグメントを修復して有効な JSON に変換
|
|
|
+
|
|
|
+### 2. EditorStreamProcessor の実装
|
|
|
+- 生のテキストストリームを処理し、完全な JSON オブジェクトに変換する専用クラス
|
|
|
+- データ処理の最適化とメモリ効率:
|
|
|
+ - 差分データの重複送信を防ぐためのキーベースの追跡システム(`sentDiffKeys` Set)
|
|
|
+ - 型安全性を確保するための Zod スキーマによるバリデーション
|
|
|
+ - 無駄な通信を減らすための差分更新検出と通知タイミングの最適化
|
|
|
+- インテリジェントな差分処理:
|
|
|
+ - メッセージ(message)と差分(diff)の処理ロジックを分離:
|
|
|
+ - メッセージ処理: 最新のメッセージのみを保持し、メッセージが変更された場合は即座に通知。冗長なメッセージ更新を防ぎつつ、ユーザーに迅速にフィードバックを提供。
|
|
|
+ - 差分処理: 各差分データに一意のキーを割り当て(`getDiffKey` メソッド)、重複処理を防止。差分のコンテキストを保持するため配列形式で蓄積。
|
|
|
+ - ストリーム中の差分の「確定状態」を判定:
|
|
|
+ - `lastContentIndex` を活用して最新コンテンツの境界を追跡
|
|
|
+ - 最終要素より前の差分データは「確定」と判断し、即座に送信
|
|
|
+ - 最終要素(現在編集中の可能性がある要素)は「未確定」と判断し、変更が安定するまで送信を保留
|
|
|
+ - 型ガード関数による適切な処理の振り分け:
|
|
|
+ - `isMessageItem`: オブジェクトが説明メッセージかを判定
|
|
|
+ - `isDiffItem`: オブジェクトが差分データ(insert/delete/retain)かを判定
|
|
|
+ - 差分の完成度判定ロジック:
|
|
|
+ - コンテンツ配列内の位置に基づく判定(前方の要素ほど安定している可能性が高い)
|
|
|
+ - 最終インデックスの変化を検出して確定状態を判断(インデックスが進んだ = 前の要素は確定)
|
|
|
+- リソース管理:
|
|
|
+ - クライアント通信終了時のクリーンアップ処理(`destroy` メソッド)
|
|
|
+ - 一時データの格納と最終結果での統合処理
|
|
|
+
|
|
|
+### 3. ストリーミング応答処理
|
|
|
+- SSE フォーマット(Server-Sent Events)を使用したリアルタイム通信
|
|
|
+- 非同期ストリーミング処理と適切なエラーハンドリング
|
|
|
+- クライアント切断時のリソース解放機構
|
|
|
+
|
|
|
+### 4. Assistant API 統合
|
|
|
+- OpenAI Assistant API を使用したエディタアシスタントの生成
|
|
|
+- スレッド管理とメッセージ処理
|
|
|
+- カスタムレスポンス形式の指定(Zod スキーマによる型安全な応答)
|
|
|
+
|
|
|
+### 5. 差分情報の処理
|
|
|
+- クォーターエディタの Delta 形式(insert, delete, retain)に対応
|
|
|
+- 差分情報とメッセージの混合コンテンツ処理
|
|
|
+- メッセージデルタのハンドリングとアノテーション処理
|
|
|
+- 差分の重複処理防止のためのユニーク識別子生成(`getDiffKey` メソッド)
|
|
|
+
|
|
|
+### 6. エラー処理とリソース管理
|
|
|
+- ストリーム処理中のエラーを適切に捕捉し、クライアントに通知
|
|
|
+- クリーンアップ処理によるメモリリークの防止
|
|
|
+- クライアント切断やサーバーエラー時の適切なリソース解放
|
|
|
+- 不完全なJSON解析エラーのサイレント処理(対象ログレベルを debug に設定)
|
|
|
+
|
|
|
+### 7. 応答形式の標準化
|
|
|
+- エディタアシスタントの一貫した応答形式の保証:
|
|
|
+ - メッセージと差分データを分離した構造
|
|
|
+ - クライアントがリアルタイムに処理できるフォーマットでの送信
|
|
|
+ - 処理完了を示す `isDone` フラグによる明示的な終了通知
|
|
|
+- コンテキストに基づいた適切な指示による高品質な応答生成
|
|
|
+- 複数言語対応(ユーザーの言語に合わせた応答)
|
|
|
+
|
|
|
+### 8. 差分データの段階的送信
|
|
|
+- ストリームから受信した差分データを確定状態と未確定状態に分類:
|
|
|
+ - 最終インデックスより前の要素、または最終コンテンツが変更された場合は「確定」と判断
|
|
|
+ - 変化しやすい現在の最終要素は「未確定」と判断し送信を保留
|
|
|
+ - この方法により、継続的に変化している最新の差分による不必要な更新通知を抑制
|
|
|
+- 差分の安定性の判断基準:
|
|
|
+ - OpenAI からのストリームでは、通常前方から順に差分が確定していくため、配列内の位置を基準に判定
|
|
|
+ - 新たな要素が追加された場合(`currentContentIndex > this.lastContentIndex`)、以前の要素は確定と見なす
|
|
|
+ - 最終要素は OpenAI が生成中の可能性が高いため、処理完了まで確定を遅延させる
|
|
|
+- 効率的な更新通知の実装:
|
|
|
+ - メッセージはリアルタイムで更新通知(ユーザーへの説明は即時性が重要)
|
|
|
+ - 差分データは新たに確定したものがある場合のみ通知(エディタの頻繁な更新を避ける)
|
|
|
+ - 処理終了時に最終確認として未送信の差分も含めた完全な結果を送信(`sendFinalResult` メソッド)
|
|
|
+ - `processedDiffIndex` と `lastSentDiffIndex` を比較して、新しい確定差分がある場合のみ更新通知
|
|
|
+
|
|
|
+### 9. 型安全性の確保
|
|
|
+- Zod スキーマを用いた厳格な型チェックと変換
|
|
|
+- TypeScript の型ガード関数による実行時型安全性の確保
|
|
|
+- エッジケース処理(不完全データ、無効な差分など)の堅牢な実装
|
|
|
+
|