final_project / app /main.py
Ana2012's picture
Update app/main.py
d451e5d verified
Raw
History Blame Contribute Delete
8.25 kB
import os
import threading
from pathlib import Path
from typing import Optional
from fastapi import FastAPI, Query, Response
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse, HTMLResponse, RedirectResponse
from pydantic import BaseModel
from .agent import ShoppingAgent
from .feedback import caminho_feedback, google_sheets_habilitado, salvar_feedback
from .google_oauth import build_flow, get_authorization_url, load_credentials, save_credentials
from .logger import salvar_log_busca
from .memory import caminho_memoria_negativa
oauth_flow_global = {}
EMBEDDING_PROVIDER = os.getenv("EMBEDDING_PROVIDER", "transformers").strip().lower()
HF_MODEL_REPO = os.getenv("HF_MODEL_REPO", "Ana2012/bertimbau-buscador").strip()
def _env_flag(name, default="true"):
return os.getenv(name, default).strip().lower() in {"1", "true", "yes", "on"}
PRELOAD_AGENT = _env_flag("PRELOAD_AGENT", "true")
LOGS_DIR = os.getenv("LOGS_DIR", "/data/logs")
DATA_DIR = "/data"
app = FastAPI(title="TCC2 Agent API")
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=False,
allow_methods=["*"],
allow_headers=["*"],
)
agent = None
agent_lock = threading.Lock()
def get_agent():
global agent
if agent is None:
with agent_lock:
if agent is None:
agent = ShoppingAgent()
return agent
@app.on_event("startup")
def preload_agent():
if PRELOAD_AGENT:
get_agent()
class ChatRequest(BaseModel):
query: Optional[str] = None
message: Optional[str] = None
top_k: int = 5
class FeedbackRequest(BaseModel):
search_id: str
query: str
rank: int
product_id: str
product_name: str
categoria_produto: Optional[str] = None
categoria_inferida: Optional[str] = None
rating: Optional[int] = None
is_helpful: Optional[bool] = None
note: Optional[str] = None
feedback: Optional[str] = None
motivo: Optional[str] = None
score_final: Optional[float] = None
score_semantico: Optional[float] = None
bonus_lexical: Optional[float] = None
penalidade_feedback: Optional[float] = None
user_message: Optional[str] = None
@app.get("/health")
def health():
runtime = get_agent().runtime_info() if agent is not None else None
return {
"status": "ok",
"agent_ready": agent is not None,
"embedding_provider": EMBEDDING_PROVIDER,
"model_repo": HF_MODEL_REPO,
"preload_agent": PRELOAD_AGENT,
"runtime": runtime,
"feedback_storage": "google_sheets" if google_sheets_habilitado() else "csv",
}
@app.get("/", include_in_schema=False)
def root():
return RedirectResponse(url="/docs")
@app.get("/favicon.ico", include_in_schema=False)
def favicon():
return Response(status_code=204)
@app.get("/auth/google")
def auth_google():
try:
flow = build_flow()
authorization_url, state = flow.authorization_url(
access_type="offline",
prompt="consent",
include_granted_scopes="true",
)
# 🔥 ESSENCIAL
oauth_flow_global[state] = flow
return RedirectResponse(url=authorization_url)
except Exception as exc:
return {
"ok": False,
"error": str(exc),
}
@app.get("/oauth2callback")
def oauth2callback(code: str = Query(...), state: str = Query(...)):
try:
flow = oauth_flow_global.get(state)
if not flow:
return HTMLResponse(
"<h3>Erro: sessao OAuth expirada ou invalida.</h3>",
status_code=400,
)
# 🔥 usa o MESMO flow (não recria!)
flow.fetch_token(code=code)
save_credentials(flow.credentials)
# limpa memória
oauth_flow_global.pop(state, None)
return HTMLResponse(
"""
<h3>Autorizacao concluida com sucesso.</h3>
<p>O backend ja pode salvar feedbacks no Google Sheets.</p>
<p>Voce ja pode fechar esta aba.</p>
"""
)
except Exception as exc:
return HTMLResponse(
f"""
<h3>Erro ao concluir autorizacao Google.</h3>
<p>{str(exc)}</p>
""",
status_code=500,
)
@app.get("/auth/status")
def auth_status():
credentials = load_credentials()
connected = credentials is not None and credentials.valid
return {
"google_sheets_connected": connected,
"message": (
"Google Sheets autorizado e pronto para uso."
if connected
else "Google Sheets ainda nao autorizado. Acesse /auth/google para conectar."
),
}
@app.get("/debug/files")
def debug_files():
data_path = Path(DATA_DIR)
logs_path = Path(LOGS_DIR)
feedback_path = Path(caminho_feedback())
memory_path = Path(caminho_memoria_negativa())
return {
"data_exists": data_path.exists(),
"logs_exists": logs_path.exists(),
"feedback_exists": feedback_path.exists(),
"negative_memory_exists": memory_path.exists(),
"data_files": sorted(p.name for p in data_path.iterdir()) if data_path.exists() else [],
"logs_files": sorted(p.name for p in logs_path.iterdir()) if logs_path.exists() else [],
"feedback_file": str(feedback_path),
"negative_memory_file": str(memory_path),
"feedback_storage": "google_sheets" if google_sheets_habilitado() else "csv",
}
@app.get("/debug/feedback")
def debug_feedback():
feedback_path = Path(caminho_feedback())
if not feedback_path.exists():
return {"error": "arquivo nao existe"}
return {"conteudo": feedback_path.read_text(encoding="utf-8")}
@app.get("/download/feedback")
def download_feedback():
feedback_path = caminho_feedback()
if not os.path.exists(feedback_path):
return {"error": "arquivo nao existe"}
return FileResponse(feedback_path, filename="feedback.csv")
@app.get("/debug/memory")
def debug_memory():
memory_path = Path(caminho_memoria_negativa())
if not memory_path.exists():
return {"status": "missing", "file": str(memory_path)}
return {
"status": "ok",
"file": str(memory_path),
"content": memory_path.read_text(encoding="utf-8"),
}
@app.post("/chat")
def chat(request: ChatRequest):
texto = request.query or request.message
if not texto:
return {"error": "query ou message deve ser informado"}
resultado = get_agent().responder(texto, top_k=request.top_k)
salvar_log_busca(resultado)
return resultado
@app.post("/feedback")
def feedback(request: FeedbackRequest):
feedback_file = caminho_feedback()
print(
"Salvando feedback:",
{
"query": request.query,
"product_id": request.product_id,
"feedback_file": feedback_file,
"logs_dir_exists": os.path.exists(LOGS_DIR),
"google_sheets_enabled": google_sheets_habilitado(),
},
)
try:
return salvar_feedback(
search_id=request.search_id,
query=request.query,
rank=request.rank,
product_id=request.product_id,
product_name=request.product_name,
categoria_produto=request.categoria_produto,
rating=request.rating,
is_helpful=request.is_helpful,
note=request.note,
categoria_inferida=request.categoria_inferida,
feedback=request.feedback,
motivo=request.motivo,
score_final=request.score_final,
score_semantico=request.score_semantico,
bonus_lexical=request.bonus_lexical,
penalidade_feedback=request.penalidade_feedback,
user_message=request.user_message,
)
except Exception as exc:
return {
"ok": False,
"saved_local": False,
"saved_google_sheets": False,
"detail": str(exc),
"feedback_file": feedback_file,
"logs_dir_exists": os.path.exists(LOGS_DIR),
"google_sheets_enabled": google_sheets_habilitado(),
}