新增 app/providers/openai/:client 传输(JSON + multipart)、errors 错误映射、 models 厂商 DTO、capabilities 尺寸算术约束、tasks 同步→异步桥、image 图片业务。 装配与配置同步接入,缺 OPENAI_API_KEY 时跳过装配、服务仍可启动。 与火山视频的三处根本差异及其处置: - 接口同步(无任务 ID、无查询端点)→ SyncTaskRegistry 在本服务内部吸收, 对外仍是 ADR-023 §4 的两段式提交/轮询。代价:本服务从此持有状态,进程重启 丢在途任务,且横向扩容前须先解决任务 ID 只在签发进程内有效的问题。 - 产物是 base64 字节而非 URL → 无过期问题,但字节只在内存里。asset_url 放 data URI 仅为满足领域不变式,绝不能原样写进 media.assets.external_url。 - 图生图走 multipart → 先下载参考图再上传;下载失败与超限按参数错误同步拒绝, 不变成注定失败的后台任务。 两处需要记住的判断: - 尺寸上限「3840x2160」文档未说清是逐边还是按像素。逐边理解会禁掉所有高于 2160 的竖图,而 1024x1536 是文档明示的标准竖图,故必然过严。采用最长边 ≤3840 且总像素 ≤3840×2160,已在 capabilities.py 与取证页标为推断。 - 两份文档都没有错误码表,故 errors.py 以 HTTP 状态码为主、type/code 为辅, 顶部标注「未经文档证实」。429 无线索时按限流而非配额耗尽(猜成配额会把可 重试的限流判死);400 无线索时归服务端错误而非内容被拒(错报会让用户去改 一个其实没问题的提示词)。 一处死锁已修并回归钉住:SyncTaskRegistry 原用 add_done_callback 记录完成时刻, 而快速完成的任务在注册时已 done,回调便同步地在持有非可重入锁的线程里执行。 改为首次被观察到时惰性记录。 测试 166 → 271(+105)。四道门禁逐条读退出码,全绿。 产物转存仍阻塞于存储决策(ADR-023 §7),图片模型因此未播种进 V7 目录。
This commit is contained in:
+18
-3
@@ -16,6 +16,7 @@ from fastapi import APIRouter, Depends, Request
|
||||
|
||||
from app.domain.generation import MediaKind
|
||||
from app.providers.base import GenerationProvider
|
||||
from app.providers.openai.client import OpenAiError
|
||||
from app.providers.registry import ProviderRegistry
|
||||
from app.providers.volcengine.client import ArkError
|
||||
|
||||
@@ -62,13 +63,18 @@ def submit_task(payload: SubmitRequest, request: Request) -> SubmitResponse:
|
||||
provider = _provider_for(_registry(request), payload.media_kind)
|
||||
try:
|
||||
provider_request_id = provider.submit(payload.to_domain())
|
||||
except ArkError as exc:
|
||||
except (ArkError, OpenAiError) as exc:
|
||||
# 服务商调用失败:原样带上分类,调用方据 retry 决定重试。
|
||||
raise ProviderError(exc.failure) from exc
|
||||
except ValueError as exc:
|
||||
# 本地预校验拦下的参数问题(超出该模型的时长/分辨率/ratio 限制,或内容为空)。
|
||||
# 属 invalid_request 而非 provider 错误——请求根本没发出去。
|
||||
# 本地预校验拦下的参数问题(超出该模型的时长/尺寸/ratio 限制、内容为空、
|
||||
# 参考图不可下载)。属 invalid_request 而非 provider 错误——请求根本没发出去。
|
||||
raise ServiceError(ServiceErrorCode.INVALID_REQUEST, str(exc)) from exc
|
||||
except RuntimeError as exc:
|
||||
# 同步型适配器的在途任务已达上限。这不是请求的问题而是容量问题,且稍后
|
||||
# 重试会好,故归 provider_unavailable(503)而非 invalid_request——后者会
|
||||
# 让调用方判为不可重试并直接失败掉一个本可成功的任务。
|
||||
raise ServiceError(ServiceErrorCode.PROVIDER_UNAVAILABLE, str(exc)) from exc
|
||||
|
||||
log.info(
|
||||
"已提交生成任务 job_id=%s provider_request_id=%s",
|
||||
@@ -96,6 +102,13 @@ def get_task(
|
||||
provider = _provider_for(_registry(request), media_kind)
|
||||
try:
|
||||
result = provider.fetch(provider_request_id)
|
||||
except KeyError as exc:
|
||||
# 同步型适配器的本地注册表里没有这个 ID:从未存在过,或进程重启后丢失
|
||||
# (两者无法区分)。两种情形下调用方都该**停止轮询**而非退避重试。
|
||||
raise ServiceError(
|
||||
ServiceErrorCode.TASK_NOT_FOUND,
|
||||
f"本服务无此任务(可能因进程重启而丢失):{provider_request_id}",
|
||||
) from exc
|
||||
except ArkError as exc:
|
||||
# 服务商说任务不存在(含超过 7 天保留期)→ 这是 service 类的 task_not_found,
|
||||
# 而不是 provider 错误:调用方要做的是停止轮询,不是退避重试。
|
||||
@@ -105,4 +118,6 @@ def get_task(
|
||||
f"服务商无此任务(或已超出其 7 天保留期):{provider_request_id}",
|
||||
) from exc
|
||||
raise ProviderError(exc.failure) from exc
|
||||
except OpenAiError as exc:
|
||||
raise ProviderError(exc.failure) from exc
|
||||
return TaskResponse.of(result)
|
||||
|
||||
@@ -37,6 +37,10 @@ class SubmitRequest(BaseModel):
|
||||
input_url: str | None = None
|
||||
ratio: str | None = None
|
||||
resolution: str | None = None
|
||||
#: 图片路径用像素尺寸;视频路径用 ratio+resolution。两家服务商的尺寸表达方式
|
||||
#: 不同,契约同时保留两种而不强行统一——任何统一都会在某一侧失真。
|
||||
width_px: int | None = None
|
||||
height_px: int | None = None
|
||||
duration_sec: int | None = None
|
||||
generate_audio: bool = True
|
||||
watermark: bool = False
|
||||
@@ -63,6 +67,8 @@ class SubmitRequest(BaseModel):
|
||||
input_url=self.input_url,
|
||||
ratio=self.ratio,
|
||||
resolution=self.resolution,
|
||||
width_px=self.width_px,
|
||||
height_px=self.height_px,
|
||||
duration_sec=self.duration_sec,
|
||||
generate_audio=self.generate_audio,
|
||||
watermark=self.watermark,
|
||||
|
||||
Reference in New Issue
Block a user