Sistema RAG (Retrieval-Augmented Generation) para consultar documentos PDF, con:
- API en FastAPI
- Cliente por consola
- Dashboard en Streamlit
- Logging de consultas en SQLite
- Python 3.10+
- FastAPI + Uvicorn
- LangChain + FAISS
- Sentence Transformers (
all-MiniLM-L6-v2) - SQLite
- Streamlit (dashboard)
- LLM configurable: Ollama o Gemini
app/
api.py
dashboard.py
loader.py
main.py
rag.py
logers/
models/
files/
logs/
vector_store/
git clone <URL_DEL_REPO>
cd RAGpython -m venv venv
.\venv\Scripts\Activate.ps1pip install fastapi uvicorn pydantic python-multipart
pip install langchain-community langchain-text-splitters faiss-cpu sentence-transformers
pip install python-dotenv google-genai ollama pypdf
pip install streamlit pandas matplotlib wordcloudOpcional (recomendado):
pip install --upgrade pipCrea un archivo .env en la raiz del proyecto con una de estas opciones.
LLM_PROVIDER=ollamaInstalar e iniciar Ollama:
- Descarga Ollama desde
https://ollama.com/downloade instalalo. - Verifica que quedo disponible:
ollama --version- Inicia el servicio de Ollama (si no se inicio automaticamente):
ollama serve- En otra terminal, descarga el modelo a usar:
ollama pull llama3- Prueba rapida opcional:
ollama run llama3 "Hola, responde en una linea"LLM_PROVIDER=gemini
GEMINI_API_KEY=tu_api_key
GEMINI_MODEL=gemini-2.0-flashDesde la raiz del proyecto:
uvicorn app.api:app --reloadAPI docs:
http://127.0.0.1:8000/docs
Usa el endpoint POST /ingest (desde Swagger UI en /docs) para subir PDFs.
Tambien puedes probar con curl:
curl -X POST "http://127.0.0.1:8000/ingest" -F "file=@files/tu_archivo.pdf"Endpoint: POST /ask
Ejemplo:
curl -X POST "http://127.0.0.1:8000/ask" ^
-H "Content-Type: application/json" ^
-d "{\"question\":\"Cual es el tema principal del documento?\"}"python -m app.mainstreamlit run app/dashboard.py- Si no existe
vector_store, debes ingestar al menos un PDF antes de consultar. - El proyecto guarda logs en
logs/logs.db. - FAISS se carga con
allow_dangerous_deserialization=Trueporque se asume que elvector_storees local y de confianza. - Si usas Ollama, asegurate de tener el servicio corriendo localmente.
La API ahora soporta consultas por fuentes multiples y modo auto (placeholder para agente/MCP).
OBSIDIAN_VAULT_DIR=files/obsidian
PDF_DIR=files/pdfs
VECTOR_STORE_PATH=vector_store
RAG_CHUNK_SIZE=1000
RAG_CHUNK_OVERLAP=200
EMBEDDING_MODEL=sentence-transformers/all-MiniLM-L6-v2POST /documents/ingest-sources- Ingesta por fuente (
obsidian,pdf, oall) - Ejemplo body:
- Ingesta por fuente (
{
"sources": ["obsidian", "pdf"]
}GET /sources- Retorna fuentes soportadas e indexadas.
POST /ask ahora acepta:
{
"question": "Que notas hablan de arquitectura?",
"mode": "manual",
"sources": ["obsidian"],
"k": 5
}mode=manual: usasources(sisourcesesnullo contieneall, consulta todas).mode=auto: placeholder para enrutamiento por agente/MCP (actualmente consulta todas).
Hook para MCP:
- El punto de extension para enrutamiento automatico de fuentes esta en rag/query/mcp_router.py.
- rag/query/handler.py inyecta el router y aplica el resultado como filtro de retrieval.
- El registro central vive en rag/sources/registry.py.
- app/rag.py usa ese registro para:
- listar fuentes soportadas
- resolver seleccion de fuentes en
/documents/ingest-sources - instanciar fuentes sin
if/elsepor cada tipo
Para agregar una nueva fuente:
- Crear una clase en
rag/sources/que implementeDataSource. - Registrar la clase en
build_default_source_registry()dentro de rag/sources/registry.py. - Asegurar que la metadata incluya
sourcecon el nombre registrado.
Con eso, la fuente ya queda disponible en /sources, en consultas manuales y en ingesta por fuentes, sin tocar endpoints.
- Error
No vector store found: ingesta primero un PDF en/ingest. - Error
SQLite objects created in a thread: el logger ya esta configurado para FastAPI concheck_same_thread=False. - Error de imports (
No module named app): ejecuta conpython -m app.maindesde la raiz.