|
|
@@ -10,19 +10,19 @@ import { EditorAssistantDiffSchema } from './schema';
|
|
|
|
|
|
const logger = loggerFactory('growi:routes:apiv3:openai:edit:editor-stream-processor');
|
|
|
|
|
|
-// 型定義
|
|
|
+// Type definitions
|
|
|
type EditorAssistantMessage = z.infer<typeof EditorAssistantMessageSchema>;
|
|
|
type EditorAssistantDiff = z.infer<typeof EditorAssistantDiffSchema>;
|
|
|
|
|
|
/**
|
|
|
- * 型ガード: メッセージ型かどうかを判定する
|
|
|
+ * Type guard: Check if item is a message type
|
|
|
*/
|
|
|
const isMessageItem = (item: unknown): item is EditorAssistantMessage => {
|
|
|
return typeof item === 'object' && item !== null && 'message' in item;
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
- * 型ガード: 差分型かどうかを判定する
|
|
|
+ * Type guard: Check if item is a diff type
|
|
|
*/
|
|
|
const isDiffItem = (item: unknown): item is EditorAssistantDiff => {
|
|
|
return typeof item === 'object' && item !== null
|
|
|
@@ -30,23 +30,23 @@ const isDiffItem = (item: unknown): item is EditorAssistantDiff => {
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
- * EditorAssistant用のストリームデータプロセッサ
|
|
|
- * JSONストリームから編集用のメッセージと差分を抽出する
|
|
|
+ * Editor Stream Processor
|
|
|
+ * Extracts messages and diffs from JSON stream for editor
|
|
|
*/
|
|
|
export class EditorStreamProcessor {
|
|
|
|
|
|
- // 最終応答データ
|
|
|
+ // Final response data
|
|
|
private message: string | null = null;
|
|
|
|
|
|
private replacements: EditorAssistantDiff[] = [];
|
|
|
|
|
|
- // 前回のコンテンツの最終要素のインデックス
|
|
|
+ // Index of the last element in previous content
|
|
|
private lastContentIndex = -1;
|
|
|
|
|
|
- // 最後に送信した差分インデックス
|
|
|
+ // Last sent diff index
|
|
|
private lastSentDiffIndex = -1;
|
|
|
|
|
|
- // 送信済みの差分キー
|
|
|
+ // Set of sent diff keys
|
|
|
private sentDiffKeys = new Set<string>();
|
|
|
|
|
|
constructor(private sseHelper: SseHelper) {
|
|
|
@@ -54,8 +54,8 @@ export class EditorStreamProcessor {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * JSONデータを処理する
|
|
|
- * @param jsonString JSON文字列
|
|
|
+ * Process JSON data
|
|
|
+ * @param jsonString JSON string
|
|
|
*/
|
|
|
process(jsonString: string): void {
|
|
|
try {
|
|
|
@@ -65,10 +65,10 @@ export class EditorStreamProcessor {
|
|
|
if (parsedJson?.contents && Array.isArray(parsedJson.contents)) {
|
|
|
const contents = parsedJson.contents;
|
|
|
|
|
|
- // 現在のコンテンツの最終要素のインデックス
|
|
|
+ // Index of the last element in current content
|
|
|
const currentContentIndex = contents.length - 1;
|
|
|
|
|
|
- // メッセージの処理
|
|
|
+ // Process message
|
|
|
let messageUpdated = false;
|
|
|
for (let i = contents.length - 1; i >= 0; i--) {
|
|
|
const item = contents[i];
|
|
|
@@ -81,11 +81,11 @@ export class EditorStreamProcessor {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 差分の処理
|
|
|
+ // Process diffs
|
|
|
let diffUpdated = false;
|
|
|
let processedDiffIndex = -1;
|
|
|
|
|
|
- // 差分が含まれているか確認
|
|
|
+ // Check if diffs are included
|
|
|
for (let i = 0; i < contents.length; i++) {
|
|
|
const item = contents[i];
|
|
|
if (!isDiffItem(item)) continue;
|
|
|
@@ -96,11 +96,11 @@ export class EditorStreamProcessor {
|
|
|
const diff = validDiff.data;
|
|
|
const key = this.getDiffKey(diff);
|
|
|
|
|
|
- // この差分がすでに送信済みかチェック
|
|
|
+ // Check if this diff has already been sent
|
|
|
if (this.sentDiffKeys.has(key)) continue;
|
|
|
|
|
|
- // 最終要素が変わった場合、または最後から2番目以前の要素の場合
|
|
|
- // → 差分が完成したと判断
|
|
|
+ // If the last element has changed, or if this is not the last element
|
|
|
+ // → Consider the diff as finalized
|
|
|
if (i < currentContentIndex || currentContentIndex > this.lastContentIndex) {
|
|
|
this.replacements.push(diff);
|
|
|
this.sentDiffKeys.add(key);
|
|
|
@@ -109,29 +109,29 @@ export class EditorStreamProcessor {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 最終インデックスを更新
|
|
|
+ // Update last index
|
|
|
this.lastContentIndex = currentContentIndex;
|
|
|
|
|
|
- // 更新通知
|
|
|
+ // Send notifications
|
|
|
if (messageUpdated) {
|
|
|
- // メッセージは更新されたらすぐに通知
|
|
|
+ // Notify immediately if message is updated
|
|
|
this.notifyClient();
|
|
|
}
|
|
|
else if (diffUpdated && processedDiffIndex > this.lastSentDiffIndex) {
|
|
|
- // 差分は新しいインデックスの差分が確定した場合のみ通知
|
|
|
+ // For diffs, only notify if a new index diff is confirmed
|
|
|
this.lastSentDiffIndex = processedDiffIndex;
|
|
|
this.notifyClient();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
catch (e) {
|
|
|
- // パースエラーは無視(不完全なJSONなので)
|
|
|
+ // Ignore parse errors (expected for incomplete JSON)
|
|
|
logger.debug('JSON parsing error (expected for partial data):', e);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 差分の一意キーを生成
|
|
|
+ * Generate unique key for a diff
|
|
|
*/
|
|
|
private getDiffKey(diff: EditorAssistantDiff): string {
|
|
|
if ('insert' in diff) return `insert-${diff.insert}`;
|
|
|
@@ -141,7 +141,7 @@ export class EditorStreamProcessor {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * クライアントに通知
|
|
|
+ * Notify the client
|
|
|
*/
|
|
|
private notifyClient(): void {
|
|
|
this.sseHelper.writeData({
|
|
|
@@ -153,18 +153,18 @@ export class EditorStreamProcessor {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 最終結果を送信
|
|
|
+ * Send final result
|
|
|
*/
|
|
|
sendFinalResult(rawBuffer: string): void {
|
|
|
try {
|
|
|
const repairedJson = jsonrepair(rawBuffer);
|
|
|
const parsedJson = JSON.parse(repairedJson);
|
|
|
|
|
|
- // 最後のデータから全ての差分を取得
|
|
|
+ // Get all diffs from the final data
|
|
|
if (parsedJson?.contents && Array.isArray(parsedJson.contents)) {
|
|
|
const contents = parsedJson.contents;
|
|
|
|
|
|
- // 未送信の差分があれば追加
|
|
|
+ // Add any unsent diffs
|
|
|
for (const item of contents) {
|
|
|
if (!isDiffItem(item)) continue;
|
|
|
|
|
|
@@ -174,7 +174,7 @@ export class EditorStreamProcessor {
|
|
|
const diff = validDiff.data;
|
|
|
const key = this.getDiffKey(diff);
|
|
|
|
|
|
- // まだ送信していない差分を追加
|
|
|
+ // Add any diffs that haven't been sent yet
|
|
|
if (!this.sentDiffKeys.has(key)) {
|
|
|
this.replacements.push(diff);
|
|
|
this.sentDiffKeys.add(key);
|
|
|
@@ -182,7 +182,7 @@ export class EditorStreamProcessor {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 最終通知(isDoneフラグ付き)
|
|
|
+ // Final notification (with isDone flag)
|
|
|
this.sseHelper.writeData({
|
|
|
editorResponse: {
|
|
|
message: this.message || '',
|
|
|
@@ -194,7 +194,7 @@ export class EditorStreamProcessor {
|
|
|
catch (e) {
|
|
|
logger.debug('Failed to parse final JSON response:', e);
|
|
|
|
|
|
- // エラー時も最終通知
|
|
|
+ // Send final notification even on error
|
|
|
this.sseHelper.writeData({
|
|
|
editorResponse: {
|
|
|
message: this.message || '',
|
|
|
@@ -206,7 +206,7 @@ export class EditorStreamProcessor {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * リソースを解放
|
|
|
+ * Release resources
|
|
|
*/
|
|
|
destroy(): void {
|
|
|
this.message = null;
|