2020 MODEL_NAME ,
2121 SUBMIT_BUTTON_SELECTOR ,
2222)
23+ from config import ONLY_COLLECT_CURRENT_USER_ATTACHMENTS , UPLOAD_FILES_DIR
2324
2425# --- models模块导入 ---
2526from models import ChatCompletionRequest , ClientDisconnectedError
@@ -125,6 +126,50 @@ async def _prepare_and_validate_request(
125126 prepared_prompt += f"\n ---\n 工具执行: { name } \n 参数:\n { args } \n 结果:\n { result_str } \n "
126127 except Exception :
127128 pass
129+ # 若配置仅收集当前用户消息附件,则在此过滤附件
130+ try :
131+ if ONLY_COLLECT_CURRENT_USER_ATTACHMENTS :
132+ latest_user = None
133+ for msg in reversed (request .messages or []):
134+ if getattr (msg , 'role' , None ) == 'user' :
135+ latest_user = msg
136+ break
137+ if latest_user is not None :
138+ filtered : List [str ] = []
139+ from api_utils .utils import extract_data_url_to_local
140+ from urllib .parse import urlparse , unquote
141+ import os
142+ # 收集该条 user 消息上的 data:/file:/绝对路径(存在的)
143+ content = getattr (latest_user , 'content' , None )
144+ # 统一从 messages 附件字段抽取
145+ for key in ('attachments' , 'images' , 'files' , 'media' ):
146+ arr = getattr (latest_user , key , None )
147+ if not isinstance (arr , list ):
148+ continue
149+ for it in arr :
150+ url_value = None
151+ if isinstance (it , str ):
152+ url_value = it
153+ elif isinstance (it , dict ):
154+ url_value = it .get ('url' ) or it .get ('path' )
155+ url_value = (url_value or '' ).strip ()
156+ if not url_value :
157+ continue
158+ if url_value .startswith ('data:' ):
159+ fp = extract_data_url_to_local (url_value )
160+ if fp :
161+ filtered .append (fp )
162+ elif url_value .startswith ('file:' ):
163+ parsed = urlparse (url_value )
164+ lp = unquote (parsed .path )
165+ if os .path .exists (lp ):
166+ filtered .append (lp )
167+ elif os .path .isabs (url_value ) and os .path .exists (url_value ):
168+ filtered .append (url_value )
169+ images_list = filtered
170+ except Exception :
171+ pass
172+
128173 return prepared_prompt , images_list
129174
130175async def _handle_response_processing (
@@ -347,11 +392,13 @@ async def _handle_playwright_response(req_id: str, request: ChatCompletionReques
347392 return None
348393
349394
350- async def _cleanup_request_resources (req_id : str , disconnect_check_task : Optional [asyncio .Task ],
351- completion_event : Optional [Event ], result_future : Future ,
352- is_streaming : bool ) -> None :
353- """清理请求资源"""
354- from server import logger
395+ async def _cleanup_request_resources (req_id : str , disconnect_check_task : Optional [asyncio .Task ],
396+ completion_event : Optional [Event ], result_future : Future ,
397+ is_streaming : bool ) -> None :
398+ """清理请求资源"""
399+ from server import logger
400+ from config import UPLOAD_FILES_DIR
401+ import os , shutil
355402
356403 if disconnect_check_task and not disconnect_check_task .done ():
357404 disconnect_check_task .cancel ()
@@ -362,7 +409,16 @@ async def _cleanup_request_resources(req_id: str, disconnect_check_task: Optiona
362409 except Exception as task_clean_err :
363410 logger .error (f"[{ req_id } ] 清理任务时出错: { task_clean_err } " )
364411
365- logger .info (f"[{ req_id } ] 处理完成。" )
412+ logger .info (f"[{ req_id } ] 处理完成。" )
413+
414+ # 清理本次请求的上传子目录,避免磁盘累积
415+ try :
416+ req_dir = os .path .join (UPLOAD_FILES_DIR , req_id )
417+ if os .path .isdir (req_dir ):
418+ shutil .rmtree (req_dir , ignore_errors = True )
419+ logger .info (f"[{ req_id } ] 已清理请求上传目录: { req_dir } " )
420+ except Exception as clean_err :
421+ logger .warning (f"[{ req_id } ] 清理上传目录失败: { clean_err } " )
366422
367423 if is_streaming and completion_event and not completion_event .is_set () and (result_future .done () and result_future .exception () is not None ):
368424 logger .warning (f"[{ req_id } ] 流式请求异常,确保完成事件已设置。" )
@@ -406,13 +462,28 @@ async def _process_request_refactored(
406462 await _handle_parameter_cache (req_id , context )
407463
408464 prepared_prompt ,image_list = await _prepare_and_validate_request (req_id , request , check_client_disconnected )
465+ # 额外合并顶层与消息级 attachments/files(兼容历史记录)已在下方处理;此处确保路径存在
466+ try :
467+ import os
468+ valid_images = []
469+ for p in image_list :
470+ if isinstance (p , str ) and p and os .path .isabs (p ) and os .path .exists (p ):
471+ valid_images .append (p )
472+ if len (valid_images ) != len (image_list ):
473+ from server import logger
474+ logger .warning (f"[{ req_id } ] 过滤掉不存在的附件路径: { set (image_list ) - set (valid_images )} " )
475+ image_list = valid_images
476+ except Exception :
477+ pass
409478 # 兼容: 顶层与消息级附件字段合并到上传列表(仅 data:/file:/绝对路径)
479+ # 附件来源策略:仅接受当前请求显式提供的 data:/file:/绝对路径(存在的)
410480 try :
481+ from api_utils .utils import extract_data_url_to_local
482+ from urllib .parse import urlparse , unquote
483+ import os
484+ # 顶层 attachments
411485 top_level_atts = getattr (request , 'attachments' , None )
412486 if isinstance (top_level_atts , list ) and len (top_level_atts ) > 0 :
413- from api_utils .utils import extract_data_url_to_local
414- from urllib .parse import urlparse , unquote
415- import os
416487 for it in top_level_atts :
417488 url_value = None
418489 if isinstance (it , str ):
@@ -423,7 +494,7 @@ async def _process_request_refactored(
423494 if not url_value :
424495 continue
425496 if url_value .startswith ('data:' ):
426- fp = extract_data_url_to_local (url_value )
497+ fp = extract_data_url_to_local (url_value , req_id = req_id )
427498 if fp :
428499 image_list .append (fp )
429500 elif url_value .startswith ('file:' ):
@@ -433,7 +504,7 @@ async def _process_request_refactored(
433504 image_list .append (lp )
434505 elif os .path .isabs (url_value ) and os .path .exists (url_value ):
435506 image_list .append (url_value )
436- # 消息级 attachments/images/files/media
507+ # 消息级 attachments/images/files/media(全量收集,但仅保留有效本地/data)
437508 for msg in (request .messages or []):
438509 for key in ('attachments' , 'images' , 'files' , 'media' ):
439510 arr = getattr (msg , key , None )
@@ -449,7 +520,7 @@ async def _process_request_refactored(
449520 if not url_value :
450521 continue
451522 if url_value .startswith ('data:' ):
452- fp = extract_data_url_to_local (url_value )
523+ fp = extract_data_url_to_local (url_value , req_id = req_id )
453524 if fp :
454525 image_list .append (fp )
455526 elif url_value .startswith ('file:' ):
0 commit comments