diff --git a/pipeline_platform/platform_ability.py b/pipeline_platform/platform_ability.py index ab70936..c5844be 100644 --- a/pipeline_platform/platform_ability.py +++ b/pipeline_platform/platform_ability.py @@ -1244,8 +1244,21 @@ async def _audit_media_convention(sor, profile_ids): 'image_files', 'video_files', 'audio_files', 'first_frame', 'image_url', 'media')) if has_upload_ref and 'b64media2url' not in rt: - issues.append("「%s」request 模板含媒体上传参数但缺 b64media2url——" - "上传文件必须转本地公网 URL 再传上游" % name) + # 三数组直通透传(image_files 等直接渲染进 content)是内部执行器的 + # 合法路径:request=None 时 b64media2url 兜底缺 BASEURL 会拼出坏路径 + # (2026-09-16 实测),data URL/公网 URL 直传上游已验证可用。 + three_arr = any(k in rt for k in ('image_files', 'video_files', 'audio_files')) + if not three_arr: + issues.append("「%s」request 模板含媒体上传参数但缺 b64media2url——" + "上传文件必须转本地公网 URL 再传上游" % name) + # 媒体输入能力模板必须渲染输入媒体(2026-09-16 i2i 闭眼编造教训): + # i2i/i2v/r2v 等能力的 request_template 若不引用任何输入媒体变量, + # 调用方传的 image_files 会在模板层静默丢失 → 模型无输入图纯编造。 + if cap in _MEDIA_INPUT_CAPS and not has_upload_ref: + issues.append("「%s」能力 %s 需要输入媒体,但 request 模板未渲染任何输入" + "媒体变量(image_files/media 等)——输入图会在模板层丢失," + "模型将无图编造;请补 content 图像数组或对应媒体参数" + % (name, cap)) if issues: return "⚠️ 媒体转换约定检查未通过:" + ";".join(issues) return "" @@ -1728,6 +1741,29 @@ def _gen_templates(protocol: str, capability: str, spec: dict) -> dict: "建议对照供应商 API 参考页人工核对") except Exception as _e: notes.append("r2v 媒体合成失败(%s),示例未见上传字段,请人工核对" % str(_e)[:80]) + elif capability == 'i2i' and protocol in ('dashscope_sync', 'dashscope_async'): + # i2i 契约合成(2026-09-16 实测教训:qwen-image-3.0-pro 自动配置出的 + # 模板 content 只有 text 项,image_files 在模板层丢失 → 模型"闭眼 i2i" + # 纯编造画面,白皮书配图 QA 逐字核对实锤)。DashScope 图像编辑家族契约: + # input.messages[].content = [{"image": url}, ..., {"text": prompt}]。 + # 页面示例常只给纯文本最简形态 → 在 content 数组头部条件渲染 image 项 + # (零媒体时整个省略,对齐 t2i 合法形态),与 r2v 合成同款思路。 + import re as _re2 + m2 = _re2.search(r'("content"\s*:\s*\[)', req) + if m2 and 'image_files' not in req: + # 单 % :本串不经 % 格式化(r2v precedent 的 %% 是因为它走 + # '...%s...' % (...) 格式化);写 %% 会把字面 {%% 留进模板 + # 致 Jinja "tag name expected"(2026-09-16 单测实抓)。 + seg = ('{% for img in (params.image_files or []) %}' + '{"image": {{ img|tojson }}},{% endfor %}') + pos2 = m2.end() + req = req[:pos2] + seg + req[pos2:] + if 'image_files' not in media_params: + media_params.append('image_files') + notes.append("示例未见输入图(页面示例为纯文本最简形态),按 " + "DashScope 图像编辑家族契约合成 content 图像数组" + "(image_files 三数组,零媒体时省略)——" + "建议对照供应商 API 参考页人工核对") else: notes.append("能力 %s 通常需要输入媒体,但文档示例未见上传字段——" "模板未生成媒体参数,请核对文档" % capability)