회의록: include_checklist 꺼짐일 때 회의 체크리스트 섹션 후처리 제거
Made-with: Cursor
This commit is contained in:
@@ -140,6 +140,12 @@ function buildMeetingMinutesSystemPrompt(settings) {
|
||||
lines.push("사용자 추가 지시:");
|
||||
lines.push(custom.trim());
|
||||
}
|
||||
if (!includeChecklist) {
|
||||
lines.push("");
|
||||
lines.push(
|
||||
"【출력에서 제외(최종)】`## 회의 체크리스트`, `## 후속 확인 체크리스트` 같은 체크리스트 전용 제목, 그 아래 `- [ ]`·불릿 목록, 회의 본문 끝의 괄호 메타 문장(예: 체크리스트를 마지막으로 작성)은 넣지 마세요."
|
||||
);
|
||||
}
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
@@ -368,10 +374,23 @@ function isMeetingChecklistSectionTitle(title) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 모델이 덧붙이는 메타 문장(체크리스트 섹션 직후 등)
|
||||
* @param {string} t
|
||||
*/
|
||||
function isChecklistMetaParentheticalLine(t) {
|
||||
const s = String(t || "").trim();
|
||||
if (!s || s.length > 200) return false;
|
||||
if (!/^\(/.test(s) || !/\)$/.test(s)) return false;
|
||||
if (/체크리스트/.test(s) && /(작성|마지막|섹션)/.test(s)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/** 체크리스트 항목 뒤에 붙는 운영/후속 안내 문단(제거 대상) */
|
||||
function isPostChecklistBoilerplateLine(t) {
|
||||
const s = String(t || "").trim();
|
||||
if (!s) return false;
|
||||
if (isChecklistMetaParentheticalLine(s)) return true;
|
||||
if (/필요\s*시\s*시연/i.test(s)) return true;
|
||||
if (/필요\s*시\s*위\s*액션\s*아이템별/i.test(s)) return true;
|
||||
if (/피드백\s*제출\s*방식/i.test(s) && /(문서|슬랙|이메일)/i.test(s)) return true;
|
||||
@@ -478,12 +497,54 @@ function removeKnownBoilerplateLines(markdown) {
|
||||
}
|
||||
|
||||
/**
|
||||
* API·저장·생성 공통: 스크립트 제거 → 체크리스트까지만 → 말미 안내 제거 → 말미 섹션(추가 메모·추가 권고 등) 제거 → 제목 승격
|
||||
* `## 회의 체크리스트` 등 제목부터 다음 `##`(동일 레벨 다른 섹션) 전까지 제거. 반복 호출로 다중 블록 제거.
|
||||
* @param {string} markdown
|
||||
* @returns {string}
|
||||
*/
|
||||
function prepareMeetingMinutesForApi(markdown) {
|
||||
function stripFirstMeetingChecklistSectionBlock(markdown) {
|
||||
const lines = String(markdown || "").split("\n");
|
||||
let start = -1;
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const hm = /^(##)\s+(.+)$/.exec(lines[i].trimEnd());
|
||||
if (hm && isMeetingChecklistSectionTitle(hm[2])) {
|
||||
start = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (start < 0) return markdown;
|
||||
let end = lines.length;
|
||||
for (let j = start + 1; j < lines.length; j++) {
|
||||
const hm = /^(##)\s+(.+)$/.exec(lines[j].trimEnd());
|
||||
if (hm) {
|
||||
end = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const out = [...lines.slice(0, start), ...lines.slice(end)];
|
||||
return out.join("\n").replace(/\n{3,}/g, "\n\n").trim();
|
||||
}
|
||||
|
||||
function stripAllMeetingChecklistSectionBlocks(markdown) {
|
||||
let md = String(markdown || "");
|
||||
for (let k = 0; k < 24; k++) {
|
||||
const next = stripFirstMeetingChecklistSectionBlock(md);
|
||||
if (next === md) break;
|
||||
md = next;
|
||||
}
|
||||
return md;
|
||||
}
|
||||
|
||||
/**
|
||||
* API·저장·생성 공통: 스크립트 제거 → (옵션) 체크리스트 섹션 삭제 → 체크리스트 이후 말미 정리 → …
|
||||
* @param {string} markdown
|
||||
* @param {{ omitMeetingChecklistSection?: boolean }} [options]
|
||||
* @returns {string}
|
||||
*/
|
||||
function prepareMeetingMinutesForApi(markdown, options = {}) {
|
||||
let md = stripVerbatimScriptSections(markdown);
|
||||
if (options.omitMeetingChecklistSection === true) {
|
||||
md = stripAllMeetingChecklistSectionBlocks(md);
|
||||
}
|
||||
md = stripTrailingAfterMeetingChecklistSection(md);
|
||||
md = removeKnownBoilerplateLines(md);
|
||||
md = stripTrailingJunkSectionsFromStart(md);
|
||||
@@ -645,7 +706,7 @@ async function transcribeMeetingAudio(openai, filePath, uiModel = DEFAULT_TRANSC
|
||||
* @param {string} opts.uiModel - gpt-5-mini | gpt-5.4
|
||||
* @param {(m: string) => string} opts.resolveApiModel
|
||||
*/
|
||||
async function generateMeetingMinutes(openai, { systemPrompt, userContent, uiModel, resolveApiModel }) {
|
||||
async function generateMeetingMinutes(openai, { systemPrompt, userContent, uiModel, resolveApiModel, omitMeetingChecklistSection }) {
|
||||
const apiModel = resolveApiModel(uiModel || "gpt-5-mini");
|
||||
const completion = await openai.chat.completions.create({
|
||||
model: apiModel,
|
||||
@@ -658,7 +719,7 @@ async function generateMeetingMinutes(openai, { systemPrompt, userContent, uiMod
|
||||
],
|
||||
});
|
||||
const raw = (completion.choices?.[0]?.message?.content || "").trim();
|
||||
return prepareMeetingMinutesForApi(raw);
|
||||
return prepareMeetingMinutesForApi(raw, { omitMeetingChecklistSection: omitMeetingChecklistSection === true });
|
||||
}
|
||||
|
||||
const CHECKLIST_EXTRACT_SYSTEM = `You extract actionable work items from Korean meeting minutes (Markdown).
|
||||
|
||||
Reference in New Issue
Block a user