/** * 회의 녹취 텍스트 → 사실 기반 구조화 회의록(Actionable Minutes) LLM 프롬프트. * 사용자 정의 규칙: Fact/Discussion/Decision/Risk/Action 분류, 메타데이터 우선. * * v2.2.259 개선(사용자 피드백 반영 — 회의록 "방향성" 개선, 외부 모범사례 근거): * - 문체: 서술형 일기체('~논의하였다/완료하였다') → **개조식·명사형 종결**('~논의/합의/완료/필요/예정'). * 한국 공문서·회의록 표준이자 가독성↑. 핵심 요약을 개조식 3~5줄 글머리표로. * - 구조 순서: '주요 논의/쟁점'을 '결정 사항' **앞**으로(이슈→결정 흐름). 국제(Context→Decision→Action)· * 국내(안건별 논의→의사결정→액션) 모범사례 일치. 옛 '논의 메모'를 상단 '주요 논의/쟁점'으로 승격·이동. * - 참석자 명단의 "(참석자 N)" 병기 누수 차단(검증 패스가 잡던 화자번호 잔존). * * v2.2.258 개선(사용자 피드백 반영): * - 화자: STT 화자번호("참석자 N")를 **팀/역할**로 정규화(개인명은 확실할 때만 병기). * 최종 문서에 "참석자 N" 토큰을 절대 노출하지 않는다. * - 전역 헤드라인: 청크 전체를 관통하는 결론/핵심 요구를 별도 추출해 맨 앞에 세운다. * - 결정/액션 경계: 일감(담당 있는 것)은 액션으로, 결정사항엔 순수 방향/정책만. * - 조건부 결정: "테스트 후 결정" 류는 결정이 아니라 오픈 이슈로. * - 폐기 가설/충돌: 즉시 반박·철회된 제안은 이슈로 격상 금지, 화자간 수치충돌은 그대로 명시. * - 슬림 포맷: 7→6 섹션, 한 사실은 한 섹션에만(중복 제거), 빈 칸은 "—". * - 근거: STT 원문 통째 인용 대신 타임스탬프 [mm:ss]로 정제(검증 가능 기록). * - 리스크 표는 실제로 리스크+완화책이 논의됐을 때만 띄운다(빈 템플릿 = 환각 유발). */ export function buildMeetPrompt(transcript: string, metadata: string): string { const metaBlock = metadata.trim() || '(메타데이터 미입력 — 녹취록 내용에서 추론하거나 "확인 불가"로 표기)'; return `# 임무 (Objective) 제공된 회의 녹취 텍스트와 메타데이터를 기반으로, 사실 기반의 구조화된 회의록(Actionable Minutes)을 생성한다. 외부/도메인 지식은 *STT 오타 보정과 용어 해석*에만 사용하고, *녹취록에 없는 새로운 사실을 추가*하는 데는 절대 쓰지 않는다. # 역할 (Role) - Fact Extractor: 녹취록에 명시적으로 존재하는 사실만 추출 - Attribution Tracker: 누가 무엇을 말했는지 추적하되, 화자를 **팀/역할**로 귀속한다(아래 '화자 정규화' 참조) - Decision Tracker: 결정 여부 구분 (명시적 합의만 결정) - Action Organizer: 실행 항목 구조화 - Context Filter: 불필요한 발언(잡담) 제거 # 데이터 우선순위 (Data Priority) 1순위: 메타데이터(회의 헤더·참석자 명단·회사 표준 팀 분류) / 2순위: 녹취록 내용. 충돌 시 반드시 메타데이터를 사용한다. # 화자 정규화 (Speaker Normalization — 최우선, 환각·오귀속 방지) 이 녹취록의 "참석자 1", "참석자 2" … 는 STT가 임의로 붙인 **화자번호**일 뿐 실명·역할이 아니다. 번호↔이름 연결고리는 녹취록에 없다. - **최종 문서에 "참석자 N"(또는 "화자 N", "발언자 A") 토큰을 절대 쓰지 말 것.** 0개여야 한다. - 메타데이터의 **회의 참석자 명단(역할:이름)**과 **회사 표준 팀 분류**를 통제 어휘집으로 삼아, 각 화자번호를 *발언 내용 단서*로 **팀/역할**에 매핑한다. (예: 라이선스·AI작업·폴리싱을 말하는 화자 → [넥서스개발팀], 모든 의사결정을 내리고 다른 사람이 "상무님"으로 부르는 화자 → [클라이언트]) - **같은 화자번호는 회의 내내 같은 팀/역할로 고정**한다(중간에 바꾸지 말 것). - 개인 실명은 명단+문맥으로 **확실할 때만** 괄호로 병기한다(예: [넥서스개발팀·김상엽]). 확신 없으면 팀/역할까지만. - 팀/역할조차 단서가 부족하면 **귀속을 생략**하고 "~라는 의견이 제시됨"처럼 주체 없이 중립 서술한다. 번호를 남기느니 주체를 비우는 게 낫다. - 무리한 매핑(특히 개인 실명 추측)은 오귀속을 낳아 신뢰도를 가장 크게 해친다 — **불확실하면 한 단계 위(개인→팀, 팀→무귀속)로 물러서라.** # STT 오타 보정 (Transcription Noise Handling — 음성→텍스트 변환물이라 오타가 많다) - 발음이 유사한 단어가 잘못 표기돼 있다. **한 단어의 철자에 집착하지 말고 주변 문맥으로 의미를 복원하라.** - 흔한 기술 용어(DRM, SDK, 딥링크, API, 렌더링, 자이로센서 등)·고유명사는 도메인 지식으로 **정규화**하라. - 메타데이터에 인명·기업명·제품명·용어가 있으면 그것을 **정답 표기**로 본다(메타데이터 = 용어집). - **핵심 구분 (절대 혼동 금지)**: '녹취록에 *있는* 단어의 철자를 문맥으로 바로잡는 것'은 허용·권장. '녹취록에 *없는* 사실(수치·결정·없던 항목)을 지어내는 것'은 금지. **철자 보정 ≠ 사실 날조.** - 오타 하나 때문에 멀쩡한 내용 전체를 "확인 불가"로 막지 말 것. # 처리 절차 (Processing Flow) 1. Speaker Normalization — 위 규칙대로 화자번호를 팀/역할로 매핑(번호 박멸). 2. Topic Reclustering — 녹취록은 비선형이다(주제가 튄다). 전체를 훑어 **흩어진 발언을 주제별로 다시 묶는다.** 앞뒤로 붙어 있다는 이유만으로 두 발언을 인과로 엮지 말 것(**인접 ≠ 연결**). 3. Global Headline — 회의 전체를 관통하는 **결론/핵심 요구**(특히 후반부에 정리된 것)를 별도로 식별해 '핵심 요약'에 세운다. 4. Dialectic Check — 각 제안이 **합의됐는지 / 반박·철회됐는지 / 미결인지**를 대화 흐름 끝까지 보고 판정한다. 즉시 일축·반박된 가설을 정식 이슈로 격상하지 말 것. 화자간 수치·의견이 갈리면 단일값으로 확정하지 말고 충돌을 그대로 적는다(예: "6 vs 8, 기준 미정"). 5. Classification — Fact / Discussion / Decision / Risk / Action 분류. 6. Decision Logic - 명시적 합의 표현 → Decision (단, 담당+행동이 있는 일감은 Action으로 보내고 결정엔 순수 방향/정책만) - "테스트해보고 결정 / 다시 보고 얘기 / 고민해보자" → Decision 아님 → Open Issue - 실행 주체 + 행동 → Action - 제안/의견 → Discussion 7. Dedup & Structuring — 표현이 달라도 의미가 같은 항목은 하나로 병합. **한 사실은 한 섹션에만** 둔다(요약·결정·액션에 같은 내용 중복 금지). # 근거·정확성 규칙 (Grounding Rules — 반드시 준수, 할루시네이션 방지) - **녹취록에 명시된 내용만 적는다.** 추론으로 빈칸을 메우거나, 별개 발언을 하나의 인과 사슬로 합성하지 말 것. - **근거 = 타임스탬프**: 모든 '결정 사항'·'액션 아이템'·리스크 항목 끝에, 근거가 된 발언의 **타임스탬프 [mm:ss]**를 붙인다(녹취록의 "참석자 N mm:ss" 표시에서 가장 가까운 시각). 타임스탬프를 찾을 수 없는 항목은 결정·액션이 아니다 — 만들지 말거나 오픈 이슈로 내려라. 이 타임스탬프는 날조 방지 + 검증 점프 장치다. STT 원문을 통째로 인용하지 말 것(길고 들쭉날쭉해진다). - **녹취록에 없는 숫자·날짜·금액·결정을 만들어내지 말 것.** (철자만 틀린 용어 정규화는 허용.) - 내용 자체가 모호하면(=철자 문제가 아니라 사실 불확실) 지어내지 말고 "(확인 필요)"를 붙인다. - Decision은 명시적 합의 표현이 있을 때만 '결정됨'. 불명확하면 오픈 이슈. - **빈 칸은 채우지 말 것**: 표에서 값을 모르면 "—"로 둔다. placeholder를 그럴듯한 추측으로 메우지 말 것. 모든 칸이 미정인 항목은 액션이 아니라 오픈 이슈다. # 출력 검증 (Validation — 출력 전 내부 점검, 로그는 출력 금지) ① "참석자 N" 토큰이 0개인가(명단의 "(참석자 N)" 병기 포함) ② 화자가 팀/역할로 귀속됐고 개인 추측이 없는가 ③ 인접 발언을 임의 연결하지 않았는가 ④ Decision이 실제 합의인가(테스트후결정·검토필요가 섞이지 않았나) ⑤ 즉시 반박된 가설을 이슈로 격상하지 않았는가 ⑥ 같은 사실이 여러 섹션에 중복되지 않았는가 ⑦ 빈 칸을 추측으로 채우지 않았는가 ⑧ 각 항목에 [mm:ss]가 있는가 ⑨ 모든 문장이 개조식·명사형 종결인가(서술형 '~하였다/합니다' 0개) ⑩ '주요 논의/쟁점'이 '결정 사항' 앞에 있는가. [메타데이터] ${metaBlock} [회의 녹취록] \`\`\` ${transcript} \`\`\` ${OUTPUT_FORMAT}`; } /** 최종 회의록 출력 형식 — 단일샷(buildMeetPrompt)과 병합 단계(buildMeetReducePrompt)가 공유. */ const OUTPUT_FORMAT = `# 작성 원칙 (회의록 품질 — 출력 전 반드시 내재화) 회의록은 *대화 요약 문서*가 아니라 **프로젝트 관리 문서**다. "무엇이 결정됐는가 / 누가(어느 팀이) 무엇을 해야 하는가 / 무엇이 아직 미결인가"를 우선한다. - **완전성 (누락 금지 — 최우선)**: 실제로 논의·결정·요청·질문된 항목은 **하나도 빠뜨리지 않는다.** '핵심 요약'만 3~5줄 다이제스트로 압축하고, **'주요 논의/결정/액션/오픈이슈' 본문 섹션은 다뤄진 모든 안건을 담아 상세히** 쓴다. 개조식·군더더기 최소화는 *문체*일 뿐 *내용 삭제가 아니다* — 각 항목은 수치·조건·대상·기한 등 핵심 디테일을 넣어 **그 한 줄만 봐도 이해되게(자기완결)** 적는다(맥락 없는 앙상한 뼈대 금지). 섹션이 길어지는 것은 정상이다. - **개조식·명사형 종결 (필수 문체)**: 모든 항목을 개조식으로 — 명사형 또는 '~함·됨·필요·예정·합의·완료·확인' 류로 끝맺는다. **서술형 종결어미('~하였다/했다/합니다/입니다/됩니다/할 예정이다/것으로 보인다') 금지** — 회의록은 일기·기사·서간문이 아니다. 한 항목 = 한 줄, 군더더기·접속사("따라서/그리고/하였으며") 최소화. - 좋은 예: \`- CDN 경로는 위버스 운영툴로 관리 — 합의\` / \`- 보안 솔루션 2개사 PoC·비용 검토 완료, 최종 도입안 미정\` - 나쁜 예: \`- CDN 경로 정보를 위버스 운영툴을 통해 관리하는 방식으로 합의하였습니다.\` / \`- …검토를 완료하였으며, 향후 …결정할 예정이다.\` - **이슈 → 결정 흐름 (구조 순서)**: 독자가 "무슨 쟁점이 있었고 → 어떻게 논의됐고 → 어떻게 됐는지"를 따라가도록, '주요 논의 / 쟁점'을 '결정 사항' **앞**에 둔다. **'주요 논의'는 각 주제를 논점→논의→결론으로 그 자리에서 매듭짓고**(결론은 *상태 한 줄* — 미결/조건부/보류거나, 확정이면 짧게), **'결정 사항'은 그중 확정 결정만** 정본으로 다시 크고 명확하게 모은다. 즉 주요 논의의 '결론'은 *상태 요약*, 결정 사항은 *확정 결정의 정본* — 성격이 달라 상태 수준 겹침은 허용하되, **같은 문장을 통째로 복붙하지는 말 것**. - **한 사실은 한 섹션에만**: 같은 항목을 통째로 여러 섹션에 반복 기재하지 말 것(예외: 위처럼 주요 논의 '결론' 상태 한 줄 ↔ 결정 사항 정본은 허용). 핵심 요약은 미리보기가 아니라 다이제스트다. - **결정 ↔ 액션 경계**: 담당+행동이 있는 *일감*은 '액션 아이템' 표로 보낸다. '결정 사항'에는 **담당자 없는 순수 방향/정책 결정만** 남긴다(예: "제품 리스트 클릭 이벤트 제거하기로 함"). "구현하기로 함"처럼 누가 할 일이면 액션이다. - **결정 ≠ 검토요청**: "테스트해보고 결정 / 다시 보고 얘기 / 고민해보자"는 결정이 아니다 → 오픈 이슈. 명시적 합의만 결정. - **담당은 팀/역할 우선**: STT 화자번호 매핑이 불확실하므로 개인명보다 **팀/역할**(예: 넥서스개발팀, 기획, UI)로 적는다. 개인이 명단+문맥으로 확실할 때만 병기. "참석자 N" 금지. - **빈 칸은 "—"**: 모르는 값을 추측·placeholder로 채우지 말 것. 통째로 미정인 항목은 액션이 아니라 오픈 이슈로 내린다. - **근거 = [mm:ss]**: 결정·액션·리스크에 STT 원문을 박지 말고 타임스탬프만 붙인다. - **사실 중심**: 추정·평가가 아니라 실제 논의·확정된 것만. ("API 연동 가능 판단됨"❌ → "API 연동 가능 여부 검토 필요"✅) # 출력 형식 (Output Format — 정확히 이 구조를 유지) # [제품/프로젝트] · 회의유형 — 핵심 안건 (예: "[자이언츠 이머시브 커머스] 데모 리뷰 — 모자 UI·모델/체형 확장". 회의유형은 녹취 성격에서 판단: 데모 리뷰 / 기획 논의 / 정기 점검 등.) ## 회의 개요 - **일시**: [YYYY년 MM월 DD일 | 확인 불가] ← 반드시 이 표기(자동 등록이 날짜를 읽음) - **장소**: [메타데이터/헤더 기준 | 확인 불가] - **회의유형**: [데모 리뷰 / 기획 논의 등] - **녹취 길이**: [헤더에 있으면 | 없으면 생략] - **작성일**: [메타데이터의 작성일 | 생략] - **참석자**: **참여한 팀/역할만 중복 없이 나열**(예: 넥서스개발팀, 개발PM, 기획, 위버스). 개인 실명은 명단+문맥 확실 시만 병기. **괄호로라도 "(참석자 N)"을 덧붙이지 말 것** — 화자번호↔역할 매핑은 본문에서만 쓰고 명단엔 노출 금지. ## 핵심 요약 회의 전체를 관통하는 **핵심 요구·결론**(특히 후반부 정리분)을 맨 앞에 세우고, **개조식 3~5줄**(명사형 종결, 글머리표)로 압축한다 — 무엇을 리뷰/논의했고 / 무엇이 정해졌고 / 다음 단계가 무엇인지. **참석하지 않은 사람이 이 부분만 읽어도 결과를 파악**할 수 있어야 한다. 디테일 나열·항목 중복·서술형 종결('~하였다') 금지. - 예) 위버스 협업 영상 보안(DRM·OTP) 강화 + 운영툴·인프라 구조 논의 - 예) 인코딩·업로드는 자체 수행, CDN 경로는 위버스 운영툴로 관리 — 합의 - 예) 보안 솔루션 2개사(라인컴퍼니·스틸리언) PoC·비용 검토 완료, 최종 도입안·일정 미정 ## 주요 논의 / 쟁점 **결정에 앞서**, 회의에서 다뤄진 안건을 **주제별**로, 각 주제가 **그 자리에서 매듭지어 보이게 "논점 → 논의 → 결론" 3단**으로 적는다(독자가 이 섹션만 읽어도 "무슨 이슈였고 → 어떻게 오갔고 → 그래서 어떻게 됐는지"를 따라가게). 발언을 그대로 옮기지 말고 **요지로 압축**, 개조식·명사형 종결, 각 줄 끝 [mm:ss]. **[주제명]** - **논점**: 핵심 쟁점/질문 한 줄 (명사형 종결) — [mm:ss] - **논의**: 실제 오간 주장·근거·선택지·대립의 요지 (녹취/노트에 있는 내용만 — 없으면 이 줄 생략, 지어내지 말 것) — [mm:ss] - **결론**: *그래서 어떻게 됐는지* 한 줄로 매듭 — 다음 중 하나로 표기: \`합의·결정됨\`(핵심 결정이면 아래 '결정 사항'에도 정본으로 크게 표기) / \`미결 — 오픈 이슈로\` / \`조건부: <선행>\` / \`보류·다음 회의로\`. **결정 안 났어도 반드시 이 줄로 현재 상태를 남긴다**(붕 뜨는 쟁점 금지) — [mm:ss] ## 결정 사항 위 쟁점에 대해 **명시적으로 합의·확정된 순수 방향/정책 결정만** 적는다(담당 있는 일감은 액션으로). 개조식·명사형 종결, 각 줄 끝 타임스탬프. \`- [결정 내용 — 명사형 종결] — [mm:ss]\` (확정된 결정이 없으면 "이번 회의에서 확정된 결정사항 없음"이라고 명시 — 빈칸·생략 금지.) ## 액션 아이템 회의 후 수행할 업무를 표로 정리한다. 담당은 **팀/역할 우선**(개인 확실 시 병기). 값을 모르는 칸은 "—". 모든 칸이 미정인 항목은 여기 넣지 말고 '오픈 이슈'로. 셀 안에서 줄바꿈·\`|\` 금지. | 담당 | 액션 | 기한 | 상태 | 출처 | | --- | --- | --- | --- | --- | - **담당**: 팀/역할(예: 넥서스개발팀, UI, 기획). 불명확하면 "—". - **액션**: 한 줄 실행문 — 캘린더 일정 제목으로 그대로 쓰이므로 그 자체로 무슨 일인지 식별되게(배경·대상·조건 포함, "검토"·"확인" 단독 동사 금지). 작업 상세를 따로 반복하지 말고 이 한 줄에 녹인다. - **기한**: 회의에서 나온 날짜/시점. 없으면 "—". - **상태**: 다음 중 정확히 하나 (캘린더 자동 등록 게이트가 이 값으로 분기하므로 형식 엄수): - \`확정\` — 진행 합의가 명시적이고 기한도 언급됨. - \`진행미정\` — 작업이 언급됐으나 진행 합의가 불명확. - \`기한미정\` — 하기로 확정됐으나 완료일 미정. - \`조건부: <선행작업>\` — 다른 작업이 끝나야 진행(예: \`조건부: 머리 정돈 테스트 후\`). - \`반복: <주기>\` — 정기 반복(예: \`반복: 매주 목요일\`). - **출처**: 근거 발언의 타임스탬프 \`[mm:ss]\`. ## 오픈 이슈 / 다음 회의로 회의 종료 시점에 **아직 결정되지 않은 미결 사항**을 한곳에 모은다(도입 여부·정의 필요·테스트 후 결정·화자간 충돌 등). 가능하면 *누가/언제 확인*까지. 각 줄 끝 [mm:ss]. - 예) 사진 노출 개수 6 vs 8 — 기준 미정, 클라이언트 확인 필요 — [58:25] ## 리스크 (선택) **실제로 리스크와 (가능하면) 완화책이 논의됐을 때만** 이 섹션과 표를 만든다. 회의에서 안 다뤄졌으면 이 섹션을 **통째로 생략**한다(빈 템플릿·"[내용 확인 필요]" 골격만 남기지 말 것). '리스크'는 위험 *요인/원인*, '영향'은 현실화 시의 *결과*다 — 두 열에 같은 문장을 반복하지 말 것. 셀 안에서 줄바꿈·\`|\` 금지. | 리스크 | 영향 | 대응 방안 | 출처 | | --- | --- | --- | --- | # 최종 점검 (출력 전 내부 확인 — 체크 로그는 출력하지 말 것) □ 모든 문장이 개조식·명사형 종결(서술형 '~하였다/했습니다/할 예정이다' 0개) □ '주요 논의/쟁점'이 '결정 사항'보다 앞에 위치 □ 주요 논의 각 주제가 논점→논의→결론으로 매듭(결론 한 줄 없이 붕 뜬 쟁점 0개) □ 참석자 명단에 "(참석자 N)" 병기 0개 □ "참석자 N" 토큰 0개 □ 화자가 팀/역할로 귀속(개인 추측 없음) □ 결정사항에 순수 방향/정책만(일감은 액션으로) □ "테스트후결정·검토필요"가 결정에 섞이지 않음 □ 즉시 반박된 가설을 이슈로 격상 안 함 □ 화자간 충돌은 단일값 확정 말고 그대로 표기 □ 같은 문장을 통째로 여러 섹션에 복붙 안 함(주요논의 결론↔결정 정본의 상태 수준 겹침은 예외) □ 빈 칸은 "—"(추측 채움 없음) □ 통째 미정 항목은 오픈이슈로 □ 액션 상태가 5종 taxonomy 형식 □ 리스크는 실제 논의됐을 때만 표 띄움 □ 모든 결정·액션·논점에 [mm:ss] 위 형식을 정확히 따르고, 모든 내용은 한국어로 작성하시오.`; /** * [세그먼트 추출 단계 — Map] 긴 녹취록(단일 컨텍스트 초과)을 조각으로 나눠 * 각 조각에서 사실만 추출한다. 입력이 짧아 모델이 충실해지고(lost-in-the-middle * 방지), 60K 자르기로 후반부가 통째로 사라지던 문제를 없앤다. * * 이 단계는 최종 출력이 아니라 *검증 가능한 노트*다 — 따라서 근거는 타임스탬프 * **와** 원문 일부를 함께 남겨 병합·검증 단계가 대조할 수 있게 한다(최종 출력만 정제). */ export function buildMeetExtractPrompt(segment: string, metadata: string, segIndex: number, segTotal: number): string { const metaBlock = metadata.trim() || '(메타데이터 없음)'; return `# 임무 긴 회의 녹취록의 **${segIndex}/${segTotal}번째 조각**이다. 이 조각에 *명시된 내용만* 아래 형식으로 추출하라. 최종 회의록은 나중에 모든 조각을 합쳐 작성하므로, 여기서는 요약·해석하지 말고 **누락 없이 추출**하는 것이 임무다. # 규칙 (할루시네이션 방지) - 이 조각에 없는 사실·수치·결정을 만들지 말 것. - **화자 정규화**: "참석자 N"은 STT 화자번호일 뿐이다. 메타데이터의 참석자 명단·회사 표준 팀 분류 + 발언 내용 단서로 각 화자를 **팀/역할**로 매핑하라. 개인명은 확실할 때만. 팀/역할도 불명이면 "[미상]". (번호는 아래 '화자 역할 매핑'에만 참고용으로 남기고, 본문 항목엔 팀/역할로 적는다.) - STT 오타는 문맥·메타데이터로 정규화하되 없는 사실을 지어내지 말 것. - **근거**: 각 항목 끝에 \`[mm:ss] "원문 일부"\` 를 붙인다(타임스탬프 = 가장 가까운 "참석자 N mm:ss" 표시의 시각, 원문 일부 = 검증용 발언 조각 15~20자). "이렇게/그거" 같은 내용 공백 발화는 근거로 쓰지 말고 "[내용 확인필요]". - **담화 상태**: 제안/결정 항목엔 \`(합의)\` / \`(미합의·제안)\` / \`(반박됨)\` / \`(철회됨)\` 중 하나를 표시. 즉시 반박·일축된 가설은 결정이 아니라 그렇게 표시만. - 조각 경계에서 잘린 문장은 무리하게 해석하지 말고 "(조각 경계에서 잘림)". [메타데이터] ${metaBlock} [녹취록 조각 ${segIndex}/${segTotal}] \`\`\` ${segment} \`\`\` # 출력 형식 (이 조각에 해당 항목이 없으면 "없음") ## 안건/주제 (이 조각에서 다뤄진 의제 목록 — 누락 점검용) - 주제명 — [mm:ss] ## 화자 역할 매핑 (이 조각에서 파악된 것) - 화자 N → [팀/역할] (판단 근거: 무슨 발언으로 그 역할로 봤는지 / 불명이면 "미상") ## 회의 목적 (드러나면 한 줄, 아니면 "없음") ## 사실(Fact) - [팀/역할] 내용 — [mm:ss] "원문 일부" ## 논의(Discussion) - [팀/역할] 내용 (담화상태) — [mm:ss] "원문 일부" ## 결정(Decision) - 내용 (합의) — [mm:ss] "원문 일부" ## 리스크/이슈 - 내용 (+논의된 대응책 있으면 함께) — [mm:ss] "원문 일부" ## 액션(Action) - [담당(팀/역할 우선)] 액션 한 줄 (기한: … / 상태후보: 확정·진행미정·기한미정·조건부·반복) — [mm:ss] "원문 일부" ## 언급된 수치·날짜·금액 (화자간 충돌이 있으면 충돌 그대로) - 항목: 값 — [mm:ss]`; } /** * [병합 단계 — Reduce] 조각별 추출 노트를 합쳐 최종 회의록을 작성한다. * 입력은 원문이 아니라 추출 노트이므로, 노트에 없는 내용을 추가하면 안 된다. */ export function buildMeetReducePrompt(notes: string, metadata: string): string { const metaBlock = metadata.trim() || '(메타데이터 미입력 — 노트에서 추론하거나 "확인 불가"로 표기)'; return `# 임무 긴 회의 녹취록을 조각별로 추출한 노트들이 아래에 있다. 이 노트만 근거로 최종 회의록(Actionable Minutes)을 작성하라. # 규칙 (병합 시 반드시 준수) - **노트에 있는 내용만** 사용한다. 노트에 없는 사실·수치·결정을 추가하지 말 것. - **화자 역할 통일**: 각 조각의 '화자 역할 매핑'을 종합해 같은 팀/역할 라벨로 통일한다. 최종 문서에 "참석자 N"이 단 하나도 남으면 안 된다(0개). 조각마다 매핑이 엇갈리면 다수·문맥으로 결정하고, 끝내 불명이면 주체 없이 중립 서술. - **전역 헤드라인 추출**: 조각 전체(특히 마지막 조각)를 관통하는 **결론·핵심 요구**를 찾아 '핵심 요약' 맨 앞에 세운다. 한 청크에만 있던 핵심 요구가 묻히지 않게 한다. - **담화 상태 반영**: \`(반박됨)\`·\`(철회됨)\`으로 표시된 가설은 오픈 이슈·결정으로 격상하지 말 것. \`(미합의)\`는 오픈 이슈/논의로. \`(합의)\`만 결정 후보. - **주요 논의 = 논점→논의→결론**: 각 주제에 대해 노트의 '논의(Discussion)'·'리스크/이슈'를 *논의* 줄로, '결정'·담화상태(합의/미합의/보류)를 *결론* 줄로 엮어 논점→논의→결론을 완성한다. **결정이 없던 쟁점도 '미결·보류' 결론을 반드시 달아** 붕 뜨지 않게 한다(결론 줄 없는 쟁점 금지). - **결정/액션 경계**: 담당+행동이 있는 일감은 액션 표로, 결정엔 순수 방향/정책만. - **의미 dedup**: 표현이 달라도 같은 작업·논점은 **하나로 병합**한다(여러 조각에서 중복 추출된 것). 한 사실은 한 섹션에만. - **충돌 보존**: 수치·의견이 화자간 갈리면 단일값으로 확정하지 말고 "A vs B, 미정"으로 오픈 이슈에 적는다. - **빈 칸은 "—"**, 모든 칸이 미정인 액션은 오픈 이슈로. 리스크는 실제 논의된 경우만 표를 만든다. - **안건 누락 점검 (필수)**: 노트의 '안건/주제' 목록을 체크리스트 삼아, 다뤄진 의제·사실·결정·액션을 **하나도 빠뜨리지 말고** 결과 문서에 반영한다(중복만 병합, 특히 회의 도입부 첫 안건). 출력이 길어지더라도 **항목을 잘라내 분량을 맞추지 말 것** — 완전성이 간결성보다 우선. - 메타데이터와 노트가 충돌하면 메타데이터 우선. [메타데이터] ${metaBlock} [조각별 추출 노트] ${notes} ${OUTPUT_FORMAT}`; } /** * [검증 패스] 완성된 회의록을 근거 소스(녹취록 또는 추출 노트)와 대조한다. * v2.2.258: 단순 '존재 확인'에서 → ①참석자 N 잔존 ②결정 과확정 ③폐기 가설 격상 * ④액션 중복 까지 점검하는 4종 방어선으로 확장(약한 로컬 모델 대비). */ export function buildMeetVerifyPrompt(report: string, source: string): string { return `# 임무 아래 [회의록]을 [근거 소스]와 대조해 결함을 점검하라. 4종을 본다. # 점검 항목 1. **근거 미확인**: '결정 사항'·'액션 아이템'의 내용(및 수치·날짜)이 근거 소스에서 확인되는가? 못 찾으면 FLAG. (표기·철자 차이는 무시, 의미로 대조.) 2. **화자번호 잔존**: 회의록 본문에 "참석자 N"/"화자 N"/"발언자 A" 같은 STT 화자번호가 남아 있는가? 있으면 FLAG. 3. **결정 과확정**: '결정 사항'(또는 '주요 논의'의 **결론** 줄에 \`합의·결정됨\`으로 적힌 것)이 소스에서는 "테스트 후 결정 / 다시 보고 얘기 / 고민해보자"처럼 *조건부·미합의*인가? 그렇다면 FLAG(결론을 '미결'로 내려야 함). 4. **폐기 가설 격상**: 소스에서 즉시 반박·철회된 발언이 회의록의 오픈이슈/리스크/결정으로 격상돼 있는가? 있으면 FLAG. 5. **액션 중복**: 액션 아이템 중 의미가 사실상 동일한데 별개 행으로 중복된 것이 있는가? 있으면 FLAG(병합 필요). # 규칙 - 새 해석·제안을 추가하지 말 것. 판정만 한다. # 출력 형식 - 결함이 없으면 정확히 한 줄: \`검증 통과\` - 있으면 항목별로: - ❗ [근거|화자번호|과확정|폐기가설|중복] "<항목 요약>" — <짧은 사유> [회의록] ${report} [근거 소스] \`\`\` ${source} \`\`\``; } /** * [검수 수정] 검증자가 지적한 부분만 고쳐 '수정된 전체 회의록'을 반환한다. * 핵심: 지적되지 않은 내용은 그대로 보존(재작성 금지), 소스에 없는 사실 추가 금지. */ export function buildMeetRevisePrompt(report: string, flagged: string, source: string): string { return `# 임무 아래 [회의록]에서 [검수 지적사항]에 해당하는 부분**만** 고쳐, 수정된 **전체 회의록**을 출력하라. # 절대 규칙 - **지적된 부분만** 수정한다. 지적되지 않은 문장·표·섹션·표현은 **한 글자도 바꾸지 말고 그대로** 둔다(전체 재작성·재요약 금지). - 수정은 [근거 소스]에 맞춘다. 소스에 **없는 새 사실·수치·날짜·항목을 만들어 넣지 말 것**. - 지적 유형별 처리: - **[근거]** 소스에서 확인되면 근거 표기만 보강, 확인 안 되면 그 항목을 삭제하거나 '오픈 이슈'로 강등. - **[화자번호]** "참석자 N"/"화자 N"/"발언자 A"를 팀/역할로 치환(불명이면 주체 없이 중립 서술). - **[과확정]** '결정 사항'에서 빼서 '오픈 이슈'로 이동. - **[폐기가설]** 반박·철회된 항목을 결정/오픈이슈/리스크에서 제거. - **[중복]** 의미가 같은 액션 행을 하나로 병합. - 출력은 수정된 **회의록 본문 하나**뿐. 머리말·설명·코드펜스(\`\`\`) 금지. [검수 지적사항] ${flagged} [근거 소스] \`\`\` ${source} \`\`\` [회의록] ${report}`; } /** * [편집(Editor)] 검수를 통과한 회의록을 보고서 형태로 구조·가독성만 다듬는다. * 편집자는 작성자가 아니다 — 소스에 없는 사실을 새로 만들지 않고, 기존 항목을 삭제·축약하지 않는다. */ export function buildMeetEditorPrompt(report: string, source: string): string { return `# 임무 아래 [회의록]을 최종 **보고서** 형태로 다듬어 출력하라. 너는 편집자이며 작성자가 아니다. # 절대 규칙 (환각·누락 금지) - **형식·구조·가독성만** 개선한다: 섹션 순서 정돈, 표 정렬, 개조식·명사형 종결 통일, 어색한 문장 다듬기. - [근거 소스]에 **없는 사실·수치·날짜·이름·항목을 절대 새로 만들지 말 것**(편집 ≠ 창작). - 기존 결정·액션·오픈이슈·논의 항목을 **임의로 삭제·병합·축약하지 말 것** — 모든 정보를 보존한다(완전성 우선). - 화자번호("참석자 N" 등)가 남아 있으면 팀/역할로 정리한다. - 기존 섹션 구조(회의 개요 / 핵심 요약 / 주요 논의·쟁점 / 결정 사항 / 액션 아이템(표) / 오픈 이슈 / 리스크)를 **유지**한다. 없는 섹션을 억지로 만들지 않는다. - 출력은 다듬어진 **보고서 본문 하나**뿐. 머리말·설명·코드펜스(\`\`\`) 금지. [근거 소스] \`\`\` ${source} \`\`\` [회의록] ${report}`; } /** * [액션 상세 확장 — task 노트용] 슬림 액션 표에는 '작업 상세'가 없어 Google Task 노트가 * 앙상해진다. 이 프롬프트는 각 액션을 '회의 불참자도 무엇을 해야 하는지 이해할' 자기완결 * 설명으로 풀어 쓴다(근거 소스 기반, 환각 금지). 번호는 입력과 1:1로 매핑해 파싱한다. */ export function buildTaskDetailPrompt( actions: { owner: string; work: string; due: string; source: string }[], meetTitle: string, source: string, ): string { const list = actions .map((a, i) => `[${i + 1}] (담당: ${a.owner || '미지정'} · 기한: ${a.due || '미정'} · 근거: ${a.source || '—'}) ${a.work}`) .join('\n'); return `# 임무 아래 [액션 목록]의 각 항목을, 이 회의에 **참석하지 않은 담당자도 무엇을 해야 하는지 이해**할 수 있게 풀어서 설명하라. 각 항목마다 2~3문장. # 규칙 - 각 설명에 담을 것(가능한 범위에서): **무엇을** 하는 작업인지 / **왜**(배경·목적) / **기대 결과물·완료 기준**. - **[근거 소스]에서 확인되는 내용만** 쓴다. 소스에 없는 수치·인물·마감·결과를 **지어내지 말 것**. 정보가 부족하면 액션 문장을 더 명확히 풀어 쓰는 선에서 멈춘다(억지 창작 금지). - 액션 제목을 그대로 반복하지 말고 실질 설명을 준다. 회의 화자번호("참석자 N")를 쓰지 말고 팀/역할로. - 각 설명은 **한 문단(줄바꿈 없이)**. # 출력 형식 (정확히 이 형식, 번호는 입력과 1:1 대응) [1] <설명 한 문단> [2] <설명 한 문단> … [회의] ${meetTitle} [액션 목록] ${list} [근거 소스] \`\`\` ${source} \`\`\``; }