d3ro-voice/packages/core/src/errors.ts
Yun Chan 8f7d300b89 feat(conversation): OpenAI gpt-realtime-2.1 라이브 음성 대화 Premium 백엔드
- realtime-token Edge Function: 티어 검증 + realtime_session 쿼터 + ephemeral key 발급
- useRealtimeConversation 훅: WebRTC 직결 (마이크 → OpenAI, 오디오 자동 재생)
- VoiceConversationPage: conversationBackend 분기 + 연결 실패 시 로컬 fallback
- AppConfig.conversationBackend + SettingsModal 음성 대화 엔진 선택
- ErrorCode 799 ConversationRealtimeTokenFailed, i18n ko/en
2026-07-21 12:10:13 +09:00

257 lines
6.7 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,
ConversationRealtimeTokenFailed = 799,
// === 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,
MeetingDocumentNotFound = 886,
MeetingDocGenerationFailed = 887,
MeetingDocExportFailed = 888,
MeetingTranscriptUpdateFailed = 889,
MeetingDocTemplateNotFound = 890,
MeetingDocTemplateBuiltinDelete = 891,
MeetingDocxExportFailed = 892,
MeetingPolishFailed = 893,
MeetingChatFailed = 894,
DiarizationFailed = 895,
DiarizationModelNotLoaded = 896,
DiarizationTokenRequired = 897,
// === 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 } }
}