fix(vision): 본문 빈 케이스에 one-shot 예시 추가

gemma4:26b 가 본문 없이 이미지만 받으면 null 반환하는 한계 우회.
prompt 강화 + null 금지 명시 만으로 부족. one-shot 예시 (강아지/화이트보드)
2개로 모델이 입출력 구조 따라가도록 유도.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
th-kim0823
2026-05-12 14:56:43 +09:00
parent 431b35a72a
commit 30b14d2b74
2 changed files with 16 additions and 9 deletions

View File

@@ -4,14 +4,19 @@ export function buildVisionPrompt(
dueCandidates: string[],
vocab: string[]
): string {
// v0.3.11vision model 이 'format:json' constraint 를 부분적으로만 따르는 경우가
// 잦음 (특히 gemma3 vision). title 한국어 + JSON only 를 prompt 에서 명시 강조,
// markdown fence 금지 표기로 schema parse 통과율 개선.
// 본문 비었으면 이미지만 보고 title/summary 채우도록 명시. 그냥 "(이미지만 있음)" 만
// 던지면 모델이 null 반환 (gemma4:26b 확인). 본문 있으면 본문 우선, 없으면 이미지 묘사.
// v0.3.14본문 빈 케이스에 one-shot 예시 추가. gemma4:26b 등이 본문 없이
// 이미지만 받으면 null 반환하는 한계 우회. 예시 입력/출력 구조 따라가도록 유도.
const bodySection = text
? `메모 본문:\n${text}\n\n첨부 이미지도 함께 분석해 요약에 반영하세요.`
: `본문이 없으니 첨부 이미지의 내용 (텍스트/사람/장면/문서 등) 을 보고 title 과 summary 를 한국어로 작성하세요. null 반환 금지.`;
: `본문이 없습니다. 첨부 이미지의 내용 (텍스트/사람/장면/문서 등) 만으로 한국어 title 과 summary 를 작성하세요. null 반환 절대 금지.
예시 (이미지: 갈색 강아지가 잔디 위에 앉은 사진):
{"title":"잔디 위 강아지","summary":"갈색 강아지가 잔디 위에 앉아 있다.\\n배경에 나무가 보인다.\\n날씨가 맑다.","tags":["pet"],"due_date":null}
예시 (이미지: 회의실 화이트보드 사진):
{"title":"회의실 화이트보드","summary":"화이트보드에 일정과 안건이 적혀 있다.\\n프로젝트 이름이 보인다.\\n다이어그램이 그려져 있다.","tags":["meeting"],"due_date":null}
이제 첨부된 실제 이미지를 보고 같은 형식으로 작성하세요.`;
return `다음 메모를 한국어로 분석해 JSON 으로 정리하세요.

View File

@@ -15,10 +15,12 @@ describe('buildVisionPrompt', () => {
expect(result).toContain('work, meeting, project, todo');
});
it('본문 빈 경우 이미지 묘사 + null 금지 명시 (v0.3.14+)', () => {
it('본문 빈 경우 이미지 묘사 + null 금지 명시 + one-shot 예시 (v0.3.14+)', () => {
const result = buildVisionPrompt('', '2026-05-09', [], []);
expect(result).toContain('본문이 없으니');
expect(result).toContain('null 반환 금지');
expect(result).toContain('본문이 없습니다');
expect(result).toContain('null 반환 절대 금지');
expect(result).toContain('예시'); // one-shot 예시 포함
expect(result).toContain('잔디 위 강아지'); // 예시 1
expect(result).not.toContain('메모 본문:\n');
});