From b2be29bd335fb49991e8f0c89154540d4a5c0f3c Mon Sep 17 00:00:00 2001
From: th-kim0823
Date: Tue, 12 May 2026 14:15:18 +0900
Subject: [PATCH] =?UTF-8?q?fix(vision):=20=EB=B3=B8=EB=AC=B8=20=EB=B9=88?=
=?UTF-8?q?=20=EC=BC=80=EC=9D=B4=EC=8A=A4=20prompt=20=EA=B0=95=ED=99=94=20?=
=?UTF-8?q?=E2=80=94=20null=20title/summary=20=ED=9A=8C=EA=B7=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
gemma4:26b 가 본문 없이 이미지만 있을 때 title=null/summary=null 반환.
prompt 가 "(이미지만 있음)" 만 던지는 게 신호 약함. 본문 비었으면
이미지 내용으로 한국어 채우라고 명시 + "null 반환 금지" 규칙 추가.
Co-Authored-By: Claude Opus 4.7 (1M context)
---
src/main/ai/visionPrompt.ts | 21 +++++++++++++--------
tests/unit/visionPrompt.test.ts | 13 ++++++++++---
2 files changed, 23 insertions(+), 11 deletions(-)
diff --git a/src/main/ai/visionPrompt.ts b/src/main/ai/visionPrompt.ts
index 7a93989..1eb9b8b 100644
--- a/src/main/ai/visionPrompt.ts
+++ b/src/main/ai/visionPrompt.ts
@@ -7,16 +7,21 @@ export function buildVisionPrompt(
// v0.3.11 — vision model 이 'format:json' constraint 를 부분적으로만 따르는 경우가
// 잦음 (특히 gemma3 vision). title 한국어 + JSON only 를 prompt 에서 명시 강조,
// markdown fence 금지 표기로 schema parse 통과율 개선.
- return `다음 메모와 첨부 이미지를 종합 분석해 한국어로 요약하세요.
+ // 본문 비었으면 이미지만 보고 title/summary 채우도록 명시. 그냥 "(이미지만 있음)" 만
+ // 던지면 모델이 null 반환 (gemma4:26b 확인). 본문 있으면 본문 우선, 없으면 이미지 묘사.
+ const bodySection = text
+ ? `메모 본문:\n${text}\n\n첨부 이미지도 함께 분석해 요약에 반영하세요.`
+ : `본문이 없으니 첨부 이미지의 내용 (텍스트/사람/장면/문서 등) 을 보고 title 과 summary 를 한국어로 작성하세요. null 반환 금지.`;
-메모 본문 (비어 있을 수 있음):
-${text || '(이미지만 있음)'}
+ return `다음 메모를 한국어로 분석해 JSON 으로 정리하세요.
-규칙:
-- "title" 은 반드시 한국어로 (영어 금지). 60자 이내.
-- "summary" 는 3줄. 이미지 시각 정보 (텍스트/사람/장면) 포함.
-- "tags" 는 영문 kebab-case (예: meeting-notes), 최대 3개. 한국어 태그 금지.
-- "due_date" 는 ISO 형식 YYYY-MM-DD 또는 null.
+${bodySection}
+
+규칙 (위반 시 재시도):
+- "title": 한국어 문자열 필수, null 금지. 60자 이내. 영어 단독 금지.
+- "summary": 한국어 문자열 필수, null 금지. 3줄. 이미지 시각 정보 (텍스트/사람/장면) 포함.
+- "tags": 영문 kebab-case 배열 (예: ["meeting-notes"]), 최대 3개. 한국어 태그 금지. 없으면 [].
+- "due_date": ISO YYYY-MM-DD 또는 null. 빈 문자열 금지.
오직 JSON 객체 하나만 출력. markdown 코드 펜스 (\`\`\`) / 설명 prose 금지.
출력 형식: {"title":"...","summary":"...","tags":[],"due_date":null}
diff --git a/tests/unit/visionPrompt.test.ts b/tests/unit/visionPrompt.test.ts
index 5b42577..4c882e3 100644
--- a/tests/unit/visionPrompt.test.ts
+++ b/tests/unit/visionPrompt.test.ts
@@ -15,9 +15,16 @@ describe('buildVisionPrompt', () => {
expect(result).toContain('work, meeting, project, todo');
});
- it('uses (이미지만 있음) placeholder when text is empty', () => {
+ it('본문 빈 경우 이미지 묘사 + null 금지 명시 (v0.3.14+)', () => {
const result = buildVisionPrompt('', '2026-05-09', [], []);
- expect(result).toContain('(이미지만 있음)');
- expect(result).not.toContain('\n\n\n'); // no double-blank from empty text
+ expect(result).toContain('본문이 없으니');
+ expect(result).toContain('null 반환 금지');
+ expect(result).not.toContain('메모 본문:\n');
+ });
+
+ it('본문 있는 경우 본문 우선 + 이미지 함께 분석 명시', () => {
+ const result = buildVisionPrompt('회의 메모', '2026-05-09', [], []);
+ expect(result).toContain('메모 본문:\n회의 메모');
+ expect(result).toContain('첨부 이미지도 함께 분석');
});
});