DocuChat lets you upload any document (PDF, DOCX, TXT) and chat with it using a full RAG pipeline. Instead of dumping the whole document into a prompt, it semantically retrieves only the most relevant chunks and sends them to Groq's LLM β giving precise, grounded answers from your exact content.
| Feature | Description |
|---|---|
| π Multi-format support | Upload PDF, DOCX, and TXT files |
| π MMR semantic search | FAISS + Maximal Marginal Relevance finds diverse, relevant passages |
| π€ Accurate answers | Strict document-grounded responses, no outside hallucination |
| π Multi-document | Query across multiple documents at once |
| π¬ Conversation memory | Follow-up questions use the last 3 turns as context |
| π·οΈ Source citations | Answers reference which document and section they came from |
| β‘ Fast inference | Groq's llama-3.3-70b-versatile at ~12ms retrieval latency |
| π Private | Embedding model runs 100% locally; only top chunks leave your machine |
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β INDEXING (on upload) β
β β
β PDF/DOCX/TXT βββΊ Text Extraction βββΊ _clean_text() β
β + Page Labels (unicode, whitespace) β
β + Table Extraction β
β β β
β βΌ β
β RecursiveCharacterTextSplitter β
β chunk_size=1000 | overlap=200 β
β β β
β βΌ β
β HuggingFace Embeddings β
β (all-MiniLM-L6-v2, normalized) β
β β β
β βΌ β
β FAISS Vector Store β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β RETRIEVAL + GENERATION β
β β
β User Question βββΊ Embed Question β
β β β
β βΌ β
β MMR Search (fetch_k=20, select k=6) β
β + Relevance Score Filter (β₯ 0.25) β
β + [Source N: filename] labels β
β β β
β βΌ β
β System Prompt + Chat History (last 3 turns) β
β + Document Context + Question β
β β β
β βΌ β
β Groq LLM (llama-3.3-70b-versatile, temp=0.1) β
β β β
β βΌ β
β Grounded Answer with Source References β
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Docuchat/
βββ docuchat/ # Main Python package
β βββ __init__.py
β βββ core/
β β βββ document.py # PDF / DOCX / TXT extraction + cleaning
β β βββ rag.py # FAISS store, MMR retrieval, RAG pipeline
β β βββ validator.py # GROQ API key validation
β βββ ui/
β βββ app.py # Streamlit chat UI
βββ tests/
β βββ evaluate_rag.py # Retrieval accuracy evaluation (no API key needed)
β βββ test_unit.py # 44 pytest unit tests
β βββ fixtures/ # Sample documents for testing
β βββ company_policy.txt # HR / policy document
β βββ product_spec.txt # Technical specification
β βββ research_paper.txt # Academic paper
βββ results/
β βββ eval_report.json # Latest evaluation results (auto-generated)
βββ uploads/ # Temporary uploaded files (gitignored)
βββ pyproject.toml
βββ README.md
| Layer | Technology |
|---|---|
| UI | Streamlit |
| LLM Framework | LangChain (langchain-groq, langchain-core) |
| LLM Provider | Groq API β llama-3.3-70b-versatile |
| Vector Store | FAISS (faiss-cpu) |
| Embeddings | HuggingFace β all-MiniLM-L6-v2 (local) |
| Text Splitting | langchain-text-splitters β RecursiveCharacterTextSplitter |
| Doc Parsing | PyPDF2, python-docx |
| Package Manager | uv |
| Testing | pytest + custom retrieval evaluator |
- Python 3.11+
- uv β install with:
curl -LsSf https://astral.sh/uv/install.sh | sh
git clone https://github.com/PrinceThummar011/Docuchat.git
cd Docuchat
uv syncuv run streamlit run docuchat/ui/app.pyOpen http://localhost:8501 in your browser.
All tests run without a Groq API key β only the embedding model (local) is required.
uv run pytest tests/test_unit.py -vuv run python tests/evaluate_rag.py # print report
uv run python tests/evaluate_rag.py --json # also save results/eval_report.jsonLast evaluated: March 11, 2026 Β· Embedding model:
all-MiniLM-L6-v2Β· Chunk size: 1000 Β· Overlap: 200
| Test Class | Tests | Result |
|---|---|---|
TestCleanText |
7 | β 7 / 7 passed |
TestTextExtraction |
6 | β 6 / 6 passed |
TestVectorStore |
7 | β 7 / 7 passed |
TestRetrievalAccuracy |
15 | β 15 / 15 passed |
TestApiKeyValidation |
9 | β 9 / 9 passed |
| Total | 44 | β 44 / 44 passed |
Methodology: 30 factual QA pairs were manually created across 3 different test documents (HR policy, technical specification, research paper). For each question, the pipeline retrieves the top-6 chunks from a combined FAISS index. A question is marked a "hit" if any retrieved chunk contains the expected answer keyword(s). No LLM call is made β this is a pure retrieval quality test.
| Metric | Score | What it means |
|---|---|---|
| Hit Rate @1 | 80.0% | Correct answer in the very first retrieved chunk |
| Hit Rate @3 | 86.7% | Correct answer found within top 3 chunks |
| Hit Rate @6 | 96.7% | Correct answer found within top 6 chunks |
| MRR (Mean Reciprocal Rank) | 0.847 | Average quality of ranking (1.0 = always rank-1) |
| Precision @6 | 26.1% | Fraction of retrieved chunks that are truly relevant |
| Avg Retrieval Latency | 12.2 ms | Time to retrieve top-6 chunks per query |
| Document | Type | Questions | @1 | @3 | @6 | MRR |
|---|---|---|---|---|---|---|
company_policy.txt |
HR / Policy | 10 | 80.0% | 80.0% | 100% | 0.850 |
product_spec.txt |
Technical Spec | 10 | 80.0% | 90.0% | 100% | 0.858 |
research_paper.txt |
Academic Paper | 10 | 80.0% | 90.0% | 90.0% | 0.833 |
| ID | Question (summarised) | @1 | @3 | @6 |
|---|---|---|---|---|
| CP-01 | Remote work days per week | β | β | β |
| CP-02 | PTO accrual rate β year 1 | β | β | β |
| CP-03 | Sick days per year | β | β | β |
| CP-04 | Primary caregiver parental leave | β | β | β |
| CP-05 | Health insurance premium coverage % | β | β | β |
| CP-06 | Annual professional development budget | β | β | β |
| CP-07 | 401k plan administrator | β | β | β |
| CP-08 | Duration of a PIP | β | β | β |
| CP-09 | Screen lock timeout requirement | β | β | β |
| CP-10 | Bereavement days β immediate family | β | β | β |
| PS-01 | Peak CEC efficiency | β | β | β |
| PS-02 | Maximum DC input power | β | β | β |
| PS-03 | Rated AC output power | β | β | β |
| PS-04 | Number of MPPT inputs | β | β | β |
| PS-05 | Ingress protection rating | β | β | β |
| PS-06 | Inverter weight | β | β | β |
| PS-07 | Standard warranty period | β | β | β |
| PS-08 | Communication protocols | β | β | β |
| PS-09 | Operating temperature range | β | β | β |
| PS-10 | Safety certifications | β | β | β |
| RP-01 | Executive function reduction % | β | β | β |
| RP-02 | Number of study participants | β | β | β |
| RP-03 | Device used to measure sleep | β | β | β |
| RP-04 | Decision-making error increase % | β | β | β |
| RP-05 | Performance overestimation gap | β | β | β |
| RP-06 | Study duration | β | β | β |
| RP-07 | Recommended sleep hours (NSF) | β | β | β |
| RP-08 | Does caffeine offset severe CPSD? | β | β | β |
| RP-09 | Institution that conducted the study | β | β | β |
| RP-10 | Cognitive test battery used | β | β | β |
Only 1 question missed at @6: RP-09 ("Which institution?") β the word "Stanford" appears only in the document header/author affiliation, which FAISS does not rank highly for abstract institution-name queries. This is a known limitation of dense retrieval on metadata-style facts.
- All evaluation metrics are real β measured by running
tests/evaluate_rag.pylocally. No numbers were fabricated. You can reproduce them withuv run python tests/evaluate_rag.py. - No Groq API key is required to run the evaluation or unit tests. The embedding model (
all-MiniLM-L6-v2) runs locally. - The 1 missed question (RP-09) is documented honestly. It reflects a genuine limitation of dense retrieval: when the answer is in a document header rather than the body text, the embedding similarity may not rank it highly.
| Decision | Rationale |
|---|---|
| Chunk size 1000 (not 256β500) | Smaller chunks cut answers mid-sentence; larger chunks provide full context |
| MMR retrieval (not top-k cosine) | Pure cosine returns near-duplicate chunks; MMR ensures diversity |
llama-3.3-70b-versatile |
The 8b-instant model gave shorter, less detailed answers |
| Temperature 0.1 | Lower temperature = more deterministic, factual answers |
| Conversation history (last 3 turns) | Enables follow-up questions like "what about the second point?" |
| Score filter β₯ 0.25 | Removes noise chunks that confuse the LLM into hallucinating |
- Scanned PDFs (image-only): PyPDF2 cannot extract text from image-based PDFs. Use OCR tools (Tesseract) as a pre-processing step.
- Very large documents (>50 pages): Indexing is fast, but the FAISS store is rebuilt in-memory on every upload. For production use, persist the index to disk.
- Tables in PDFs: PDF table extraction is limited. DOCX tables are fully extracted.
- Dense retrieval blind spot: Rare named entities that appear only in document metadata (author names, institution headers) may not retrieve correctly, as seen in RP-09.
Step 1 βββΊ Get a free GROQ API key at https://console.groq.com/keys
Paste it in the sidebar (starts with gsk_)
Step 2 βββΊ Upload your documents (PDF / DOCX / TXT)
Knowledge base builds automatically in the background
Step 3 βββΊ Ask any question in the chat box
e.g. "What are the key responsibilities?"
"Summarize the contract terms"
"What is the project deadline?"
"What did you mean in your previous answer?" β follow-ups work!
Step 4 βββΊ Get accurate, source-grounded answers β
e.g. "According to [Source: contract.pdf], the deadline is March 31."
- Go to console.groq.com/keys
- Sign up / Log in (free)
- Click Create API Key
- Copy the key (starts with
gsk_) - Paste it in the DocuChat sidebar
Groq offers a generous free tier β no credit card required.
- β No API keys are stored or hardcoded in the repo
- β
Uploaded documents are stored locally only in
uploads/ - β Your key is used only to call the Groq API on your behalf
- β
The embedding model (
all-MiniLM-L6-v2) runs 100% locally - β Only the top-6 most relevant text chunks leave your machine (to Groq)