diff --git a/Backend/app/db/db.py b/Backend/app/db/db.py index ae0f517..a72e1c0 100644 --- a/Backend/app/db/db.py +++ b/Backend/app/db/db.py @@ -19,6 +19,12 @@ # Initialize async SQLAlchemy components try: + # Supabase (and some other cloud providers) may have issues with IPv6. + # We can try to force parameters or handle connection logic robustly. + # For now, we wrap the engine creation in a try-except block to prevent + # the entire app from crashing if credentials are wrong or DB is unreachable. + + # "ssl": "require" is critical for Supabase connections engine = create_async_engine( DATABASE_URL, echo=True, connect_args={"ssl": "require"} ) @@ -30,11 +36,24 @@ print("✅ Database connected successfully!") except SQLAlchemyError as e: print(f"❌ Error connecting to the database: {e}") + # Set to None so main.py can check against them engine = None AsyncSessionLocal = None Base = None async def get_db(): + """ + Dependency generator for database sessions. + + Yields: + AsyncSession: An asynchronous database session. + + Raises: + RuntimeError: If the database engine is not initialized. + """ + if AsyncSessionLocal is None: + raise RuntimeError("Database engine is not initialized. Check your connection settings.") + async with AsyncSessionLocal() as session: yield session diff --git a/Backend/app/main.py b/Backend/app/main.py index 86d892a..fc75033 100644 --- a/Backend/app/main.py +++ b/Backend/app/main.py @@ -19,6 +19,17 @@ # Async function to create database tables with exception handling async def create_tables(): + """ + Creates database tables asynchronously if the database engine is available. + + This function attempts to create all tables defined in the SQLAlchemy models + (models.Base and chat.Base). It handles cases where the database engine + might not be initialized due to connection errors. + """ + if engine is None: + print("⚠️ Database engine is not available. Skipping table creation.") + return + try: async with engine.begin() as conn: await conn.run_sync(models.Base.metadata.create_all) @@ -31,9 +42,22 @@ async def create_tables(): # Lifespan context manager for startup and shutdown events @asynccontextmanager async def lifespan(app: FastAPI): + """ + Lifespan context manager for the FastAPI application. + + Handles startup and shutdown events. On startup, it attempts to + create database tables and seed the database. + + Args: + app (FastAPI): The FastAPI application instance. + """ print("App is starting...") await create_tables() - await seed_db() + # verify engine is not None before seeding + if engine: + await seed_db() + else: + print("⚠️ Database engine is not available. Skipping data seeding.") yield print("App is shutting down...") @@ -60,6 +84,12 @@ async def lifespan(app: FastAPI): @app.get("/") async def home(): + """ + Root endpoint for the API. + + Returns: + dict: A welcome message. + """ try: return {"message": "Welcome to Inpact API!"} except Exception as e: diff --git a/Backend/app/services/db_service.py b/Backend/app/services/db_service.py index ccb4199..f71f649 100644 --- a/Backend/app/services/db_service.py +++ b/Backend/app/services/db_service.py @@ -11,6 +11,20 @@ def match_creators_for_brand(sponsorship_id: str) -> List[Dict[str, Any]]: + """ + Finds creator matches for a given brand sponsorship. + + Analyzes audience insights for all creators and calculates a match score + based on the sponsorship's requirements (age, location, engagement rate, budget). + + Args: + sponsorship_id (str): The unique identifier of the sponsorship. + + Returns: + List[Dict[str, Any]]: A list of matching creators, including their match details. + Returns an empty list if the sponsorship is not found or + no suitable creators are found. + """ # Fetch sponsorship details sponsorship_resp = supabase.table("sponsorships").select("*").eq("id", sponsorship_id).execute() if not sponsorship_resp.data: @@ -49,6 +63,20 @@ def match_creators_for_brand(sponsorship_id: str) -> List[Dict[str, Any]]: def match_brands_for_creator(creator_id: str) -> List[Dict[str, Any]]: + """ + Finds brand sponsorship matches for a given creator. + + Analyzes all available sponsorships and calculates a match score based on + the creator's audience insights (age, location, engagement, price). + + Args: + creator_id (str): The unique identifier of the creator. + + Returns: + List[Dict[str, Any]]: A list of matching sponsorships, including their match details. + Returns an empty list if the creator's audience data is not found + or no suitable sponsorships are found. + """ # Fetch creator's audience insights audience_resp = supabase.table("audience_insights").select("*").eq("user_id", creator_id).execute() if not audience_resp.data: