Skip to content

feat(real-person): susciyuan virtual_character 真人渠道对接 + 自动分组路由 (Phase A) - #1175

Open
think-back wants to merge 11 commits into
mainfrom
feat/susciyuan-real-person-20260911
Open

think-back wants to merge 11 commits into
mainfrom
feat/susciyuan-real-person-20260911

Conversation

@think-back

Copy link
Copy Markdown
Collaborator

目标

为 susciyuan(涑元智算,渠道 272,asset_materialization.provider=virtual_character)接入真人素材(volc_real_person)对接,并让这类渠道进入自动分组随机路由,与原生 BytePlus、tokenspace_material 并存。对接方案参考 flatkey 既有真人 provider 抽象(native BytePlus / TokenSpace),新增第三个显式 provider。

Phase A(本 PR 范围,已实现 + 已验证)

  • 8 方法 realPersonProvider 实现 virtualCharacterRealPersonProviderservice/virtual_character_real_person.go):
    • 核验会话:CreateVisualValidateSession(POST 拿 launch_url H5 链接)/ GetVisualValidateResult(轮询 succeeded/pending/failed → 复用既有 AssetMaterializeFailure 重试语义)。
    • 素材:CreateAsset(io.Pipe 流式 multipart 上传本人肖像)/ GetAsset / DeleteAsset / ListAssetscharacter_id 作为 UpstreamGroupId 单键。
    • REST 传输层拒绝重定向、Bearer 鉴权、LimitReader 限流、HTTP 状态 → 错误分类(429→Throttled / 408→Timeout / 5xx→Upstream5xx / 4xx→Definitive)。
    • 响应信封 {success,data,message,error:{code}}source_type 校验为 volc_real_person
  • 进自动分组随机路由realPersonChannelIsAutomaticCandidate 改为对非原生渠道委托 realPersonProviderForChannel,使 virtual_character / tokenspace_material 与 native BytePlus 一同进入随机池(此前显式 provider 被排除在自动池外)。
  • 分发派发realPersonProviderForChannelswitch 派发 virtual_character,保留"恰好一个启用 key"约束。
  • multipart 临时存储闸门realPersonAssetMultipartStore 允许 virtual_character 走 GCS 回退(否则肖像上传在到达上游前就 503 fail-closed)。
  • relay dormant 闸门加固controller/relay.go 三处 ChannelTypeBytePlus pinned-lock 闸门放宽接受 DoubaoVideo 真人渠道,镜像 middleware/distributor.goselectBytePlusPinnedAssetChannel(该路径在生产 video-submit 上休眠——走 ResolveLegacyBytePlusAssetBindingReferences,从不设 pinned key;additive,原生行为不变)。
  • 无新增 i18n:provider 只返回类型化 AssetMaterializeFailure/error,用户可见文案沿用既有 real_person.* key。

测试:单测严格 TDD(provider 静态契约、状态映射、重定向阻断、HTTP 错误映射、会话创建/轮询、错误不泄漏 API Key、GetAsset/DeleteAsset、肖像 multipart 上传、显式 provider 进自动池、multipart 闸门放行 virtual_character)。全部新测试通过。

Phase B(不在本 PR

asset://<provider_asset_id> 线缆桥接(把生成请求里的 asset:// 引用改写到上游真人素材 id)。它需要真人在 H5 完成人脸核验 + 上传肖像才能拿到 provider_asset_id,无法在无真人参与下验证,故排除在本 PR 验收之外。生产真人「出片」在 Phase B 落地前不算完成。

数据面(仅 staging)

渠道 272 的配置(provider=virtual_character、单个启用 key、ability 行、enable status)只在 staging 应用,不动生产。

验证情况

  • go vet ./service/... ./controller/... 干净。
  • 全仓 Go 包(service/controller/middleware/model/relay)编译通过;根 main 包因 //go:embed web/classic/dist 需先构建前端而失败,此为预存在、与本改动无关(baseline 同样失败)。
  • 跨包测试 ./service/... ./middleware/... ./controller/...:本分支 62 失败 == 代码同一的 origin/main baseline(486d10394)62 失败,两集合逐字节相同,零新增回归。这些预存在失败均为环境依赖(本机缺完整 DB/env),不在本改动调用图内。

🤖 Generated with Claude Code

Phase A (this deliverable): verification+routing+8-method provider, keyed by
management id, verifiable via unit tests + live pre-verification path.
Phase B (deferred): asset://<provider_asset_id> wire bridge via two-field
scoped AssetBinding — its payoff needs a live human H5 flow (excluded from
agreed acceptance) and bridging BytePlus-table real-person assets to the
generalized pipeline is a separate design.
…date only

Confirmed against origin/main: staging native BytePlus requires a callback
base, so auto-routing already passes the gate and can select susciyuan once
it is an automatic candidate — no callback relaxation needed (and a naive
pre-selection probe would double-draw, Rule 11). Provider errors reuse
existing AssetMaterializeFailure classes -> existing real_person.* keys, so
no new i18n string; a task verifies this.
…te set

realPersonChannelIsAutomaticCandidate now delegates to realPersonProviderForChannel
for non-native channels, so tokenspace_material and virtual_character (susciyuan)
channels enter group-based random routing alongside native BytePlus. Prior rule
excluded all explicit providers from the automatic pool.

Pre-existing service-package failures (ResolveBytePlusAssetReferences*, DingTalk*,
Recall*, AssetBinding*, Solana, Cache — 20 total) are present unchanged at the
code-identical origin/main baseline (4ef3cd8f7) and lie outside this call graph.
…re gate

realPersonAssetMultipartStore fell back to the GCS temp store only for
tokenSpaceRealPersonProvider when a channel carries no explicit
StorageCredentials. susciyuan (virtual_character) has the same shape, so
portrait upload failed closed with a 503 before reaching the upstream.
Admit both explicit providers via a type switch.

Test appended to the existing byteplus_real_person_asset_test.go suite.
…explicit providers

The three ChannelTypeBytePlus gates in lockBytePlusAssetPinnedChannel /
validateBytePlusAssetPinnedLock reject any non-native channel that carries a
pinned-asset lock. They are dormant on the production video-submit path (which
routes through ResolveLegacyBytePlusAssetBindingReferences and never sets
ContextKeyBytePlusAssetPinnedChannelID), but widen them anyway to accept
DoubaoVideo real-person channels, mirroring selectBytePlusPinnedAssetChannel in
middleware/distributor.go. Not on the hot path; additive, native behaviour
unchanged.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants