fix(platform): media键条件渲染下沉到真实示例路径(_tpl_from_example)——四种键位+干跑覆盖
上一提交只修了合成兜底路径;用权威文档示例重新apply会走真实示例路径, 该路径零媒体同样发出"media": []空数组。本次统一下沉: - 新增 _media_any_expr(mps):「任一媒体有值」Jinja布尔(字符串/数组归一), 合成/真实两路径共用 - _tpl_from_example: media数组token记录(键名,mps),替换阶段按json.dumps 逗号位置分三模式(首/中键带尾逗号,末键吃前逗号,独键直包)整键条件化 - 单测22项全绿:四种键位×(零媒体省略/三模态/字符串形态/干跑)+合成路径 +schema(媒体非必填/prompt必填/multiple/ratio六值枚举)
This commit is contained in:
parent
89acb08ea9
commit
03d1e13ebd
@ -1032,6 +1032,20 @@ def _is_media_array(lst, capability):
|
||||
return True
|
||||
|
||||
|
||||
def _media_any_expr(mps):
|
||||
"""「任一媒体参数有值」Jinja 布尔表达式(字符串/数组两形态归一)。
|
||||
|
||||
2026-09-06 用户纠正后引入:全能参考模型(wan3.0 类 r2v)文档明示
|
||||
「prompt 和 media 必填其一」「文生视频不传入任何媒体文件」——零媒体是
|
||||
合法 t2v 形态且文档示例**不带 media 键**。无条件渲染会发出 "media": []
|
||||
空数组(API 未承诺接受,不能赌),故 media 键必须条件渲染:有媒体才
|
||||
输出键,零媒体整个省略。真实示例路径与合成兜底路径共用本表达式。
|
||||
"""
|
||||
return ' or '.join(
|
||||
'(params.%s if params.%s is not string and params.%s else '
|
||||
'([params.%s] if params.%s is string else []))' % ((mp,) * 5) for mp in mps)
|
||||
|
||||
|
||||
def _media_array_expr(elements):
|
||||
"""媒体数组示例 → Jinja 动态组装表达式(三数组契约 image_files/
|
||||
audio_files/video_files,值为字符串或数组均可)。
|
||||
@ -1094,6 +1108,7 @@ def _tpl_from_example(example, capability):
|
||||
返回 (模板串, media_params, biz_params, used_example)。
|
||||
"""
|
||||
tokens = {}
|
||||
cond_tokens = {}
|
||||
media_params, biz_params = [], []
|
||||
used_example = isinstance(example, dict) and bool(example)
|
||||
tree = example if used_example else _example_to_nested(None)
|
||||
@ -1111,7 +1126,14 @@ def _tpl_from_example(example, capability):
|
||||
for mp in mps:
|
||||
if mp not in media_params:
|
||||
media_params.append(mp)
|
||||
return _put(expr)
|
||||
tk = _put(expr)
|
||||
# media 键条件渲染(2026-09-06 用户纠正):零媒体=合法 t2v
|
||||
# 形态且文档示例不带 media 键,无条件渲染发出 "media": []
|
||||
# 空数组(API 未承诺接受,不能赌)。记录 (token→键名/媒体参数)
|
||||
# 供替换阶段整键包 Jinja 条件。仅 dict 下的数组键可条件化。
|
||||
if parent_key:
|
||||
cond_tokens[tk] = (parent_key, mps)
|
||||
return tk
|
||||
return [walk(v, parent_key, sib_type) for v in node]
|
||||
if not isinstance(node, dict):
|
||||
return node
|
||||
@ -1150,6 +1172,25 @@ def _tpl_from_example(example, capability):
|
||||
body = walk(tree)
|
||||
s = json.dumps(body, ensure_ascii=False)
|
||||
for k, expr in tokens.items():
|
||||
if k in cond_tokens:
|
||||
# media 键条件渲染:零媒体时整键省略(对齐文档 t2v 形态)。
|
||||
# json.dumps 分隔符固定 ", ",按键在对象中的位置分三模式吃逗号:
|
||||
# 首/中键(后随 ", ")→ 条件段自带尾逗号
|
||||
# 末键(前缀 ", ") → 条件段吃掉前逗号
|
||||
# 独键 → 直接包
|
||||
keyname, mps = cond_tokens[k]
|
||||
anyexpr = _media_any_expr(mps)
|
||||
seg_body = '"%s": %s' % (keyname, expr)
|
||||
pat_first = '"%s": "%s", ' % (keyname, k)
|
||||
pat_last = ', "%s": "%s"' % (keyname, k)
|
||||
pat_only = '"%s": "%s"' % (keyname, k)
|
||||
if pat_first in s:
|
||||
s = s.replace(pat_first, ' {%% if %s %%}%s, {%% endif %%}' % (anyexpr, seg_body))
|
||||
elif pat_last in s:
|
||||
s = s.replace(pat_last, '{%% if %s %%}, %s{%% endif %%}' % (anyexpr, seg_body))
|
||||
elif pat_only in s:
|
||||
s = s.replace(pat_only, ' {%% if %s %%}%s{%% endif %%}' % (anyexpr, seg_body))
|
||||
continue
|
||||
s = s.replace('"%s"' % k, expr)
|
||||
return s, media_params, biz_params, used_example
|
||||
|
||||
@ -1277,11 +1318,8 @@ def _gen_templates(protocol: str, capability: str, spec: dict) -> dict:
|
||||
# 文件」——零媒体是合法 t2v 形态,且文档 t2v 示例**不带 media
|
||||
# 键**;无条件渲染会发出 "media": [] 空数组(API 未承诺接受,
|
||||
# 不能赌)。有媒体才渲染 media 键,零媒体整个省略。
|
||||
anyexpr = ' or '.join(
|
||||
'(params.%s if params.%s is not string and params.%s else '
|
||||
'([params.%s] if params.%s is string else []))'
|
||||
% ((mp,) * 5) for mp in mps)
|
||||
# 空格不可省:media_seg 以 {% 开头,紧跟 input 的 { 会拼成
|
||||
anyexpr = _media_any_expr(mps)
|
||||
# 前导空格不可省:段以 {% 开头,紧跟 input 的 { 会拼成
|
||||
# "{{%" —— Jinja 词法把 {{ 当变量表达式开始 → unexpected '%'
|
||||
# (2026-09-06 单测实抓)。JSON 空白无副作用。
|
||||
media_seg = (' {%% if %s %%}"media": %s, {%% endif %%}'
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user