File size: 6,760 Bytes
bee13be
 
 
 
 
 
 
 
 
 
 
 
 
 
66201b1
bee13be
66201b1
bee13be
 
66201b1
 
bee13be
 
 
 
 
 
 
 
 
66201b1
bee13be
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66201b1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bee13be
66201b1
bee13be
66201b1
bee13be
 
66201b1
 
bee13be
 
 
 
 
 
 
 
 
66201b1
bee13be
66201b1
 
 
 
 
 
bee13be
 
66201b1
bee13be
66201b1
bee13be
 
 
66201b1
 
 
 
bee13be
 
 
 
 
66201b1
 
bee13be
 
 
 
66201b1
bee13be
66201b1
bee13be
 
66201b1
 
bee13be
 
 
 
 
 
 
 
 
66201b1
bee13be
 
66201b1
bee13be
66201b1
bee13be
 
66201b1
 
bee13be
 
 
3d48d38
 
 
 
 
 
66201b1
3d48d38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66201b1
 
 
 
 
3d48d38
66201b1
 
 
 
 
 
3d48d38
 
 
 
66201b1
 
 
 
3d48d38
 
 
 
 
 
 
 
 
66201b1
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
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