feat: 接入模型动态 Fallback 与调用审计
This commit is contained in:
@@ -59,7 +59,14 @@ class VolcanoArkProvider:
|
||||
payload=data,
|
||||
)
|
||||
|
||||
def chat_completion(self, *, model: str, messages: list[dict[str, str]], endpoint: str = "chat/completions") -> dict[str, Any]:
|
||||
def chat_completion(
|
||||
self,
|
||||
*,
|
||||
model: str,
|
||||
messages: list[dict[str, str]],
|
||||
endpoint: str = "chat/completions",
|
||||
timeout: float = 120,
|
||||
) -> dict[str, Any]:
|
||||
if not self.api_key:
|
||||
raise ValueError("VOLCANO_ARK_API_KEY is not configured")
|
||||
|
||||
@@ -67,7 +74,7 @@ class VolcanoArkProvider:
|
||||
f"{self.base_url.rstrip('/')}/{endpoint.lstrip('/')}",
|
||||
headers={"Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json"},
|
||||
json={"model": model, "messages": messages},
|
||||
timeout=120,
|
||||
timeout=timeout,
|
||||
)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
@@ -80,6 +87,7 @@ class VolcanoArkProvider:
|
||||
endpoint: str = "chat/completions",
|
||||
temperature: float = 0.8,
|
||||
extra_body: dict[str, Any] | None = None,
|
||||
timeout: float = 300,
|
||||
) -> Iterator[dict[str, Any]]:
|
||||
"""流式对话:逐块 yield {type:'delta'|'tool_call'|'done', ...}。
|
||||
OpenAI 兼容 SSE(火山 ARK / 各中转站同构),供脚本 agent 的 SSE 端实时转发。"""
|
||||
@@ -97,7 +105,7 @@ class VolcanoArkProvider:
|
||||
},
|
||||
json=body,
|
||||
stream=True,
|
||||
timeout=300,
|
||||
timeout=timeout,
|
||||
) as response:
|
||||
response.raise_for_status()
|
||||
# SSE 响应常不带 charset,requests 会按 latin-1 解码 → 中文乱码。强制 UTF-8。
|
||||
@@ -157,6 +165,7 @@ class VolcanoArkProvider:
|
||||
endpoint: str = "images/generations",
|
||||
image: str | list[str] | None = None,
|
||||
size: str = "2K",
|
||||
timeout: float = 180,
|
||||
) -> dict[str, Any]:
|
||||
if not self.api_key:
|
||||
raise ValueError("VOLCANO_ARK_API_KEY is not configured")
|
||||
@@ -174,7 +183,7 @@ class VolcanoArkProvider:
|
||||
f"{self.base_url.rstrip('/')}/{endpoint.lstrip('/')}",
|
||||
headers={"Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json"},
|
||||
json=body,
|
||||
timeout=180,
|
||||
timeout=timeout,
|
||||
)
|
||||
# 非 2xx 抽出火山真实报错(error.code/message)而非裸 HTTP 400 —— 否则 Seedream 的
|
||||
# 内容审核 / 尺寸过小(历史 4:5 套图 raise_for_status 吞 body 的踩坑)等真因看不见。
|
||||
@@ -195,6 +204,7 @@ class VolcanoArkProvider:
|
||||
content_items: list[dict[str, Any]] | None = None,
|
||||
seed: int | None = None,
|
||||
search_mode: str = "off",
|
||||
timeout: float = 120,
|
||||
) -> dict[str, Any]:
|
||||
if not self.api_key:
|
||||
raise ValueError("VOLCANO_ARK_API_KEY is not configured")
|
||||
@@ -223,18 +233,24 @@ class VolcanoArkProvider:
|
||||
f"{self.base_url.rstrip('/')}/{endpoint.lstrip('/')}",
|
||||
headers={"Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json"},
|
||||
json=body,
|
||||
timeout=120,
|
||||
timeout=timeout,
|
||||
)
|
||||
_raise_volcano_error(response)
|
||||
return response.json()
|
||||
|
||||
def poll_video_task(self, *, endpoint: str, provider_task_id: str) -> dict[str, Any]:
|
||||
def poll_video_task(
|
||||
self,
|
||||
*,
|
||||
endpoint: str,
|
||||
provider_task_id: str,
|
||||
timeout: float = 60,
|
||||
) -> dict[str, Any]:
|
||||
if not self.api_key:
|
||||
raise ValueError("VOLCANO_ARK_API_KEY is not configured")
|
||||
response = requests.get(
|
||||
f"{self.base_url.rstrip('/')}/{endpoint.rstrip('/')}/{provider_task_id}",
|
||||
headers={"Authorization": f"Bearer {self.api_key}"},
|
||||
timeout=60,
|
||||
timeout=timeout,
|
||||
)
|
||||
_raise_volcano_error(response)
|
||||
return response.json()
|
||||
@@ -305,7 +321,15 @@ class VolcanoTtsProvider:
|
||||
def configured(self) -> bool:
|
||||
return bool(self.appid and self.access_token)
|
||||
|
||||
def synthesize(self, *, text: str, voice_type: str, speed_ratio: float = 1.0, uid: str = "airshelf") -> tuple[bytes, int]:
|
||||
def synthesize(
|
||||
self,
|
||||
*,
|
||||
text: str,
|
||||
voice_type: str,
|
||||
speed_ratio: float = 1.0,
|
||||
uid: str = "airshelf",
|
||||
timeout: float = 60,
|
||||
) -> tuple[bytes, int]:
|
||||
"""合成一段语音。返回 (mp3 字节, 时长毫秒;接口没回时长则为 0)。"""
|
||||
if not self.configured:
|
||||
raise TtsNotConfigured(
|
||||
@@ -322,7 +346,7 @@ class VolcanoTtsProvider:
|
||||
self.base_url,
|
||||
headers={"Authorization": f"Bearer;{self.access_token}"},
|
||||
json=body,
|
||||
timeout=60,
|
||||
timeout=timeout,
|
||||
)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
|
||||
Reference in New Issue
Block a user