{"id":51772020,"url":"https://github.com/alexvijo/private-rag","last_synced_at":"2026-07-20T02:31:30.977Z","repository":{"id":368938159,"uuid":"1287257577","full_name":"alexvijo/private-rag","owner":"alexvijo","description":"Chat RAG local sobre tus documentos (PDF, DOCX, XLSX, EPUB, TXT, CSV) con citas de fuentes. Backend FastAPI + ChromaDB + sentence-transformers, frontend Angular, LLM configurable (Ollama local u OpenAI).","archived":false,"fork":false,"pushed_at":"2026-07-02T21:05:33.000Z","size":145,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-07-02T23:09:37.968Z","etag":null,"topics":["angular","chromadb","docker","fastapi","llm","ollama","openai","rag","retrieval-augmented-generation","sentence-transformers","typescript","vector-database"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alexvijo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-07-02T14:18:36.000Z","updated_at":"2026-07-02T21:05:38.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/alexvijo/private-rag","commit_stats":null,"previous_names":["alexvijo/private-rag"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/alexvijo/private-rag","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexvijo%2Fprivate-rag","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexvijo%2Fprivate-rag/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexvijo%2Fprivate-rag/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexvijo%2Fprivate-rag/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alexvijo","download_url":"https://codeload.github.com/alexvijo/private-rag/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexvijo%2Fprivate-rag/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35671346,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"ssl_error","status_checked_at":"2026-07-20T02:08:09.736Z","response_time":111,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["angular","chromadb","docker","fastapi","llm","ollama","openai","rag","retrieval-augmented-generation","sentence-transformers","typescript","vector-database"],"created_at":"2026-07-20T02:31:25.199Z","updated_at":"2026-07-20T02:31:30.972Z","avatar_url":"https://github.com/alexvijo.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# RAG Chat — Chat inteligente sobre tus documentos\n\nAplicación RAG (Retrieval-Augmented Generation) completa y lista para ejecutar: sube documentos\nPDF, DOCX, XLSX, TXT, CSV o EPUB, y haz preguntas sobre su contenido. El asistente responde\n**exclusivamente** con información encontrada en tus documentos, citando las fuentes exactas, y\ndeclara explícitamente cuando no tiene suficiente información.\n\nFlujo implementado: **cargar documento → parsear → dividir en chunks con solapamiento → generar\nembeddings → indexar en vector store persistente → recuperar contexto relevante → generar\nrespuesta con un prompt estricto anti-alucinación**.\n\n## Stack técnico\n\n| Capa | Tecnología | Por qué |\n|---|---|---|\n| Backend | **Python + FastAPI** | El ecosistema de parsing/RAG (pypdf, python-docx, openpyxl, EbookLib, chromadb, sentence-transformers) es nativamente Python. FastAPI aporta tipado, docs automáticas (OpenAPI) y async nativo. |\n| Frontend | **Angular 18** (standalone components + signals) | Pedido explícito del proyecto; arquitectura modular con servicios tipados y componentes independientes. |\n| Vector store | **ChromaDB** (persistente en disco) | Persiste automáticamente, soporta borrado/filtrado por metadata (`doc_id`), ideal para CRUD de documentos individuales. |\n| Embeddings | **sentence-transformers** (`all-MiniLM-L6-v2`) | Modelo local, gratuito, rápido y sin necesidad de API key. |\n| LLM | **Ollama** (por defecto, local y gratis) u **OpenAI** | Seleccionable por variable de entorno `LLM_PROVIDER`, sin tocar código. |\n\n## Arquitectura\n\n```\nprivate-rag/\n├── backend/                     # API FastAPI\n│   ├── app/\n│   │   ├── main.py              # App FastAPI, CORS, startup\n│   │   ├── config.py            # Configuración vía variables de entorno\n│   │   ├── dependencies.py      # Inyección de dependencias (singleton RagService)\n│   │   ├── models/schemas.py    # Modelos Pydantic (request/response)\n│   │   ├── ingestion/\n│   │   │   ├── parsers.py       # Extracción de texto: PDF, DOCX, XLSX, TXT, CSV, EPUB\n│   │   │   └── chunking.py      # Text splitter recursivo con overlap\n│   │   ├── embeddings/\n│   │   │   └── embedder.py      # Wrapper de sentence-transformers\n│   │   ├── vectorstore/\n│   │   │   └── chroma_store.py  # Acceso a ChromaDB (add/query/delete)\n│   │   ├── generation/\n│   │   │   ├── llm_client.py    # Cliente LLM (Ollama / OpenAI, intercambiable)\n│   │   │   ├── prompt.py        # Prompt estricto anti-alucinación (+ variante con búsqueda web)\n│   │   │   └── web_search.py    # Búsqueda web vía DuckDuckGo (sin API key)\n│   │   ├── routers/\n│   │   │   ├── documents.py     # Endpoints: upload, list, delete, reindex\n│   │   │   └── chat.py          # Endpoint: chat\n│   │   └── services/\n│   │       └── rag_service.py   # Orquesta todo el flujo RAG\n│   ├── data/                    # uploads/ + chroma_db/ (persistente, gitignored)\n│   ├── requirements.txt\n│   └── .env.example\n├── frontend/                    # Angular 18 (standalone)\n│   └── src/app/\n│       ├── core/\n│       │   ├── models/          # Interfaces TS compartidas\n│       │   └── services/        # document.service.ts, chat.service.ts, selected-documents.service.ts\n│       └── features/\n│           ├── chat/            # Ventana de chat con citación de fuentes\n│           └── documents/       # Panel de subida/gestión de documentos\n├── sample_docs/                 # Documentos de prueba (PDF, DOCX, XLSX, TXT, CSV, EPUB)\n├── docker-compose.yml\n└── README.md\n```\n\n## Instalación y ejecución\n\n### Requisitos previos\n\n- **Python 3.11+** (recomendado 3.11–3.12; ver nota sobre Python 3.14 más abajo)\n- **Node.js 20+** y npm\n- **Ollama** (opción por defecto, 100% local y gratis) → [ollama.com](https://ollama.com), o una **API key de OpenAI** si prefieres usar `LLM_PROVIDER=openai`\n\n\u003e **Python 3.14**: algunas dependencias pineadas a versiones antiguas (`pandas`, `pydantic`,\n\u003e `EbookLib`, `chromadb`) no publican wheel precompilada para 3.14 en Windows y pip intentaría\n\u003e compilarlas desde código fuente (requiere Visual Studio Build Tools). `requirements.txt` ya usa\n\u003e mínimos (`\u003e=`) para esos paquetes concretos, que resuelven a versiones con wheel disponible;\n\u003e el resto mantiene versión exacta. Si usas Python 3.11–3.12 no deberías notar diferencia.\n\n\u003e **Ollama, `OLLAMA_MODEL` debe coincidir EXACTO con `ollama list`**: si tienes más de una\n\u003e instalación/instancia de Ollama en el sistema (por ejemplo el servicio de Windows y otra\n\u003e lanzada manualmente), pueden escuchar en el mismo puerto pero servir modelos distintos.\n\u003e Comprueba con `curl http://localhost:11434/api/tags` (o `ollama list` en la misma sesión que\n\u003e arrancó el servidor) qué modelo está realmente disponible, y usa ese nombre completo tal cual\n\u003e (p.ej. `llama3.2:3b`, no `llama3.2` a secas) en `OLLAMA_MODEL`.\n\n### Opción rápida: script de arranque\n\nUn único comando crea los entornos (venv + node_modules) si no existen, instala dependencias,\ncomprueba Ollama y levanta backend + frontend en paralelo:\n\n```powershell\n# Windows\n./start.ps1\n```\n\n```bash\n# Linux/Mac\n./start.sh\n```\n\nBackend en `http://localhost:8000`, frontend en `http://localhost:4200`. Ctrl+C detiene ambos.\nUsa `-SkipInstall` (PowerShell) o `SKIP_INSTALL=1` (bash) para saltarte la instalación de\ndependencias en arranques posteriores. Requiere los mismos prerrequisitos que la instalación\nmanual (Python, Node, y Ollama si aplica).\n\n### 1. Backend (manual, paso a paso)\n\n```bash\ncd backend\npython -m venv venv\n\n# Windows\nvenv\\Scripts\\activate\n# Linux/Mac\nsource venv/bin/activate\n\npip install -r requirements.txt\n\ncp .env.example .env\n# Edita .env si quieres cambiar el proveedor de LLM u otros parámetros\n\nuvicorn app.main:app --reload --port 8000\n```\n\nLa API queda disponible en `http://localhost:8000` (documentación interactiva en\n`http://localhost:8000/docs`).\n\n**Si usas Ollama** (por defecto), en otra terminal:\n\n```bash\nollama pull llama3.2:3b\nollama serve      # normalmente ya se ejecuta como servicio tras instalar Ollama\n```\n\n**Si prefieres OpenAI**, edita `backend/.env`:\n\n```env\nLLM_PROVIDER=openai\nOPENAI_API_KEY=sk-...\nOPENAI_MODEL=gpt-4o-mini\n```\n\n### 2. Frontend (manual)\n\n```bash\ncd frontend\nnpm install\nnpm start\n```\n\nLa aplicación queda disponible en `http://localhost:4200`.\n\n### 3. Con Docker Compose (backend + frontend)\n\n```bash\ndocker compose up --build\n```\n\n- Frontend: `http://localhost:4200`\n- Backend: `http://localhost:8000`\n\nPor defecto usa Ollama ejecutándose en el host (`host.docker.internal:11434`). Para usar OpenAI,\ndefine `LLM_PROVIDER=openai` y `OPENAI_API_KEY` como variables de entorno antes de levantar los\ncontenedores.\n\n## Ejemplo de uso\n\n1. Abre `http://localhost:4200`.\n2. Arrastra a la barra lateral los archivos de `sample_docs/` (o los tuyos propios):\n   - `politica_vacaciones.txt`\n   - `catalogo_productos.csv`\n   - `manual_onboarding.docx`\n   - `informe_ventas.xlsx`\n   - `especificaciones_producto.pdf`\n3. Espera a que aparezcan en la lista de \"Documentos\" (indica cuántos chunks se generaron).\n4. Pregunta en el chat, por ejemplo:\n   - *\"¿Cuántos días de vacaciones tengo al año?\"* → responde con base en `politica_vacaciones.txt`.\n   - *\"¿Qué precio tiene el monitor 4K?\"* → responde con base en `catalogo_productos.csv`.\n   - *\"¿Cuál es la capital de Francia?\"* → responde: *\"No encuentro suficiente información en\n     los documentos para responder con seguridad.\"* (pregunta fuera de contexto).\n5. Haz clic en \"Ver fuentes\" bajo cualquier respuesta para ver los fragmentos exactos usados.\n6. Usa \"Reindexar todo\" tras cambiar `CHUNK_SIZE`/`CHUNK_OVERLAP` en `.env`, o \"Borrar índice\"\n   para empezar de cero.\n7. Marca documentos concretos con checkbox para acotar la búsqueda, activa \"Buscar en la web\" si\n   necesitas complementar con información externa, o cambia de modelo LLM desde el desplegable —\n   ver detalle de cada función a continuación.\n\n## Funcionalidades del chat\n\n- **Selector de modelo LLM**: si usas Ollama, el desplegable sobre el chat lista los modelos\n  descargados (`ollama list`) y permite elegir uno distinto al de `.env` para una pregunta puntual.\n- **Estado de conexión**: un indicador junto al selector muestra si el backend y el proveedor LLM\n  responden (`checking` / `ok` / `degraded` / `error`), refrescado periódicamente.\n- **Cancelar solicitud**: mientras el asistente está generando una respuesta, un botón permite\n  abortar la petición en curso.\n- **Selección de documentos**: marca uno o varios documentos con checkbox en el panel lateral para\n  limitar el retrieval solo a esos ficheros (por defecto se consulta todo el índice).\n- **Búsqueda web (opcional)**: activa el interruptor \"Buscar en la web\" para complementar el\n  contexto con resultados de DuckDuckGo (sin API key) y permitir que el modelo use también\n  conocimiento externo, no solo tus documentos. Con esta opción activa se desactiva el\n  comportamiento estrictamente anti-alucinación descrito más abajo.\n\n## Variables de entorno principales (`backend/.env`)\n\n| Variable | Descripción | Por defecto |\n|---|---|---|\n| `CHUNK_SIZE` / `CHUNK_OVERLAP` | Tamaño de chunk y solapamiento (caracteres) | `1000` / `150` |\n| `EMBEDDING_MODEL` | Modelo de sentence-transformers | `all-MiniLM-L6-v2` |\n| `TOP_K` | Nº de chunks recuperados por pregunta | `6` |\n| `MAX_CONTEXT_TOKENS` | Límite de tokens del contexto recuperado | `8000` |\n| `LLM_PROVIDER` | `ollama` u `openai` | `ollama` |\n| `OLLAMA_MODEL` | Modelo servido por Ollama (tag exacto de `ollama list`) | `llama3.2:3b` |\n| `OPENAI_MODEL` | Modelo de OpenAI (si aplica) | `gpt-4o-mini` |\n| `LLM_TEMPERATURE` | Temperatura de generación | `0.1` |\n\n## Endpoints principales\n\n| Método | Ruta | Descripción |\n|---|---|---|\n| `POST` | `/api/documents/upload` | Sube uno o varios archivos (multipart), los indexa |\n| `GET` | `/api/documents` | Lista documentos indexados |\n| `DELETE` | `/api/documents/{doc_id}` | Elimina un documento y sus chunks |\n| `POST` | `/api/documents/reindex` | Reindexa todos los documentos ya subidos |\n| `DELETE` | `/api/documents` | Borra completamente el índice |\n| `POST` | `/api/chat` | `{ \"question\", \"top_k\", \"model\", \"web_search\", \"doc_ids\" }` → respuesta + fuentes (documentos y/o web) |\n| `GET` | `/api/chat/models` | Lista los modelos disponibles del proveedor LLM activo (solo Ollama expone listado) |\n| `GET` | `/api/health` | Estado del servicio, proveedor LLM activo, nº de documentos/chunks |\n\n## Comportamiento anti-alucinación\n\nEl prompt de sistema (`backend/app/generation/prompt.py`) instruye al LLM a:\n\n1. Usar **solo** el contexto recuperado, nunca conocimiento externo.\n2. Responder literalmente *\"No encuentro suficiente información en los documentos para responder\n   con seguridad.\"* si el contexto no basta.\n3. Citar el documento/fragmento de origen al afirmar datos concretos.\n\nAdemás, `rag_service.py` aplica un **umbral mínimo de similitud coseno** (`MIN_RELEVANCE_SCORE =\n0.15`): si ningún chunk recuperado supera ese umbral, ni siquiera se llama al LLM — se devuelve\ndirectamente la respuesta de \"sin contexto\", evitando alucinaciones por chunks irrelevantes.\n\nEste comportamiento estricto aplica cuando **\"Buscar en la web\" está desactivado** (por defecto).\nSi se activa esa opción (`web_search: true`), el sistema usa un prompt distinto\n(`SYSTEM_PROMPT_WEB`) que sí permite complementar los documentos con resultados de búsqueda web y\nconocimiento general del modelo.\n\n## Recomendaciones de mejoras futuras\n\n- **Streaming de respuestas** (Server-Sent Events) para mostrar tokens a medida que se generan.\n- **Autenticación de usuarios** y multi-tenancy (índices separados por usuario/organización).\n- **Re-ranking** de los chunks recuperados con un cross-encoder antes de pasar al LLM.\n- **Chunking semántico** basado en embeddings (en vez de solo separadores de caracteres).\n- **Soporte para más formatos**: PPTX, Markdown, HTML, imágenes con OCR.\n- **Historial de conversación** con memoria contextual (RAG conversacional multi-turno).\n- **Observabilidad**: métricas de latencia, tasa de \"sin contexto\", logging estructurado.\n- **Tests automatizados** (pytest para backend, Jasmine/Karma o Vitest para frontend).\n- **CI/CD**: pipeline de GitHub Actions para lint, tests y build en cada PR.\n- **Despliegue en producción**: backend detrás de un proxy con HTTPS, vector store gestionado\n  (Chroma Cloud, Qdrant, pgvector) para escalar más allá de un único proceso.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falexvijo%2Fprivate-rag","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falexvijo%2Fprivate-rag","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falexvijo%2Fprivate-rag/lists"}