Spaces:
Sleeping
Sleeping
claude's playground
feat(agent verf): Add multi-provider LLM infrastructure with dual-mode support
0a6602d | # ============================================================================ | |
| # agent verf - Authentication & User Management | |
| # Version: 0.1.0 | |
| # Last Updated: 2026-01-22 | |
| # | |
| # Handles user management for dual-mode operation. | |
| # Users authenticate via Google OAuth (Supabase Auth). | |
| # | |
| # User Tiers: | |
| # - Regular users: Free mode only | |
| # - Premium users: Venice mode by default, can toggle to Free | |
| # ============================================================================ | |
| import os | |
| import structlog | |
| from typing import Optional | |
| from pydantic import BaseModel | |
| from enum import Enum | |
| from supabase import AsyncClient, create_async_client | |
| from src.utils.llm import VerificationMode | |
| logger = structlog.get_logger() | |
| # ============================================================================ | |
| # User Models | |
| # ============================================================================ | |
| class User(BaseModel): | |
| """User account data.""" | |
| id: str | |
| google_id: str | |
| email: Optional[str] = None | |
| display_name: Optional[str] = None | |
| avatar_url: Optional[str] = None | |
| is_premium: bool = False | |
| preferred_mode: str = "free" | |
| def get_verification_mode(self) -> VerificationMode: | |
| """Get the user's verification mode.""" | |
| if not self.is_premium: | |
| return VerificationMode.FREE | |
| return VerificationMode(self.preferred_mode) | |
| class UserCreate(BaseModel): | |
| """Data for creating a new user.""" | |
| google_id: str | |
| email: Optional[str] = None | |
| display_name: Optional[str] = None | |
| avatar_url: Optional[str] = None | |
| class UserUpdate(BaseModel): | |
| """Data for updating a user.""" | |
| preferred_mode: Optional[str] = None | |
| display_name: Optional[str] = None | |
| avatar_url: Optional[str] = None | |
| # ============================================================================ | |
| # User Service | |
| # ============================================================================ | |
| class UserService: | |
| """ | |
| Service for managing users in Supabase. | |
| Handles: | |
| - User creation on first login | |
| - User lookups by Google ID | |
| - Premium mode toggling | |
| """ | |
| def __init__(self): | |
| """Initialize with Supabase client.""" | |
| self._client: Optional[AsyncClient] = None | |
| async def _get_client(self) -> AsyncClient: | |
| """Get or create the Supabase async client.""" | |
| if self._client is None: | |
| url = os.getenv("SUPABASE_URL", "") | |
| key = os.getenv("SUPABASE_SERVICE_KEY", "") | |
| if not url.startswith("http"): | |
| url = f"https://{url}" | |
| self._client = await create_async_client(url, key) | |
| return self._client | |
| async def get_or_create_user( | |
| self, | |
| google_id: str, | |
| email: Optional[str] = None, | |
| display_name: Optional[str] = None, | |
| avatar_url: Optional[str] = None, | |
| ) -> User: | |
| """ | |
| Get existing user or create new one. | |
| Called after successful Google OAuth login. | |
| """ | |
| client = await self._get_client() | |
| # Try to find existing user | |
| result = await client.table("users").select("*").eq("google_id", google_id).execute() | |
| if result.data: | |
| user_data = result.data[0] | |
| logger.info("User found", user_id=user_data["id"], google_id=google_id) | |
| return User(**user_data) | |
| # Create new user | |
| new_user = { | |
| "google_id": google_id, | |
| "email": email, | |
| "display_name": display_name, | |
| "avatar_url": avatar_url, | |
| "is_premium": False, | |
| "preferred_mode": "free", | |
| } | |
| result = await client.table("users").insert(new_user).execute() | |
| user_data = result.data[0] | |
| logger.info("User created", user_id=user_data["id"], google_id=google_id) | |
| return User(**user_data) | |
| async def get_user_by_id(self, user_id: str) -> Optional[User]: | |
| """Get user by their UUID.""" | |
| client = await self._get_client() | |
| result = await client.table("users").select("*").eq("id", user_id).execute() | |
| if result.data: | |
| return User(**result.data[0]) | |
| return None | |
| async def get_user_by_google_id(self, google_id: str) -> Optional[User]: | |
| """Get user by their Google ID.""" | |
| client = await self._get_client() | |
| result = await client.table("users").select("*").eq("google_id", google_id).execute() | |
| if result.data: | |
| return User(**result.data[0]) | |
| return None | |
| async def update_user_mode(self, user_id: str, mode: VerificationMode) -> Optional[User]: | |
| """ | |
| Update user's preferred mode. | |
| Only premium users can change their mode. | |
| """ | |
| client = await self._get_client() | |
| # First check if user is premium | |
| user = await self.get_user_by_id(user_id) | |
| if not user: | |
| logger.warning("User not found", user_id=user_id) | |
| return None | |
| if not user.is_premium: | |
| logger.warning("Non-premium user attempted mode change", user_id=user_id) | |
| return None | |
| # Update the mode | |
| result = await client.table("users").update({ | |
| "preferred_mode": mode.value | |
| }).eq("id", user_id).execute() | |
| if result.data: | |
| logger.info("User mode updated", user_id=user_id, mode=mode.value) | |
| return User(**result.data[0]) | |
| return None | |
| async def set_premium_status(self, user_id: str, is_premium: bool) -> Optional[User]: | |
| """ | |
| Set user's premium status. | |
| Admin-only operation. | |
| """ | |
| client = await self._get_client() | |
| update_data = {"is_premium": is_premium} | |
| # If removing premium, reset to free mode | |
| if not is_premium: | |
| update_data["preferred_mode"] = "free" | |
| result = await client.table("users").update(update_data).eq("id", user_id).execute() | |
| if result.data: | |
| logger.info("User premium status updated", user_id=user_id, is_premium=is_premium) | |
| return User(**result.data[0]) | |
| return None | |
| async def get_verification_mode(self, user_id: Optional[str]) -> VerificationMode: | |
| """ | |
| Get the verification mode for a user. | |
| Returns FREE if user is not found or not premium. | |
| """ | |
| if not user_id: | |
| return VerificationMode.FREE | |
| user = await self.get_user_by_id(user_id) | |
| if not user: | |
| return VerificationMode.FREE | |
| return user.get_verification_mode() | |
| # ============================================================================ | |
| # Singleton Instance | |
| # ============================================================================ | |
| _user_service: Optional[UserService] = None | |
| def get_user_service() -> UserService: | |
| """Get the singleton UserService instance.""" | |
| global _user_service | |
| if _user_service is None: | |
| _user_service = UserService() | |
| return _user_service | |