Spaces:
Running
Running
| """Patch: allow multiple file uploads in one request. | |
| Backend changes: | |
| 1. Replace the single-file helper with a multi-file helper. | |
| 2. Rewrite the upload route to accept up to 20 files and return a list of | |
| DatasetUploadResponse, uploading each file to the session's Hub dataset | |
| repo and injecting a context note for each. | |
| """ | |
| import ast | |
| import re | |
| import os | |
| AGENT_FILE = "/app/backend/routes/agent.py" | |
| with open(AGENT_FILE) as f: | |
| c = f.read() | |
| # ---- 1. Replace single-file helper with multi-file helper ---- | |
| old_helper = '''def _dataset_upload_file_from_form(form: FormData) -> UploadFile: | |
| uploaded_files = [ | |
| (key, value) | |
| for key, value in form.multi_items() | |
| if isinstance(value, UploadFile) | |
| ] | |
| if len(uploaded_files) != 1: | |
| raise HTTPException( | |
| status_code=400, | |
| detail="Upload exactly one dataset file.", | |
| ) | |
| field_name, upload = uploaded_files[0] | |
| if field_name != "file": | |
| raise HTTPException( | |
| status_code=400, | |
| detail="Missing 'file' upload field.", | |
| ) | |
| return upload | |
| ''' | |
| new_helper = '''def _dataset_upload_files_from_form(form: FormData) -> list[UploadFile]: | |
| """Return all uploaded files from the multipart form (field 'file' or 'files').""" | |
| uploaded_files = [ | |
| value | |
| for key, value in form.multi_items() | |
| if isinstance(value, UploadFile) | |
| ] | |
| if not uploaded_files: | |
| raise HTTPException( | |
| status_code=400, | |
| detail="No file uploads found in the request.", | |
| ) | |
| return uploaded_files | |
| ''' | |
| if old_helper in c: | |
| c = c.replace(old_helper, new_helper) | |
| print("OK: replaced helper with multi-file helper") | |
| else: | |
| print("WARN: single-file helper not found (check indentation)") | |
| # ---- 2. Rewrite the upload route to handle multiple files ---- | |
| # Replace the entire function based on its decorator + route path. | |
| start_marker = '@router.post("/session/{session_id}/datasets"' | |
| end_marker = '@router.patch("/session/{session_id}/yolo")' | |
| start = c.find(start_marker) | |
| end = c.find(end_marker) | |
| if start == -1 or end == -1: | |
| print(f"FAIL: route markers not found (start={start}, end={end})") | |
| raise SystemExit(1) | |
| new_route = '''@router.post("/session/{session_id}/datasets", response_model=list[DatasetUploadResponse]) | |
| async def upload_session_dataset( | |
| session_id: str, | |
| request: Request, | |
| user: dict = Depends(get_current_user), | |
| ) -> list[DatasetUploadResponse]: | |
| """Upload one or more document/dataset files to a private Hub dataset for this session.""" | |
| files: list[UploadFile] = [] | |
| try: | |
| _reject_oversize_dataset_upload(request) | |
| agent_session = await _check_session_access(session_id, user, request) | |
| if not agent_session or not agent_session.is_active: | |
| raise HTTPException(status_code=404, detail="Session not found") | |
| if agent_session.is_processing: | |
| raise HTTPException( | |
| status_code=409, | |
| detail="Cannot upload files while the agent is processing.", | |
| ) | |
| if agent_session.session.pending_approval: | |
| raise HTTPException( | |
| status_code=409, | |
| detail="Resolve pending approvals before uploading files.", | |
| ) | |
| hf_token = ( | |
| resolve_hf_request_token(request, include_env_fallback=False) | |
| or _user_hf_token(user) | |
| or resolve_hf_request_token(request) | |
| ) | |
| if not hf_token: | |
| raise HTTPException( | |
| status_code=401, | |
| detail="A Hugging Face token is required to upload files.", | |
| ) | |
| form = await request.form( | |
| max_files=20, | |
| max_fields=20, | |
| max_part_size=MAX_DATASET_UPLOAD_BYTES, | |
| ) | |
| files = _dataset_upload_files_from_form(form) | |
| if not files: | |
| raise HTTPException(status_code=400, detail="No files to upload.") | |
| hf_username = user.get("username") or agent_session.hf_username | |
| results: list[DatasetUploadResponse] = [] | |
| for file in files: | |
| uploaded = await push_dataset_upload_to_hub( | |
| upload=file, | |
| session_id=session_id, | |
| hf_username=hf_username, | |
| hf_token=hf_token, | |
| ) | |
| agent_session.session.context_manager.add_message( | |
| Message(role="user", content=format_uploaded_document_context( | |
| filename=uploaded.original_filename, | |
| stored_filename=uploaded.filename, | |
| repo_id=uploaded.repo_id, | |
| path_in_repo=uploaded.path_in_repo, | |
| hub_url=uploaded.hub_url, | |
| size_bytes=uploaded.size_bytes, | |
| file_format=uploaded.format, | |
| extracted_text=uploaded.extracted_text, | |
| warning=uploaded.extraction_warning, | |
| )) | |
| ) | |
| results.append(DatasetUploadResponse(**uploaded.response_payload())) | |
| logger.info( | |
| "Uploaded file %s to %s for session %s", | |
| uploaded.filename, | |
| uploaded.repo_id, | |
| session_id, | |
| ) | |
| session_manager._touch(agent_session) | |
| await session_manager.persist_session_snapshot(agent_session) | |
| return results | |
| except HTTPException: | |
| raise | |
| except HfHubHTTPError as e: | |
| logger.warning( | |
| "Hub rejected file upload for session %s: status=%s request_id=%s", | |
| session_id, | |
| getattr(e.response, "status_code", None), | |
| getattr(e, "request_id", None), | |
| ) | |
| raise _dataset_upload_hub_http_exception(e) | |
| except Exception: | |
| logger.exception("File upload failed for session %s", session_id) | |
| raise HTTPException( | |
| status_code=502, | |
| detail="File upload failed. Please try again.", | |
| ) | |
| finally: | |
| for f in files: | |
| await f.close() | |
| ''' | |
| c = c[:start] + new_route + c[end:] | |
| with open(AGENT_FILE, "w") as f: | |
| f.write(c) | |
| try: | |
| ast.parse(c) | |
| print("OK: agent.py written & syntax valid") | |
| except SyntaxError as e: | |
| print(f"FAIL: agent.py syntax error: {e}") | |
| raise | |
| print("DONE: multi-file upload backend patch complete") | |