from typing import Any, Dict, List, Optional from google.oauth2.credentials import Credentials from google_auth_oauthlib.flow import InstalledAppFlow from google.auth.transport.requests import Request from googleapiclient.discovery import build import os import pickle from datetime import datetime from loguru import logger from .utils import timing_decorator from .constants import SHEET_RANGE SCOPES = ['https://www.googleapis.com/auth/spreadsheets'] class SheetsClient: def __init__(self, credentials_file: str, token_file: str, sheet_id: str): """ Khởi tạo SheetsClient với thông tin xác thực và sheet_id. Input: credentials_file (str), token_file (str), sheet_id (str) Output: SheetsClient instance. """ self.credentials_file = credentials_file self.token_file = token_file self.sheet_id = sheet_id self.creds = None self.service = None def authenticate(self) -> None: """ Xác thực với Google Sheets API, tạo self.service. Input: None Output: None (raise exception nếu lỗi) """ if os.path.exists(self.token_file): with open(self.token_file, 'rb') as token: self.creds = pickle.load(token) if not self.creds or not self.creds.valid: if self.creds and self.creds.expired and self.creds.refresh_token: self.creds.refresh(Request()) else: flow = InstalledAppFlow.from_client_secrets_file( self.credentials_file, SCOPES) self.creds = flow.run_local_server(port=0) with open(self.token_file, 'wb') as token: pickle.dump(self.creds, token) self.service = build('sheets', 'v4', credentials=self.creds) @timing_decorator async def get_conversation_history(self, user_id: str, page_id: str) -> List[Dict[str, Any]]: """ Lấy lịch sử hội thoại của user từ Google Sheets. Input: user_id (str), page_id (str) Output: list[dict] các dòng hội thoại (nếu có). """ try: if not self.service: self.authenticate() if not self.service: raise RuntimeError("Google Sheets service not initialized") range_name = SHEET_RANGE result = self.service.spreadsheets().values().get( spreadsheetId=self.sheet_id, range=range_name ).execute() values = result.get('values', []) history = [] for row in values: if len(row) >= 6 and row[0] == user_id and row[1] == page_id: history.append({ 'user_id': row[0], 'page_id': row[1], 'timestamp': row[2], 'message': row[3], 'keywords': row[4], 'response': row[5] }) return history except Exception as e: logger.error(f"Error getting conversation history: {e}") return [] @timing_decorator async def log_conversation( self, user_id: str, page_id: str, message: str, keywords: List[str], response: str ) -> bool: """ Ghi log hội thoại vào Google Sheets. Input: user_id (str), page_id (str), message (str), keywords (list[str]), response (str) Output: bool (True nếu thành công, False nếu lỗi) """ try: if not self.service: self.authenticate() if not self.service: raise RuntimeError("Google Sheets service not initialized") timestamp = datetime.now().isoformat() values = [[ user_id, page_id, timestamp, message, ','.join(keywords), response ]] body = { 'values': values } range_name = SHEET_RANGE self.service.spreadsheets().values().append( spreadsheetId=self.sheet_id, range=range_name, valueInputOption='RAW', body=body ).execute() return True except Exception as e: logger.error(f"Error logging conversation: {e}") return False