feat: v2链路文件上传(cockpit_chat_v2.dspy接收file提取文本注入prompt)

This commit is contained in:
ymq 2026-08-15 19:15:34 +08:00
parent 849a761b76
commit 74142a8a05

View File

@ -2,6 +2,27 @@
# 替代 cockpit_chat.dspy使用 pipeline-core/pipeline-service v2 架构
import aiohttp
import os
import re
import zipfile
from ahserver.filestorage import FileStorage
def _extract_text(path, name):
"""提取文件文本内容docx/txt/md等返回文本或空字符串。二进制/无法解析返回空。"""
ext = os.path.splitext(name)[1].lower()
try:
if ext in ('.txt', '.md', '.json', '.csv', '.py', '.log', '.yaml', '.yml', '.xml', '.html', '.ini'):
with open(path, 'r', encoding='utf-8', errors='ignore') as f:
return f.read()[:15000]
if ext == '.docx':
with zipfile.ZipFile(path) as z:
xml = z.read('word/document.xml').decode('utf-8', errors='ignore')
texts = re.findall(r'<w:t[^>]*>(.*?)</w:t>', xml)
return '\n'.join(texts)[:15000]
except Exception:
pass
return ''
action = (params_kw or {}).get('action', 'send_message')
msg = ''
@ -37,6 +58,24 @@ if action == 'send_message':
prompt = (params_kw or {}).get('prompt', '') or msg
prompt = prompt.strip()
# 处理用户上传的文件multipart file 字段 → web_path提取文本作为中性上下文注入 prompt
file_ctx = ''
_fval = (params_kw or {}).get('file')
_fpaths = _fval if isinstance(_fval, list) else ([_fval] if _fval else [])
for _fp in _fpaths:
try:
_abs = FileStorage().realPath(_fp)
_name = os.path.basename(_abs)
_txt = _extract_text(_abs, _name)
if _txt:
file_ctx += f"【文件 {_name} 内容】\n{_txt}\n\n"
else:
file_ctx += f"【文件 {_name}】二进制文件,无法直接读取文本。\n\n"
except Exception:
pass
if file_ctx:
prompt = "用户本次上传了以下文件:\n\n" + file_ctx + "\n用户指令" + prompt
# ── 意图识别:停止类指令 ──
stop_keywords = ['停止', '取消', '停下', '终止', '停', 'stop', 'cancel', 'abort']
if any(kw == prompt.strip().lower() or kw in prompt.strip().lower() for kw in stop_keywords):