Phase 26: P1 architecture refactor — DI container, service layer, async callbacks

- config.py: APIConfig + AppConfig dataclasses, env vars centralized
- api_client.py: APIClientProtocol (Protocol) + HTTPAPIClient class, remove module-level globals
- services.py: ChatService, DocumentService, TTSService (TTS moved from app.py)
- container.py: manual DI container with lazy singleton properties
- app.py: all callbacks converted to async, asyncio.run() fully removed, container wired in
- .env.example: add TTS_EDGE_VOICE entry
- ROADMAP.md: P0/P1 checklist updated to reflect completed work

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
sal
2026-06-01 17:36:35 +09:00
parent be4b7c40cb
commit d81a2f5888
7 changed files with 307 additions and 177 deletions
+41
View File
@@ -0,0 +1,41 @@
"""수동 DI 컨테이너."""
from api_client import HTTPAPIClient
from config import AppConfig
from services import ChatService, DocumentService, TTSService
class Container:
def __init__(self, config: AppConfig):
self._config = config
self._api_client: HTTPAPIClient | None = None
self._chat_service: ChatService | None = None
self._document_service: DocumentService | None = None
self._tts_service: TTSService | None = None
@property
def config(self) -> AppConfig:
return self._config
@property
def api_client(self) -> HTTPAPIClient:
if self._api_client is None:
self._api_client = HTTPAPIClient(self._config.api)
return self._api_client
@property
def chat_service(self) -> ChatService:
if self._chat_service is None:
self._chat_service = ChatService(self.api_client)
return self._chat_service
@property
def document_service(self) -> DocumentService:
if self._document_service is None:
self._document_service = DocumentService(self.api_client)
return self._document_service
@property
def tts_service(self) -> TTSService:
if self._tts_service is None:
self._tts_service = TTSService(self._config)
return self._tts_service