final_project / app /feedback.py
Ana2012's picture
Update app/feedback.py
66201b1 verified
Raw
History Blame Contribute Delete
6.76 kB
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