fix(platform): DashScope同步生成模板生成器(2026-09-08 qwen-image-plus真图验证后根治)

数据手工修通后回填生成器,让后续DashScope同步模型自动配对不用手改:
- _dashscope_envelope:SDK kwargs形态({model,messages,size...})→原生HTTP信封
  ({model,input:{messages},parameters:{...}}),平铺体提交必400 InvalidParameter
  (实测"messages parameter invalid");代码级确定性归一不靠提取LLM自觉
- _gen_templates对dashscope_sync/async协议先过信封归一
- _resp_tpl_for协议感知:dashscope_sync产物路径output.choices[0].message.content[0]
  .{image|video|audio}(实测形态),文档response示例给output.*路径则优先;同步命名
  空间无task_id/status只引用output/usage/request(StrictUndefined防崩)
- 信封归一纯函数单测4例PASS
This commit is contained in:
yumoqing 2026-09-08 13:44:14 +08:00
parent 1bc7413c1f
commit a9cac99c52

View File

@ -1338,6 +1338,33 @@ def _media_array_expr(elements):
return ''.join(segs), params
def _dashscope_envelope(example):
"""DashScope SDK kwargs 形态 → 原生 HTTP 信封归一2026-09-08 实测根因)。
文档常只给 Python SDK 示例MultiModalConversation.call(messages=...,
size=...)提取 LLM 照抄成平铺 {model, messages, size, watermark...}
但原生 HTTP 端点要求 {"model", "input": {"messages": [...]},
"parameters": {...}}平铺体提交必 400 InvalidParameter
qwen-image-plus 实测messages parameter invalid
代码级确定性归一不靠提取 LLM 自觉顶层有 messages 且无 input 信封
messages input model/input/parameters 外的业务键全进 parameters
"""
if not isinstance(example, dict) or not example:
return example
if 'input' in example or 'parameters' in example:
return example # 已是信封形态curl 示例),不动
msgs = example.get('messages')
if not isinstance(msgs, list):
return example # 非 SDK kwargs 形态,不动
out = {'model': example.get('model', '')}
out['input'] = {'messages': msgs}
params = {k: v for k, v in example.items()
if k not in ('model', 'messages')}
if params:
out['parameters'] = params
return out
def _tpl_from_example(example, capability):
"""文档请求示例 → Jinja2 请求体模板(结构逐字保留,值换成运行时变量)。
@ -1493,6 +1520,25 @@ def _resp_tpl_for(capability, spec):
if not field and hits:
field = hits[0]
note = ''
proto = str(spec.get('protocol') or '').strip()
if proto == 'dashscope_sync':
# DashScope 同步生成实测响应形态2026-09-08 qwen-image-plus 真图验证):
# output.choices[0].message.content[0].{image|video|audio}
# 同步路径渲染命名空间无 task_id/statusStrictUndefined 会崩),
# 模板只引用 output/usage/request 三个必有变量。
# 优先级:文档响应示例给出的 output.* 产物路径 > 实测兜底形态。
if field and field.startswith('output.'):
path_expr = field
note = '' # 文档确证,无需兜底声明
else:
seg_key = {'image': 'image', 'video': 'video', 'audio': 'audio'}.get(outkey, outkey)
path_expr = 'output.choices[0].message.content[0].%s' % seg_key
if not field:
note = ('产物路径按 DashScope 同步生成实测形态生成(%s'
'文档未提供响应示例,如上游形态不同需修正' % path_expr)
resp = ('{"%s": "{{ downloadfile2url(request, %s) }}", '
'"usage": {{ json.dumps(usage) }}}' % (outkey, path_expr))
return resp, note
if not field:
field = _MEDIA_OUT_FIELD.get(outkey, 'result_url')
note = ('产物字段名「%s」按供应商惯例兜底(文档未提供响应示例或示例中无 URL 字段),'
@ -1563,6 +1609,10 @@ def _gen_templates(protocol: str, capability: str, spec: dict) -> dict:
example = _example_to_nested(spec.get("request_fields"))
notes.append("文档未提供完整请求示例,模板按 request_fields 字段路径生成,"
"业务参数无默认值(调用时必须显式传入),建议人工核对")
# DashScope SDK kwargs → 原生 HTTP 信封归一2026-09-08 qwen-image-plus 实测:
# 平铺体提交 400 InvalidParameter必须 input.messages + parameters 信封)
if protocol in ('dashscope_sync', 'dashscope_async'):
example = _dashscope_envelope(example)
req, media_params, biz_params, _used = _tpl_from_example(example, capability)
if capability in _MEDIA_CAPS:
resp, rnote = _resp_tpl_for(capability, spec)