文档
03 平台04 媒体供应03_设计

MG-03-006 供应商适配器

状态说明:以当前有效边界为准。供应执行规则与历史实现证据保留;客户身份、售价、结算、全量旧跨仓契约及图像开放计划不代表当前验收范围。

1. 目标

Provider 差异必须留在适配器,调度器只理解 Supply、规范化请求、能力、成本和统一 错误,不允许出现 if provider == omega 等平台分支。

2. 接口拆分

不要建立一个要求所有 Provider 实现全部媒体能力的巨型接口。

CatalogAdapter

type CatalogAdapter interface {
    TestConnection(ctx context.Context, channel Connection) error
    DiscoverModels(ctx context.Context, channel Connection) ([]DiscoveredModel, error)
}

可选:

type PriceDiscoveryAdapter interface {
    DiscoverPrices(ctx context.Context, channel Connection) ([]DiscoveredPrice, error)
}

VideoAdapter

生产接口以 internal/video/provider.Adapter 为准(下列为省略包前缀的签名):

type Adapter interface {
    Validate(context.Context, SupplySnapshot, domain.Request) *ProviderError
    Submit(context.Context, AttemptSnapshot, *Connection, domain.Request) (Submission, error)
    Poll(context.Context, ProviderTaskReference, *Connection) (PollResult, error)
}

目录使用 internal/provider/catalog.Adapter 和可选 PriceDiscoveryAdapter;错误分类在各原生实现内部完成,不另建 ClassifyError 公共接口。 新协议的文件组织、注册及验收流程见 原生接入规范。JS 安装与绑定入口已退役;历史执行器暂留用于兼容。

ImageSyncAdapter

type ImageSyncAdapter interface {
    Validate(ctx context.Context, supply SupplySnapshot, req image.Request) error
    Generate(ctx context.Context, attempt AttemptSnapshot, req image.Request) (image.Result, error)
    ClassifyError(err error, response *ProviderResponse) ProviderError
}

异步图像 Provider 额外实现 ImageAsyncAdapter 的 Submit/Poll。

3. 模型发现

模型发现流程:

  1. 后端解密 Credential;
  2. 由 Provider Adapter 调用模型列表接口;
  3. 返回原始模型 ID、展示名和 Provider 元数据;
  4. 与上次快照比较新增、移除和变更;
  5. 管理员选择导入;
  6. 导入创建 disabled Supply Draft;
  7. 补齐能力、成本和测试证据后才可启用。

发现到模型不代表该模型已验证或可生产。

模型接口没有价格时不得推测价格。价格来源按以下优先级:

  1. 管理员明确覆盖;
  2. Provider 价格接口;
  3. 适配器经过审查的目录;
  4. 未知,禁止自动调度。

4. 错误分类

统一错误:

type ProviderError struct {
    Category  ErrorCategory
    Scope     ErrorScope
    Retryable bool
    Code      string
    Message   string
    RetryAfter time.Duration
}

适配器必须覆盖:

  • HTTP 状态;
  • Provider 错误码;
  • 响应体状态;
  • 提交超时;
  • 查询任务错误;
  • 内容审核;
  • 真人政策;
  • 余额、认证和限流;
  • 模型不存在;
  • Provider 返回成功但字段缺失。

不能只按 HTTP 4xx/5xx 粗略判断。

5. 提交幂等与不确定性

  • 如果 Provider 支持 Client Request ID 或 Idempotency Key,必须使用 Attempt ID;
  • Provider POST 超时后,适配器必须指示是否能通过请求号查询;
  • 无法确认受理时返回 submission_uncertain;
  • 调度器不得把未知提交当作普通失败;
  • Provider Task ID 和查询所需 Credential Version 必须持久化。

6. 素材

  • 异步视频和图像使用平台临时素材 URL,避免用户 URL 在排队或重试时过期;
  • Provider 要求 upload-ref 时,适配器负责上传并保存 Provider 临时引用;
  • Adapter 不得改变素材顺序或静默删除字段;
  • 降级变换在 Adapter 之前由已发布 Degradation Rule 执行;
  • 外部 URL 获取由平台统一执行 SSRF 和大小校验。

7. 结果

适配器返回规范化结果引用:

provider_url
content_type
expected_size
provider_metadata

Provider URL 只交给 Result Worker,不直接作为长期公开结果。Result Worker 转存、 校验并创建平台 MediaAsset 后,任务才成功。

同步图像可以在响应时间内完成校验和存储;如果返回 Base64,禁止写入日志。

8. 真实测试证据

每个生产 Supply 至少保存:

  • Provider 模型 ID;
  • 请求 Profile;
  • 脱敏请求 Fixture;
  • 脱敏成功响应 Fixture;
  • 错误分类 Fixture;
  • 能力边界测试;
  • 价格来源和时间;
  • 是否失败扣费;
  • 视频真人政策证据;
  • 结果 URL 有效期和下载行为;
  • 测试时间和执行人。

缺少证据的 Supply 保持 disabled。

9. 从 new-api 复用

每个 Provider 适配任务先审查:

  1. 请求 DTO 是否可以脱离 Gin/new-api Context;
  2. 是否依赖旧 Channel、ModelMapping、Group、Priority 或 Weight;
  3. 是否正确保留显式零值;
  4. 错误处理是否足够区分内容与 Provider 故障;
  5. 是否泄漏 Key、URL 或响应体;
  6. 是否支持模型发现;
  7. 是否包含可复用的查询和结果解析。

只移植协议逻辑,使用新项目接口重新包装。禁止把旧调度模型一并复制。

On this page