- CLAUDE.md: 프로젝트 규칙, 기술 스택, 코딩 규칙, 페이즈 로드맵 - .claude/settings.json: 권한, 강제 훅 (매 프롬프트 설계서 규칙 주입) - .claude/skills/: implement-phase, review-phase, scaffold, test-commit, debug - .claude/agents/: electron-architect, voice-pipeline-expert, ui-specialist - docs/design/00-09: 마스터 아키텍처, 서비스 명세(16개), IPC(113채널), DB스키마, UI컴포넌트, 검증리포트, 외부엔진연동, 갭분석, VoiceMode패턴, 디자인시스템, 히스토리팝업 - docs/phases/1-7+3.5: 전체 구현 페이즈 문서 - docs/re-findings/: Speakly RE 노하우 5개 문서
5.6 KiB
5.6 KiB
Phase 4: Ollama LLM 연동 (텍스트 다듬기, 번역)
목표
Ollama REST API를 통해 로컬 LLM과 연동하여, 전사된 텍스트를 다듬기(polishing)하거나 번역(translate)할 수 있는 상태. 스트리밍 응답을 UI에 실시간 표시하고, 커스텀 명령어의 기본 구조를 갖춘다.
태스크
4.1 LocalLLMService 구현
src/main/services/LocalLLMService.ts- Ollama REST API 연동 (
/api/generate,/api/chat,/api/tags) - 싱글톤 + EventEmitter 패턴
- 상태 머신:
Unavailable → Available → Generating → Available(서비스 명세 LLMState 참조) - Ollama 가용성 폴링 (5초 간격,
OLLAMA_CONFIG.pollIntervalMs) availability-changed이벤트로 UI에 상태 전파- ConfigService에서
llm.serverUrl,llm.defaultModel읽기
4.2 비스트리밍 생성 (generate)
POST /api/generate호출 (stream: false)- GenerateOptions 지원: model, temperature, maxTokens, topP, topK, systemPrompt
- GenerateResult 반환: text, model, promptTokens, completionTokens, totalDuration
- 타임아웃 처리 (AbortController, 기본 120초)
4.3 스트리밍 생성 (stream)
POST /api/generate(stream: true) → NDJSON 파싱- fetch + ReadableStream으로 청크 처리
token이벤트를 통해 점진적 토큰 전달- AbortController로 중간 취소 지원
- 버퍼 관리: 불완전한 JSON 라인 처리
4.4 텍스트 다듬기 모드 (Polishing)
- PostProcessCommand
{ type: 'polish', style?: 'formal' | 'casual' }처리 - 시스템 프롬프트 설계:
[formal] 다음 음성 전사 텍스트를 자연스럽고 격식 있는 문어체로 다듬어주세요. 원래 의미를 유지하면서 문법 오류를 수정하고, 불필요한 반복이나 필러를 제거하세요. 다듬어진 텍스트만 출력하세요. 설명이나 부가 문구를 붙이지 마세요. [casual] 다음 음성 전사 텍스트를 자연스러운 구어체로 다듬어주세요. 원래 의미와 톤을 유지하면서 문법 오류만 수정하세요. 다듬어진 텍스트만 출력하세요. - VoiceModeService의 Processing 상태에서 호출
4.5 번역 모드 (Translate)
- PostProcessCommand
{ type: 'translate', targetLanguage: string }처리 - 시스템 프롬프트 설계:
다음 텍스트를 {targetLanguage}로 번역해주세요. 자연스럽고 정확한 번역만 출력하세요. 원문이나 설명을 붙이지 마세요. - 감지 언어 → 대상 언어 자동 전환 (한국어 감지 시 영어로, 영어 감지 시 한국어로)
- ConfigService에서 기본 대상 언어 설정 지원
4.6 커스텀 명령어 기본 구조
- PostProcessCommand
{ type: 'custom', prompt: string }처리 - 사용자가 직접 시스템 프롬프트를 지정하여 LLM에 전달
- CustomInstruction 인터페이스 초기 정의:
interface CustomInstruction { id: string; name: string; prompt: string; isBuiltin: boolean; createdAt: number; } - Phase 6에서 완전 구현 (CRUD, 프리셋, 핫키 바인딩)
4.7 스트리밍 응답 UI 표시
- RecordingTipWindow에
processing상태 추가- Thinking 프로그레스 바 (점근 수렴 패턴:
min(95, (1 - 1/(1+1.5*t)) * 100)%) - 스트리밍 토큰이 도착하면 텍스트 실시간 표시
- Thinking 프로그레스 바 (점근 수렴 패턴:
- ResultPopupWindow에 스트리밍 텍스트 영역 추가
- 토큰 도착 시 점진적 텍스트 추가
- 완료 시 복사 버튼 활성화
- IPC 채널:
llm:streamToken(main→renderer, 스트리밍 토큰)llm:streamComplete(main→renderer, 생성 완료)llm:streamError(main→renderer, 에러)
4.8 VoiceModeService LLM 통합
- RecognitionState.Processing 상태에서 LLM 호출
- 전사 완료 → postProcessCommand에 따라 분기:
none: 바로 텍스트 삽입polish/translate/custom: LLM 스트리밍 호출 → 완료 후 텍스트 삽입
processing-update이벤트를 통해 UI에 진행 상황 전달- LLM 미가용 시 postProcess를
none으로 폴백 + 사용자 알림
4.9 에러 처리
- Ollama 서버 미실행:
LLM_CONNECTION_FAILED에러, UI에 "Ollama가 실행 중이 아닙니다" 표시 - 모델 미설치:
LLM_MODEL_NOT_FOUND에러, UI에 모델 설치 안내 표시 - 생성 실패/타임아웃:
LLM_GENERATION_FAILED, 원본 텍스트로 폴백 옵션 제공 - 네트워크 에러: 재시도 없이 즉시 에러 표시 (로컬이므로 재시도 불필요)
4.10 IPC 채널 추가
llm:getStatus— LLM 가용 상태 조회llm:getModels— 설치된 Ollama 모델 목록llm:generate— 비스트리밍 텍스트 생성llm:stream— 스트리밍 텍스트 생성 시작llm:cancelStream— 스트리밍 취소llm:checkConnection— Ollama 연결 테스트
Speakly RE 참조
- GensparkService: 클라우드 LLM 호출 패턴 (D3RO는 로컬 Ollama로 대체)
- CustomInstructionService: 명령어 구조, 프롬프트 템플릿
- VoiceModeService: Processing 상태 전이, 후처리 파이프라인
- RecordingTip: thinking 상태 프로그레스 바, 점근 수렴 패턴
완료 조건
- Ollama 가용성 자동 감지 및 UI 표시
- 전사된 텍스트를 다듬기(polish) 모드로 LLM 처리 가능
- 전사된 텍스트를 번역(translate) 모드로 LLM 처리 가능
- 커스텀 프롬프트로 자유 LLM 처리 가능
- 스트리밍 토큰이 UI에 실시간 표시됨
- Ollama 미실행/모델 미설치 시 적절한 에러 메시지 표시
- LLM 미가용 시 원본 텍스트 삽입으로 폴백