Spaces:
Sleeping
Sleeping
| 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 |