File size: 4,857 Bytes
aa168a1
 
 
 
 
 
 
 
 
 
 
 
 
 
bb41bc4
aa168a1
 
 
bb41bc4
aa168a1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bb41bc4
aa168a1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bb41bc4
aa168a1
 
 
 
 
 
 
 
 
 
 
 
 
 
8395475
bb41bc4
 
aa168a1
 
 
 
 
d34b880
aa168a1
 
 
 
 
d34b880
bb41bc4
aa168a1
 
 
bb41bc4
 
 
 
 
aa168a1
 
 
 
 
 
bb41bc4
aa168a1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bb41bc4
aa168a1
 
 
 
 
 
 
 
 
 
bb41bc4
aa168a1
 
 
 
bb41bc4
aa168a1
bb41bc4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
aa168a1
 
bb41bc4
 
 
c7832ca
bb41bc4
 
 
 
 
 
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
import json
import os
import tempfile
from pathlib import Path

from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import Flow
from googleapiclient.discovery import build

SCOPES = [
    "https://www.googleapis.com/auth/spreadsheets",
    "https://www.googleapis.com/auth/drive.file",
]

TOKEN_FILENAME = "google_token.json"
DATA_DIR = Path("/data")
FALLBACK_DATA_DIR = Path(tempfile.gettempdir()) / "tcc2_agent"


class GoogleOAuthError(RuntimeError):
    pass


class GoogleAuthRequiredError(GoogleOAuthError):
    pass


def _resolve_data_dir():
    preferred_dir = os.environ.get("GOOGLE_TOKEN_DIR", "").strip()
    candidates = [Path(preferred_dir)] if preferred_dir else []
    candidates.extend([DATA_DIR, FALLBACK_DATA_DIR])

    for directory in candidates:
        try:
            directory.mkdir(parents=True, exist_ok=True)
            return directory
        except OSError:
            continue

    raise GoogleOAuthError(
        "Nao foi possivel criar um diretorio para armazenar o token OAuth."
    )


def get_token_path():
    return _resolve_data_dir() / TOKEN_FILENAME


def _client_config():
    client_id = os.environ.get("GOOGLE_CLIENT_ID", "").strip()
    client_secret = os.environ.get("GOOGLE_CLIENT_SECRET", "").strip()
    redirect_uri = os.environ.get("GOOGLE_REDIRECT_URI", "").strip()

    missing = [
        name
        for name, value in {
            "GOOGLE_CLIENT_ID": client_id,
            "GOOGLE_CLIENT_SECRET": client_secret,
            "GOOGLE_REDIRECT_URI": redirect_uri,
        }.items()
        if not value
    ]

    if missing:
        raise GoogleOAuthError("Variaveis OAuth ausentes: " + ", ".join(missing))

    return {
        "web": {
            "client_id": client_id,
            "client_secret": client_secret,
            "auth_uri": "https://accounts.google.com/o/oauth2/auth",
            "token_uri": "https://oauth2.googleapis.com/token",
            "redirect_uris": [redirect_uri],
        }
    }


def build_flow(state=None):
    flow = Flow.from_client_config(_client_config(), scopes=SCOPES, state=state)
    flow.redirect_uri = os.environ.get("GOOGLE_REDIRECT_URI")
    return flow


def get_authorization_url():
    flow = build_flow()

    authorization_url, state = flow.authorization_url(
        access_type="offline",
        prompt="consent",
        include_granted_scopes="true",
    )

    return authorization_url, state  # importante retornar state


def save_credentials(credentials):
    if not credentials.refresh_token:
        raise GoogleOAuthError(
            "Refresh token nao recebido. Revogue o acesso e autorize novamente."
        )

    token_path = get_token_path()
    token_path.write_text(credentials.to_json(), encoding="utf-8")


def load_credentials():
    token_path = get_token_path()

    if not token_path.exists():
        return None

    try:
        payload = json.loads(token_path.read_text(encoding="utf-8"))
        credentials = Credentials.from_authorized_user_info(payload, SCOPES)
    except Exception:
        return None

    if credentials.expired and credentials.refresh_token:
        try:
            credentials.refresh(Request())
            save_credentials(credentials)
        except Exception:
            return None

    if not credentials.valid:
        return None

    return credentials


def get_sheets_service():
    credentials = load_credentials()

    if credentials is None:
        raise GoogleAuthRequiredError(
            "Google Sheets nao autorizado. Acesse /auth/google primeiro."
        )

    return build("sheets", "v4", credentials=credentials, cache_discovery=False)


def append_feedback_to_sheet(feedback_data):
    spreadsheet_id = os.environ.get("GOOGLE_SPREADSHEET_ID", "").strip()

    if not spreadsheet_id:
        raise GoogleOAuthError("GOOGLE_SPREADSHEET_ID nao configurado.")

    service = get_sheets_service()

    fields = [
        "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",
    ]

    row = [[str(feedback_data.get(field, "") or "") for field in fields]]

    try:
        return service.spreadsheets().values().append(
            spreadsheetId=spreadsheet_id,
            range="Feedback!A1:R1",
            valueInputOption="USER_ENTERED",
            insertDataOption="INSERT_ROWS",
            body={"values": row},
        ).execute()
    except Exception as e:
        raise GoogleOAuthError(f"Erro ao enviar para Google Sheets: {e}")