from typing import Any, Dict, List, Optional from supabase import create_client, Client from loguru import logger from .utils import timing_decorator class SupabaseClient: def __init__(self, url: str, key: str): """ Khởi tạo SupabaseClient với url và key. Input: url (str), key (str) Output: SupabaseClient instance. """ self.client: Client = create_client(url, key) @timing_decorator def get_page_token(self, page_id: str): """ Lấy access token của Facebook page từ Supabase. Input: page_id (str) Output: access_token (str) hoặc None nếu không có. """ try: response = self.client.table('page_tokens').select('access_token').eq('page_id', page_id).execute() if response.data and len(response.data) > 0: return response.data[0]['access_token'] return None except Exception as e: logger.error(f"Error getting page token: {e}") return None @timing_decorator def match_documents(self, embedding: List[float], match_count: int = 5): """ Truy vấn vector similarity search qua RPC match_documents. Input: embedding (list[float]), match_count (int) Output: list[dict] kết quả truy vấn. """ try: response = self.client.rpc( 'match_documents', { 'query_embedding': embedding, 'match_threshold': 0.7, 'match_count': match_count } ).execute() if response.data: return response.data return [] except Exception as e: logger.error(f"Error matching documents: {e}") return [] @timing_decorator def store_embedding(self, text: str, embedding: List[float], metadata: Dict[str, Any]): """ Lưu embedding vào Supabase. Input: text (str), embedding (list[float]), metadata (dict) Output: bool (True nếu thành công, False nếu lỗi) """ try: response = self.client.table('embeddings').insert({ 'content': text, 'embedding': embedding, 'metadata': metadata }).execute() return bool(response.data) except Exception as e: logger.error(f"Error storing embedding: {e}") return False