feat: add ASR provider support for voice co-creation

This commit is contained in:
2026-04-24 17:58:49 +08:00
parent 7e450aa5fc
commit 3805c18622
22 changed files with 471 additions and 126 deletions

View File

@@ -113,6 +113,14 @@ def _get_default_config(adapter_name: str) -> AdapterConfig | None:
timeout_ms=1000,
)
# --- ASR Defaults ---
if adapter_name == "openai_asr":
return AdapterConfig(
api_key=settings.openai_api_key,
model=settings.voice_transcription_model,
timeout_ms=60000,
)
# --- Text Defaults ---
if adapter_name in ("gemini", "text_primary"):
return AdapterConfig(
@@ -289,7 +297,7 @@ async def _route_with_failover(
"""通用 provider failover 路由。
Args:
provider_type: 供应商类型 (text/image/tts/storybook)
provider_type: 供应商类型 (text/image/tts/storybook/asr)
strategy: 路由策略
db: 数据库会话(可选,用于指标收集和熔断检查)
user_id: 用户 ID可选用于成本追踪和预算检查
@@ -297,7 +305,14 @@ async def _route_with_failover(
story_id: 故事 ID可选用于关联 provider 事件)
**kwargs: 传递给适配器的参数
"""
providers = await _get_providers_with_config(provider_type)
provider_names = kwargs.pop("provider_names", None)
if provider_names:
providers = [
(name, _get_default_config(name) or AdapterConfig(api_key=""), None)
for name in provider_names
]
else:
providers = await _get_providers_with_config(provider_type)
if not providers:
raise ValueError(f"No {provider_type} providers configured.")
@@ -457,6 +472,35 @@ async def _route_with_failover(
raise ValueError(f"No {provider_type} provider succeeded. Errors: {' | '.join(errors)}")
async def transcribe_audio(
audio_bytes: bytes,
file_name: str | None = None,
mime_type: str | None = None,
transcript_hint: str | None = None,
language: str | None = None,
provider_names: list[str] | None = None,
strategy: RoutingStrategy = RoutingStrategy.PRIORITY,
db: AsyncSession | None = None,
user_id: str | None = None,
):
"""语音转写,支持 provider failover。"""
from app.services.adapters.asr.models import TranscriptionOutput
result: TranscriptionOutput = await _route_with_failover(
"asr",
strategy=strategy,
db=db,
user_id=user_id,
audio_bytes=audio_bytes,
file_name=file_name,
mime_type=mime_type,
transcript_hint=transcript_hint,
language=language,
provider_names=provider_names,
)
return result
async def generate_story_content(
input_type: Literal["keywords", "full_story"],
data: str,