From aa7eb9d99fbde4f5fe8e281232b59b9141177946 Mon Sep 17 00:00:00 2001 From: altair823 Date: Sun, 10 May 2026 14:16:58 +0900 Subject: [PATCH] =?UTF-8?q?perf(v032):=20AiWorker=20per-tag=20emit=20Promi?= =?UTF-8?q?se.all=20=EB=B3=91=EB=A0=AC=ED=99=94=20(#32)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 기존 serial for-await: 3 태그 → 3 round-trip file-append. Promise.all: 동일 결과, file-append 동시 실행 (telemetry 파일은 append-only, 순서 의존 단위 0). Co-Authored-By: Claude Opus 4.7 (1M context) --- src/main/ai/AiWorker.ts | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/main/ai/AiWorker.ts b/src/main/ai/AiWorker.ts index ecf47c3..ae4306d 100644 --- a/src/main/ai/AiWorker.ts +++ b/src/main/ai/AiWorker.ts @@ -187,22 +187,24 @@ export class AiWorker { // v0.2.3 #3 — per-tag vocab hit/miss 분류 (updateAiResult 후 → tagId 보장) // dedup: AI 응답에 같은 태그 중복 가능 — INSERT OR IGNORE 와 정합한 1-emit/태그 보장 const vocabSet = new Set(vocab.map((v) => v.toLowerCase())); - for (const tagName of new Set(res.tags)) { - if (vocabSet.has(tagName.toLowerCase())) { - const tagId = this.repo.getTagIdByName(tagName); - if (tagId !== null) { + await Promise.all( + Array.from(new Set(res.tags)).map(async (tagName) => { + if (vocabSet.has(tagName.toLowerCase())) { + const tagId = this.repo.getTagIdByName(tagName); + if (tagId !== null) { + await this.telemetry.emit({ + kind: 'tag_vocab_hit', + payload: { tagId, vocabSize: vocab.length } + }).catch(() => {}); + } + } else { await this.telemetry.emit({ - kind: 'tag_vocab_hit', - payload: { tagId, vocabSize: vocab.length } + kind: 'tag_vocab_miss', + payload: { vocabSize: vocab.length } }).catch(() => {}); } - } else { - await this.telemetry.emit({ - kind: 'tag_vocab_miss', - payload: { vocabSize: vocab.length } - }).catch(() => {}); - } - } + }) + ); } this.emit(job.noteId); return;