feat(platform): 媒体转换铁律落地——apply落库强制审计生成类模板(上行b64media2url/下行downloadfile2url,每个llm配置都检查);非标骨架模板自带转换约定占位
This commit is contained in:
parent
812f3fc6de
commit
c74bf38506
@ -448,13 +448,63 @@ async def _h_apply_llm_config(sor, params, ctx):
|
||||
if protocol not in RUNTIME_PROTOCOLS:
|
||||
rt_note = ("⚠️ 协议「%s」的适配模板已存档,但当前运行时调用链仅支持 %s——"
|
||||
"该供应商模型暂不可被产线直接调用" % (protocol, "/".join(RUNTIME_PROTOCOLS)))
|
||||
audit_note = await _audit_media_convention(sor, list(profile_ids.values()))
|
||||
return json.dumps({
|
||||
"vendor": vendor_action, "profiles": profile_ids,
|
||||
"models_created": created, "models_updated": updated, "models_skipped": skipped,
|
||||
"runtime_note": rt_note,
|
||||
"media_audit": audit_note,
|
||||
}, ensure_ascii=False)
|
||||
|
||||
|
||||
# 生成类能力:出参是文件(图/视频/音频/3D),response 必须 downloadfile2url 落地
|
||||
_MEDIA_CAPS = ('t2i', 'i2v', 't2v', 't2a', 'tts', 'i2i', 'v2v', '3d')
|
||||
|
||||
|
||||
async def _audit_media_convention(sor, profile_ids):
|
||||
"""强制检查(2026-09-05 用户规则:每个 llm 配置都要检查媒体转换约定):
|
||||
|
||||
生成类能力的适配模板——
|
||||
request_template 含上传媒体参数时,必须用 {{b64media2url(request, xxx_file)}}
|
||||
转本地公网 URL 再传上游;
|
||||
response_template 必须用 {{downloadfile2url(request, <产物url>)}}
|
||||
把生成物落地为本地持久 URL(上游 URL 有效期短,视频仅 24 小时)。
|
||||
返回检查结论(无问题为空串),随 apply 结果返回给内部 agent 转告。
|
||||
"""
|
||||
if not profile_ids:
|
||||
return ""
|
||||
issues = []
|
||||
for pid in profile_ids:
|
||||
recs = await sor.sqlExe(
|
||||
"SELECT name, capability, request_template, response_template "
|
||||
"FROM llm_api_profile WHERE id=${i}$", {"i": pid})
|
||||
await sor.sqlExe("COMMIT", {})
|
||||
if not recs:
|
||||
continue
|
||||
r = recs[0]
|
||||
cap = getattr(r, 'capability', '') or ''
|
||||
name = getattr(r, 'name', '') or pid
|
||||
if cap not in _MEDIA_CAPS:
|
||||
continue # 非生成类(t2t/embedding/rerank)无生成物
|
||||
rt = getattr(r, 'request_template', '') or ''
|
||||
st = getattr(r, 'response_template', '') or ''
|
||||
if '__note__' in st and 'downloadfile2url' not in st:
|
||||
issues.append("「%s」response 模板是骨架——生成物必须用 "
|
||||
"downloadfile2url(request, <产物url>) 落地后再返回" % name)
|
||||
elif st and 'downloadfile2url' not in st:
|
||||
issues.append("「%s」response 模板缺 downloadfile2url——生成类能力"
|
||||
"(%s)的产物 URL 必须落地为本地持久 URL" % (name, cap))
|
||||
# 上传参数线索:模板里出现 image/video/audio 文件参数但没有 b64media2url
|
||||
has_upload_ref = any(k in rt for k in ('image_file', 'video_file', 'audio_file',
|
||||
'first_frame', 'image_url', 'media'))
|
||||
if has_upload_ref and 'b64media2url' not in rt:
|
||||
issues.append("「%s」request 模板含媒体上传参数但缺 b64media2url——"
|
||||
"上传文件必须转本地公网 URL 再传上游" % name)
|
||||
if issues:
|
||||
return "⚠️ 媒体转换约定检查未通过:" + ";".join(issues)
|
||||
return ""
|
||||
|
||||
|
||||
def _default_templates(protocol: str, capability: str, spec: dict) -> dict:
|
||||
"""生成适配模板默认值(path/headers 独立列 + data/response 模板)。
|
||||
|
||||
@ -475,15 +525,30 @@ def _default_templates(protocol: str, capability: str, spec: dict) -> dict:
|
||||
"completion_tokens": "usage.completion_tokens"},
|
||||
}, ensure_ascii=False)
|
||||
return {"path": chat_path, "headers": headers, "req": req, "resp": resp}
|
||||
# 非标准协议:骨架模板(字段路径来自文档提取),标注需人工核对
|
||||
# 非标准协议:骨架模板(字段路径来自文档提取),标注需人工核对。
|
||||
# 生成类能力(_MEDIA_CAPS)骨架直接带媒体转换约定占位——按用户铁律:
|
||||
# 上行 b64media2url(上传转公网URL)、下行 downloadfile2url(生成物落地)。
|
||||
req = json.dumps({
|
||||
"data": {"__from_doc__": spec.get("request_fields") or []},
|
||||
"__note__": "非 openai_compat 协议骨架模板,需按文档人工核对",
|
||||
}, ensure_ascii=False)
|
||||
resp = json.dumps({
|
||||
"content": spec.get("response_format", "") or "待按文档填写",
|
||||
"__note__": "需人工核对",
|
||||
}, ensure_ascii=False)
|
||||
resp_body = {"content": spec.get("response_format", "") or "待按文档填写",
|
||||
"__note__": "需人工核对"}
|
||||
if capability in _MEDIA_CAPS:
|
||||
# 生成类:骨架给出落地写法提示,人工只需把 <产物url字段> 换成真实路径
|
||||
resp_body = {
|
||||
"status": "SUCCEEDED",
|
||||
"video": "{{ downloadfile2url(request, output.video_url) }}",
|
||||
"__note__": "生成类能力:产物 URL 必须用 downloadfile2url 落地为本地"
|
||||
"持久 URL(上游仅 24 小时有效);上传媒体在 request 模板用 "
|
||||
"b64media2url(request, xxx_file);产物字段名按文档核对",
|
||||
}
|
||||
req = json.dumps({
|
||||
"data": {"__from_doc__": spec.get("request_fields") or [],
|
||||
"__upload__": "{{ b64media2url(request, params.xxx_file) }}"},
|
||||
"__note__": "上传媒体一律 xxx_file 命名 + b64media2url 转公网 URL",
|
||||
}, ensure_ascii=False)
|
||||
resp = json.dumps(resp_body, ensure_ascii=False)
|
||||
return {"path": chat_path, "headers": headers, "req": req, "resp": resp}
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user