PARA.Ai_api / app.py
caarleexx's picture
Upload 11 files
9514a77 verified
#!/usr/bin/env python3
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List, Optional
import logging
import time
import json
from pathlib import Path
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
STATUS_FILE = Path('/tmp/setup_status.json')
READY_FLAG = Path('/tmp/faiss_ready')
def get_setup_status():
if not STATUS_FILE.exists():
return {'status': 'initializing', 'message': 'Setup não iniciado', 'progress': 0}
try:
with open(STATUS_FILE) as f:
return json.load(f)
except:
return {'status': 'unknown', 'message': 'Erro ao ler status', 'progress': 0}
def is_ready():
return READY_FLAG.exists()
query_engine = None
def get_query_engine():
global query_engine
if query_engine is None:
if not is_ready():
raise HTTPException(status_code=503, detail="RAG em construção. Tente em alguns minutos.")
logger.info("Carregando QueryEngine...")
from query_engine import QueryEngine
query_engine = QueryEngine()
logger.info("✅ QueryEngine carregado!")
return query_engine
app = FastAPI(title="Para.AI RAG Cluster (LangChain)", version="1.0.0")
class EmbeddingSearchRequest(BaseModel):
query: str
top_k: int = 10
return_embeddings: bool = False
class KeywordSearchRequest(BaseModel):
keywords: List[str]
operator: str = "AND"
top_k: int = 20
class IDSearchRequest(BaseModel):
ids: List[str]
return_embeddings: bool = False
@app.get("/")
async def root():
setup_status = get_setup_status()
ready = is_ready()
response = {"status": "online", "rag_ready": ready, "setup": setup_status, "backend": "LangChain + FAISS (CPU)"}
if ready and query_engine:
response["cluster_id"] = query_engine.config.get('cluster_id')
response["chunk_range"] = [query_engine.config.get('chunk_start'), query_engine.config.get('chunk_end')]
return response
@app.get("/setup/status")
async def setup_status():
return get_setup_status()
@app.get("/health")
async def health():
return {"status": "ok", "timestamp": time.time()}
@app.post("/search/embedding")
async def search_embedding(request: EmbeddingSearchRequest):
engine = get_query_engine()
try:
start = time.time()
results = engine.search_by_embedding(request.query, request.top_k, request.return_embeddings)
results['query_time_ms'] = round((time.time() - start) * 1000, 2)
return results
except Exception as e:
logger.error(f"Erro: {e}")
raise HTTPException(status_code=500, detail=str(e))
@app.post("/search/keywords")
async def search_keywords(request: KeywordSearchRequest):
engine = get_query_engine()
try:
start = time.time()
results = engine.search_by_keywords(request.keywords, request.operator, request.top_k)
results['query_time_ms'] = round((time.time() - start) * 1000, 2)
return results
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/search/by_id")
async def search_by_id(request: IDSearchRequest):
engine = get_query_engine()
try:
start = time.time()
results = engine.search_by_ids(request.ids, request.return_embeddings)
results['query_time_ms'] = round((time.time() - start) * 1000, 2)
return results
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/cluster/info")
async def cluster_info():
engine = get_query_engine()
try:
info = engine.get_cluster_info()
info['uptime_seconds'] = round(time.time() - app.state.start_time, 2)
return info
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.on_event("startup")
async def startup_event():
app.state.start_time = time.time()
logger.info("="*80)
logger.info("🚀 Para.AI RAG (LangChain + FAISS) ONLINE")
logger.info("="*80)
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=7860)