Phase 15.5 구현: 화자 구분 (Speaker Diarization)

- Sidecar: pyannote /diarize 엔드포인트 + requirements.txt 업데이트
- LLM 기반 화자 추정 (Phase 1 — 오디오 보존 없이 전사 텍스트 분석)
- CaptionSegment에 speaker 필드 추가
- EditableSegment: 화자별 색상 바 + 화자 Chip 표시
- TranscriptTab: 화자 구분 버튼 + 진행률
- 설정: HuggingFace 토큰 입력 + Diarization 토글
- IPC: DIARIZE + DIARIZATION_PROGRESS 채널
- 에러코드: 895-897
- 12개 locale i18n
This commit is contained in:
Yun Chan 2026-04-08 12:14:00 +09:00
parent da25791c75
commit fc7628327a
25 changed files with 679 additions and 18 deletions

View file

@ -81,6 +81,7 @@ export function MeetingDetailTabs({
const [tabIndex, setTabIndex] = useState(0)
const [dialogOpen, setDialogOpen] = useState(false)
const [generating, setGenerating] = useState(false)
const [diarizing, setDiarizing] = useState(false)
const [editingTitle, setEditingTitle] = useState(false)
const [titleDraft, setTitleDraft] = useState(detail.title ?? '')
@ -176,6 +177,17 @@ export function MeetingDetailTabs({
[],
)
// ── 화자 구분 ──
const handleDiarize = useCallback(async () => {
setDiarizing(true)
const resp = await window.electronAPI.meetingMode.diarize({ sessionId: detail.id })
if (resp.success) {
const updated = await window.electronAPI.meetingMode.getSession({ sessionId: detail.id })
if (updated.success) setDetail(updated.data)
}
setDiarizing(false)
}, [detail.id])
// ── 문서 생성 ──
const handleGenerate = useCallback(
async (templateId: string, customPrompt?: string, customTitle?: string) => {
@ -306,6 +318,8 @@ export function MeetingDetailTabs({
memos={detail.memos}
onEditSegment={handleEditSegment}
onSaveTranscript={handleSaveTranscript}
onDiarize={handleDiarize}
diarizing={diarizing}
/>
)}
{documents.filter(Boolean).map((doc, idx) => {