Welcome back
-+
Sign in to your account to continue
+diff --git a/Backend/app/routes/ai.py b/Backend/app/routes/ai.py index a21a482..8427dce 100644 --- a/Backend/app/routes/ai.py +++ b/Backend/app/routes/ai.py @@ -11,22 +11,53 @@ # Initialize router router = APIRouter() -# Load environment variables for Supabase and Gemini -SUPABASE_URL = os.environ.get("SUPABASE_URL") -SUPABASE_KEY = os.environ.get("SUPABASE_KEY") -GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY") +# Cache for the lazily-created Supabase client so it is built only once. +_supabase_client: Client | None = None -# Validate required environment variables -if not all([SUPABASE_URL, SUPABASE_KEY, GEMINI_API_KEY]): - raise ValueError("Missing required environment variables: SUPABASE_URL, SUPABASE_KEY, GEMINI_API_KEY") -supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY) +def get_supabase_client() -> Client: + """ + Lazily create and return the Supabase client. + + Reading the environment variables and constructing the client is deferred + to request time so that importing this module never crashes the whole app + when the required variables are missing. If the configuration is absent we + raise an HTTPException so only the AI endpoints fail (with a clear 503), + not unrelated routes. + """ + global _supabase_client + if _supabase_client is not None: + return _supabase_client + + supabase_url = os.environ.get("SUPABASE_URL") + supabase_key = os.environ.get("SUPABASE_KEY") + if not supabase_url or not supabase_key: + raise HTTPException( + status_code=503, + detail="AI service is not configured: missing SUPABASE_URL and/or SUPABASE_KEY.", + ) + + _supabase_client = create_client(supabase_url, supabase_key) + return _supabase_client + + +def get_gemini_api_key() -> str: + """Return the Gemini API key, raising a clear 503 if it is not configured.""" + gemini_api_key = os.environ.get("GEMINI_API_KEY") + if not gemini_api_key: + raise HTTPException( + status_code=503, + detail="AI service is not configured: missing GEMINI_API_KEY.", + ) + return gemini_api_key + def fetch_from_gemini(): prompt = ( "List the top 6 trending content niches for creators and brands this week. For each, provide: name (the niche), insight (a short qualitative reason why it's trending), and global_activity (a number from 1 to 5, where 5 means very high global activity in this category, and 1 means low).Return as a JSON array of objects with keys: name, insight, global_activity." ) - url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-lite:generateContent?key={GEMINI_API_KEY}" + gemini_api_key = get_gemini_api_key() + url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-lite:generateContent?key={gemini_api_key}" # Set up retry strategy retry_strategy = Retry( total=3, @@ -60,6 +91,7 @@ def trending_niches(): - Otherwise, fetch from Gemini, store in Supabase, and return the new data. - If Gemini fails, fallback to the most recent data available. """ + supabase = get_supabase_client() today = str(date.today()) # Check if today's data exists in Supabase result = supabase.table("trending_niches").select("*").eq("fetched_at", today).execute() @@ -75,6 +107,8 @@ def trending_niches(): "fetched_at": today }).execute() result = supabase.table("trending_niches").select("*").eq("fetched_at", today).execute() + except HTTPException: + raise except Exception as e: print("Gemini fetch failed:", e) # fallback: serve most recent data diff --git a/Frontend/src/pages/Login.tsx b/Frontend/src/pages/Login.tsx index 875567a..ab220bb 100644 --- a/Frontend/src/pages/Login.tsx +++ b/Frontend/src/pages/Login.tsx @@ -1,12 +1,9 @@ import { useState } from "react"; -import { Link, useNavigate } from "react-router-dom"; +import { Link } from "react-router-dom"; import { Eye, EyeOff, Rocket } from "lucide-react"; import { supabase } from "../utils/supabase"; -import { useAuth } from "../context/AuthContext"; export default function LoginPage() { - const Navigate = useNavigate(); - const { login } = useAuth(); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [showPassword, setShowPassword] = useState(false); @@ -19,7 +16,7 @@ export default function LoginPage() { setError(""); try { - const { data, error } = await supabase.auth.signInWithPassword({ + const { error } = await supabase.auth.signInWithPassword({ email, password, }); @@ -32,7 +29,7 @@ export default function LoginPage() { // AuthContext will handle navigation based on user onboarding status and role setIsLoading(false); - } catch (err) { + } catch { setError("Invalid email or password. Please try again."); } finally { setIsLoading(false); @@ -40,7 +37,7 @@ export default function LoginPage() { }; const handleGoogleLogin = async () => { - const { data, error } = await supabase.auth.signInWithOAuth({ + const { error } = await supabase.auth.signInWithOAuth({ provider: "google", }); @@ -53,190 +50,204 @@ export default function LoginPage() { }; return ( -
+
Sign in to your account to continue
+