creativesar/face
0
1from fastapi import APIRouter, HTTPException, BackgroundTasks2from pydantic import BaseModel3from typing import List, Dict, Any4import logging5import os6from dotenv import load_dotenv7 8# Load environment variables9load_dotenv()10 11# Import services12from services.optimized_openrouter_rag_service import OptimizedOpenRouterRAGService13from services.qdrant_service import QdrantService14from services.openrouter_service import OpenRouterService15 16# Configure logging17logging.basicConfig(level=logging.INFO)18logger = logging.getLogger(__name__)19 20# Initialize services21openrouter_service = OpenRouterService()22qdrant_service = QdrantService()23rag_service = OptimizedOpenRouterRAGService(openrouter_service, qdrant_service)24 25router = APIRouter()26 27class ContentIndexRequest(BaseModel):28 content: str29 chapter_id: str30 section_title: str31 source_url: str32 33class BatchContentIndexRequest(BaseModel):34 contents: List[ContentIndexRequest]35 36class PersonalizeContentRequest(BaseModel):37 chapter_id: str38 user_id: str39 user_background: Dict[str, Any]40 41@router.post("/index")42async def index_content(content_data: ContentIndexRequest):43 """44 Index a single piece of content for RAG retrieval45 """46 try:47 logger.info(f"Indexing content for chapter: {content_data.chapter_id}")48 49 result = await rag_service.index_content(50 content=content_data.content,51 chapter_id=content_data.chapter_id,52 section_title=content_data.section_title,53 source_url=content_data.source_url54 )55 56 return {57 "success": True,58 "document_id": result["document_id"],59 "indexed_content_length": result["indexed_content_length"]60 }61 except Exception as e:62 logger.error(f"Error indexing content: {str(e)}")63 raise HTTPException(status_code=500, detail=str(e))64 65@router.post("/batch-index")66async def batch_index_content(content_data: BatchContentIndexRequest):67 """68 Index multiple pieces of content at once69 """70 try:71 logger.info(f"Batch indexing {len(content_data.contents)} content items")72 73 # Convert to the format expected by the service74 contents = [75 {76 "content": item.content,77 "chapter_id": item.chapter_id,78 "section_title": item.section_title,79 "source_url": item.source_url80 }81 for item in content_data.contents82 ]83 84 results = await rag_service.batch_index_content(contents)85 86 return {87 "success": True,88 "indexed_count": len(results),89 "results": results90 }91 except Exception as e:92 logger.error(f"Error batch indexing content: {str(e)}")93 raise HTTPException(status_code=500, detail=str(e))94 95@router.get("/status")96async def content_status():97 """98 Get status of the content indexing system99 """100 try:101 # Test Qdrant connection and get point count102 point_count = await qdrant_service.count_points()103 104 return {105 "status": "ready",106 "indexed_documents_count": point_count,107 "services": {108 "qdrant": await qdrant_service.test_connection(),109 "openrouter": await openrouter_service.test_connection()110 }111 }112 except Exception as e:113 logger.error(f"Error getting content status: {str(e)}")114 raise HTTPException(status_code=500, detail=str(e))115 116@router.post("/ingest-from-docs")117async def ingest_from_docs(background_tasks: BackgroundTasks):118 """119 Ingest content from the docs directory (for textbook content)120 This would read the Docusaurus docs and index them121 """122 try:123 # This would typically read from the docs directory124 # and index all the content for RAG125 docs_path = os.getenv("DOCS_PATH", "/app/docs") # Default path in Docker126 127 if not os.path.exists(docs_path):128 raise HTTPException(status_code=404, detail=f"Docs path not found: {docs_path}")129 130 # This is a simplified version - in a real implementation, you'd want to131 # parse all the markdown files and extract content properly132 import os133 import glob134 135 markdown_files = glob.glob(f"{docs_path}/**/*.md", recursive=True)136 markdown_files += glob.glob(f"{docs_path}/**/*.mdx", recursive=True)137 138 content_items = []139 for file_path in markdown_files:140 try:141 with open(file_path, 'r', encoding='utf-8') as f:142 content = f.read()143 144 # Extract chapter/section info from file path145 relative_path = os.path.relpath(file_path, docs_path)146 chapter_id = relative_path.replace('/', '_').replace('\\', '_').replace('.md', '').replace('.mdx', '')147 section_title = os.path.basename(file_path).replace('.md', '').replace('.mdx', '')148 149 content_items.append({150 "content": content,151 "chapter_id": chapter_id,152 "section_title": section_title,153 "source_url": f"/docs/{relative_path}"154 })155 except Exception as e:156 logger.warning(f"Could not process file {file_path}: {str(e)}")157 158 # Index all content items159 results = await rag_service.batch_index_content(content_items)160 161 return {162 "success": True,163 "processed_files": len(content_items),164 "indexed_documents": len(results),165 "results": results166 }167 except Exception as e:168 logger.error(f"Error ingesting from docs: {str(e)}")169 raise HTTPException(status_code=500, detail=str(e))170 171@router.post("/personalize")172async def personalize_content(personalize_data: PersonalizeContentRequest):173 """174 Get personalized content based on user background175 """176 try:177 # In a real implementation, this would adapt content based on user background178 # For now, we'll return the original content with some basic adaptation info179 logger.info(f"Personalizing content for chapter {personalize_data.chapter_id} for user {personalize_data.user_id}")180 181 # This would typically search for content related to the chapter_id182 # and adapt it based on the user's background183 # For now, we'll return a placeholder response184 return {185 "chapter_id": personalize_data.chapter_id,186 "user_id": personalize_data.user_id,187 "adaptation_info": "Content adaptation based on user background would happen here",188 "original_content": "Original textbook content would be returned here, adapted based on user background",189 "user_background": personalize_data.user_background190 }191 except Exception as e:192 logger.error(f"Error personalizing content: {str(e)}")193 raise HTTPException(status_code=500, detail=str(e))