feat: implement RAG Service MVP with PARSER + Memory integration
RAG Service Implementation: - Create rag-service/ with full structure (config, document_store, embedding, pipelines) - Document Store: PostgreSQL + pgvector via Haystack - Embedding: BAAI/bge-m3 (multilingual, 1024 dim) - Ingest Pipeline: Convert ParsedDocument to Haystack Documents, embed, index - Query Pipeline: Retrieve documents, generate answers via DAGI Router - FastAPI endpoints: /ingest, /query, /health Tests: - Unit tests for ingest and query pipelines - E2E test with example parsed JSON - Test fixtures with real PARSER output example Router Integration: - Add mode='rag_query' routing rule in router-config.yml - Priority 7, uses local_qwen3_8b for RAG queries Docker: - Add rag-service to docker-compose.yml - Configure dependencies (router, city-db) - Add model cache volume Documentation: - Complete README with API examples - Integration guides for PARSER and Router
This commit is contained in:
105
services/rag-service/app/main.py
Normal file
105
services/rag-service/app/main.py
Normal file
@@ -0,0 +1,105 @@
|
||||
"""
|
||||
RAG Service - FastAPI application
|
||||
Retrieval-Augmented Generation for MicroDAO
|
||||
"""
|
||||
|
||||
import logging
|
||||
from fastapi import FastAPI, HTTPException
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
|
||||
from app.models import IngestRequest, IngestResponse, QueryRequest, QueryResponse
|
||||
from app.ingest_pipeline import ingest_parsed_document
|
||||
from app.query_pipeline import answer_query
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# FastAPI app
|
||||
app = FastAPI(
|
||||
title="RAG Service",
|
||||
description="Retrieval-Augmented Generation service for MicroDAO",
|
||||
version="1.0.0"
|
||||
)
|
||||
|
||||
# CORS middleware
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
|
||||
@app.get("/health")
|
||||
async def health():
|
||||
"""Health check endpoint"""
|
||||
return {
|
||||
"status": "healthy",
|
||||
"service": "rag-service",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
|
||||
|
||||
@app.post("/ingest", response_model=IngestResponse)
|
||||
async def ingest_endpoint(request: IngestRequest):
|
||||
"""
|
||||
Ingest parsed document from PARSER service into RAG
|
||||
|
||||
Body:
|
||||
- dao_id: DAO identifier
|
||||
- doc_id: Document identifier
|
||||
- parsed_json: ParsedDocument JSON from PARSER service
|
||||
- user_id: Optional user identifier
|
||||
"""
|
||||
try:
|
||||
result = ingest_parsed_document(
|
||||
dao_id=request.dao_id,
|
||||
doc_id=request.doc_id,
|
||||
parsed_json=request.parsed_json,
|
||||
user_id=request.user_id
|
||||
)
|
||||
|
||||
return IngestResponse(**result)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Ingest endpoint error: {e}", exc_info=True)
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@app.post("/query", response_model=QueryResponse)
|
||||
async def query_endpoint(request: QueryRequest):
|
||||
"""
|
||||
Answer query using RAG pipeline
|
||||
|
||||
Body:
|
||||
- dao_id: DAO identifier
|
||||
- question: User question
|
||||
- top_k: Optional number of documents to retrieve
|
||||
- user_id: Optional user identifier
|
||||
"""
|
||||
try:
|
||||
result = await answer_query(
|
||||
dao_id=request.dao_id,
|
||||
question=request.question,
|
||||
top_k=request.top_k,
|
||||
user_id=request.user_id
|
||||
)
|
||||
|
||||
return QueryResponse(**result)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Query endpoint error: {e}", exc_info=True)
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
from app.core.config import settings
|
||||
|
||||
uvicorn.run(
|
||||
"app.main:app",
|
||||
host=settings.API_HOST,
|
||||
port=settings.API_PORT,
|
||||
reload=True
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user