|
|
from supabase import create_client, Client |
|
|
from typing import Optional |
|
|
import logging |
|
|
|
|
|
from app.config.settings import settings |
|
|
from app.db.models import NarratorExtractionRecord, NarratorAnalysisRecord |
|
|
|
|
|
|
|
|
class DatabaseService: |
|
|
"""Service for database operations with Supabase.""" |
|
|
|
|
|
def __init__(self): |
|
|
self.logger = logging.getLogger(__name__) |
|
|
self.supabase: Optional[Client] = None |
|
|
|
|
|
if settings.SUPABASE_URL and settings.SUPABASE_SERVICE_KEY: |
|
|
try: |
|
|
self.supabase = create_client( |
|
|
settings.SUPABASE_URL, |
|
|
settings.SUPABASE_SERVICE_KEY |
|
|
) |
|
|
except Exception as e: |
|
|
self.logger.error(f"Failed to initialize Supabase client: {e}") |
|
|
|
|
|
async def store_extraction_record(self, record: NarratorExtractionRecord) -> Optional[str]: |
|
|
"""Store narrator extraction record in database.""" |
|
|
if not self.supabase: |
|
|
self.logger.warning("Supabase client not available, skipping database storage") |
|
|
return None |
|
|
|
|
|
try: |
|
|
|
|
|
record_dict = record.dict(exclude_none=True) |
|
|
if "id" in record_dict and record_dict["id"] is None: |
|
|
del record_dict["id"] |
|
|
|
|
|
|
|
|
if record.created_at: |
|
|
record_dict["created_at"] = record.created_at.isoformat() |
|
|
|
|
|
response = self.supabase.table("narrator_extractions").insert(record_dict).execute() |
|
|
|
|
|
if response.data: |
|
|
return response.data[0]["id"] |
|
|
else: |
|
|
self.logger.error("No data returned from extraction record insertion") |
|
|
return None |
|
|
|
|
|
except Exception as e: |
|
|
self.logger.error(f"Error storing extraction record: {e}") |
|
|
return None |
|
|
|
|
|
async def store_analysis_record(self, record: NarratorAnalysisRecord) -> Optional[str]: |
|
|
"""Store narrator analysis record in database.""" |
|
|
if not self.supabase: |
|
|
self.logger.warning("Supabase client not available, skipping database storage") |
|
|
return None |
|
|
|
|
|
try: |
|
|
|
|
|
record_dict = record.dict(exclude_none=True) |
|
|
if "id" in record_dict and record_dict["id"] is None: |
|
|
del record_dict["id"] |
|
|
|
|
|
|
|
|
if record.created_at: |
|
|
record_dict["created_at"] = record.created_at.isoformat() |
|
|
|
|
|
response = self.supabase.table("narrator_analyses").insert(record_dict).execute() |
|
|
|
|
|
if response.data: |
|
|
return response.data[0]["id"] |
|
|
else: |
|
|
self.logger.error("No data returned from analysis record insertion") |
|
|
return None |
|
|
|
|
|
except Exception as e: |
|
|
self.logger.error(f"Error storing analysis record: {e}") |
|
|
return None |
|
|
|
|
|
async def get_user_extractions(self, user_id: str, limit: int = 50) -> list: |
|
|
"""Get user's extraction history.""" |
|
|
if not self.supabase: |
|
|
return [] |
|
|
|
|
|
try: |
|
|
response = self.supabase.table("narrator_extractions").select("*").eq("user_id", user_id).order("created_at", desc=True).limit(limit).execute() |
|
|
return response.data or [] |
|
|
except Exception as e: |
|
|
self.logger.error(f"Error fetching user extractions: {e}") |
|
|
return [] |
|
|
|
|
|
async def get_user_analyses(self, user_id: str, limit: int = 50) -> list: |
|
|
"""Get user's analysis history.""" |
|
|
if not self.supabase: |
|
|
return [] |
|
|
|
|
|
try: |
|
|
response = self.supabase.table("narrator_analyses").select("*").eq("user_id", user_id).order("created_at", desc=True).limit(limit).execute() |
|
|
return response.data or [] |
|
|
except Exception as e: |
|
|
self.logger.error(f"Error fetching user analyses: {e}") |
|
|
return [] |
|
|
|
|
|
async def get_extraction_stats(self) -> dict: |
|
|
"""Get extraction statistics.""" |
|
|
if not self.supabase: |
|
|
return {} |
|
|
|
|
|
try: |
|
|
response = self.supabase.rpc("get_extraction_stats").execute() |
|
|
return response.data[0] if response.data else {} |
|
|
except Exception as e: |
|
|
self.logger.error(f"Error fetching extraction stats: {e}") |
|
|
return {} |
|
|
|
|
|
async def get_popular_narrators(self, limit: int = 10) -> list: |
|
|
"""Get most analyzed narrators.""" |
|
|
if not self.supabase: |
|
|
return [] |
|
|
|
|
|
try: |
|
|
response = self.supabase.rpc("get_popular_narrators", {"limit_count": limit}).execute() |
|
|
return response.data or [] |
|
|
except Exception as e: |
|
|
self.logger.error(f"Error fetching popular narrators: {e}") |
|
|
return [] |
|
|
|