diff --git a/wwwroot/api/cockpit_chat_v2.dspy b/wwwroot/api/cockpit_chat_v2.dspy index 07b2f7c..a5cf997 100644 --- a/wwwroot/api/cockpit_chat_v2.dspy +++ b/wwwroot/api/cockpit_chat_v2.dspy @@ -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']*>(.*?)', 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):