mirror of
https://github.com/snailyp/gemini-balance.git
synced 2026-09-04 23:19:17 +08:00
对多个模块进行了重构,以改进错误处理和日志记录机制。 主要变更包括: - 在 `gemini_routes` 中,现在会返回更具体的错误信息,包括错误码和错误消息,而不仅仅是异常的字符串表示。 - 在 `api_client` 中,简化了 Gemini API 客户端的错误处理逻辑,移除了冗余的 `try...except` 块,让异常直接向上抛出。 - 在多个服务(如 `openai_chat_service`, `embedding_service`, `tts_service` 等)中,增加了根据配置项 `ERROR_LOG_RECORD_REQUEST_BODY` 来决定是否记录请求体的逻辑,以增强隐私和性能控制。 - 在前端 `keys_status.js` 中,更新了密钥验证结果的处理逻辑,以适应后端返回的新的错误对象结构(包含 `error_code` 和 `error_message`),并移除了冗余的 `executeVerifyAllKeys` 函数。
106 lines
3.7 KiB
Python
106 lines
3.7 KiB
Python
import datetime
|
|
import io
|
|
import re
|
|
import time
|
|
import wave
|
|
from typing import Optional
|
|
|
|
from google import genai
|
|
|
|
from app.config.config import settings
|
|
from app.core.constants import TTS_VOICE_NAMES
|
|
from app.database.services import add_error_log, add_request_log
|
|
from app.domain.openai_models import TTSRequest
|
|
from app.log.logger import get_openai_logger
|
|
|
|
logger = get_openai_logger()
|
|
|
|
|
|
def _create_wav_file(audio_data: bytes) -> bytes:
|
|
"""Creates a WAV file in memory from raw audio data."""
|
|
with io.BytesIO() as wav_file:
|
|
with wave.open(wav_file, "wb") as wf:
|
|
wf.setnchannels(1) # Mono
|
|
wf.setsampwidth(2) # 16-bit
|
|
wf.setframerate(24000) # 24kHz sample rate
|
|
wf.writeframes(audio_data)
|
|
return wav_file.getvalue()
|
|
|
|
|
|
class TTSService:
|
|
async def create_tts(self, request: TTSRequest, api_key: str) -> Optional[bytes]:
|
|
"""
|
|
使用 Google Gemini SDK 创建音频。
|
|
"""
|
|
start_time = time.perf_counter()
|
|
request_datetime = datetime.datetime.now()
|
|
is_success = False
|
|
status_code = None
|
|
response = None
|
|
error_log_msg = ""
|
|
try:
|
|
client = genai.Client(api_key=api_key)
|
|
response = await client.aio.models.generate_content(
|
|
model=settings.TTS_MODEL,
|
|
contents=f"Speak in a {settings.TTS_SPEED} speed voice: {request.input}",
|
|
config={
|
|
"response_modalities": ["Audio"],
|
|
"speech_config": {
|
|
"voice_config": {
|
|
"prebuilt_voice_config": {
|
|
"voice_name": (
|
|
request.voice
|
|
if request.voice in TTS_VOICE_NAMES
|
|
else settings.TTS_VOICE_NAME
|
|
)
|
|
}
|
|
}
|
|
},
|
|
},
|
|
)
|
|
if (
|
|
response.candidates
|
|
and response.candidates[0].content.parts
|
|
and response.candidates[0].content.parts[0].inline_data
|
|
):
|
|
raw_audio_data = (
|
|
response.candidates[0].content.parts[0].inline_data.data
|
|
)
|
|
is_success = True
|
|
status_code = 200
|
|
return _create_wav_file(raw_audio_data)
|
|
except Exception as e:
|
|
is_success = False
|
|
error_log_msg = f"Generic error: {e}"
|
|
logger.error(f"An error occurred in TTSService: {error_log_msg}")
|
|
match = re.search(r"status code (\d+)", str(e))
|
|
if match:
|
|
status_code = int(match.group(1))
|
|
else:
|
|
status_code = 500
|
|
raise
|
|
finally:
|
|
end_time = time.perf_counter()
|
|
latency_ms = int((end_time - start_time) * 1000)
|
|
if not is_success:
|
|
await add_error_log(
|
|
gemini_key=api_key,
|
|
model_name=settings.TTS_MODEL,
|
|
error_type="google-tts",
|
|
error_log=error_log_msg,
|
|
error_code=status_code,
|
|
request_msg=(
|
|
request.input
|
|
if settings.ERROR_LOG_RECORD_REQUEST_BODY
|
|
else None
|
|
),
|
|
)
|
|
await add_request_log(
|
|
model_name=settings.TTS_MODEL,
|
|
api_key=api_key,
|
|
is_success=is_success,
|
|
status_code=status_code,
|
|
latency_ms=latency_ms,
|
|
request_time=request_datetime,
|
|
)
|