| """Single production composition root for the FCC server.""" |
|
|
| import os |
| from functools import partial |
| from pathlib import Path |
|
|
| from free_claude_code.api.app import create_app |
| from free_claude_code.api.ports import ApiServices |
| from free_claude_code.config.logging_config import configure_logging |
| from free_claude_code.config.paths import server_log_path |
| from free_claude_code.config.settings import Settings |
| from free_claude_code.messaging.transcription import TranscriptionService |
| from free_claude_code.messaging.voice import Transcriber |
| from free_claude_code.providers.admission import ProviderAdmissionController |
| from free_claude_code.providers.base import BaseProvider, ProviderConfig |
| from free_claude_code.providers.nvidia_nim.voice import NvidiaNimTranscriber |
| from free_claude_code.providers.openai_codex import ( |
| OpenAIAuthManager, |
| OpenAICodexProvider, |
| ) |
| from free_claude_code.providers.runtime import ProviderRuntime |
| from free_claude_code.providers.runtime.config import split_api_key_pool |
| from free_claude_code.providers.runtime.factory import create_provider |
|
|
| from .application import ApplicationRuntime, RestartCallback |
| from .asgi import RuntimeASGIApp |
| from .codex_catalog import CodexModelCatalogPublisher |
| from .provider_manager import ProviderRuntimeManager |
|
|
|
|
| def build_asgi_app( |
| settings: Settings, |
| restart_callback: RestartCallback | None = None, |
| ) -> RuntimeASGIApp: |
| """Construct the complete server application and its resource owner.""" |
| log_path = Path(os.getenv("LOG_FILE", server_log_path())) |
| configure_logging( |
| log_path, |
| level=settings.log_level, |
| verbose_third_party=settings.log_raw_api_payloads, |
| ) |
| openai_auth = OpenAIAuthManager(proxy=settings.openai_proxy) |
| openai_factory = partial(_create_openai_provider, auth=openai_auth) |
| provider_constructor = partial( |
| create_provider, |
| injected_factories={"openai": openai_factory}, |
| ) |
| runtime_factory = partial( |
| ProviderRuntime, |
| provider_constructor=provider_constructor, |
| ) |
| provider_manager = ProviderRuntimeManager( |
| settings, |
| runtime_factory=runtime_factory, |
| connected_provider_ids=openai_auth.connected_provider_ids, |
| model_catalog_publisher=CodexModelCatalogPublisher(), |
| ) |
| runtime = ApplicationRuntime( |
| provider_manager, |
| transcriber=_create_transcriber(settings), |
| restart_callback=restart_callback, |
| connected_accounts={"openai": openai_auth}, |
| ) |
| services = ApiServices( |
| requests=provider_manager, |
| admin=runtime, |
| tasks=runtime, |
| ) |
| return RuntimeASGIApp(create_app(services), runtime) |
|
|
|
|
| def _create_openai_provider( |
| config: ProviderConfig, |
| _settings: Settings, |
| admission: ProviderAdmissionController, |
| *, |
| auth: OpenAIAuthManager, |
| ) -> BaseProvider: |
| return OpenAICodexProvider(config, auth=auth, admission=admission) |
|
|
|
|
| def _first_pool_key(value: str) -> str: |
| """Return the first key of a comma-separated credential pool. |
| |
| Provider chat credentials may be configured as a comma-separated pool for |
| round-robin rotation, but the voice transcribers consume a single key and |
| must never send the raw joined pool as one token. |
| """ |
|
|
| keys = split_api_key_pool(value) |
| return keys[0] if keys else "" |
|
|
|
|
| def _create_transcriber(settings: Settings) -> Transcriber | None: |
| if not settings.voice_note_enabled: |
| return None |
| if settings.whisper_device == "nvidia_nim": |
| return NvidiaNimTranscriber( |
| model=settings.whisper_model, |
| api_key=_first_pool_key(settings.nvidia_nim_api_key), |
| ) |
| return TranscriptionService( |
| model=settings.whisper_model, |
| device=settings.whisper_device, |
| huggingface_api_key=_first_pool_key(settings.huggingface_api_key), |
| ) |
|
|