feat: v2.2.83 → v2.2.91 — info prompt 강화 + 사용자 노출 설정 + 답변 포맷 정리
[v2.2.83] /youtube info 프롬프트 강화 - 비유 방향 보존 룰 (Hugging Face=자료실 같은 짝 뒤집기 방지) - 신뢰도 라벨 4종 ([근거 명시] / [화자 주장] / [가정] / [정리자 추론]) - 타임스탬프 fail 룰 (인용·구간 요약 모두 mm:ss 필수) - "정리자 노트" 별도 섹션으로 추론 격리 [v2.2.85] polishPersona self-check 5가지 - 정리·리뷰·요약 답변 출력 직전 머릿속 체크: (1) 사실 오류 (2) 없는 내용 추가 (3) 뉘앙스 유지 (4) 중요도 비례 (5) 중복 제거 [v2.2.86] chunkedSwitchTokens 절대 임계값 게이트 - 입력 < 50k 토큰이면 키워드·길이 트리거 무시하고 단일 호출 - 큰 컨텍스트 모델(131k+)에서 chunked 과잉 발동 방지 [v2.2.87] MAX_SECTIONS 5→3 cap - 총 호출 7회 → 5회 (outline + 3 section + polish) - 사용자 피드백 "6+회는 과하다" [v2.2.88] 이모지 사용 금지 룰 - polishPersona / directPersona / sectionPersona 모두 적용 - 사용자 피드백 "이모지는 시각 노이즈" [v2.2.89] 사용자 노출 설정 두 항목 - chunkedMaxSections config 신규 (default 3, 1~10 clamp) - MAX_SECTIONS_HARD_CEILING (10) 으로 안전망 격상 - Astra Settings 패널 "고급" 섹션에 두 슬라이더 노출 [v2.2.90] 가이드 문구 단순화 - "작은 모델은 낮추라" 문구 빼고 일관되게 50000 권장으로 [v2.2.91] 답변 포맷 가독성 fix - persona 의 "TL;DR" 표현 전부 "한 줄 요약" 으로 단일화 - stripMarkdownFormatting 에 헤더 후 빈 줄 강제 삽입 (marked.parse 가 라벨·본문을 별도 단락으로 인식 → 시각 분리) [테스트] 400/400 통과 (resilience_stress + chunked flow + MAX_SECTIONS cap 등) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -800,13 +800,27 @@ function buildInfoExtractionPrompt(video: any, userContent: string): string {
|
||||
이 영상을 다시 보지 않고도 핵심 정보를 그대로 활용할 수 있도록, 영상이 *말한 것*
|
||||
(주장·사실·근거·결론)을 구조화해서 정리하세요.
|
||||
|
||||
[분석 원칙]
|
||||
1. 영상 본문(자막)에 *명시된 것* 만 인용. 추측·일반론·외부 지식 보강 금지.
|
||||
2. 자막에 없는 사실은 "본문에 명시되지 않음" 이라고 표시. 채워 넣지 말 것.
|
||||
3. 정보의 신뢰도 단계 표기: \`[근거 명시]\` (구체 출처·수치·인용)·\`[화자 주장]\`
|
||||
(출처 없는 단정)·\`[가정]\` (조건부 표현). 모든 핵심 주장에 라벨링.
|
||||
4. 타임스탬프는 mm:ss 형식으로 인용 직후 괄호에. 예: "…라고 말한다 (12:34)".
|
||||
5. 한국어 마크다운. 표·불릿 자유롭게.
|
||||
[분석 원칙 — 모두 반드시 준수]
|
||||
1. **출처 분리** — 영상 본문(자막)에 *명시된 것* 만 핵심 섹션에 넣음. 정리자의 추론·외부
|
||||
지식·자기 해석은 별도 \`## 🧩 정리자 노트\` 섹션에만. 두 줄 섞지 말 것.
|
||||
2. **빈 곳 채우지 말 것** — 자막에 없는 사실은 "본문에 명시되지 않음" 또는 "해당 사례 없음".
|
||||
3. **신뢰도 라벨 필수** — 모든 핵심 주장 앞에 다음 중 하나:
|
||||
- \`[근거 명시]\` 구체 출처·수치·인용이 본문에 있음
|
||||
- \`[화자 주장]\` 출처 없는 단정 (디노가 그렇게 말함)
|
||||
- \`[가정]\` 조건부·"~인 것 같다" 표현
|
||||
- \`[정리자 추론]\` 본문에 없지만 정리자가 추가 (이건 정리자 노트 섹션 전용)
|
||||
4. **타임스탬프 필수** — 본문 인용·구간 요약·발언 따옴표는 끝에 \`(mm:ss)\` 무조건 붙임.
|
||||
이걸 빠뜨리면 fail. "(시점 미상)" 도 허용 안 함 — 모르면 인용 자체 빼기.
|
||||
5. **화자 한 줄 비유 보존 + 방향 보존** — 영상에 비유·은유·"X 는 Y 같은 것" 식 압축 표현이
|
||||
있으면 반드시 별도 섹션 \`## 💡 화자 한 줄 비유\` 에 보존. 영상의 결정적 요약이 거기
|
||||
들어 있을 가능성 큼. 없으면 "본문에 명시된 한 줄 비유 없음" 명시.
|
||||
⚠️ **비유는 방향이 뒤집히기 쉬움** — 화자가 "Hugging Face = 자료실, Reddit = 공부방"
|
||||
이라 했으면 정확히 그 짝(어느 쪽이 자료실이고 어느 쪽이 공부방인지)을 그대로 따옴표
|
||||
인용으로 보존. 정리자가 단어 위치를 바꾸거나 뜻을 의역하면 안 됨. 고유명사·수치·
|
||||
대응 관계도 마찬가지 — 본문 그대로.
|
||||
6. **순서·단계 발명 금지** — 화자가 "A → B → C 순서로" 라고 명시하지 *않았으면* "단계적
|
||||
학습 순서" 같은 흐름을 정리자가 만들지 말 것. 굳이 필요하면 정리자 노트로.
|
||||
7. 한국어 마크다운. 표·불릿 자유롭게.
|
||||
|
||||
[영상 메타데이터]
|
||||
\`\`\`json
|
||||
@@ -816,17 +830,24 @@ ${JSON.stringify(slim, null, 2)}
|
||||
[자막 본문]
|
||||
${trimmed}${userBlock}
|
||||
|
||||
[필수 출력 형식 — 정확히 이 구조. 아래 6개 섹션 외 추가 금지]
|
||||
[필수 출력 형식 — 정확히 이 구조. 아래 8개 섹션 외 추가 금지]
|
||||
|
||||
# ${slim.title || video.title} — 정보 추출 카드
|
||||
|
||||
> **영상 URL**: ${slim.url} · **분석 일자**: ${today} · **길이**: ${slim.durationHms || (slim.durationSec ? formatHms(slim.durationSec) : '?')} · **채널**: ${slim.channel || '?'}
|
||||
|
||||
## 🎯 한 줄 요약 (TL;DR)
|
||||
(영상의 핵심 메시지 한 문장. "무엇이 누구에게 왜 중요한가" 를 압축. 제목 그대로 베끼지 말고 본문 기준으로 다시 쓸 것)
|
||||
(영상의 핵심 메시지 한 문장. "무엇이 누구에게 왜 중요한가" 를 압축. 제목 그대로 베끼지
|
||||
말고 본문 기준으로 다시 쓸 것. 정리자의 해석은 금지 — 화자의 말 그대로 압축)
|
||||
|
||||
## 💡 화자 한 줄 비유 (Anchor Metaphor)
|
||||
영상에서 화자가 *전체 메시지를 한 줄로 압축한 비유·은유* 가 있으면 그대로 따옴표로
|
||||
보존. 영상 마무리부에 자주 등장. 예: "Hugging Face = 자료실, Reddit = 공부방,
|
||||
유튜브 = 복습실" 같은 식. 없으면 "본문에 명시된 한 줄 비유 없음".
|
||||
|
||||
## 📌 핵심 주장 3~5개
|
||||
영상이 제시한 *주요 결론·주장* 만. 각 항목 한 줄 + 신뢰도 라벨 + 본문 인용 (mm:ss).
|
||||
영상이 *명시한* 주요 결론·주장만. 정리자 추론은 여기 들어오면 안 됨 (그건 🧩 섹션).
|
||||
각 항목 한 줄 + 신뢰도 라벨 + 본문 인용 (mm:ss).
|
||||
- **[근거 명시]** "주장 한 줄" — 본문 인용 (mm:ss)
|
||||
- **[화자 주장]** "주장 한 줄" — 본문 인용 (mm:ss)
|
||||
- …
|
||||
@@ -842,9 +863,16 @@ ${trimmed}${userBlock}
|
||||
데이터가 없는 영상이면 "본문에 명시된 구체 수치·출처 없음" 한 줄.
|
||||
|
||||
## 🧭 구조 요약 (Sectioned Summary)
|
||||
영상을 chapters (있으면) 또는 30초 버킷으로 구간 나눠 각 구간의 *내용 요약*. 1~2문장씩.
|
||||
- **[00:00–02:30]** 도입부에서 다룬 내용 한 문장 요약
|
||||
- **[02:30–05:00]** 본론 첫 부분…
|
||||
영상을 chapters (메타데이터에 있으면 그것 사용) 또는 30초 버킷으로 구간 나눠 각 구간의
|
||||
*내용 요약*. 1~2문장씩. 각 항목 끝에 타임스탬프 범위 필수.
|
||||
- **[00:00–02:30]** 도입부에서 다룬 내용 한 문장 요약 (mm:ss–mm:ss)
|
||||
- **[02:30–05:00]** 본론 첫 부분… (mm:ss–mm:ss)
|
||||
- …
|
||||
|
||||
## 🔗 인용용 한 줄 카드 (Citation Snippets)
|
||||
영상의 *결정적 발언* 을 그대로 따옴표로 보존. 사장님이 글·발표·메모에 인용할 때 복붙용.
|
||||
3~5개. 길이는 한 문장. 타임스탬프 필수.
|
||||
- "직접 인용 한 문장" — ${slim.title || video.title}, ${slim.channel || '?'} (mm:ss)
|
||||
- …
|
||||
|
||||
## ❓ 더 파고들 질문 (Open Questions)
|
||||
@@ -853,11 +881,15 @@ ${trimmed}${userBlock}
|
||||
- "본문에서 X 가 Y 라고 했지만 Z 데이터 출처는 명시 안 됨 — 원 데이터 찾아볼 것"
|
||||
- …
|
||||
|
||||
## 🔗 인용용 한 줄 카드 (Citation Snippets)
|
||||
영상의 *결정적 발언* 을 그대로 따옴표로 보존. 사장님이 글·발표·메모에 인용할 때 복붙용.
|
||||
3~5개. 길이는 한 문장.
|
||||
- "직접 인용 한 문장" — ${slim.title || video.title}, ${slim.channel || '?'} (mm:ss)
|
||||
- …`;
|
||||
## 🧩 정리자 노트 (원본 보강) — 선택
|
||||
*본문에 없지만* 정리자가 추가로 짚고 싶은 맥락·해석·연결·경고. 위 6개 핵심 섹션과
|
||||
구조적으로 격리되어, 독자가 "이건 화자가 말한 게 아니라 LLM 이 추론한 거" 라고
|
||||
명확히 인지하도록. 모든 항목은 \`[정리자 추론]\` 라벨로 시작.
|
||||
- **[정리자 추론]** 화자가 "여러 채널을 동시 시청" 하라 했지만, 입문자 페이스를 고려하면
|
||||
먼저 한 채널을 깊게 따라가는 것도 한 가지 시작점이 될 수 있음.
|
||||
- …
|
||||
|
||||
특별히 보강할 게 없으면 이 섹션 통째로 "정리자 추가 노트 없음 — 본문 그대로가 명확함" 한 줄.`;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -83,6 +83,8 @@ interface SettingsState {
|
||||
maxAutoSteps: number;
|
||||
maxContextSize: number;
|
||||
chatTemperature: number;
|
||||
chunkedSwitchTokens: number;
|
||||
chunkedMaxSections: number;
|
||||
};
|
||||
datacollect: {
|
||||
bridgeUrl: string;
|
||||
@@ -585,6 +587,12 @@ export class SettingsPanelProvider implements vscode.WebviewViewProvider {
|
||||
if (typeof msg.chatTemperature === 'number' && Number.isFinite(msg.chatTemperature)) {
|
||||
await this._safeConfigUpdate('chatTemperature', Math.max(0, Math.min(2, msg.chatTemperature)));
|
||||
}
|
||||
if (typeof msg.chunkedSwitchTokens === 'number' && Number.isFinite(msg.chunkedSwitchTokens)) {
|
||||
await this._safeConfigUpdate('chunkedSwitchTokens', Math.max(1000, Math.floor(msg.chunkedSwitchTokens)));
|
||||
}
|
||||
if (typeof msg.chunkedMaxSections === 'number' && Number.isFinite(msg.chunkedMaxSections)) {
|
||||
await this._safeConfigUpdate('chunkedMaxSections', Math.max(1, Math.min(10, Math.floor(msg.chunkedMaxSections))));
|
||||
}
|
||||
}
|
||||
|
||||
// ────────────── Datacollect (slash 명령) ──────────────
|
||||
@@ -657,6 +665,8 @@ export class SettingsPanelProvider implements vscode.WebviewViewProvider {
|
||||
maxAutoSteps: cfg.get<number>('maxAutoSteps', 50) ?? 50,
|
||||
maxContextSize: cfg.get<number>('maxContextSize', 32000) ?? 32000,
|
||||
chatTemperature: cfg.get<number>('chatTemperature', 0.3) ?? 0.3,
|
||||
chunkedSwitchTokens: cfg.get<number>('chunkedSwitchTokens', 50000) ?? 50000,
|
||||
chunkedMaxSections: cfg.get<number>('chunkedMaxSections', 3) ?? 3,
|
||||
},
|
||||
datacollect: {
|
||||
bridgeUrl: cfg.get<string>('datacollectBridgeUrl', '') || '',
|
||||
|
||||
Reference in New Issue
Block a user