Chat File Attachments#
RAGFlow supports attaching files (documents, images, URLs) to chat messages. Attached files are stored as blobs in object storage, referenced by metadata in the conversation's message JSON array, processed during inference, and cleaned up when sessions are deleted.
Upload#
File uploads for chat use the POST /api/v1/documents/upload endpoint (upload_info function in document_api.py). It accepts either:
- A multipart
filefield (one or multiple files), or - A
?url=query parameter (fetches and crawls the URL usingcrawl4ai)
Both paths delegate to FileService.upload_info(), which:
- Validates the file (PDF corruption repair, SSRF guard for URLs)
- Assigns a UUID as the
locationkey - Writes the blob to object storage via
FileService.put_blob()into the bucket{user_id}-downloads - Returns a file metadata dict
{
"id": "<uuid>",
"name": "report.pdf",
"size": 12345,
"extension": "pdf",
"mime_type": "application/pdf",
"created_by": "<user_id>",
"created_at": 1721000000.0,
"preview_url": null
}
The caller embeds this object into the files array of the next chat message.
Storage Layout#
All chat-uploaded blobs live in the STORAGE_IMPL backend under the bucket {user_id}-downloads, keyed by the UUID location from the upload response . This is distinct from knowledge-base document storage. The abstraction layer (settings.STORAGE_IMPL) supports MinIO, S3, Azure Blob, OSS, GCS, Infinity, and OpenDAL backends transparently.
Message JSON Structure#
File references are stored inside the message JSON array on the Conversation row. Each user message object may include a files array:
{
"role": "user",
"content": "Summarize this document",
"id": "<msg_uuid>",
"created_at": 1721000000.0,
"files": [
{
"id": "<blob_uuid>",
"name": "report.pdf",
"mime_type": "application/pdf",
"created_by": "<user_id>"
}
]
}
When submitting via the completion API, files can be passed as top-level files in the request body (they are automatically attached to the last user message) or inline within messages[].files . The legacy async_completion path also propagates files from kwargs into the question object .
Processing During Inference#
At inference time, split_file_attachments() in dialog_service.py dispatches attached files:
- Text files / PDFs / HTML: parsed via
FileService.get_files(files, raw=False)β content appended to the system prompt as context - Images (non-vision models): converted to base64 data URIs and injected into the last user message via
convert_last_user_msg_to_multimodal(), with factory-specific formatting for Gemini, Anthropic, and OpenAI-compatible providers - Images (vision models): fetched as raw binary blobs via
FileService.get_files(files, raw=True)and passed as theimages=parameter directly to the model
FileService.get_files() uses a ThreadPoolExecutor (max 5 workers) to fetch and parse attachments in parallel .
Cleanup on Session Deletion#
When sessions are deleted via DELETE /api/v1/chats/{chat_id}/sessions, the handler iterates over every message in the conversation and calls settings.STORAGE_IMPL.rm("{user_id}-downloads", file_id) for each file reference found in msg["files"] . Blob deletion failures are logged as warnings but do not block the session row deletion.
Key Files#
| File | Role |
|---|---|
api/apps/restful_apis/document_api.py | POST /documents/upload β chat file upload endpoint |
api/db/services/file_service.py | upload_info(), put_blob(), get_blob(), get_files() |
api/apps/restful_apis/chat_api.py | delete_sessions() β blob cleanup on session deletion |
api/db/services/dialog_service.py | split_file_attachments(), convert_last_user_msg_to_multimodal() |
api/db/services/conversation_service.py | async_completion() β propagates files into message objects |