Spaces:
Sleeping
Sleeping
File size: 8,251 Bytes
e9058d2 6a10cc7 e9058d2 6cc7077 e9058d2 6cc7077 e9058d2 6cc7077 e9058d2 6cc7077 1ca9988 d451e5d 1ca9988 6cc7077 1ca9988 6cc7077 e9058d2 1ca9988 0afaf00 1ca9988 d451e5d 0afaf00 1ca9988 0afaf00 d451e5d 1ca9988 5177768 6cc7077 5177768 1ca9988 6cc7077 5c99a7e 6cc7077 5c99a7e e9058d2 d451e5d e9058d2 6cc7077 e9058d2 6cc7077 e9058d2 6cc7077 e9058d2 6cc7077 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 | 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(),
} |