Spaces:
Sleeping
Sleeping
| 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}") |