- Added `errors.py` to define a centralized error management system with error codes and metadata. - Created `VRCTError` class for generating standardized error responses. - Introduced `error_handling_migration_guide.md` to document migration patterns for existing error handling to the new system. - Updated error handling patterns in the codebase to utilize the new error management system.
695 lines
25 KiB
Python
695 lines
25 KiB
Python
# src-python/errors.py
|
|
"""
|
|
統一エラー管理システム
|
|
|
|
すべてのエラーを一元管理し、エンドポイントとエラーコードの対応を明確にする。
|
|
"""
|
|
|
|
from typing import Any, Optional, Dict
|
|
from enum import Enum
|
|
|
|
|
|
class ErrorCode(str, Enum):
|
|
"""エラーコード定数
|
|
|
|
命名規則: カテゴリ_具体的な内容
|
|
"""
|
|
# ============================================================================
|
|
# デバイス関連エラー (DEVICE_*)
|
|
# ============================================================================
|
|
DEVICE_NO_MIC = "DEVICE_NO_MIC"
|
|
DEVICE_NO_SPEAKER = "DEVICE_NO_SPEAKER"
|
|
|
|
# ============================================================================
|
|
# 翻訳関連エラー (TRANSLATION_*)
|
|
# ============================================================================
|
|
TRANSLATION_ENGINE_LIMIT = "TRANSLATION_ENGINE_LIMIT"
|
|
TRANSLATION_VRAM_CHAT = "TRANSLATION_VRAM_CHAT"
|
|
TRANSLATION_VRAM_MIC = "TRANSLATION_VRAM_MIC"
|
|
TRANSLATION_VRAM_SPEAKER = "TRANSLATION_VRAM_SPEAKER"
|
|
TRANSLATION_VRAM_ENABLE = "TRANSLATION_VRAM_ENABLE"
|
|
TRANSLATION_DISABLED_VRAM = "TRANSLATION_DISABLED_VRAM"
|
|
|
|
# ============================================================================
|
|
# 音声認識関連エラー (TRANSCRIPTION_*)
|
|
# ============================================================================
|
|
TRANSCRIPTION_VRAM_MIC = "TRANSCRIPTION_VRAM_MIC"
|
|
TRANSCRIPTION_VRAM_SPEAKER = "TRANSCRIPTION_VRAM_SPEAKER"
|
|
TRANSCRIPTION_SEND_DISABLED_VRAM = "TRANSCRIPTION_SEND_DISABLED_VRAM"
|
|
TRANSCRIPTION_RECEIVE_DISABLED_VRAM = "TRANSCRIPTION_RECEIVE_DISABLED_VRAM"
|
|
|
|
# ============================================================================
|
|
# ウェイトダウンロード関連エラー (WEIGHT_*)
|
|
# ============================================================================
|
|
WEIGHT_CTRANSLATE2_DOWNLOAD = "WEIGHT_CTRANSLATE2_DOWNLOAD"
|
|
WEIGHT_WHISPER_DOWNLOAD = "WEIGHT_WHISPER_DOWNLOAD"
|
|
|
|
# ============================================================================
|
|
# バリデーションエラー (VALIDATION_*)
|
|
# ============================================================================
|
|
VALIDATION_MIC_THRESHOLD = "VALIDATION_MIC_THRESHOLD"
|
|
VALIDATION_SPEAKER_THRESHOLD = "VALIDATION_SPEAKER_THRESHOLD"
|
|
VALIDATION_MIC_RECORD_TIMEOUT = "VALIDATION_MIC_RECORD_TIMEOUT"
|
|
VALIDATION_MIC_PHRASE_TIMEOUT = "VALIDATION_MIC_PHRASE_TIMEOUT"
|
|
VALIDATION_MIC_MAX_PHRASES = "VALIDATION_MIC_MAX_PHRASES"
|
|
VALIDATION_SPEAKER_RECORD_TIMEOUT = "VALIDATION_SPEAKER_RECORD_TIMEOUT"
|
|
VALIDATION_SPEAKER_PHRASE_TIMEOUT = "VALIDATION_SPEAKER_PHRASE_TIMEOUT"
|
|
VALIDATION_SPEAKER_MAX_PHRASES = "VALIDATION_SPEAKER_MAX_PHRASES"
|
|
VALIDATION_INVALID_IP = "VALIDATION_INVALID_IP"
|
|
VALIDATION_CANNOT_SET_IP = "VALIDATION_CANNOT_SET_IP"
|
|
|
|
# ============================================================================
|
|
# 認証エラー (AUTH_*)
|
|
# ============================================================================
|
|
AUTH_DEEPL_LENGTH = "AUTH_DEEPL_LENGTH"
|
|
AUTH_DEEPL_FAILED = "AUTH_DEEPL_FAILED"
|
|
AUTH_PLAMO_LENGTH = "AUTH_PLAMO_LENGTH"
|
|
AUTH_PLAMO_FAILED = "AUTH_PLAMO_FAILED"
|
|
AUTH_GEMINI_LENGTH = "AUTH_GEMINI_LENGTH"
|
|
AUTH_GEMINI_FAILED = "AUTH_GEMINI_FAILED"
|
|
AUTH_OPENAI_INVALID = "AUTH_OPENAI_INVALID"
|
|
AUTH_OPENAI_FAILED = "AUTH_OPENAI_FAILED"
|
|
AUTH_GROQ_INVALID = "AUTH_GROQ_INVALID"
|
|
AUTH_GROQ_FAILED = "AUTH_GROQ_FAILED"
|
|
AUTH_OPENROUTER_INVALID = "AUTH_OPENROUTER_INVALID"
|
|
AUTH_OPENROUTER_FAILED = "AUTH_OPENROUTER_FAILED"
|
|
|
|
# ============================================================================
|
|
# モデル選択エラー (MODEL_*)
|
|
# ============================================================================
|
|
MODEL_PLAMO_INVALID = "MODEL_PLAMO_INVALID"
|
|
MODEL_GEMINI_INVALID = "MODEL_GEMINI_INVALID"
|
|
MODEL_OPENAI_INVALID = "MODEL_OPENAI_INVALID"
|
|
MODEL_GROQ_INVALID = "MODEL_GROQ_INVALID"
|
|
MODEL_OPENROUTER_INVALID = "MODEL_OPENROUTER_INVALID"
|
|
MODEL_LMSTUDIO_INVALID = "MODEL_LMSTUDIO_INVALID"
|
|
MODEL_OLLAMA_INVALID = "MODEL_OLLAMA_INVALID"
|
|
|
|
# ============================================================================
|
|
# 接続エラー (CONNECTION_*)
|
|
# ============================================================================
|
|
CONNECTION_LMSTUDIO_FAILED = "CONNECTION_LMSTUDIO_FAILED"
|
|
CONNECTION_OLLAMA_FAILED = "CONNECTION_OLLAMA_FAILED"
|
|
CONNECTION_LMSTUDIO_URL_INVALID = "CONNECTION_LMSTUDIO_URL_INVALID"
|
|
|
|
# ============================================================================
|
|
# WebSocketエラー (WEBSOCKET_*)
|
|
# ============================================================================
|
|
WEBSOCKET_HOST_INVALID = "WEBSOCKET_HOST_INVALID"
|
|
WEBSOCKET_PORT_UNAVAILABLE = "WEBSOCKET_PORT_UNAVAILABLE"
|
|
WEBSOCKET_SERVER_UNAVAILABLE = "WEBSOCKET_SERVER_UNAVAILABLE"
|
|
|
|
# ============================================================================
|
|
# VRC連携エラー (VRC_*)
|
|
# ============================================================================
|
|
VRC_MIC_MUTE_SYNC_OSC_DISABLED = "VRC_MIC_MUTE_SYNC_OSC_DISABLED"
|
|
|
|
# ============================================================================
|
|
# 汎用エラー (GENERAL_*)
|
|
# ============================================================================
|
|
GENERAL_EXCEPTION = "GENERAL_EXCEPTION"
|
|
GENERAL_UNKNOWN = "GENERAL_UNKNOWN"
|
|
|
|
|
|
class ErrorCategory(str, Enum):
|
|
"""エラーカテゴリ"""
|
|
DEVICE = "device"
|
|
TRANSLATION = "translation"
|
|
TRANSCRIPTION = "transcription"
|
|
WEIGHT = "weight"
|
|
VALIDATION = "validation"
|
|
AUTH = "auth"
|
|
MODEL = "model"
|
|
CONNECTION = "connection"
|
|
WEBSOCKET = "websocket"
|
|
VRC = "vrc"
|
|
GENERAL = "general"
|
|
|
|
|
|
# エラーコードのメタデータ定義
|
|
ERROR_METADATA: Dict[ErrorCode, Dict[str, Any]] = {
|
|
# デバイスエラー
|
|
ErrorCode.DEVICE_NO_MIC: {
|
|
"category": ErrorCategory.DEVICE,
|
|
"message": "No mic device detected",
|
|
"severity": "error",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.DEVICE_NO_SPEAKER: {
|
|
"category": ErrorCategory.DEVICE,
|
|
"message": "No speaker device detected",
|
|
"severity": "error",
|
|
"user_action_required": True,
|
|
},
|
|
|
|
# 翻訳エラー
|
|
ErrorCode.TRANSLATION_ENGINE_LIMIT: {
|
|
"category": ErrorCategory.TRANSLATION,
|
|
"message": "Translation engine limit error",
|
|
"severity": "warning",
|
|
"user_action_required": False,
|
|
"auto_fallback": True,
|
|
},
|
|
ErrorCode.TRANSLATION_VRAM_CHAT: {
|
|
"category": ErrorCategory.TRANSLATION,
|
|
"message": "VRAM out of memory during translation of chat",
|
|
"severity": "critical",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.TRANSLATION_VRAM_MIC: {
|
|
"category": ErrorCategory.TRANSLATION,
|
|
"message": "VRAM out of memory during translation of mic",
|
|
"severity": "critical",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.TRANSLATION_VRAM_SPEAKER: {
|
|
"category": ErrorCategory.TRANSLATION,
|
|
"message": "VRAM out of memory during translation of speaker",
|
|
"severity": "critical",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.TRANSLATION_VRAM_ENABLE: {
|
|
"category": ErrorCategory.TRANSLATION,
|
|
"message": "VRAM out of memory enabling translation",
|
|
"severity": "critical",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.TRANSLATION_DISABLED_VRAM: {
|
|
"category": ErrorCategory.TRANSLATION,
|
|
"message": "Translation disabled due to VRAM overflow",
|
|
"severity": "critical",
|
|
"user_action_required": True,
|
|
},
|
|
|
|
# 音声認識エラー
|
|
ErrorCode.TRANSCRIPTION_VRAM_MIC: {
|
|
"category": ErrorCategory.TRANSCRIPTION,
|
|
"message": "VRAM out of memory during mic transcription",
|
|
"severity": "critical",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.TRANSCRIPTION_VRAM_SPEAKER: {
|
|
"category": ErrorCategory.TRANSCRIPTION,
|
|
"message": "VRAM out of memory during speaker transcription",
|
|
"severity": "critical",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.TRANSCRIPTION_SEND_DISABLED_VRAM: {
|
|
"category": ErrorCategory.TRANSCRIPTION,
|
|
"message": "Transcription send disabled due to VRAM overflow",
|
|
"severity": "critical",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.TRANSCRIPTION_RECEIVE_DISABLED_VRAM: {
|
|
"category": ErrorCategory.TRANSCRIPTION,
|
|
"message": "Transcription receive disabled due to VRAM overflow",
|
|
"severity": "critical",
|
|
"user_action_required": True,
|
|
},
|
|
|
|
# ウェイトダウンロードエラー
|
|
ErrorCode.WEIGHT_CTRANSLATE2_DOWNLOAD: {
|
|
"category": ErrorCategory.WEIGHT,
|
|
"message": "CTranslate2 weight download error",
|
|
"severity": "error",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.WEIGHT_WHISPER_DOWNLOAD: {
|
|
"category": ErrorCategory.WEIGHT,
|
|
"message": "Whisper weight download error",
|
|
"severity": "error",
|
|
"user_action_required": True,
|
|
},
|
|
|
|
# バリデーションエラー
|
|
ErrorCode.VALIDATION_MIC_THRESHOLD: {
|
|
"category": ErrorCategory.VALIDATION,
|
|
"message": "Mic energy threshold value is out of range",
|
|
"severity": "warning",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.VALIDATION_SPEAKER_THRESHOLD: {
|
|
"category": ErrorCategory.VALIDATION,
|
|
"message": "Speaker energy threshold value is out of range",
|
|
"severity": "warning",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.VALIDATION_MIC_RECORD_TIMEOUT: {
|
|
"category": ErrorCategory.VALIDATION,
|
|
"message": "Mic record timeout value is out of range",
|
|
"severity": "warning",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.VALIDATION_MIC_PHRASE_TIMEOUT: {
|
|
"category": ErrorCategory.VALIDATION,
|
|
"message": "Mic phrase timeout value is out of range",
|
|
"severity": "warning",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.VALIDATION_MIC_MAX_PHRASES: {
|
|
"category": ErrorCategory.VALIDATION,
|
|
"message": "Mic max phrases value is out of range",
|
|
"severity": "warning",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.VALIDATION_SPEAKER_RECORD_TIMEOUT: {
|
|
"category": ErrorCategory.VALIDATION,
|
|
"message": "Speaker record timeout value is out of range",
|
|
"severity": "warning",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.VALIDATION_SPEAKER_PHRASE_TIMEOUT: {
|
|
"category": ErrorCategory.VALIDATION,
|
|
"message": "Speaker phrase timeout value is out of range",
|
|
"severity": "warning",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.VALIDATION_SPEAKER_MAX_PHRASES: {
|
|
"category": ErrorCategory.VALIDATION,
|
|
"message": "Speaker max phrases value is out of range",
|
|
"severity": "warning",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.VALIDATION_INVALID_IP: {
|
|
"category": ErrorCategory.VALIDATION,
|
|
"message": "Invalid IP address",
|
|
"severity": "warning",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.VALIDATION_CANNOT_SET_IP: {
|
|
"category": ErrorCategory.VALIDATION,
|
|
"message": "Cannot set IP address",
|
|
"severity": "error",
|
|
"user_action_required": True,
|
|
},
|
|
|
|
# 認証エラー
|
|
ErrorCode.AUTH_DEEPL_LENGTH: {
|
|
"category": ErrorCategory.AUTH,
|
|
"message": "DeepL auth key length is not correct",
|
|
"severity": "warning",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.AUTH_DEEPL_FAILED: {
|
|
"category": ErrorCategory.AUTH,
|
|
"message": "Authentication failure of deepL auth key",
|
|
"severity": "error",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.AUTH_PLAMO_LENGTH: {
|
|
"category": ErrorCategory.AUTH,
|
|
"message": "Plamo auth key length is not correct",
|
|
"severity": "warning",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.AUTH_PLAMO_FAILED: {
|
|
"category": ErrorCategory.AUTH,
|
|
"message": "Authentication failure of plamo auth key",
|
|
"severity": "error",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.AUTH_GEMINI_LENGTH: {
|
|
"category": ErrorCategory.AUTH,
|
|
"message": "Gemini auth key length is not correct",
|
|
"severity": "warning",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.AUTH_GEMINI_FAILED: {
|
|
"category": ErrorCategory.AUTH,
|
|
"message": "Authentication failure of gemini auth key",
|
|
"severity": "error",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.AUTH_OPENAI_INVALID: {
|
|
"category": ErrorCategory.AUTH,
|
|
"message": "OpenAI auth key is not valid",
|
|
"severity": "warning",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.AUTH_OPENAI_FAILED: {
|
|
"category": ErrorCategory.AUTH,
|
|
"message": "Authentication failure of OpenAI auth key",
|
|
"severity": "error",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.AUTH_GROQ_INVALID: {
|
|
"category": ErrorCategory.AUTH,
|
|
"message": "Groq auth key is not valid",
|
|
"severity": "warning",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.AUTH_GROQ_FAILED: {
|
|
"category": ErrorCategory.AUTH,
|
|
"message": "Authentication failure of Groq auth key",
|
|
"severity": "error",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.AUTH_OPENROUTER_INVALID: {
|
|
"category": ErrorCategory.AUTH,
|
|
"message": "OpenRouter auth key is not valid",
|
|
"severity": "warning",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.AUTH_OPENROUTER_FAILED: {
|
|
"category": ErrorCategory.AUTH,
|
|
"message": "Authentication failure of OpenRouter auth key",
|
|
"severity": "error",
|
|
"user_action_required": True,
|
|
},
|
|
|
|
# モデル選択エラー
|
|
ErrorCode.MODEL_PLAMO_INVALID: {
|
|
"category": ErrorCategory.MODEL,
|
|
"message": "Plamo model is not valid",
|
|
"severity": "warning",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.MODEL_GEMINI_INVALID: {
|
|
"category": ErrorCategory.MODEL,
|
|
"message": "Gemini model is not valid",
|
|
"severity": "warning",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.MODEL_OPENAI_INVALID: {
|
|
"category": ErrorCategory.MODEL,
|
|
"message": "OpenAI model is not valid",
|
|
"severity": "warning",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.MODEL_GROQ_INVALID: {
|
|
"category": ErrorCategory.MODEL,
|
|
"message": "Groq model is not valid",
|
|
"severity": "warning",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.MODEL_OPENROUTER_INVALID: {
|
|
"category": ErrorCategory.MODEL,
|
|
"message": "OpenRouter model is not valid",
|
|
"severity": "warning",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.MODEL_LMSTUDIO_INVALID: {
|
|
"category": ErrorCategory.MODEL,
|
|
"message": "LMStudio model is not valid",
|
|
"severity": "warning",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.MODEL_OLLAMA_INVALID: {
|
|
"category": ErrorCategory.MODEL,
|
|
"message": "ollama model is not valid",
|
|
"severity": "warning",
|
|
"user_action_required": True,
|
|
},
|
|
|
|
# 接続エラー
|
|
ErrorCode.CONNECTION_LMSTUDIO_FAILED: {
|
|
"category": ErrorCategory.CONNECTION,
|
|
"message": "Cannot connect to LMStudio server",
|
|
"severity": "error",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.CONNECTION_OLLAMA_FAILED: {
|
|
"category": ErrorCategory.CONNECTION,
|
|
"message": "Cannot connect to ollama server",
|
|
"severity": "error",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.CONNECTION_LMSTUDIO_URL_INVALID: {
|
|
"category": ErrorCategory.CONNECTION,
|
|
"message": "LMStudio URL is not valid",
|
|
"severity": "warning",
|
|
"user_action_required": True,
|
|
},
|
|
|
|
# WebSocketエラー
|
|
ErrorCode.WEBSOCKET_HOST_INVALID: {
|
|
"category": ErrorCategory.WEBSOCKET,
|
|
"message": "WebSocket server host is not available",
|
|
"severity": "error",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.WEBSOCKET_PORT_UNAVAILABLE: {
|
|
"category": ErrorCategory.WEBSOCKET,
|
|
"message": "WebSocket server port is not available",
|
|
"severity": "error",
|
|
"user_action_required": True,
|
|
},
|
|
ErrorCode.WEBSOCKET_SERVER_UNAVAILABLE: {
|
|
"category": ErrorCategory.WEBSOCKET,
|
|
"message": "WebSocket server host or port is not available",
|
|
"severity": "error",
|
|
"user_action_required": True,
|
|
},
|
|
|
|
# VRC連携エラー
|
|
ErrorCode.VRC_MIC_MUTE_SYNC_OSC_DISABLED: {
|
|
"category": ErrorCategory.VRC,
|
|
"message": "Cannot enable VRC mic mute sync while OSC query is disabled",
|
|
"severity": "warning",
|
|
"user_action_required": True,
|
|
},
|
|
|
|
# 汎用エラー
|
|
ErrorCode.GENERAL_EXCEPTION: {
|
|
"category": ErrorCategory.GENERAL,
|
|
"message": "An error occurred",
|
|
"severity": "error",
|
|
"user_action_required": False,
|
|
},
|
|
ErrorCode.GENERAL_UNKNOWN: {
|
|
"category": ErrorCategory.GENERAL,
|
|
"message": "Unknown error",
|
|
"severity": "error",
|
|
"user_action_required": False,
|
|
},
|
|
}
|
|
|
|
|
|
class VRCTError:
|
|
"""VRCTエラーハンドリングクラス"""
|
|
|
|
@staticmethod
|
|
def create_error_response(
|
|
error_code: ErrorCode,
|
|
data: Any = None,
|
|
details: Optional[Dict[str, Any]] = None,
|
|
custom_message: Optional[str] = None
|
|
) -> Dict[str, Any]:
|
|
"""統一されたエラーレスポンスを生成
|
|
|
|
Args:
|
|
error_code: エラーコード
|
|
data: エラー時に戻す値(通常は元の値)
|
|
details: 追加の詳細情報
|
|
custom_message: カスタムメッセージ(指定しない場合はデフォルトメッセージ)
|
|
|
|
Returns:
|
|
エラーレスポンス辞書
|
|
"""
|
|
metadata = ERROR_METADATA.get(error_code, ERROR_METADATA[ErrorCode.GENERAL_UNKNOWN])
|
|
|
|
return {
|
|
"status": 400,
|
|
"result": {
|
|
"error_code": error_code.value,
|
|
"message": custom_message or metadata["message"],
|
|
"data": data,
|
|
"details": details or {},
|
|
"category": metadata["category"].value,
|
|
"severity": metadata["severity"],
|
|
}
|
|
}
|
|
|
|
@staticmethod
|
|
def create_exception_error_response(
|
|
exception: Exception,
|
|
data: Any = None,
|
|
error_code: ErrorCode = ErrorCode.GENERAL_EXCEPTION
|
|
) -> Dict[str, Any]:
|
|
"""例外からエラーレスポンスを生成
|
|
|
|
Args:
|
|
exception: 発生した例外
|
|
data: エラー時に戻す値
|
|
error_code: エラーコード
|
|
|
|
Returns:
|
|
エラーレスポンス辞書
|
|
"""
|
|
return VRCTError.create_error_response(
|
|
error_code=error_code,
|
|
data=data,
|
|
custom_message=f"Error: {str(exception)}",
|
|
details={"exception_type": type(exception).__name__}
|
|
)
|
|
|
|
|
|
# エンドポイントとエラーコードのマッピング
|
|
# UIがエラーハンドリングする際の参照として使用
|
|
ENDPOINT_ERROR_MAPPING: Dict[str, Dict[str, ErrorCode]] = {
|
|
# run_mapping経由のエラー通知
|
|
"/run/error_device": {
|
|
"NO_MIC": ErrorCode.DEVICE_NO_MIC,
|
|
"NO_SPEAKER": ErrorCode.DEVICE_NO_SPEAKER,
|
|
},
|
|
"/run/error_translation_engine": {
|
|
"LIMIT": ErrorCode.TRANSLATION_ENGINE_LIMIT,
|
|
},
|
|
"/run/error_translation_chat_vram_overflow": {
|
|
"VRAM": ErrorCode.TRANSLATION_VRAM_CHAT,
|
|
},
|
|
"/run/error_translation_mic_vram_overflow": {
|
|
"VRAM": ErrorCode.TRANSLATION_VRAM_MIC,
|
|
},
|
|
"/run/error_translation_speaker_vram_overflow": {
|
|
"VRAM": ErrorCode.TRANSLATION_VRAM_SPEAKER,
|
|
},
|
|
"/run/error_transcription_mic_vram_overflow": {
|
|
"VRAM": ErrorCode.TRANSCRIPTION_VRAM_MIC,
|
|
},
|
|
"/run/error_transcription_speaker_vram_overflow": {
|
|
"VRAM": ErrorCode.TRANSCRIPTION_VRAM_SPEAKER,
|
|
},
|
|
"/run/error_ctranslate2_weight": {
|
|
"DOWNLOAD": ErrorCode.WEIGHT_CTRANSLATE2_DOWNLOAD,
|
|
},
|
|
"/run/error_whisper_weight": {
|
|
"DOWNLOAD": ErrorCode.WEIGHT_WHISPER_DOWNLOAD,
|
|
},
|
|
|
|
# エンドポイント直接のエラーレスポンス
|
|
"/set/data/mic_threshold": {
|
|
"OUT_OF_RANGE": ErrorCode.VALIDATION_MIC_THRESHOLD,
|
|
},
|
|
"/set/data/speaker_threshold": {
|
|
"OUT_OF_RANGE": ErrorCode.VALIDATION_SPEAKER_THRESHOLD,
|
|
},
|
|
"/set/data/mic_record_timeout": {
|
|
"OUT_OF_RANGE": ErrorCode.VALIDATION_MIC_RECORD_TIMEOUT,
|
|
},
|
|
"/set/data/mic_phrase_timeout": {
|
|
"OUT_OF_RANGE": ErrorCode.VALIDATION_MIC_PHRASE_TIMEOUT,
|
|
},
|
|
"/set/data/mic_max_phrases": {
|
|
"OUT_OF_RANGE": ErrorCode.VALIDATION_MIC_MAX_PHRASES,
|
|
},
|
|
"/set/data/speaker_record_timeout": {
|
|
"OUT_OF_RANGE": ErrorCode.VALIDATION_SPEAKER_RECORD_TIMEOUT,
|
|
},
|
|
"/set/data/speaker_phrase_timeout": {
|
|
"OUT_OF_RANGE": ErrorCode.VALIDATION_SPEAKER_PHRASE_TIMEOUT,
|
|
},
|
|
"/set/data/speaker_max_phrases": {
|
|
"OUT_OF_RANGE": ErrorCode.VALIDATION_SPEAKER_MAX_PHRASES,
|
|
},
|
|
"/set/data/osc_ip_address": {
|
|
"INVALID": ErrorCode.VALIDATION_INVALID_IP,
|
|
"CANNOT_SET": ErrorCode.VALIDATION_CANNOT_SET_IP,
|
|
},
|
|
"/set/data/deepl_auth_key": {
|
|
"LENGTH": ErrorCode.AUTH_DEEPL_LENGTH,
|
|
"FAILED": ErrorCode.AUTH_DEEPL_FAILED,
|
|
},
|
|
"/set/data/plamo_auth_key": {
|
|
"LENGTH": ErrorCode.AUTH_PLAMO_LENGTH,
|
|
"FAILED": ErrorCode.AUTH_PLAMO_FAILED,
|
|
},
|
|
"/set/data/selected_plamo_model": {
|
|
"INVALID": ErrorCode.MODEL_PLAMO_INVALID,
|
|
},
|
|
"/set/data/gemini_auth_key": {
|
|
"LENGTH": ErrorCode.AUTH_GEMINI_LENGTH,
|
|
"FAILED": ErrorCode.AUTH_GEMINI_FAILED,
|
|
},
|
|
"/set/data/selected_gemini_model": {
|
|
"INVALID": ErrorCode.MODEL_GEMINI_INVALID,
|
|
},
|
|
"/set/data/openai_auth_key": {
|
|
"INVALID": ErrorCode.AUTH_OPENAI_INVALID,
|
|
"FAILED": ErrorCode.AUTH_OPENAI_FAILED,
|
|
},
|
|
"/set/data/selected_openai_model": {
|
|
"INVALID": ErrorCode.MODEL_OPENAI_INVALID,
|
|
},
|
|
"/set/data/groq_auth_key": {
|
|
"INVALID": ErrorCode.AUTH_GROQ_INVALID,
|
|
"FAILED": ErrorCode.AUTH_GROQ_FAILED,
|
|
},
|
|
"/set/data/selected_groq_model": {
|
|
"INVALID": ErrorCode.MODEL_GROQ_INVALID,
|
|
},
|
|
"/set/data/openrouter_auth_key": {
|
|
"INVALID": ErrorCode.AUTH_OPENROUTER_INVALID,
|
|
"FAILED": ErrorCode.AUTH_OPENROUTER_FAILED,
|
|
},
|
|
"/set/data/selected_openrouter_model": {
|
|
"INVALID": ErrorCode.MODEL_OPENROUTER_INVALID,
|
|
},
|
|
"/run/lmstudio_connection": {
|
|
"FAILED": ErrorCode.CONNECTION_LMSTUDIO_FAILED,
|
|
},
|
|
"/set/data/lmstudio_url": {
|
|
"INVALID": ErrorCode.CONNECTION_LMSTUDIO_URL_INVALID,
|
|
},
|
|
"/set/data/selected_lmstudio_model": {
|
|
"INVALID": ErrorCode.MODEL_LMSTUDIO_INVALID,
|
|
},
|
|
"/run/ollama_connection": {
|
|
"FAILED": ErrorCode.CONNECTION_OLLAMA_FAILED,
|
|
},
|
|
"/set/data/selected_ollama_model": {
|
|
"INVALID": ErrorCode.MODEL_OLLAMA_INVALID,
|
|
},
|
|
"/set/data/websocket_host": {
|
|
"INVALID_IP": ErrorCode.VALIDATION_INVALID_IP,
|
|
"UNAVAILABLE": ErrorCode.WEBSOCKET_HOST_INVALID,
|
|
},
|
|
"/set/data/websocket_port": {
|
|
"UNAVAILABLE": ErrorCode.WEBSOCKET_PORT_UNAVAILABLE,
|
|
},
|
|
"/set/enable/websocket_server": {
|
|
"UNAVAILABLE": ErrorCode.WEBSOCKET_SERVER_UNAVAILABLE,
|
|
},
|
|
"/set/enable/vrc_mic_mute_sync": {
|
|
"OSC_DISABLED": ErrorCode.VRC_MIC_MUTE_SYNC_OSC_DISABLED,
|
|
},
|
|
}
|
|
|
|
|
|
def get_error_metadata(error_code: ErrorCode) -> Dict[str, Any]:
|
|
"""エラーコードのメタデータを取得
|
|
|
|
Args:
|
|
error_code: エラーコード
|
|
|
|
Returns:
|
|
メタデータ辞書
|
|
"""
|
|
return ERROR_METADATA.get(error_code, ERROR_METADATA[ErrorCode.GENERAL_UNKNOWN])
|
|
|
|
|
|
def is_critical_error(error_code: ErrorCode) -> bool:
|
|
"""クリティカルエラーかどうかを判定
|
|
|
|
Args:
|
|
error_code: エラーコード
|
|
|
|
Returns:
|
|
クリティカルエラーの場合True
|
|
"""
|
|
metadata = get_error_metadata(error_code)
|
|
return metadata.get("severity") == "critical"
|
|
|
|
|
|
def requires_user_action(error_code: ErrorCode) -> bool:
|
|
"""ユーザーアクションが必要なエラーかどうかを判定
|
|
|
|
Args:
|
|
error_code: エラーコード
|
|
|
|
Returns:
|
|
ユーザーアクションが必要な場合True
|
|
"""
|
|
metadata = get_error_metadata(error_code)
|
|
return metadata.get("user_action_required", False)
|