회의록 AI: 추가 지시 우선, 체크리스트/액션 시스템 강제 완화, include_checklist 기본 끔

Made-with: Cursor
This commit is contained in:
2026-04-15 17:15:51 +09:00
parent 51a402d223
commit 046366599d
6 changed files with 58 additions and 69 deletions

View File

@@ -41,7 +41,7 @@
- 학습센터 UI (좌측 메뉴 + 상단 헤더 + 강의 카드 레이아웃)
- **AI 탐색** (`/ai-explore`): 전체 너비 레이아웃, AI 서비스 카드(프롬프트·회의록 등). 검색창에 **「프롬프트」**가 포함된 채 검색(Enter) 시 프롬프트 라이브러리로 이동
- **회의록 AI** (`/ai-explore/meeting-minutes`): 출력 형식 패널에서 체크리스트는 별도 체크박스 없이 시스템 프롬프트에 항상 반영됩니다(업무 체크리스트 AI 연동). 기본 **추가 지시** 문구`views/meeting-minutes.ejs``mmDefaultCustomInstructions`입니다.
- **회의록 AI** (`/ai-explore/meeting-minutes`): 회의록 생성 시스템 프롬프트는 `lib/meeting-minutes.js``buildMeetingMinutesSystemPrompt`에서 구성하며, **추가 지시**가 형식·섹션(체크리스트 포함 여부, 액션 표기 등)에 우선합니다. DB `meeting_ai_prompts.include_checklist``true`일 때만 회의 체크리스트 강제 블록을 넣고, 기본값은 `false`입니다. 기존 DB에 `include_checklist = true`가 남아 있으면 `UPDATE meeting_ai_prompts SET include_checklist = false`로 끄거나, 화면에서 **프롬프트 저장**으로 덮어씁니다. 기본 **추가 지시**`views/meeting-minutes.ejs``mmDefaultCustomInstructions`입니다.
- **대시보드** (`/dashboard`): AI 탐색과 유사한 카드 그리드·검색으로 대시보드를 모아 표시. 첫 카드 **경영성과 대시보드**는 `/dashboard/business-performance`로 연결
- **경영성과 대시보드** (`/dashboard/business-performance`): **위쪽 대시보드 조회**(Chart.js 인라인), **아래 엑셀 업로드**(`.xlsx`, 매출일보 시트) 순서. 본문은 AI 프롬프트 페이지와 동일하게 **`main.container.container-ai-full`**(전체 너비·좌우 24px)로 맞춤. 대시보드 상단 **연도·분기**로 `mgmt_perf_uploads`에 저장된 해당 기간 **최신 스냅샷**을 불러오며, 쿼리 **`?year=2026&quarter=1`** 또는 폼 조회와 동일. 해당 기간 업로드가 없으면 기본 JSON 샘플을 쓰고 안내 문구를 표시합니다. `public/mgmt-perf/dashboard.css`에 있던 **범용 `.container { background: white }`** 는 앱 페이지에서 `main.container`까지 적용되어 회색 본문이 가려졌으므로 제거하고, 흰 카드는 **`.mgmt-perf-embed .container`** 만 사용합니다. 업로드는 DB(`mgmt_perf_uploads` / `mgmt_perf_snapshots`) 또는 DB 미연결 시 `data/mgmt-perf-last-state.json`에 스냅샷 저장. 최근 업로드 행 **`DELETE /api/mgmt-perf/upload/:id`** 로 삭제(PG는 CASCADE, 파일 전용 모드는 `id=file`). 단독 임베드 페이지는 `/dashboard/business-performance/embed`(본문에 `body.mgmt-perf-standalone`으로 어두운 배경). Express에서 **`/mgmt-perf/*``public/mgmt-perf/`** 정적 제공이 등록되어 있어 `dashboard-app.js`·`chart.umd.min.js`(CDN 대신 동봉)가 항상 같은 오리진에서 로드됩니다. 업로드 시 **한글 파일명**은 multer 기본(`defParamCharset` 생략 시 latin1)으로 온 `originalname`을 **`lib/decode-upload-filename.js`**의 `decodeUploadFilename`으로 보정합니다(`decodeURIComponent(escape(...))` 우선, 이어서 `Buffer` latin1→utf8). Busboy에 `defParamCharset: 'utf8'`를 켜면 이중 디코딩으로 깨질 수 있어 두지 않습니다. 탭 전환·차트 렌더는 **ASCII 섹션 id**(`mgmt-sec-sales` 등)와 `state.currentSection`으로 동기화합니다. 리버스 프록시 사용 시 업로드 실패하면 **`client_max_body_size`**(예: 64m)와 **`/api/`·`/mgmt-perf/` → Node** 전달 여부를 확인. 엑셀 집계 치환은 `npm install``xlsx` 설치 후 서버 재시작.
- **경영성과 데이터 확인**: 브라우저에서 `GET /api/mgmt-perf/status`(JSON)로 최근 스냅샷의 `payloadKeys`, `_uploadMeta`(행 수 등)를 확인할 수 있습니다. **현재 구현**은 엑셀에서 **매출일보 행 수·시트명만** `payload._uploadMeta`에 넣고, **차트 수치는 기본 시드 JSON**(`data/mgmt-perf-default-payload.json`)을 씁니다. 5,000행이어도 차트가 엑셀 집계와 일치하려면 **별도 집계·매핑 로직**이 필요합니다.

