refactor: 将 kimi-k3 多模态内容构建改为纯 Jinja2 模板
- 删除 build_kimi_content() Python 函数 - 在 SQL data 模板中用纯 Jinja2 语法构建 content 数组 - 新增 file_to_b64() 和 file_mime() 辅助函数注册到 ServerEnv - 保持向后兼容,功能不变
This commit is contained in:
parent
ce17c48022
commit
e0855b6415
@ -502,34 +502,23 @@ async def llm_query_price(llmid, config_data):
|
|||||||
prices = await env.buffered_charging(llm.ppid, config_data)
|
prices = await env.buffered_charging(llm.ppid, config_data)
|
||||||
return prices
|
return prices
|
||||||
|
|
||||||
def build_kimi_content(prompt='', image_files=None, video_files=None):
|
import base64 as _base64
|
||||||
"""构造 kimi 多模态 content 数组 JSON,注册到 ServerEnv 供 uapi data 模板调用"""
|
import mimetypes as _mimetypes
|
||||||
import base64, json, mimetypes, os
|
import os as _os
|
||||||
fs = FileStorage()
|
|
||||||
parts = []
|
|
||||||
if prompt:
|
|
||||||
parts.append({"type": "text", "text": prompt})
|
|
||||||
for f in (image_files or []):
|
|
||||||
fp = fs.realPath(f)
|
|
||||||
if not os.path.isfile(fp):
|
|
||||||
continue
|
|
||||||
mime, _ = mimetypes.guess_type(fp)
|
|
||||||
if not mime:
|
|
||||||
mime = 'application/octet-stream'
|
|
||||||
with open(fp, 'rb') as fh:
|
|
||||||
b64 = base64.b64encode(fh.read()).decode('utf-8')
|
|
||||||
parts.append({"type": "image_url", "image_url": f'data:{mime};base64,{b64}'})
|
|
||||||
for f in (video_files or []):
|
|
||||||
fp = fs.realPath(f)
|
|
||||||
if not os.path.isfile(fp):
|
|
||||||
continue
|
|
||||||
mime, _ = mimetypes.guess_type(fp)
|
|
||||||
if not mime:
|
|
||||||
mime = 'application/octet-stream'
|
|
||||||
with open(fp, 'rb') as fh:
|
|
||||||
b64 = base64.b64encode(fh.read()).decode('utf-8')
|
|
||||||
parts.append({"type": "video_url", "video_url": f'data:{mime};base64,{b64}'})
|
|
||||||
return json.dumps(parts, ensure_ascii=False)
|
|
||||||
|
|
||||||
ServerEnv().build_kimi_content = build_kimi_content
|
def _file_to_b64(filepath):
|
||||||
|
"""读取文件并返回 base64 字符串"""
|
||||||
|
with open(filepath, 'rb') as fh:
|
||||||
|
return _base64.b64encode(fh.read()).decode('utf-8')
|
||||||
|
|
||||||
|
def _file_mime(filepath):
|
||||||
|
"""猜测文件 MIME 类型"""
|
||||||
|
mime, _ = _mimetypes.guess_type(filepath)
|
||||||
|
return mime or 'application/octet-stream'
|
||||||
|
|
||||||
|
ServerEnv().base64 = _base64
|
||||||
|
ServerEnv().mimetypes = _mimetypes
|
||||||
|
ServerEnv().os = _os
|
||||||
|
ServerEnv().file_to_b64 = _file_to_b64
|
||||||
|
ServerEnv().file_mime = _file_mime
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
-- Kimi K3 API 接入 (月之暗面 / Moonshot)
|
-- Kimi K3 API 接入 (月之暗面 / Moonshot)
|
||||||
-- Base URL: https://api.moonshot.cn/v1
|
-- Base URL: https://api.moonshot.cn/v1
|
||||||
-- 兼容 OpenAI 格式, 文档: https://platform.kimi.com/docs/api/chat
|
-- 兼容 OpenAI 格式, 文档: https://platform.kimi.com/docs/api/chat
|
||||||
-- 多模态: image_files/video_files 通过 build_kimi_content() 转 data URI 数组
|
-- 多模态: image_files/video_files 在 data 模板中用纯 Jinja2 构造 content 数组
|
||||||
-- ============================================================
|
-- ============================================================
|
||||||
|
|
||||||
-- ============================================================
|
-- ============================================================
|
||||||
@ -41,7 +41,31 @@ VALUES (
|
|||||||
{% if sys_prompt %}
|
{% if sys_prompt %}
|
||||||
{"role": "system", "content": {{json.dumps(sys_prompt, ensure_ascii=False)}}},
|
{"role": "system", "content": {{json.dumps(sys_prompt, ensure_ascii=False)}}},
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{"role": "user", "content": {{build_kimi_content(prompt, image_files, video_files)}}}
|
{% set _parts = [] %}
|
||||||
|
{% if prompt %}
|
||||||
|
{% set _ = _parts.append({"type": "text", "text": prompt}) %}
|
||||||
|
{% endif %}
|
||||||
|
{% if image_files %}
|
||||||
|
{% for _f in image_files %}
|
||||||
|
{% set _fp = FileStorage().realPath(_f) %}
|
||||||
|
{% if os.path.isfile(_fp) %}
|
||||||
|
{% set _mime = file_mime(_fp) %}
|
||||||
|
{% set _b64 = file_to_b64(_fp) %}
|
||||||
|
{% set _ = _parts.append({"type": "image_url", "image_url": "data:" + _mime + ";base64," + _b64}) %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% if video_files %}
|
||||||
|
{% for _f in video_files %}
|
||||||
|
{% set _fp = FileStorage().realPath(_f) %}
|
||||||
|
{% if os.path.isfile(_fp) %}
|
||||||
|
{% set _mime = file_mime(_fp) %}
|
||||||
|
{% set _b64 = file_to_b64(_fp) %}
|
||||||
|
{% set _ = _parts.append({"type": "video_url", "video_url": "data:" + _mime + ";base64," + _b64}) %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{"role": "user", "content": {{json.dumps(_parts, ensure_ascii=False)}}}
|
||||||
],
|
],
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if stream %}
|
{% if stream %}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user