GoShipped

πŸ“š RAG & Files

File uploads, embeddings, and retrieval are already in the chat path. Files stay on only if you keep an OpenAI key.

Upload a document, retrieve the useful bits, send them to the model. GoShipped already has that pipeline.

RAG here means: store what they uploaded, retrieve the bits that match the question, and put those bits in the model prompt. It is not a generic vector-database tutorial.

You are here to decide whether files are part of the product β€” and to keep an OpenAI key while they are.

User uploads a PDF
        ↓
GoShipped stores and processes it
        ↓
Content is chunked and embedded
        ↓
Relevant context is retrieved
        ↓
AI answers using the document

One end-to-end path

  1. User attaches spec.pdf in chat (apps/web β†’ POST /api/v1/files/upload)
  2. Bytes go to Supabase Storage bucket chat-files at users/{user}/conversations/{id}/{file_id}/spec.pdf
  3. A row is written to uploaded_files
  4. PDF text is extracted, split (with page numbers), embedded with OpenAI (text-embedding-3-small), stored in uploaded_file_chunks
  5. The next question runs match_uploaded_file_chunks (pgvector)
  6. Excerpts land in the chat system prompt (build_file_context) β€” the model is told to cite filename and page when useful

Small text/code files skip the vector path and inject directly. Every PDF uses extraction + chunks.

Small files vs large files

FileWhat happens
Text/code under FILE_SMALL_THRESHOLD_CHARS (20,000)Full text injected (budgeted). No chunks.
Text/code at or above thatChunk (~1800 chars, 200 overlap) + embed + retrieve top 8
Any PDFExtract β†’ page-aware chunks β†’ embed β†’ retrieve
Embed/extract failsprocessing_status=failed. Large text can fall back to a truncated inject.

OpenAI while files are on

Chat can be Anthropic. RAG cannot.

apps/api/app/services/embedding_service.py always calls the OpenAI provider.

If features.files is true, doctor requires OPENAI_API_KEY. Turn the flag off if you only have Anthropic. Same rule for Memory.

What you turn on

SwitchEffect
features.filesProduct-wide uploads + file context. false β†’ 404 on the files API, no attach button.
Plan files_enabled / file_uploads_per_month / max_file_size_mbWho may upload, how often, how large (plans/config.py)
SUPABASE_SERVICE_ROLE_KEYServer upload to Storage
Bucket chat-filesCreate in the Supabase Storage dashboard β€” not created by SQL migrations

Schema: supabase/migrations/003_uploaded_files.sql, 004_uploaded_file_chunks.sql, 005_uploaded_files_pdf.sql. Commands: Database & Storage.

Limits (shipped defaults)

LimitDefault
Extensions.txt .md .py .js .ts .tsx .jsx .json .html .css .sql .yaml .yml .pdf
Text/code size2 MB (FILE_UPLOAD_MAX_BYTES)
PDF size10 MB (FILE_UPLOAD_PDF_MAX_BYTES)
Context per turn50k chars total; 20k direct / 25k retrieved

Plan max file size is separate (Free 10 MB, Pro 50 MB in the shipped catalog) β€” the env caps still apply to the upload parser.

Tune retrieval with FILE_CHUNK_MATCH_COUNT, FILE_CHUNK_SIZE, and the context budgets in apps/api/.env.

Code map

PiecePath
Upload routeapps/api/app/api/v1/files.py
Store + retrieveapps/api/app/services/file_service.py
Chunkingapps/api/app/services/file_chunking.py
PDF textapps/api/app/services/pdf_extraction.py
Embeddingsapps/api/app/services/embedding_service.py
Prompt blockapps/api/app/services/file_context_hints.py
Attach UIapps/web/src/hooks/use-files.ts, chat-input.tsx

You rarely replace this pipeline. You change flags, limits, and whether your product should accept files at all.

On this page