View File

@@ -144,7 +144,7 @@ CREATE TABLE IF NOT EXISTS meeting_ai_prompts (
include_attendees BOOLEAN NOT NULL DEFAULT true,
include_summary BOOLEAN NOT NULL DEFAULT true,
include_action_items BOOLEAN NOT NULL DEFAULT true,
include_checklist BOOLEAN NOT NULL DEFAULT true,
include_checklist BOOLEAN NOT NULL DEFAULT false,
custom_instructions TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
@@ -154,7 +154,7 @@ CREATE TABLE IF NOT EXISTS meeting_ai_prompts (
CREATE INDEX IF NOT EXISTS idx_meeting_ai_prompts_user ON meeting_ai_prompts (user_email);
-- 기존 DB: 신규 행 기본값만 갱신(이미 저장된 include_checklist 값은 유지)
ALTER TABLE meeting_ai_prompts ALTER COLUMN include_checklist SET DEFAULT true;
ALTER TABLE meeting_ai_prompts ALTER COLUMN include_checklist SET DEFAULT false;
CREATE TABLE IF NOT EXISTS meeting_ai_meetings (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

View File

@@ -16,7 +16,7 @@ const defaultPromptRow = (email) => ({
include_attendees: true,
include_summary: true,
include_action_items: true,
include_checklist: true,
include_checklist: false,
custom_instructions: null,
});
@@ -70,7 +70,7 @@ async function ensureUserAndDefaultPrompt(pgPool, email) {
await pgPool.query(`INSERT INTO meeting_ai_users (email) VALUES ($1) ON CONFLICT (email) DO NOTHING`, [email]);
await pgPool.query(
`INSERT INTO meeting_ai_prompts (user_email, include_title_line, include_attendees, include_summary, include_action_items, include_checklist)
VALUES ($1, true, true, true, true, true)
VALUES ($1, true, true, true, true, false)
ON CONFLICT (user_email) DO NOTHING`,
[email]
);
@@ -104,7 +104,7 @@ async function getPromptRow(pgPool, email) {
include_attendees: p.include_attendees !== false,
include_summary: p.include_summary !== false,
include_action_items: p.include_action_items !== false,
include_checklist: true,
include_checklist: p.include_checklist === true,
custom_instructions: p.custom_instructions,
created_at: p.created_at || null,
updated_at: p.updated_at || null,
@@ -134,7 +134,7 @@ async function upsertPrompt(pgPool, email, fields) {
fields.includeAttendees,
fields.includeSummary,
fields.includeActionItems,
true,
fields.includeChecklist === true,
fields.customInstructions || null,
]
);
@@ -151,7 +151,7 @@ async function upsertPrompt(pgPool, email, fields) {
include_attendees: fields.includeAttendees,
include_summary: fields.includeSummary,
include_action_items: fields.includeActionItems,
include_checklist: true,
include_checklist: fields.includeChecklist === true,
custom_instructions: fields.customInstructions || null,
updated_at: t,
created_at: prev.created_at || t,

View File

@@ -48,50 +48,18 @@ function resolveTranscriptionApiModel(uiModel) {
* DB에 저장된 옵션으로 시스템 프롬프트 구성
* @param {object} settings - meeting_ai_prompts 행(카멜 또는 스네이크)
*/
/** 액션 아이템 — 정의·목적·What/Who/When (회의록 생성 시스템 프롬프트용) */
const ACTION_ITEMS_GUIDANCE_LINES = [
"【액션 아이템(Action Item)】",
"정의: 회의 중 논의된 내용에 따라 구성원들이 완료해야 하는 구체적인 작업, 활동 또는 조치입니다.",
"목적: 누가(Who), 언제(When), 무엇을(What), 필요 시 어떻게(How)까지 명확히 하여 후속 조치를 추적·관리합니다.",
"필수 요소: What(수행해야 할 구체적 작업), Who(작업을 완료할 책임이 있는 특정 개인), When(완료해야 하는 구체적 일시·기한). 원문에 없으면 추측하지 말고 미정·TBD 등으로 표기하세요.",
"작성 예시: \"김대리(Who) - 10월 24일까지(When) - OO 프로젝트 보고서 초안 작성 및 참석자 배포(What)\".",
"회의록에는 반드시 별도 마크다운 섹션(예: ## 액션 아이템 또는 ## Action Items)으로 번호 목록·하위 항목·표 등으로 정리하세요. 액션 아이템과 회의 체크리스트 섹션은 서로 구분하세요.",
/** 액션 아이템 — 형식은 사용자 추가 지시 우선(What/Who/When 강제 없음) */
const ACTION_ITEMS_GUIDANCE_MINIMAL = [
"【액션 아이템】",
"「Action Item」포함이 켜져 있으면 별도 마크다운 섹션(예: ## 액션 아이템 또는 ## Action Items)으로 후속 과제를 정리합니다.",
"**항목 표기(번호·부제목·영문 Who/When/What 라벨 사용 여부 등)는 아래「사용자 추가 지시」를 가장 우선합니다.** 추가 지시에 형식이 없으면 간단한 번호 목록·불릿으로, 원문·전사에서 확정된 일만 적습니다.",
"담당자·이름·기한은 **회의 원문·전사에 명시된 경우에만** 적습니다. 없거나 불명확하면 생략하거나 미정·TBD로 표기하고, 원문에 없는 인물·담당을 추측하여 쓰지 마세요.",
];
/**
* 회의록·담당자 표기 시 참고할 사내 임직원 성명(쉼표 구분, 중복은 로드 시 제거)
* 전사 오타·유사 발음 교정용 — 영어·외국어·외부 인명은 원문 유지
*/
const MEETING_EMPLOYEE_NAMES_RAW =
"강봉조, 강선규, 강성국, 강성준, 강신균, 강인창, 강종덕, 고영철, 곽병우, 구본엽, 구병철, 권기현, 권순영, 권현철, 김광오, 김광용, 김기덕, 김기연, 김기홍, 김다경, 김대환, 김도균, 김동욱, 김상진, 김성빈, 김성희, 김수지, 김승현, 김의수, 김용현, 김재복, 김정섭, 김정훈, 김태식, 김태우, 김하영, 김항래, 김혜정, 김형규, 김형철, 김효규, 김창열, 남서연, 노은식, 노윤규, 노현주, 류덕현, 박경덕, 박기형, 박대희, 박병찬, 박상욱, 박상현, 박용영, 박정관, 박종철, 박현규, 배문우, 배준영, 서민호, 서원민, 설재민, 성필영, 송제웅, 송지연, 송홍규, 신동균, 신극돈, 신에스더, 신우재, 신화섭, 안종석, 양동환, 양성민, 양소라, 양준삼, 오승우, 오주헌, 우현, 유용일, 유서연, 유성호, 유주상, 유철명, 유휘상, 유웨이, 윤도상, 윤비시아, 윤상혁, 윤지은, 윤종석, 은재민, 이가람, 이강열, 이규민, 이길현, 이동명, 이동석, 이리종철, 이민호, 이병훈, 이사우, 이상규, 이상설, 이상윤, 이상훈, 이성희, 이승묵, 이아정, 이영환, 이재국, 이재동, 이정용, 이정열, 이주승, 이태용, 이석제, 임영규, 임창민, 임현도, 임호균, 장병주, 장소라, 전문호, 정관욱, 정광연, 정대진, 정안용, 정일구, 정재형, 정정주, 정진용, 정인선, 정효진, 조익환, 조정숙, 조현우, 지준경, 진현우, 진형민, 채광석, 천지영, 최봉진, 최상현, 최세영, 최연봉, 최연이, 최원녕, 최인환, 최정운, 최철, 최환성, 한수진, 한준희, 한혜연, 허수연, 허수정, 현진섭, 형성복";
function getMeetingEmployeeNamesDeduped() {
const seen = new Set();
const out = [];
for (const part of MEETING_EMPLOYEE_NAMES_RAW.split(/[,\s]+/)) {
const t = part.trim();
if (!t || seen.has(t)) continue;
seen.add(t);
out.push(t);
}
return out;
}
/** @type {string[]|null} */
let _employeeNamesForPromptCache = null;
function getMeetingEmployeeNamesCommaSeparated() {
if (!_employeeNamesForPromptCache) {
_employeeNamesForPromptCache = getMeetingEmployeeNamesDeduped().join(", ");
}
return _employeeNamesForPromptCache;
}
const EMPLOYEE_NAME_GUIDANCE_LINES = [
"【임직원 인명 표기】",
"참석자·발언자·액션 아이템의 담당자(Who)·회의 체크리스트에 언급된 주요 담당자 등, 사람 이름을 쓸 때 원문·전사가 음성 인식 오류·유사 발음으로 틀릴 수 있습니다.",
"아래는 사내 임직원 성명 참고 목록입니다. 문맥상 동일 인물로 확실할 때만, 목록에서 가장 가까운 표기로 통일해 주세요. 억지로 맞추지 마세요.",
"영어·외국어 표기, 또는 위 목록과 완전히 다른 고유 인명(외부 인물·고객 등)은 원문 그대로 두어도 됩니다.",
"임직원 참고 목록: " + getMeetingEmployeeNamesCommaSeparated(),
const EMPLOYEE_NAME_GUIDANCE_MINIMAL = [
"【인명·담당자】",
"참석자·담당자 이름은 **원문·전사에 실제로 등장한 표기**를 따릅니다. 음성 인식 오류로 같은 사람이 문맥상 확실할 때만 철자를 다듬습니다.",
"사내 다른 성명 목록으로 바꿔 끼우거나, 전사에 없는 사람을 만들어내지 마세요.",
];
/** 회의 체크리스트 — 정의·목적·전·중·후 + 업무 체크리스트 AI 연동 */
@@ -109,6 +77,7 @@ function buildMeetingMinutesSystemPrompt(settings) {
const includeAttendees = settings.includeAttendees !== false && settings.include_attendees !== false;
const includeSummary = settings.includeSummary !== false && settings.include_summary !== false;
const includeActionItems = settings.includeActionItems !== false && settings.include_action_items !== false;
const includeChecklist = settings.includeChecklist === true || settings.include_checklist === true;
const custom =
(settings.customInstructions && String(settings.customInstructions)) ||
(settings.custom_instructions && String(settings.custom_instructions)) ||
@@ -116,10 +85,11 @@ function buildMeetingMinutesSystemPrompt(settings) {
const lines = [
"당신은 사내 회의록을 정리하는 전문가입니다. 입력된 회의 원문(또는 음성 전사)을 바탕으로 읽기 쉬운 회의록을 한국어로 작성합니다.",
"【규칙 우선순위】이 메시지 아래에「사용자 추가 지시」가 있으면, 섹션 구성·액션 항목 표기·체크리스트 포함 여부 등은 **사용자 추가 지시를 최우선**으로 따릅니다. 일반 지시와 다르면 사용자 추가 지시가 우선합니다.",
];
EMPLOYEE_NAME_GUIDANCE_LINES.forEach((line) => lines.push(line));
EMPLOYEE_NAME_GUIDANCE_MINIMAL.forEach((line) => lines.push(line));
lines.push("");
lines.push("출력 형식 요구:");
lines.push("출력 형식 요구(위 체크박스·저장값):");
if (includeTitle) lines.push("- 맨 위에 회의 제목 한 줄(입력에 제목이 없으면 내용에서 추정).");
if (includeAttendees) lines.push("- 참석자·발언자가 드러나면 구분해 정리.");
if (includeSummary) lines.push("- 핵심 요약(불릿 또는 짧은 단락).");
@@ -127,22 +97,41 @@ function buildMeetingMinutesSystemPrompt(settings) {
lines.push("");
lines.push("【원문·전사와 회의록 분리】");
lines.push("- 음성 전사·회의 원문 전체를 회의록 본문에 다시 붙여 넣지 마세요. 원문/전사는 시스템에서 별도 필드(전사 기록·회의 원문)로 이미 보관됩니다.");
lines.push("- ‘스크립트’, ‘스크랩트’(오타), ‘원문 전사’, ‘전사문’, Verbatim 등 원문을 통째로 실어 나르는 제목의 섹션을 만들지 마세요. 요약·결정·액션·체크리스트만 회의록에 포함하세요.");
lines.push("- 회의 제목, 참석자, 요약, 결정 사항, 액션 아이템 등은 반드시 마크다운 제목(예: ## 회의 제목, ### 요약)으로 구분해 주세요.");
if (includeChecklist) {
lines.push(
"- ‘스크립트’, ‘스크랩트’(오타), ‘원문 전사’, ‘전사문’, Verbatim 등 원문을 통째로 실어 나르는 제목의 섹션을 만들지 마세요. 요약·결정·액션·체크리스트만 회의록 본문에 포함하세요."
);
} else {
lines.push(
"- ‘스크립트’, ‘스크랩트’(오타), ‘원문 전사’, ‘전사문’, Verbatim 등 원문을 통째로 실어 나르는 제목의 섹션을 만들지 마세요. 요약·결정·액션 등 **사용자 추가 지시에 적은 섹션만** 포함하세요."
);
lines.push(
"- 사용자 추가 지시에 「회의 체크리스트」「후속 확인 체크리스트」 등이 없으면, 그런 제목의 별도 체크리스트 섹션을 만들지 마세요."
);
}
lines.push("- 회의 제목, 참석자, 요약, 결정 사항, 액션 아이템 등은 마크다운 제목(예: ## 회의 제목, ### 요약)으로 구분해 주세요.");
if (includeActionItems) {
lines.push("");
ACTION_ITEMS_GUIDANCE_LINES.forEach((line) => lines.push(line));
ACTION_ITEMS_GUIDANCE_MINIMAL.forEach((line) => lines.push(line));
}
if (includeChecklist) {
lines.push("");
MEETING_CHECKLIST_GUIDANCE_LINES.forEach((line) => lines.push(line));
}
lines.push("");
MEETING_CHECKLIST_GUIDANCE_LINES.forEach((line) => lines.push(line));
lines.push("");
lines.push("【말미 섹션 금지】");
lines.push(
"- 회의 체크리스트·액션 아이템 이후에 ‘추가 메모’, ‘확인 필요 사항’, ‘추가 메모 / 확인 필요 사항’ 등 제목의 섹션을 두지 마세요. CSV·표 제안, 설문/스크립트 초안, ‘필요하시면’ 안내 등 말미 부가 안내도 포함하지 않습니다."
);
lines.push(
"- 체크리스트 섹션을 마지막으로 두고, 그 아래에 시연·피드백 제출 방식(문서/슬랙/이메일) 회신, 액션 우선순위 재정렬·담당·기한 확정 안내, DRM·후보군 추가 작성 제안 같은 **운영/후속 안내 문단**을 붙이지 마세요."
);
if (includeChecklist) {
lines.push(
"- 회의 체크리스트·액션 아이템 이후에 ‘추가 메모’, ‘확인 필요 사항’, ‘추가 메모 / 확인 필요 사항’ 등 제목의 섹션을 두지 마세요. CSV·표 제안, 설문/스크립트 초안, ‘필요하시면’ 안내 등 말미 부가 안내도 포함하지 않습니다."
);
lines.push(
"- 체크리스트 섹션을 마지막으로 두고, 그 아래에 시연·피드백 제출 방식(문서/슬랙/이메일) 회신, 액션 우선순위 재정렬·담당·기한 확정 안내, DRM·후보군 추가 작성 제안 같은 **운영/후속 안내 문단**을 붙이지 마세요."
);
} else {
lines.push(
"- 액션 아이템·결정 사항 이후에 ‘추가 메모’, ‘확인 필요 사항’, ‘추가 메모 / 확인 필요 사항’ 등 제목의 섹션을 두지 마세요. CSV·표 제안, 설문/스크립트 초안, ‘필요하시면’ 안내 등 말미 부가 안내도 포함하지 않습니다."
);
}
lines.push(
"- ‘추가 권고’, ‘회의록 작성자의 제안’, 엑셀 담당자 배정 템플릿·추적 체크리스트 제안 등 **회의 본문과 무관한 조언·제안 섹션**을 두지 마세요."
);

View File

@@ -1066,7 +1066,7 @@ function mapRowToMeetingPrompt(row) {
includeAttendees: row.include_attendees !== false,
includeSummary: row.include_summary !== false,
includeActionItems: row.include_action_items !== false,
includeChecklist: true,
includeChecklist: row.include_checklist === true,
customInstructions: row.custom_instructions || "",
createdAt: row.created_at,
updatedAt: row.updated_at,
@@ -1832,7 +1832,7 @@ app.put("/api/meeting-minutes/prompt", requireMeetingMinutesEmail, express.json(
const includeAttendees = b.includeAttendees !== false;
const includeSummary = b.includeSummary !== false;
const includeActionItems = b.includeActionItems !== false;
const includeChecklist = true;
const includeChecklist = b.includeChecklist === true;
const customInstructions = (b.customInstructions || "").toString().slice(0, 8000);
const row = await meetingAiStore.upsertPrompt(pgPool, req.meetingUserEmail, {
includeTitleLine,

View File

@@ -11,13 +11,13 @@
<% var mmDefaultCustomInstructions = `아래 회의 내용(또는 녹취/메모)을 바탕으로 다음 형식으로 정리해 주세요.
원문·전사 전체를 회의록에 다시 붙여 넣지 마세요.
‘스크립트’·‘스크랩트’(오타)·‘원문 전사’ 같은 섹션은 만들지 말고, 요약·결정·액션·체크리스트만 작성하세요.
‘스크립트’·‘스크랩트’(오타)·‘원문 전사’ 같은 섹션은 만들지 말고, 요약·결정·액션만 작성하세요.
회의 제목·참석자·요약 등은 ## 마크다운 제목으로 구분하세요.
1) 회의 개요: 일시, 참석자(알 수 있는 경우), 목적
2) 논의 안건별 요약
3) 결정 사항 (명확한 문장으로)
4) 액션 아이템: 별도 섹션. 각 항목에 What(할 일)·Who(담당자)·When(기한)을 구체적으로
4) 액션 아이템: 별도 섹션. 각 항목에 할 일·담당자·기한을 구체적으로 적어주세요. 만약 담당자와 기한을 알 수 없으면 안적어도 무방합니다.
‘추가 권고’, ‘회의록 작성자의 제안’, 엑셀 템플릿·추적 체크리스트 제안 등은 넣지 마세요.`; %>
<% var mmNow = new Date(); var mmTodayIso = mmNow.getFullYear() + '-' + ('0' + (mmNow.getMonth() + 1)).slice(-2) + '-' + ('0' + mmNow.getDate()).slice(-2); %>
@@ -52,7 +52,7 @@
</button>
</div>
<div class="mm-prompt-body" id="mmPromptBody" hidden>
<p class="subtitle">회의록에 포함할 항목을 선택하고, 추가 지시를 입력할 수 있습니다. 시스템 프롬프트에 액션 아이템(What·Who·When)과 회의 체크리스트(전·중·후) 정의가 포함되며, 체크리스트는 업무 체크리스트 AI 연동을 위해 항상 포함됩니다.</p>
<p class="subtitle">회의록에 포함할 항목을 선택하고, 추가 지시를 입력할 수 있습니다. 형식·섹션 구성은 <strong>추가 지시</strong>가 시스템 기본보다 우선합니다. 회의 체크리스트 섹션은 DB에 별도로 켜지 않은 경우 생성하지 않으며, 저장 후 업무 체크리스트 자동 연동은 액션·후속 항목에서 추출합니다.</p>
<div class="mm-prompt-form" id="mmPromptForm">
<div class="mm-checkbox-row" role="group" aria-label="회의록에 포함할 항목">
<label class="mm-checkbox-item"><input type="checkbox" id="mmIncTitle" checked /> <span>제목 한 줄</span></label>
@@ -591,7 +591,7 @@
includeAttendees: document.getElementById('mmIncAtt').checked,
includeSummary: document.getElementById('mmIncSum').checked,
includeActionItems: document.getElementById('mmIncAct').checked,
includeChecklist: true,
includeChecklist: false,
customInstructions: document.getElementById('mmCustomInstr').value
};
api('/api/meeting-minutes/prompt', {