회의록 AI: 추가 지시 우선, 체크리스트/액션 시스템 강제 완화, include_checklist 기본 끔
Made-with: Cursor
This commit is contained in:
@@ -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행이어도 차트가 엑셀 집계와 일치하려면 **별도 집계·매핑 로직**이 필요합니다.
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(
|
||||
"- ‘추가 권고’, ‘회의록 작성자의 제안’, 엑셀 담당자 배정 템플릿·추적 체크리스트 제안 등 **회의 본문과 무관한 조언·제안 섹션**을 두지 마세요."
|
||||
);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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', {
|
||||
|
||||
Reference in New Issue
Block a user