fix(upload): 驾驶舱上传文件落项目根目录+前端hook补文件发送(FormData)

This commit is contained in:
ymq 2026-08-31 17:54:28 +08:00
parent 0c66bdee81
commit e1dbc51792
2 changed files with 19 additions and 4 deletions

View File

@ -58,14 +58,18 @@ if action == 'send_message':
prompt = (params_kw or {}).get('prompt', '') or msg
prompt = prompt.strip()
# 处理用户上传的文件multipart file 字段 → web_path提取文本作为中性上下文注入 prompt
# 处理用户上传的文件multipart file 字段 → web_path
# 1. 抽取文本作为中性上下文注入 prompt
# 2. 收集 (绝对路径, 文件名),稍后复制进项目根目录,让会话 agent 的 read_file 能找到
file_ctx = ''
_uploads = [] # [(src_abs, filename)]
_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)
_uploads.append((_abs, _name))
_txt = _extract_text(_abs, _name)
if _txt:
file_ctx += f"【文件 {_name} 内容】\n{_txt}\n\n"
@ -73,8 +77,6 @@ if action == 'send_message':
file_ctx += f"【文件 {_name}】二进制文件,无法直接读取文本。\n\n"
except Exception:
pass
if file_ctx:
prompt = "用户本次上传了以下文件:\n\n" + file_ctx + "\n用户指令" + prompt
# 停止/暂停指令不再用硬编码关键字短路——交给 LLM 意图识别agent system prompt 已明确:
# 用户指令「暂停/停止推进」时调 pause_project。硬编码子串匹配会把「为什么任务取消了」这类
@ -86,6 +88,8 @@ if action == 'send_message':
# ── 加载上下文 ──
session_id = (params_kw or {}).get('session_id', '')
ctx = {'pid': '', 'name': '', 'pipeline_id': ''}
_saved_files = []
_pdir = ''
async with DBPools().sqlorContext(dbname) as sor:
ctx['pid'], _ = await get_session_context(sor, uid, session_id)
if ctx['pid']:
@ -94,6 +98,17 @@ if action == 'send_message':
if proj_recs:
ctx['name'] = getattr(proj_recs[0], 'name', '')
ctx['pipeline_id'] = getattr(proj_recs[0], 'pipeline_id', '') or ''
# ── 上传文件落盘到项目根目录(会话 agent 的 read_file 以项目目录为根)──
if _uploads:
_pdir, _ = await get_project_dir_by_id(sor, ctx['pid'])
_saved_files = copy_uploads_to_project(_pdir, _uploads)
if file_ctx or _saved_files:
_loc = ''
if _saved_files:
_loc = "文件已保存到项目根目录(" + _pdir + "),可用 read_file 直接读取:\n"
_loc += "\n".join(" - " + n for n, _ in _saved_files) + "\n\n"
prompt = "用户本次上传了以下文件:\n" + _loc + file_ctx + "\n用户指令" + prompt
# ── 走 gateway 统一入口Web AgentIO 通道)──
# model_id前端模型下拉选中的模型 → gateway 校验后持久化到项目(项目模型一经设置

View File

