import csv import os import tempfile from datetime import datetime, timezone from pathlib import Path from .google_oauth import GoogleAuthRequiredError, append_feedback_to_sheet, load_credentials from .memory import salvar_memoria_negativa DEFAULT_LOGS_DIR = Path(os.getenv("LOGS_DIR", "/data/logs")) FALLBACK_LOGS_DIR = Path(tempfile.gettempdir()) / "tcc2_agent" / "logs" FEEDBACK_HEADERS = [ "timestamp", "search_id", "query", "rank", "product_id", "product_name", "categoria_inferida", "categoria_produto", "rating", "is_helpful", "feedback", "motivo", "score_final", "score_semantico", "bonus_lexical", "penalidade_feedback", "user_message", "note", ] def _resolve_logs_dir(): preferred_dir = os.environ.get("LOGS_DIR", "").strip() candidates = [Path(preferred_dir)] if preferred_dir else [] candidates.extend([DEFAULT_LOGS_DIR, FALLBACK_LOGS_DIR]) for directory in candidates: try: directory.mkdir(parents=True, exist_ok=True) return directory except OSError: continue raise OSError( "Nao foi possivel criar um diretorio para armazenar os logs de feedback. " "Defina LOGS_DIR para um caminho gravavel." ) def caminho_feedback(): return str(_resolve_logs_dir() / "feedback.csv") def inicializar_arquivo_feedback(): feedback_file = caminho_feedback() if not os.path.exists(feedback_file): with open(feedback_file, mode="w", newline="", encoding="utf-8") as f: writer = csv.writer(f) writer.writerow(FEEDBACK_HEADERS) def google_sheets_habilitado(): try: return load_credentials() is not None and bool(os.getenv("GOOGLE_SPREADSHEET_ID", "").strip()) except Exception: return False def _append_feedback_csv(row): inicializar_arquivo_feedback() feedback_file = caminho_feedback() with open(feedback_file, mode="a", newline="", encoding="utf-8") as f: writer = csv.writer(f) writer.writerow([row.get(header, "") for header in FEEDBACK_HEADERS]) def _derive_feedback_fields(rating=None, is_helpful=None, feedback=None): derived_feedback = feedback derived_is_helpful = is_helpful if derived_feedback is None: if rating is not None and rating >= 4: derived_feedback = "positivo" elif rating is not None and rating <= 2: derived_feedback = "negativo" elif rating == 3: derived_feedback = "neutro" else: derived_feedback = "" if derived_is_helpful is None: if rating is not None and rating >= 4: derived_is_helpful = True elif rating is not None and rating <= 2: derived_is_helpful = False elif rating == 3: derived_is_helpful = "" else: derived_is_helpful = "" return derived_feedback, derived_is_helpful def _build_feedback_payload( search_id, query, rank, product_id, product_name, categoria_inferida=None, categoria_produto=None, rating=None, is_helpful=None, feedback=None, motivo=None, score_final=None, score_semantico=None, bonus_lexical=None, penalidade_feedback=None, user_message=None, note=None, ): derived_feedback, derived_is_helpful = _derive_feedback_fields( rating=rating, is_helpful=is_helpful, feedback=feedback, ) return { "timestamp": datetime.now(timezone.utc).isoformat(), "search_id": search_id or "", "query": query, "rank": rank if rank is not None else "", "product_id": product_id, "product_name": product_name, "categoria_inferida": categoria_inferida or "", "categoria_produto": categoria_produto or "", "rating": rating if rating is not None else "", "is_helpful": derived_is_helpful, "feedback": derived_feedback, "motivo": motivo or "", "score_final": score_final if score_final is not None else "", "score_semantico": score_semantico if score_semantico is not None else "", "bonus_lexical": bonus_lexical if bonus_lexical is not None else "", "penalidade_feedback": penalidade_feedback if penalidade_feedback is not None else "", "user_message": user_message or "", # ajuste aqui "note": note or "", } def salvar_feedback( search_id, query, rank, product_id, product_name, categoria_inferida=None, categoria_produto=None, rating=None, is_helpful=None, feedback=None, motivo=None, score_final=None, score_semantico=None, bonus_lexical=None, penalidade_feedback=None, user_message=None, note=None, ): row = _build_feedback_payload( search_id=search_id, query=query, rank=rank, product_id=product_id, product_name=product_name, categoria_inferida=categoria_inferida, categoria_produto=categoria_produto, rating=rating, is_helpful=is_helpful, feedback=feedback, motivo=motivo, score_final=score_final, score_semantico=score_semantico, bonus_lexical=bonus_lexical, penalidade_feedback=penalidade_feedback, user_message=user_message, note=note, ) _append_feedback_csv(row) saved_google_sheets = False warning = None try: append_feedback_to_sheet(row) saved_google_sheets = True except GoogleAuthRequiredError: warning = "Feedback salvo localmente, mas nao enviado ao Google Sheets. Acesse /auth/google para autorizar." except Exception as exc: warning = ( "Feedback salvo localmente, mas nao enviado ao Google Sheets. " f"Erro de sincronizacao: {exc}" ) # 🔥 ajuste aqui (tratamento de string → int) try: rating_num = int(row.get("rating")) except (TypeError, ValueError): rating_num = None is_helpful_value = row.get("is_helpful") if ( (isinstance(rating_num, int) and rating_num <= 2) or is_helpful_value is False ): salvar_memoria_negativa( query=query, product_id=product_id, product_name=product_name, rating=rating_num, motivo=row.get("motivo") or row.get("feedback") or "feedback_negativo", search_id=row.get("search_id"), rank=row.get("rank"), ) response = { "ok": True, "saved_local": True, "saved_google_sheets": saved_google_sheets, } if warning: response["warning"] = warning return response