An internal knowledge assistant that enables users to upload documents, index them using vector embeddings, and ask natural language questions. Guidely combines semantic search with Retrieval-Augmented Generation (RAG) to provide concise answers together with the document sources used to generate them.
Guidely is a Retrieval-Augmented Generation (RAG) application built with FastAPI, React (Vite), FAISS, Sentence Transformers, and Google Gemini.
Instead of searching documents using keyword matching, Guidely converts documents into vector embeddings and retrieves the most semantically relevant chunks before generating an answer with an LLM.
The application follows the workflow:
Upload Documents
↓
Extract Text
↓
Chunk Documents
↓
Generate Embeddings
↓
Store in FAISS
↓
Ask Question
↓
Retrieve Top-k Chunks
↓
Generate AI Answer
↓
Return Answer + Sources
- Upload TXT, PDF and DOCX documents
- Automatic document parsing
- Text chunking
- Sentence Transformer embeddings
- Persistent FAISS vector store
- Semantic similarity search
- AI answer generation using Gemini
- Source attribution
- Duplicate document detection using hashing
- Embedding cache for unchanged documents
- Logging
- Health endpoint
- Metrics endpoint
- Search page
- Admin upload page
- Source references
- Friendly error handling
- FastAPI
- FAISS
- Sentence Transformers (all-MiniLM-L6-v2)
- Google Gemini API
- NumPy
- Pickle
- React
- Vite
guidely/
│
├── backend/
│ ├── data/
│ │ ├── sample-docs/
│ │ └── retrieval-validation.md
│ ├── routes/
│ ├── services/
│ ├── models/
│ ├── tests/
│ ├── data/
│ └── main.py
│
├── frontend/
│ ├── src/
│ ├── public/
│ └── package.json
│
├── README.md
└── .env
+-------------------+
| React Client |
+---------+---------+
|
|
HTTP Requests
|
v
+-------------------+
| FastAPI |
+---------+---------+
|
+----------------+----------------+
| |
v v
Document Processing Search Pipeline
| |
Extract Text Embed Question
| |
Chunk Text FAISS Search
| |
Generate Embeddings Retrieve Top-k Chunks
| |
Store in FAISS Gemini
| |
+---------------+-----------------+
|
JSON Response
Users upload supported documents.
Supported formats:
- TXT
- DOCX
The uploaded document is:
- Parsed
- Converted to raw text
- Split into fixed-size chunks
Each chunk is converted into a vector embedding using Sentence Transformers.
Embeddings are stored in a persistent FAISS vector index.
Chunk metadata is stored alongside each embedding.
When a question is submitted:
- Generate an embedding for the question.
- Retrieve the most relevant chunks using FAISS.
- Build a context from the retrieved chunks.
- Send the context and question to Gemini.
- Return:
- Generated answer
- Source documents
- Chunk references
POST /documents/upload
Uploads and indexes a document.
POST /search
Returns:
- answer
- referenced sources
GET /system/health
Returns application health.
GET /system/metrics
Returns runtime metrics including:
- queries served
- cache hits, misses, and hit rate
- generated embeddings
- median and p95 query latency
- failure counts by error type
The project includes five internal knowledge-base documents:
employee-handbook.txtit-security-policy.txtcustomer-support-guide.txtnew-hire-onboarding.txtexpense-faq.txt
At least five sample documents are included in:
backend/data/sample-docs/
git clone <repository-url>
cd guidelyRun these commands from the project root.
python3 -m venv backend/venv
source backend/venv/bin/activate
pip install -r requirements.txtCopy the environment template and add your Google AI Studio key:
cp .env.example .envGEMINI_API_KEY is required. GEMINI_MODEL, GEMINI_TIMEOUT_MS,
CORS_ORIGINS, and VITE_API_BASE_URL are optional configuration values with
local-development defaults. Keep .env private; it is ignored by Git.
cd backend
uvicorn main:app --reloadBackend runs on
http://localhost:8000
cd ..
cd frontend
npm install
npm run devFrontend runs on
http://localhost:5173
The API handles:
- Empty questions
- Unsupported file types
- Empty documents
- Documents with no extractable text
- Corrupted documents
- Missing AI configuration
- No relevant search results
- AI service failures
The backend logs:
- Uploaded documents
- Cache hits
- Search requests
- Query latency
- AI failures
- Processing errors
Run the automated tests from the project root after installing the backend dependencies:
PYTHONPATH=backend backend/venv/bin/python -m unittest discover -s backend/tests -vFor manual retrieval validation, upload all files in backend/data/sample-docs/
and run the 15 questions in backend/data/retrieval-validation.md. A query is a
pass when its expected document appears in the first three returned sources.
Retrieval@3 = passed queries / 15 * 100
The full validation session is automated with two scripts run in this order from the project root while the backend is up:
backend/venv/bin/python scripts/test_failures.py
backend/venv/bin/python scripts/validate_guidely.pytest_failures.py must run first against an empty store (wipe
backend/data/faiss/ and backend/data/cache/ and restart the backend); it
exercises the four required failure cases and then indexes the sample docs so
the no-key case reaches the answer-generation step on a temporary instance.
validate_guidely.py then runs the happy-path checks. Artifacts are written to
scripts/guidely_failure_report.json, scripts/guidely_answers.json, and
scripts/guidely_source_precision.json.
View live backend metrics in a browser at:
http://localhost:8000/system/metrics
Record measured results below after running the validation steps. Do not replace the placeholders with estimated values.
Results recorded on 2026-08-23 (local dev, warm cache):
| Metric | Result | Status |
|---|---|---|
| Retrieval@3 | 15/15 queries = 100% (target >= 80%) | Pass |
| Answer reference coverage | 15/15 answers cite the expected file = 100% (target >= 90%) | Pass |
| Source precision | 10/10 rank-1 snippets found verbatim in the cited files = 100% (target >= 80%) | Pass |
| Median latency | 2.39s warm cache (target < 3s) | Pass |
| p95 latency | 2.61s warm cache (target < 5s) | Pass |
| Embedding cache effectiveness | 10/10 repeated uploads of unchanged docs skipped re-indexing, 0 embeddings regenerated (target 100%) | Pass |
| Failure handling | empty query -> 400, corrupted file -> 400, unsupported type -> 400, no results -> 404, missing model key -> 503, all with clear messages and logged in failure_counts |
Pass |
| Indexing throughput (optional) | 5 sample files indexed in 1.41s; unchanged re-uploads are skipped | Pass |
Notes on reading /system/metrics:
cache_hit_rateaggregates every upload attempt since startup, so a session that starts from an empty store reports first-time indexing as misses. For unchanged documents the behaviour is 100% hits: every repeated upload returns "Document already indexed. Skipping re-indexing." and generates no new embeddings.- The
missing_model_keyfailure is counted on the temporary no-key instance thatscripts/test_failures.pyspawns; the merged view across both instances is inscripts/guidely_failure_report.json.
- Query-aware snippets
- Hybrid keyword + semantic search
- Conversation history
- Authentication
- Document tagging
- CSV query export
- Streaming responses
Amon Mandela Ochuka