From 36d77ca22427a9dece105acd8d2ea85013948563 Mon Sep 17 00:00:00 2001 From: Yun Chan Date: Sun, 5 Apr 2026 13:52:41 +0900 Subject: [PATCH] =?UTF-8?q?=ED=95=98=EB=84=A4=EC=8A=A4=20=EC=A0=84?= =?UTF-8?q?=EB=A9=B4=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20+=20Phase=20?= =?UTF-8?q?10=20=ED=82=AC=EB=9F=AC=20=ED=94=BC=EC=B2=98=20=EC=84=A4?= =?UTF-8?q?=EA=B3=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CLAUDE.md | 67 ++--- docs/phases/phase-10-killer-features.md | 318 ++++++++++++++++++++++++ 2 files changed, 343 insertions(+), 42 deletions(-) create mode 100644 docs/phases/phase-10-killer-features.md diff --git a/CLAUDE.md b/CLAUDE.md index 692a51d..d31602a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -77,48 +77,11 @@ npm run typecheck # tsc --noEmit 6. **녹음 UI**: 9개 웨이브 바, cos 분포 가중치, 100ms 애니메이션 ## 현재 상태 -Phase: 9 완료 (Phase 1~9 전부 완료) -마지막 작업: Phase 9 — About 탭 + WAV 저장 + 마이크 테스트 + 온보딩 + MetalDial -다음 작업: 폴리싱, TTS, 빌드 배포 최적화 +Phase: 9 완료 + 폴리싱 완료 (Phase 1~9 전부 완료) +마지막 작업: Ollama 설치 안내 UI + Settings 속도 개선 + 커맨드 선택 팝업 + 실시간 UI 갱신 +다음 작업: **Phase 10 킬러 피처** (실시간 자막, 스크린 컨텍스트, 음성 메모장, 멀티 LLM 체인, 음성 단축키) 차단 이슈: @nut-tree-fork/nut-js 포크 사용 -### ⚠️ 핵심 병목: VoiceModeService ↔ 팝업 연동 미구현 -Speakly RE 재조사로 발견된 치명적 갭: -1. **VoiceModeService가 RecordingTip/ResultPopup과 전혀 연동 안 됨** - - 녹음 시작 시 팝업 표시 안 함, 에러 시 팝업 숨김 안 함 - - Speakly: VoiceModeService가 이벤트 발행 → main/index.js에서 RecordingTipWindow 메서드 호출 -2. **RecordingTipUIState 상태 머신 없음** - - Speakly: OPENING→RECORDING→THINKING→COMPLETED/ERROR/CANCELLED - - D3RO: 상태 없이 수동 show/hide만 -3. **session-aware 윈도우 관리 없음** - - Speakly: showForSession(sessionId) / hideForSession(sessionId) — race condition 방지 -4. **에러 후 복구 안 됨** - - 에러 시 RecordingTip이 "실패" 상태로 남아있고, 핫키가 안 먹힘 - - Speakly: 에러 표시 → 3초 후 자동 숨김 → idle 복귀 - -### Speakly 음성 파이프라인 패턴 (RE 결과) -``` -[핫키 press] → Action Queue에 enqueue → processActionQueue() - → startRecording(): - 1. 시스템 오디오 뮤트 (500ms 후) - 2. emit('recording-tip:show-opening') → RecordingTip 표시 - 3. MicNativeService.start() → 오디오 스트리밍 - 4. emit('recording-tip:mic-ready') → 웨이브 바 활성 - 5. RecognitionSession 생성 → STT 연결 - → 녹음 중: 오디오 레벨 → sendAudioLevel() → 웨이브 바 - -[핫키 release] → stopAndProcess(): - 1. MicNativeService.stop() - 2. accidentalPress 체크 (< 700ms → 취소) - 3. 언뮤트 + 종료 효과음 - 4. RecordingTip → thinking 상태 - 5. session.commitAndWait() → 전사 결과 대기 - 6. 전사 완료 → 텍스트 삽입 시도 - 7. 삽입 성공 → RecordingTip 숨김 - 8. 삽입 실패 → ResultPopup 표시 - 9. 에러 → RecordingTip에 에러 표시 → 3초 후 숨김 -``` - ### DS 컴포넌트 현황 (src/renderer/components/ds/) - CrtDisplay.tsx: WebGL CRT 셰이더 (파형+스캔라인+비네팅+글리치) ✅ - InstrumentPanel.tsx: 메탈 섀시 컨테이너 (각인 텍스트, 노이즈) ✅ @@ -126,9 +89,23 @@ Speakly RE 재조사로 발견된 치명적 갭: - PhysicalButton.tsx: 물리 버튼 (돌출 그림자, 눌림 피드백) ✅ - MetalCard.tsx: 메탈 카드 컨테이너 ✅ - PhosphorText.tsx: 인광 텍스트 (hero/value/label/dim) ✅ -- ❌ MetalDial: 미구현 (시안 A의 핵심 요소) +- MetalDial.tsx: 메탈 다이얼 (동심원 텍스처, 드래그 회전, 금속 광택) ✅ -### Phase 8 구현 내용 (진행 중) +### Phase 9 구현 내용 +- **Settings About 탭**: 앱/Electron 버전, 기술 스택, 프로젝트 링크, 정밀기기 디자인 +- **녹음 WAV 저장**: VoiceModeService 세션 완료 시 WAV 파일 저장 + HistoryService audioLocalPath 연동 +- **마이크 테스트 UI**: Settings Audio 탭 레벨 바 (3초 캡처, audio-level 이벤트) +- **온보딩 플로우**: 4단계 위저드 (환영→마이크 설정→핫키 설정→Ollama 설정→완료) +- **MetalDial 컴포넌트**: 동심원 텍스처, 드래그 회전, 금속 광택 — 시안 A 핵심 요소 완성 +- **오디오 디바이스 선택**: AudioEndpoint + 디바이스 캐싱, Settings에서 실시간 전환 +- **Commands CRUD IPC 연결**: instruction:* 핸들러 완전 연동 + 활성 명령어 선택 UI +- **Ctrl+Shift+C 커맨드 팝업**: 커서 위치에 명령어 선택 팝업, 키보드 탐색 (Arrow/Enter/ESC) +- **Dictionary 편집**: 인라인 편집 + STT initialPrompt에 사전 단어 주입 +- **Ollama 설치 안내**: OllamaGuideModal + 넛징 버블 (Ollama 미실행 시 자동 표시) +- **실시간 UI 갱신**: app:dataChanged IPC 이벤트 → Dashboard/History/Dictionary 자동 리프레시 +- **Settings 속도 개선**: 비동기 디바이스 로드 + 부팅 시 프리캐싱으로 모달 열기 지연 제거 + +### Phase 8 구현 내용 - **SSOT 완료**: d3roPalette에 11개 토큰 추가 (sidebar, chassis, inactive, dimLabel 등) - **매직넘버 제거**: tsx/ts 파일 매직넘버 0개 달성 (theme.ts 제외) - **DS 컴포넌트 SSOT**: 6개 모두 d3roPalette 참조로 교체 @@ -233,6 +210,9 @@ Speakly RE 재조사로 발견된 치명적 갭: - Phase 6: 커스텀 명령어 + 설정 UI 고도화 - Phase 7: 테스트 + 빌드 + 배포 - Phase 7.5: Speakly 패턴 보강 (SoundEffect, AutoLaunch, EditMonitor, 오디오 뮤트) +- Phase 8: UI 디자인 재설계 + SSOT + DS 컴포넌트 정비 +- Phase 9: 품질 보강 + UX 개선 (온보딩, 마이크 테스트, WAV 저장, 커맨드 팝업, Ollama 안내) +- Phase 10: 킬러 피처 — Speakly를 넘어서 (실시간 자막, 스크린 컨텍스트, 음성 메모장, 멀티 LLM 체인, 음성 단축키) ## 설계 문서 (구현 시 반드시 참조) @docs/design/00-master-architecture.md @@ -250,6 +230,9 @@ Speakly RE 재조사로 발견된 치명적 갭: @docs/phases/phase-6.md @docs/phases/phase-7.md @docs/phases/phase-7.5.md +@docs/phases/phase-8.md +@docs/phases/phase-9.md +@docs/phases/phase-10-killer-features.md ## RE 노하우 (패턴 적용 근거) @docs/re-findings/speakly-architecture.md diff --git a/docs/phases/phase-10-killer-features.md b/docs/phases/phase-10-killer-features.md new file mode 100644 index 0000000..037436d --- /dev/null +++ b/docs/phases/phase-10-killer-features.md @@ -0,0 +1,318 @@ +# Phase 10: 킬러 피처 — Speakly를 넘어서 + +> Speakly가 제공하지 않는 D3RO-VOICE 고유 기능. +> 완전 로컬이라는 강점을 극대화하여 차별화된 사용자 경험을 제공한다. + +--- + +## 10.1 실시간 자막 모드 (Live Caption) + +### 목표 +핫키 없이 마이크를 계속 듣고, 화면 하단에 실시간 자막을 오버레이로 표시한다. +회의/강의/영상 시청 시 자동 자막 + 회의록 자동 생성. + +### 구현 방안 +- **Streaming Transcription**: Whisper의 VAD(Voice Activity Detection) 기반 세그먼트 분할 + - 오디오를 5~10초 청크로 분할, 이전 컨텍스트를 initialPrompt로 전달 + - 침묵 감지(500ms 이상) 시 세그먼트 확정 → 다음 세그먼트 시작 +- **오버레이 윈도우**: 항상 최상위(alwaysOnTop), 반투명 배경, 화면 하단 고정 + - Vanilla JS 팝업 (React 번들 불필요, 빠른 렌더링) + - 최근 3줄 표시, 오래된 줄은 페이드아웃 + - 위치/크기 드래그로 조정 가능 +- **회의록 저장**: 모든 세그먼트를 타임스탬프와 함께 히스토리에 자동 저장 + - 세션 종료 시 전체 텍스트를 마크다운으로 내보내기 가능 + - 화자 분리(speaker diarization)는 Phase 10+ (Whisper 자체 미지원, 추후 pyannote 등 연동) + +### 필요 서비스 +- `LiveCaptionService` (신규): 스트리밍 전사 오케스트레이션 +- `AudioCaptureService`: 지속 캡처 모드 추가 (기존 세션 모드와 별도) +- `LocalSTTService`: 스트리밍 전사 API 추가 (청크 단위 transcribe) +- `WindowManager`: LiveCaptionWindow 프리로딩 + 관리 + +### IPC 채널 +| 채널 | 방향 | 설명 | +|------|------|------| +| `caption:start` | handle | 실시간 자막 시작 | +| `caption:stop` | handle | 실시간 자막 종료 | +| `caption:getState` | handle | 자막 상태 조회 (active/inactive) | +| `caption:setPosition` | handle | 오버레이 위치 설정 | +| `caption:segment` | send | 확정된 자막 세그먼트 (main→renderer) | +| `caption:delta` | send | 중간 전사 결과 (main→renderer) | +| `caption:sessionSaved` | send | 회의록 저장 완료 | + +### UI 컴포넌트 +- **LiveCaptionWindow** (Vanilla JS 팝업): 오버레이 자막 표시 +- **CaptionControlBar**: 트레이 메뉴 또는 Dashboard에 시작/정지 토글 +- **CaptionHistoryView**: 저장된 회의록 열람 (HistoryPage 확장) + +### 우선순위: **1순위** (가장 차별화되는 기능) + +--- + +## 10.2 스크린 컨텍스트 (Screen Context) + +### 목표 +활성 앱 이름 + 선택된 텍스트를 LLM 프롬프트에 함께 전달하여 컨텍스트 인식 처리. +예: VS Code에서 코드 선택 후 "이거 설명해줘" → 코드+음성 합쳐서 LLM 처리. + +### 구현 방안 +- **활성 윈도우 감지**: Windows UI Automation API 또는 `@electron/windows-utils` + - 활성 앱 프로세스명, 윈도우 타이틀 가져오기 + - `GetForegroundWindow()` + `GetWindowText()` + `GetModuleFileName()` +- **선택 텍스트 가져오기**: 두 가지 전략 + 1. **클립보드 방식** (안전): Ctrl+C 시뮬레이션 → 클립보드에서 읽기 → 원본 복원 + 2. **UI Automation** (고급): IUIAutomation의 TextPattern으로 직접 읽기 + - 초기에는 클립보드 방식, 추후 UI Automation으로 고도화 +- **LLM 프롬프트 주입**: VoiceModeService에서 컨텍스트를 시스템 프롬프트에 삽입 + ``` + [컨텍스트] + 활성 앱: Visual Studio Code + 활성 파일: src/main/services/VoiceModeService.ts + 선택된 텍스트: + ```typescript + private tryFlushAll(): void { ... } + ``` + + [사용자 음성] + 이 함수가 뭐하는 건지 설명해줘 + ``` +- **앱별 프롬프트 커스텀**: 앱 이름에 따라 다른 시스템 프롬프트 적용 + - VS Code → "코드 관련 질문입니다" + - Chrome → "웹 페이지 내용 관련 질문입니다" + - 일반 → "텍스트 관련 질문입니다" + +### 필요 서비스 +- `ContextService` (신규): 활성 윈도우 + 선택 텍스트 캡처 +- `LocalLLMService`: 컨텍스트 주입 시스템 프롬프트 확장 +- `VoiceModeService`: 녹음 시작 시 자동 컨텍스트 캡처 +- `ConfigService`: 앱별 컨텍스트 설정 저장 + +### IPC 채널 +| 채널 | 방향 | 설명 | +|------|------|------| +| `context:getActiveApp` | handle | 활성 앱 정보 조회 | +| `context:getSelectedText` | handle | 선택된 텍스트 가져오기 | +| `context:setAppConfig` | handle | 앱별 컨텍스트 설정 | +| `context:getAppConfigs` | handle | 앱별 설정 목록 | + +### UI 컴포넌트 +- **ContextIndicator**: StatusBar에 현재 활성 앱 + 컨텍스트 상태 표시 +- **ContextSettingsTab**: Settings에 앱별 프롬프트 커스텀 UI +- **RecordingTip 확장**: 컨텍스트 캡처 상태 아이콘 표시 + +### 우선순위: **2순위** (실용성 높음, 코드 작업 시 매우 유용) + +--- + +## 10.3 음성 메모장 (Voice Memo) + +### 목표 +전사 결과를 카테고리별로 자동 정리하는 전용 메모 시스템. +태그, 마크다운 내보내기, 검색, 필터 지원. + +### 구현 방안 +- **태그 시스템**: `#회의`, `#아이디어`, `#할일`, `#메모` 등 해시태그 자동 감지 + - 전사 텍스트에서 `#단어` 패턴 추출 + - LLM 자동 태그 제안 (선택적): 텍스트 내용 분석 → 태그 추천 + - 수동 태그 추가/편집 +- **카테고리 자동 분류**: LLM 기반 또는 키워드 기반 + - "할 일", "해야 할 것" → `#할일` 자동 태그 + - "아이디어", "생각" → `#아이디어` 자동 태그 +- **마크다운 내보내기**: 태그별/날짜별 그룹핑된 마크다운 파일 생성 + ```markdown + # 음성 메모 — 2026-04-05 + + ## #회의 + - 10:30 AM: 프로젝트 킥오프 미팅에서 논의한 내용... + - 02:15 PM: 디자인 리뷰 피드백... + + ## #할일 + - 11:00 AM: Phase 10 설계서 작성할 것 + ``` +- **DB 확장**: memo 테이블 또는 history 테이블에 태그 컬럼 추가 + ```sql + CREATE TABLE memo_tags ( + id TEXT PRIMARY KEY, + history_id TEXT NOT NULL REFERENCES history(id), + tag TEXT NOT NULL, + created_at INTEGER NOT NULL + ); + CREATE INDEX idx_memo_tags_tag ON memo_tags(tag); + ``` + +### 필요 서비스 +- `MemoService` (신규): 메모 CRUD + 태그 관리 + 내보내기 +- `HistoryService`: 태그 연동 확장 +- `LocalLLMService`: 자동 태그 제안 (선택적) + +### IPC 채널 +| 채널 | 방향 | 설명 | +|------|------|------| +| `memo:getTags` | handle | 전체 태그 목록 | +| `memo:setTags` | handle | 히스토리 항목에 태그 설정 | +| `memo:getByTag` | handle | 태그별 메모 조회 | +| `memo:export` | handle | 마크다운 내보내기 | +| `memo:suggestTags` | handle | LLM 기반 태그 자동 제안 | + +### UI 컴포넌트 +- **MemoPage**: 사이드바에 MEMO 탭 추가, 태그 클라우드 + 메모 목록 +- **TagEditor**: 태그 추가/삭제 인라인 편집 (Chip 기반) +- **MemoExportDialog**: 내보내기 범위/포맷 선택 + +### 우선순위: **3순위** (히스토리 확장, 비교적 단순) + +--- + +## 10.4 멀티 LLM 체인 (Multi-LLM Chain) + +### 목표 +여러 LLM 명령어를 순차 실행하는 파이프라인 기능. +예: 전사 → 번역 → 요약을 한번의 핫키로 실행. + +### 구현 방안 +- **파이프라인 정의**: CustomInstruction에 chain 기능 추가 + ```typescript + interface InstructionChain { + id: string; + name: string; + steps: ChainStep[]; + hotkey?: HotkeyBinding; + } + + interface ChainStep { + instructionId: string; // 기존 CustomInstruction ID 참조 + inputSource: 'previous' | 'original'; // 이전 단계 결과 or 원본 + options?: { + targetLanguage?: string; + temperature?: number; + }; + } + ``` +- **실행 엔진**: VoiceModeService에서 체인 실행 + 1. 전사 완료 → 첫 번째 명령어 실행 + 2. 결과 → 두 번째 명령어의 입력으로 전달 + 3. ... → 최종 결과를 텍스트 삽입 + - 각 단계 진행 상황을 RecordingTip에 표시 + - 중간 취소 가능 (현재 단계 완료 후 중단) +- **파이프라인 에디터**: 드래그 앤 드롭으로 단계 구성 + - 기존 명령어 목록에서 드래그하여 체인에 추가 + - 화살표로 단계 간 연결 시각화 + - 테스트 실행: 샘플 텍스트로 체인 전체 실행 결과 미리보기 + +### 필요 서비스 +- `ChainExecutionService` (신규): 체인 실행 엔진 +- `CustomInstructionService`: chain 저장/관리 확장 +- `LocalLLMService`: 순차 호출 + 이전 결과 컨텍스트 전달 +- `VoiceModeService`: 체인 모드 추가 + +### IPC 채널 +| 채널 | 방향 | 설명 | +|------|------|------| +| `chain:getAll` | handle | 체인 목록 조회 | +| `chain:create` | handle | 체인 생성 | +| `chain:update` | handle | 체인 수정 | +| `chain:delete` | handle | 체인 삭제 | +| `chain:execute` | handle | 체인 수동 실행 (텍스트 입력) | +| `chain:progress` | send | 체인 실행 진행 상황 (현재 단계/총 단계) | + +### UI 컴포넌트 +- **ChainEditorPage**: 파이프라인 에디터 (CommandsPage 확장 또는 별도 탭) +- **ChainStepCard**: 각 단계 카드 (명령어 이름 + 설정) +- **ChainPreview**: 체인 실행 결과 미리보기 + +### 우선순위: **4순위** (고급 기능, 파워 유저 대상) + +--- + +## 10.5 음성 단축키 (Voice Command) + +### 목표 +녹음 시작 후 "번역해줘", "요약해줘" 같은 음성 키워드로 명령어를 자동 선택. +핫키 없이 음성만으로 명령어 전환 가능. + +### 구현 방안 +- **키워드 매칭**: Whisper 전사 결과에서 첫 N초(3초) 또는 첫 문장에서 키워드 탐색 + ```typescript + interface VoiceCommand { + id: string; + keywords: string[]; // ["번역해줘", "번역", "translate"] + instructionId: string; // 연결된 CustomInstruction + triggerPosition: 'start' | 'end' | 'any'; // 키워드 위치 + } + + // 매칭 로직 + function matchVoiceCommand(text: string, commands: VoiceCommand[]): VoiceCommand | null { + for (const cmd of commands) { + for (const keyword of cmd.keywords) { + if (text.startsWith(keyword) || text.includes(keyword)) { + return cmd; + } + } + } + return null; + } + ``` +- **키워드 제거**: 매칭된 키워드를 전사 텍스트에서 제거 후 LLM에 전달 + - "이 코드 설명해줘" → 키워드 "설명해줘" 제거 → "이 코드"를 LLM에 전달 + - 키워드가 문장 시작/끝에 있을 때만 제거 (중간은 유지) +- **프리셋 키워드**: 기본 명령어에 기본 키워드 매핑 + - 번역: "번역해줘", "번역", "translate", "영어로" + - 요약: "요약해줘", "요약", "summarize" + - 다듬기: "다듬어줘", "다듬기", "polish" + - 설명: "설명해줘", "explain" +- **커스텀 키워드 등록**: Settings에서 명령어별 키워드 편집 + +### 필요 서비스 +- `VoiceCommandService` (신규): 키워드 매칭 + 명령어 라우팅 +- `VoiceModeService`: 전사 완료 후 키워드 매칭 → 명령어 자동 선택 +- `CustomInstructionService`: 명령어별 키워드 저장 +- `ConfigService`: 음성 단축키 on/off 설정 + +### IPC 채널 +| 채널 | 방향 | 설명 | +|------|------|------| +| `voiceCommand:getAll` | handle | 음성 명령어 목록 | +| `voiceCommand:setKeywords` | handle | 명령어별 키워드 설정 | +| `voiceCommand:setEnabled` | handle | 음성 단축키 활성화/비활성화 | +| `voiceCommand:matched` | send | 키워드 매칭 알림 (어떤 명령어가 선택됐는지) | + +### UI 컴포넌트 +- **VoiceCommandSettings**: Settings에 음성 단축키 탭 또는 섹션 +- **KeywordEditor**: 명령어별 키워드 목록 편집 (Chip 입력) +- **RecordingTip 확장**: 키워드 감지 시 선택된 명령어 아이콘 표시 + +### 우선순위: **5순위** (UX 개선, 키워드 정확도 검증 필요) + +--- + +## 구현 우선순위 요약 + +| 순위 | 피처 | 난이도 | 임팩트 | 의존성 | +|------|------|--------|--------|--------| +| 1 | 실시간 자막 | 높음 | 매우 높음 | STT 스트리밍 | +| 2 | 스크린 컨텍스트 | 중간 | 높음 | Windows API | +| 3 | 음성 메모장 | 낮음 | 중간 | DB 확장 | +| 4 | 멀티 LLM 체인 | 중간 | 중간 | CustomInstruction 확장 | +| 5 | 음성 단축키 | 낮음 | 중간 | STT 결과 후처리 | + +### 권장 구현 순서 +1. **10.3 음성 메모장** — 가장 단순, 기존 인프라 활용도 높음 +2. **10.5 음성 단축키** — 키워드 매칭만 추가, VoiceModeService 확장 +3. **10.2 스크린 컨텍스트** — Windows API 연동 필요하지만 기존 패턴 재사용 +4. **10.4 멀티 LLM 체인** — 파이프라인 에디터 UI가 복잡 +5. **10.1 실시간 자막** — 스트리밍 전사 + 오버레이 윈도우 = 가장 큰 작업량 + +--- + +## Speakly 대비 차별점 + +| 기능 | Speakly | D3RO-VOICE | +|------|---------|-----------| +| 실시간 자막 | X | Phase 10.1 | +| 스크린 컨텍스트 | 부분 (활성 앱명만) | Phase 10.2 (선택 텍스트 포함) | +| 음성 메모장 | X | Phase 10.3 | +| 멀티 LLM 체인 | X | Phase 10.4 | +| 음성 단축키 | X | Phase 10.5 | +| 완전 로컬 | X (클라우드 의존) | O (Ollama + Whisper) | +| 커서 히스토리 팝업 | X | Phase 3.5 (이미 완료) | +| Ctrl+Shift+C 커맨드 팝업 | X | Phase 9 (이미 완료) |