실시간 녹음 + 타임스탬프 메모 + STT 전사 + LLM 구조화 회의록 + PDF/MD 내보내기. CaptionService 연동, 동시 사용 충돌 방지, 긴 회의 2-pass 요약 지원. DB 2테이블, IPC 15채널, UI 3뷰(목록/녹음/상세), 12개 locale i18n.
244 lines
6.3 KiB
TypeScript
244 lines
6.3 KiB
TypeScript
// src/shared/errors.ts
|
|
|
|
export enum ErrorCode {
|
|
// === Success ===
|
|
Success = 0,
|
|
|
|
// === STT (100-199) ===
|
|
STTEngineNotInstalled = 100,
|
|
STTModelNotFound = 101,
|
|
STTModelNotLoaded = 102,
|
|
STTModelLoadFailed = 103,
|
|
STTModelDownloadFailed = 104,
|
|
STTModelDownloadCancelled = 105,
|
|
STTTranscriptionFailed = 110,
|
|
STTTranscriptionTimeout = 111,
|
|
STTTranscriptionCancelled = 112,
|
|
STTNoAudioData = 113,
|
|
STTAudioTooShort = 114,
|
|
STTLanguageNotSupported = 120,
|
|
STTSidecarSpawnFailed = 130,
|
|
STTSidecarCrashed = 131,
|
|
STTSidecarCommunicationFailed = 132,
|
|
STTGPUNotAvailable = 140,
|
|
|
|
// === TTS (200-299) ===
|
|
TTSEngineNotInstalled = 200,
|
|
TTSVoiceNotFound = 201,
|
|
TTSVoiceNotLoaded = 202,
|
|
TTSVoiceLoadFailed = 203,
|
|
TTSVoiceDownloadFailed = 204,
|
|
TTSSynthesisFailed = 210,
|
|
TTSPlaybackFailed = 211,
|
|
TTSPlaybackInterrupted = 212,
|
|
TTSTextTooLong = 220,
|
|
TTSTextEmpty = 221,
|
|
|
|
// === LLM / Ollama (300-399) ===
|
|
LLMServerUnreachable = 300,
|
|
LLMServerConnectionFailed = 301,
|
|
LLMServerTimeout = 302,
|
|
LLMModelNotFound = 310,
|
|
LLMModelNotLoaded = 311,
|
|
LLMModelLoadFailed = 312,
|
|
LLMModelPullFailed = 313,
|
|
LLMModelPullCancelled = 314,
|
|
LLMProcessingFailed = 320,
|
|
LLMProcessingTimeout = 321,
|
|
LLMProcessingCancelled = 322,
|
|
LLMResponseParseFailed = 323,
|
|
LLMInvalidAction = 330,
|
|
LLMPromptTooLong = 331,
|
|
|
|
// === Audio (400-499) ===
|
|
AudioDeviceNotFound = 400,
|
|
AudioDeviceAccessDenied = 401,
|
|
AudioDeviceBusy = 402,
|
|
AudioCaptureStartFailed = 410,
|
|
AudioCaptureStopFailed = 411,
|
|
AudioCaptureFailed = 412,
|
|
AudioNoPermission = 420,
|
|
AudioStreamError = 430,
|
|
AudioBufferOverflow = 431,
|
|
|
|
// === Hotkey (500-599) ===
|
|
HotkeyRegistrationFailed = 500,
|
|
HotkeyConflict = 501,
|
|
HotkeySystemReserved = 502,
|
|
HotkeyHookInitFailed = 510,
|
|
HotkeyHookCrashed = 511,
|
|
|
|
// === TextInsert (600-699) ===
|
|
TextInsertFailed = 600,
|
|
TextInsertClipboardSaveFailed = 601,
|
|
TextInsertClipboardRestoreFailed = 602,
|
|
TextInsertKeySimulationFailed = 603,
|
|
TextInsertNoActiveWindow = 610,
|
|
TextInsertTargetAppNotResponding = 611,
|
|
|
|
// === History / Dictionary / DB (700-799) ===
|
|
DBOpenFailed = 700,
|
|
DBMigrationFailed = 701,
|
|
DBQueryFailed = 702,
|
|
DBWriteFailed = 703,
|
|
HistoryNotFound = 710,
|
|
HistoryExportFailed = 711,
|
|
DictionaryNotFound = 720,
|
|
DictionaryDuplicate = 721,
|
|
DictionaryImportFailed = 722,
|
|
DictionaryExportFailed = 723,
|
|
DictionaryImportInvalidFormat = 724,
|
|
|
|
// === Phase 10: Memo Tags (730-739) ===
|
|
MemoTagDuplicate = 730,
|
|
MemoTagNotFound = 731,
|
|
MemoExportFailed = 732,
|
|
|
|
// === Phase 10: Voice Commands (740-749) ===
|
|
VoiceCommandMatchFailed = 740,
|
|
VoiceCommandNotFound = 741,
|
|
|
|
// === Phase 10: Screen Context (750-759) ===
|
|
ContextCaptureFailed = 750,
|
|
ContextSelectedTextFailed = 751,
|
|
|
|
// === Phase 10: LLM Chain (760-769) ===
|
|
ChainNotFound = 760,
|
|
ChainExecutionFailed = 761,
|
|
ChainStepFailed = 762,
|
|
ChainCancelled = 763,
|
|
|
|
// === Phase 10: Live Caption (770-779) ===
|
|
CaptionStartFailed = 770,
|
|
CaptionAlreadyActive = 771,
|
|
CaptionSTTFailed = 772,
|
|
|
|
// === Phase 12: File Transcription (780-784) ===
|
|
FileTranscriptionFFmpegFailed = 780,
|
|
FileTranscriptionInvalidFormat = 781,
|
|
FileTranscriptionChunkFailed = 782,
|
|
FileTranscriptionCancelled = 783,
|
|
FileTranscriptionFileTooLarge = 784,
|
|
|
|
// === Phase 12: Meeting Summary (785-789) ===
|
|
MeetingSummaryGenerationFailed = 785,
|
|
MeetingSummaryNoTranscript = 786,
|
|
MeetingSummaryExportFailed = 787,
|
|
|
|
// === Phase 12: Dictation Template (790-794) ===
|
|
TemplateNotFound = 790,
|
|
TemplateSessionAlreadyActive = 791,
|
|
TemplateSessionNotActive = 792,
|
|
TemplateFieldRecordingFailed = 793,
|
|
TemplateInvalidFormat = 794,
|
|
|
|
// === Phase 13: Voice Conversation (795-799) ===
|
|
ConversationSessionAlreadyActive = 795,
|
|
ConversationNoActiveSession = 796,
|
|
ConversationTTSFailed = 797,
|
|
ConversationLLMFailed = 798,
|
|
|
|
// === Phase 13: Local RAG (870-874) ===
|
|
RAGDocumentNotFound = 870,
|
|
RAGIndexingFailed = 871,
|
|
RAGEmbeddingFailed = 872,
|
|
RAGQueryFailed = 873,
|
|
RAGUnsupportedFormat = 874,
|
|
|
|
// === Phase 13: Voice Action (875-879) ===
|
|
VoiceActionPlanFailed = 875,
|
|
VoiceActionExecutionFailed = 876,
|
|
VoiceActionBlocked = 877,
|
|
VoiceActionInvalidPlan = 878,
|
|
|
|
// === Phase 14: Meeting Mode (880-889) ===
|
|
MeetingAlreadyRecording = 880,
|
|
MeetingNotRecording = 881,
|
|
MeetingProcessingFailed = 882,
|
|
MeetingSessionNotFound = 883,
|
|
MeetingExportFailed = 884,
|
|
MeetingPdfFailed = 885,
|
|
|
|
// === Config (800-849) ===
|
|
ConfigReadFailed = 800,
|
|
ConfigWriteFailed = 801,
|
|
ConfigInvalidValue = 802,
|
|
ConfigKeyNotFound = 803,
|
|
ConfigResetFailed = 804,
|
|
ConfigMigrationFailed = 810,
|
|
|
|
// === License (850-869) ===
|
|
LicenseKeyInvalid = 850,
|
|
LicenseKeyExpired = 851,
|
|
LicenseActivationFailed = 852,
|
|
LicenseDeactivationFailed = 853,
|
|
LicenseMachineIdMismatch = 854,
|
|
LicenseOfflineGraceExpired = 855,
|
|
LicenseVerificationFailed = 856,
|
|
FeatureNotAvailable = 860,
|
|
QuotaExceeded = 861,
|
|
TierRequired = 862,
|
|
|
|
// === System / Window (900-999) ===
|
|
WindowCreationFailed = 900,
|
|
WindowNotFound = 901,
|
|
TrayCreationFailed = 910,
|
|
NotificationFailed = 920,
|
|
PermissionDenied = 930,
|
|
ExternalOpenFailed = 940,
|
|
SoundPlayFailed = 950,
|
|
AppAlreadyRunning = 960,
|
|
UnknownError = 999
|
|
}
|
|
|
|
/**
|
|
* D3RO-VOICE 표준 에러 객체 (Speakly NXError 패턴)
|
|
*/
|
|
export class D3ROError extends Error {
|
|
readonly code: ErrorCode
|
|
readonly details?: Record<string, unknown>
|
|
|
|
constructor(code: ErrorCode, message: string, details?: Record<string, unknown>) {
|
|
super(message)
|
|
this.name = 'D3ROError'
|
|
this.code = code
|
|
this.details = details
|
|
}
|
|
|
|
toJSON(): D3ROErrorJSON {
|
|
return {
|
|
code: this.code,
|
|
message: this.message,
|
|
details: this.details
|
|
}
|
|
}
|
|
|
|
static fromJSON(json: D3ROErrorJSON): D3ROError {
|
|
return new D3ROError(json.code, json.message, json.details)
|
|
}
|
|
}
|
|
|
|
export interface D3ROErrorJSON {
|
|
code: ErrorCode
|
|
message: string
|
|
details?: Record<string, unknown>
|
|
}
|
|
|
|
/**
|
|
* IPC 핸들러에서 사용하는 표준 응답 래퍼.
|
|
*/
|
|
export type IPCResult<T> =
|
|
| { success: true; data: T }
|
|
| { success: false; error: D3ROErrorJSON }
|
|
|
|
export function ipcSuccess<T>(data: T): IPCResult<T> {
|
|
return { success: true, data }
|
|
}
|
|
|
|
export function ipcError<T>(
|
|
code: ErrorCode,
|
|
message: string,
|
|
details?: Record<string, unknown>
|
|
): IPCResult<T> {
|
|
return { success: false, error: { code, message, details } }
|
|
}
|