Refactor: split services.py into services/ package
ChatService → services/chat.py DocumentService → services/document.py TTSService → services/tts.py services/__init__.py re-exports all three for backward-compatible imports Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
from services.chat import ChatService
|
||||
from services.document import DocumentService
|
||||
from services.tts import TTSService
|
||||
|
||||
__all__ = ["ChatService", "DocumentService", "TTSService"]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,26 @@
|
||||
from typing import AsyncIterator
|
||||
|
||||
from api_client import APIClientProtocol
|
||||
|
||||
|
||||
class ChatService:
|
||||
def __init__(self, api_client: APIClientProtocol):
|
||||
self._api = api_client
|
||||
|
||||
def chat(
|
||||
self, message: str, user_id: str, show_thinking: bool
|
||||
) -> AsyncIterator[tuple[str, str | None]]:
|
||||
return self._api.chat(message, user_id, show_thinking)
|
||||
|
||||
async def reset(self, user_id: str) -> None:
|
||||
await self._api.reset(user_id)
|
||||
|
||||
async def save_feedback(
|
||||
self,
|
||||
user_id: str,
|
||||
user_msg: str,
|
||||
asst_msg: str,
|
||||
rating: int,
|
||||
run_id: str | None,
|
||||
) -> None:
|
||||
await self._api.save_feedback(user_id, user_msg, asst_msg, rating, run_id)
|
||||
@@ -0,0 +1,15 @@
|
||||
from api_client import APIClientProtocol
|
||||
|
||||
|
||||
class DocumentService:
|
||||
def __init__(self, api_client: APIClientProtocol):
|
||||
self._api = api_client
|
||||
|
||||
async def ingest(self, file_path: str) -> dict:
|
||||
return await self._api.ingest(file_path)
|
||||
|
||||
async def list_documents(self) -> list[str]:
|
||||
return await self._api.list_documents()
|
||||
|
||||
async def delete_document(self, source: str) -> None:
|
||||
await self._api.delete_document(source)
|
||||
@@ -0,0 +1,53 @@
|
||||
import asyncio
|
||||
import platform
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
from config import AppConfig
|
||||
|
||||
|
||||
class TTSService:
|
||||
def __init__(self, config: AppConfig):
|
||||
self._voice = config.tts_voice
|
||||
self._edge_voice = config.tts_edge_voice
|
||||
|
||||
async def speak(self, text: str) -> str | None:
|
||||
"""크로스플랫폼 TTS. macOS: say→edge-tts→pyttsx3 / Windows: edge-tts→pyttsx3"""
|
||||
if not text:
|
||||
return None
|
||||
|
||||
if platform.system() == "Darwin":
|
||||
try:
|
||||
tmp = tempfile.NamedTemporaryFile(suffix=".aiff", delete=False)
|
||||
tmp.close()
|
||||
await asyncio.to_thread(
|
||||
subprocess.run,
|
||||
["say", "-v", self._voice, "-o", tmp.name, text],
|
||||
check=True,
|
||||
capture_output=True,
|
||||
)
|
||||
return tmp.name
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
import edge_tts
|
||||
tmp = tempfile.NamedTemporaryFile(suffix=".mp3", delete=False)
|
||||
tmp.close()
|
||||
await edge_tts.Communicate(text, self._edge_voice).save(tmp.name)
|
||||
return tmp.name
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
import pyttsx3
|
||||
tmp = tempfile.NamedTemporaryFile(suffix=".wav", delete=False)
|
||||
tmp.close()
|
||||
def _save():
|
||||
engine = pyttsx3.init()
|
||||
engine.save_to_file(text, tmp.name)
|
||||
engine.runAndWait()
|
||||
await asyncio.to_thread(_save)
|
||||
return tmp.name
|
||||
except Exception:
|
||||
return None
|
||||
Reference in New Issue
Block a user