Phase 14 구현: 회의 모드 (Meeting Mode)

실시간 녹음 + 타임스탬프 메모 + STT 전사 + LLM 구조화 회의록 + PDF/MD 내보내기.
CaptionService 연동, 동시 사용 충돌 방지, 긴 회의 2-pass 요약 지원.
DB 2테이블, IPC 15채널, UI 3뷰(목록/녹음/상세), 12개 locale i18n.
This commit is contained in:
Yun Chan 2026-04-08 01:16:52 +09:00
parent dd68fc9ccd
commit d0c4f9ee53
38 changed files with 2550 additions and 769 deletions

View file

@ -136,6 +136,18 @@ import type {
TemplateSessionInfo,
TemplateFieldCompletedEvent,
TemplateSessionCompletedEvent,
MeetingStartResult,
MeetingMemo,
MeetingAddMemoParams,
MeetingModeStateInfo,
MeetingSessionPage,
MeetingGetSessionsParams,
MeetingSessionDetail,
MeetingGetSessionParams,
MeetingDeleteSessionParams,
MeetingExportParams,
MeetingProcessingProgress,
CaptionSegment,
} from '@shared/types'
import { Feature } from '@shared/types'
import type { IPCResult } from '@shared/errors'
@ -553,6 +565,40 @@ const electronAPI = {
onError: (cb: (data: ConversationError) => void): Unsubscribe =>
on(IPC_CHANNELS.VOICE_CONVERSATION.ERROR, cb),
},
// ── Meeting Mode (Phase 14) ───────────────────────────
meetingMode: {
startRecording: () =>
invoke<MeetingStartResult>(IPC_CHANNELS.MEETING_MODE.START_RECORDING),
stopRecording: () =>
invoke<void>(IPC_CHANNELS.MEETING_MODE.STOP_RECORDING),
addMemo: (params: MeetingAddMemoParams) =>
invoke<MeetingMemo>(IPC_CHANNELS.MEETING_MODE.ADD_MEMO, params),
getState: () =>
invoke<MeetingModeStateInfo>(IPC_CHANNELS.MEETING_MODE.GET_STATE),
getSessions: (params: MeetingGetSessionsParams) =>
invoke<MeetingSessionPage>(IPC_CHANNELS.MEETING_MODE.GET_SESSIONS, params),
getSession: (params: MeetingGetSessionParams) =>
invoke<MeetingSessionDetail>(IPC_CHANNELS.MEETING_MODE.GET_SESSION, params),
deleteSession: (params: MeetingDeleteSessionParams) =>
invoke<void>(IPC_CHANNELS.MEETING_MODE.DELETE_SESSION, params),
updateTitle: (params: { sessionId: string; title: string }) =>
invoke<void>(IPC_CHANNELS.MEETING_MODE.UPDATE_TITLE, params),
exportPdf: (params: MeetingExportParams) =>
invoke<string>(IPC_CHANNELS.MEETING_MODE.EXPORT_PDF, params),
exportMarkdown: (params: MeetingExportParams) =>
invoke<string>(IPC_CHANNELS.MEETING_MODE.EXPORT_MARKDOWN, params),
onStateChanged: (cb: (e: MeetingModeStateInfo) => void): Unsubscribe =>
on(IPC_CHANNELS.MEETING_MODE.STATE_CHANGED, cb),
onSegment: (cb: (e: CaptionSegment) => void): Unsubscribe =>
on(IPC_CHANNELS.MEETING_MODE.SEGMENT, cb),
onProcessingProgress: (cb: (e: MeetingProcessingProgress) => void): Unsubscribe =>
on(IPC_CHANNELS.MEETING_MODE.PROCESSING_PROGRESS, cb),
onSessionCompleted: (cb: (e: MeetingSessionDetail) => void): Unsubscribe =>
on(IPC_CHANNELS.MEETING_MODE.SESSION_COMPLETED, cb),
onError: (cb: (e: { code: number; message: string }) => void): Unsubscribe =>
on(IPC_CHANNELS.MEETING_MODE.ERROR, cb),
},
} as const
contextBridge.exposeInMainWorld('electronAPI', electronAPI)