e58159fc42
Phase 1: 异常体系统一 - 新增 PlatformError / PlatformErrorType 标准定义 - 改造所有 Provider 异常抛出为 PlatformError - 注册全局 PlatformError exception handler Phase 2: Adapter Protocol - 新增 app/ai/adapters/base.py(PlatformAdapter + SyncCapable + TaskCapable + CallbackCapable) - 新增 app/ai/adapters/constants.py(Method 常量) - 新增 PlatformConfigLoader(config/platform-config.yaml) Phase 3: HTTP Client 统一 - ViduProvider 从 aiohttp 迁移到 httpx(注入方式) - VolcengineCaptionService 改为注入 http_client - lifespan 统一管理所有 Client 创建和关闭 Phase 4: Gateway 骨架 + Adapter 实现 - 新增 ViduAdapter / VolcengineArkAdapter / VolcengineCaptionAdapter - 新增 PlatformGateway(call_sync / submit_task / query_task / handle_webhook) - 新增 LLMGateway(带 Fallback 降级链) - lifespan 注册所有 Adapter 和 Gateway Phase 6: 清理与验证 - 从 Settings 移除 VIDU_BASE_URL / VOLCENGINE_BASE_URL - Provider 改为从 PlatformConfigLoader 读取 base_url - 清理 volcengine_caption_service 全局单例 - config_loader 默认路径改为 platform-config.yaml - Scheduler 注入共享 HTTP client - vidu.py 回调路由使用 Adapter 验签和解析 - ruff 全量通过,应用启动测试通过
102 lines
3.3 KiB
Python
102 lines
3.3 KiB
Python
"""
|
|
火山方舟 Adapter
|
|
================
|
|
|
|
实现 PlatformAdapter + SyncCapable。
|
|
直接接入 VolcengineProvider,提供标准 Protocol 接口。
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from typing import Any
|
|
|
|
from app.ai.adapters.base import AdapterResponse, PlatformAdapter, SyncCapable
|
|
from app.ai.adapters.constants import Method
|
|
from app.ai.providers.volcengine_provider import VolcengineProvider
|
|
from app.core.exceptions import PlatformError, PlatformErrorType
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class VolcengineArkAdapter(PlatformAdapter, SyncCapable):
|
|
"""火山方舟 LLM 平台标准 Adapter"""
|
|
|
|
platform_id = "volcengine_ark"
|
|
|
|
def __init__(self, provider: VolcengineProvider):
|
|
self.provider = provider
|
|
|
|
# ── PlatformAdapter ──
|
|
|
|
async def health(self) -> AdapterResponse:
|
|
try:
|
|
health = await self.provider.health_check()
|
|
return AdapterResponse(
|
|
success=health.is_available,
|
|
data={"response_time_ms": health.response_time},
|
|
)
|
|
except Exception as e:
|
|
return AdapterResponse(
|
|
success=False,
|
|
error_message=str(e),
|
|
retryable=False,
|
|
)
|
|
|
|
async def close(self) -> None:
|
|
if hasattr(self.provider.client, "close"):
|
|
await self.provider.client.close()
|
|
|
|
# ── SyncCapable ──
|
|
|
|
async def call(self, method: str, payload: dict[str, Any]) -> AdapterResponse:
|
|
try:
|
|
if method == Method.CHAT:
|
|
result = await self.provider.generate(
|
|
prompt=payload["prompt"],
|
|
model=payload.get("model"),
|
|
temperature=payload.get("temperature", 0.7),
|
|
max_tokens=payload.get("max_tokens"),
|
|
system_prompt=payload.get("system_prompt"),
|
|
)
|
|
return AdapterResponse(
|
|
success=True,
|
|
data={
|
|
"content": result.content,
|
|
"usage": result.usage,
|
|
"model": result.model,
|
|
},
|
|
)
|
|
|
|
elif method == Method.IMAGE_GENERATE:
|
|
result = await self.provider.generate_image(
|
|
prompt=payload["prompt"],
|
|
model=payload.get("model"),
|
|
size=payload.get("size", "1024x1024"),
|
|
)
|
|
return AdapterResponse(success=True, data=result)
|
|
|
|
elif method == Method.EMBEDDING:
|
|
result = await self.provider.create_embeddings(
|
|
texts=payload["texts"],
|
|
model=payload.get("model"),
|
|
)
|
|
return AdapterResponse(success=True, data=result)
|
|
|
|
else:
|
|
return AdapterResponse(
|
|
success=False,
|
|
error_message=f"不支持的方法: {method}",
|
|
retryable=False,
|
|
)
|
|
|
|
except PlatformError:
|
|
raise
|
|
except Exception as e:
|
|
raise PlatformError(
|
|
f"火山方舟 {method} 调用失败: {e}",
|
|
platform="volcengine_ark",
|
|
retryable=False,
|
|
error_type=PlatformErrorType.UNKNOWN,
|
|
) from e
|