@ -192,7 +192,7 @@
"event": "inputed",
"actiontype": "script",
"target": "self",
"script": "var ai=bricks.getWidgetById('chat_input',bricks.app);if(ai&&ai.inputw&&!ai._hooked){ai._hooked=true;ai.inputw.unbind('inputed');ai.inputw.bind('inputed',function(e){console.log('HOOKED inputed');var p=e.params.prompt||'';var mid=e.params.model_id||'';var chat=bricks.getWidgetById('chat_scroll',bricks.app);var at=null;if(chat){var ab=new bricks.HBox({width:'100%'});var am=new bricks.VBox({width:'85%',alignSelf:'flex-start',bgcolor:'#e8f0fe',borderRadius:'12px',padding:'12px 16px',marginBottom:'10px',gap:'4px'});am.add_widget(new bricks.Text({text:'Agent',cfontsize:0.75,color:'#3b82f6',fontWeight:'bold'}));at=new bricks.Text({text:'...',cfontsize:0.85,color:'#64748b'});am.add_widget(at);ab.add_widget(new bricks.Svg({rate:2,url:bricks_resource('imgs/llm.svg')}));ab.add_widget(am);ab.add_widget(new bricks.VBox({css:'filler'}));chat.add_widget(ab)}var xhr=new XMLHttpRequest();xhr.open('POST','/pipeline-sdlc/api/cockpit_chat_v2.dspy');xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');var lastLen=0;xhr.onprogress=function(){var t=xhr.responseText;var d=t.substring(lastLen);lastLen=t.length;var lines=d.split(String.fromCharCode(10));for(var j=0;j<lines.length;j++){var line=lines[j].trim();if(!line)continue;try{var obj=JSON.parse(line);if(obj.content&&at){var pw=at.parent();if(pw){pw.remove_widget(at);at=null}var tw=new bricks.Text({text:obj.content,cfontsize:0.85,color:'#334155',whiteSpace:'pre-wrap',width:'100%'});pw.add_widget(tw);chat.scrollToBottom()}}catch(e){console.log(e)}}};xhr.onload=function(){var s=bricks.getWidgetById('stats_row',bricks.app);if(s)s.render({})};xhr.onerror=function(){if(at)at.set_text('网络错误')};xhr.send('message_text='+encodeURIComponent(p)+'&model_id='+encodeURIComponent(mid))})}"
"script": "var ai=bricks.getWidgetById('chat_input',bricks.app);if(ai&&ai.inputw&&!ai._hooked){ai._hooked=true;ai.inputw.unbind('inputed');ai.inputw.bind('inputed',function(e){console.log('HOOKED inputed');var p=e.params.prompt||'';var mid=e.params.model_id||'';var chat=bricks.getWidgetById('chat_scroll',bricks.app);var at=null;if(chat){var ab=new bricks.HBox({width:'100%'});var am=new bricks.VBox({width:'85%',alignSelf:'flex-start',bgcolor:'#e8f0fe',borderRadius:'12px',padding:'12px 16px',marginBottom:'10px',gap:'4px'});am.add_widget(new bricks.Text({text:'Agent',cfontsize:0.75,color:'#3b82f6',fontWeight:'bold'}));at=new bricks.Text({text:'...',cfontsize:0.85,color:'#64748b'});am.add_widget(at);ab.add_widget(new bricks.Svg({rate:2,url:bricks_resource('imgs/llm.svg')}));ab.add_widget(am);ab.add_widget(new bricks.VBox({css:'filler'}));chat.add_widget(ab)}var xhr=new XMLHttpRequest();xhr.open('POST','/pipeline-sdlc/api/cockpit_chat_v2.dspy');var lastLen=0;xhr.onprogress=function(){var t=xhr.responseText;var d=t.substring(lastLen);lastLen=t.length;var lines=d.split(String.fromCharCode(10));for(var j=0;j<lines.length;j++){var line=lines[j].trim();if(!line)continue;try{var obj=JSON.parse(line);if(obj.content&&at){var pw=at.parent();if(pw){pw.remove_widget(at);at=null}var tw=new bricks.Text({text:obj.content,cfontsize:0.85,color:'#334155',whiteSpace:'pre-wrap',width:'100%'});pw.add_widget(tw);chat.scrollToBottom()}}catch(e){console.log(e)}}};xhr.onload=function(){var s=bricks.getWidgetById('stats_row',bricks.app);if(s)s.render({})};xhr.onerror=function(){if(at)at.set_text('网络错误')};var fd=new FormData();fd.append('message_text',p);fd.append('model_id',mid);(e.params.add_files||[]).forEach(function(f){fd.append('file',f)});xhr.send(fd)})}"
}
]
}