paulhemb commited on
Commit
5b287c8
·
verified ·
1 Parent(s): 4239c63

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +27 -26
main.py CHANGED
@@ -13,7 +13,7 @@ from models import (
13
  from reddit_client import RedditClient
14
  from analyzer import call_groq_for_insight
15
  from serp_client import get_search_volume, search_competitors, search_funding_news
16
- from supabase_client import supabase
17
  from config import GROQ_MODEL, GROQ_API_KEY, SUPABASE_JWT_SECRET
18
 
19
  # Groq client is imported in analyzer
@@ -22,7 +22,7 @@ reddit_client = RedditClient()
22
 
23
  app = FastAPI(title="Founder Intelligence Engine API", version="2.0")
24
 
25
- # CORS – allow all origins for development; restrict in production
26
  app.add_middleware(
27
  CORSMiddleware,
28
  allow_origins=["*"],
@@ -42,19 +42,19 @@ async def root():
42
  @app.post("/auth/signup", response_model=UserProfile)
43
  async def signup(user: UserSignup):
44
  try:
45
- # 1. Create auth user
46
- response = supabase.auth.sign_up({
47
  "email": user.email,
48
  "password": user.password,
49
  "options": {"data": {"full_name": user.full_name}}
50
  })
51
  user_data = response.user
52
 
53
- # 2. Check if profile already exists (e.g., from a previous attempt)
54
- existing = supabase.table("profiles").select("*").eq("id", user_data.id).execute()
55
  if not existing.data:
56
  # Create profile record
57
- supabase.table("profiles").insert({
58
  "id": user_data.id,
59
  "email": user_data.email,
60
  "full_name": user.full_name,
@@ -73,13 +73,12 @@ async def signup(user: UserSignup):
73
  )
74
  except Exception as e:
75
  # If the user already exists in auth but not in profiles, we can still return a helpful message
76
- # But Supabase will raise an exception for duplicate email.
77
  raise HTTPException(status_code=400, detail=str(e))
78
 
79
  @app.post("/auth/login")
80
  async def login(creds: UserLogin):
81
  try:
82
- response = supabase.auth.sign_in_with_password({
83
  "email": creds.email,
84
  "password": creds.password
85
  })
@@ -89,34 +88,40 @@ async def login(creds: UserLogin):
89
 
90
  @app.get("/auth/me", response_model=UserProfile)
91
  async def get_me(user=Depends(get_current_user)):
 
 
 
 
 
 
92
  return UserProfile(
93
  id=user["id"],
94
  email=user["email"],
95
- full_name=user["profile"]["full_name"],
96
- subscription_tier=user["profile"]["subscription_tier"],
97
- subscription_status=user["profile"]["subscription_status"],
98
- created_at=user["profile"]["created_at"]
99
  )
100
 
101
  # ====================== Subscription Plans ======================
102
  @app.get("/plans", response_model=List[SubscriptionPlan])
103
  async def list_plans():
104
- plans = supabase.table("plans").select("*").execute()
105
  return [SubscriptionPlan(**p) for p in plans.data]
106
 
107
  # ====================== Helper: Check subscription limits ======================
108
  def check_subscription_limit(user_id: str, requested_posts: int):
109
  """Raise 403 if user exceeds plan limits."""
110
- profile = supabase.table("profiles").select("subscription_tier").eq("id", user_id).execute()
111
  tier = profile.data[0]["subscription_tier"] if profile.data else "free"
112
  # Fetch plan features
113
- plan = supabase.table("plans").select("features").eq("name", tier.capitalize()).execute()
114
  if plan.data:
115
  features = plan.data[0]["features"]
116
  posts_limit = features.get("posts_per_month", 10) # default free limit
117
  # Count posts this month for this user
118
  start_of_month = datetime.now().replace(day=1, hour=0, minute=0, second=0).isoformat()
119
- count_res = supabase.table("insights").select("id", count="exact").eq("user_id", user_id).gte("created_at", start_of_month).execute()
120
  current_count = count_res.count if hasattr(count_res, 'count') else 0
121
  if current_count + requested_posts > posts_limit:
122
  raise HTTPException(status_code=403, detail=f"Monthly post limit of {posts_limit} reached. Upgrade your plan.")
@@ -152,8 +157,8 @@ async def analyze(request: AnalysisRequest, user=Depends(get_current_user)):
152
  "insight_data": insight,
153
  "opportunity_score": insight["opportunity_score"]
154
  }
155
- # Insert into Supabase
156
- supabase.table("insights").insert(result).execute()
157
  all_results.append({
158
  "subreddit": sub,
159
  "post_title": post.get("title"),
@@ -166,7 +171,7 @@ async def analyze(request: AnalysisRequest, user=Depends(get_current_user)):
166
 
167
  @app.get("/insights", response_model=List[InsightResponse])
168
  async def get_insights(user=Depends(get_current_user)):
169
- res = supabase.table("insights").select("*").eq("user_id", user["id"]).order("created_at", desc=True).execute()
170
  insights = []
171
  for row in res.data:
172
  insights.append(InsightResponse(
@@ -183,15 +188,13 @@ async def get_insights(user=Depends(get_current_user)):
183
  # ====================== Query / RAG ======================
184
  @app.post("/query", response_model=QueryResponse)
185
  async def query_insights(request: QueryRequest, user=Depends(get_current_user)):
186
- # Simple keyword search over user's insights (full text search on insight_data)
187
- insights = supabase.table("insights").select("*").eq("user_id", user["id"]).execute()
188
  relevant = []
189
  for row in insights.data:
190
  data = row["insight_data"]
191
  text = f"{data.get('burning_pain','')} {data.get('startup_idea','')} {data.get('customer_type','')}"
192
  if request.query.lower() in text.lower():
193
  relevant.append(row)
194
- # If no exact matches, return top N by opportunity_score
195
  if not relevant:
196
  relevant = sorted(insights.data, key=lambda x: x["opportunity_score"], reverse=True)[:request.n_results]
197
  else:
@@ -200,9 +203,7 @@ async def query_insights(request: QueryRequest, user=Depends(get_current_user)):
200
  if not relevant:
201
  raise HTTPException(status_code=404, detail="No relevant insights found")
202
 
203
- # Build context
204
  context = "\n\n".join([f"From r/{r['subreddit']}: {r['insight_data'].get('burning_pain','')} {r['insight_data'].get('startup_idea','')}" for r in relevant])
205
- # Call Groq to answer
206
  from groq import Groq
207
  groq = Groq(api_key=GROQ_API_KEY)
208
  try:
@@ -259,7 +260,7 @@ Insight: {request.insight}
259
  # ====================== Trends ======================
260
  @app.get("/trends", response_model=TrendResponse)
261
  async def trends(subreddit: str = None, user=Depends(get_current_user)):
262
- query = supabase.table("insights").select("timestamp", "subreddit").eq("user_id", user["id"])
263
  if subreddit:
264
  query = query.eq("subreddit", subreddit)
265
  res = query.execute()
 
13
  from reddit_client import RedditClient
14
  from analyzer import call_groq_for_insight
15
  from serp_client import get_search_volume, search_competitors, search_funding_news
16
+ from supabase_client import supabase_auth, supabase_db
17
  from config import GROQ_MODEL, GROQ_API_KEY, SUPABASE_JWT_SECRET
18
 
19
  # Groq client is imported in analyzer
 
22
 
23
  app = FastAPI(title="Founder Intelligence Engine API", version="2.0")
24
 
25
+ # CORS
26
  app.add_middleware(
27
  CORSMiddleware,
28
  allow_origins=["*"],
 
42
  @app.post("/auth/signup", response_model=UserProfile)
43
  async def signup(user: UserSignup):
44
  try:
45
+ # 1. Create auth user (using anon client)
46
+ response = supabase_auth.auth.sign_up({
47
  "email": user.email,
48
  "password": user.password,
49
  "options": {"data": {"full_name": user.full_name}}
50
  })
51
  user_data = response.user
52
 
53
+ # 2. Check if profile already exists (using service client to bypass RLS)
54
+ existing = supabase_db.table("profiles").select("*").eq("id", user_data.id).execute()
55
  if not existing.data:
56
  # Create profile record
57
+ supabase_db.table("profiles").insert({
58
  "id": user_data.id,
59
  "email": user_data.email,
60
  "full_name": user.full_name,
 
73
  )
74
  except Exception as e:
75
  # If the user already exists in auth but not in profiles, we can still return a helpful message
 
76
  raise HTTPException(status_code=400, detail=str(e))
77
 
78
  @app.post("/auth/login")
79
  async def login(creds: UserLogin):
80
  try:
81
+ response = supabase_auth.auth.sign_in_with_password({
82
  "email": creds.email,
83
  "password": creds.password
84
  })
 
88
 
89
  @app.get("/auth/me", response_model=UserProfile)
90
  async def get_me(user=Depends(get_current_user)):
91
+ # user already contains profile info from the token validation
92
+ # but we can fetch fresh profile from DB if needed
93
+ profile = supabase_db.table("profiles").select("*").eq("id", user["id"]).execute()
94
+ if not profile.data:
95
+ raise HTTPException(status_code=404, detail="Profile not found")
96
+ p = profile.data[0]
97
  return UserProfile(
98
  id=user["id"],
99
  email=user["email"],
100
+ full_name=p["full_name"],
101
+ subscription_tier=p["subscription_tier"],
102
+ subscription_status=p["subscription_status"],
103
+ created_at=p["created_at"]
104
  )
105
 
106
  # ====================== Subscription Plans ======================
107
  @app.get("/plans", response_model=List[SubscriptionPlan])
108
  async def list_plans():
109
+ plans = supabase_db.table("plans").select("*").execute()
110
  return [SubscriptionPlan(**p) for p in plans.data]
111
 
112
  # ====================== Helper: Check subscription limits ======================
113
  def check_subscription_limit(user_id: str, requested_posts: int):
114
  """Raise 403 if user exceeds plan limits."""
115
+ profile = supabase_db.table("profiles").select("subscription_tier").eq("id", user_id).execute()
116
  tier = profile.data[0]["subscription_tier"] if profile.data else "free"
117
  # Fetch plan features
118
+ plan = supabase_db.table("plans").select("features").eq("name", tier.capitalize()).execute()
119
  if plan.data:
120
  features = plan.data[0]["features"]
121
  posts_limit = features.get("posts_per_month", 10) # default free limit
122
  # Count posts this month for this user
123
  start_of_month = datetime.now().replace(day=1, hour=0, minute=0, second=0).isoformat()
124
+ count_res = supabase_db.table("insights").select("id", count="exact").eq("user_id", user_id).gte("created_at", start_of_month).execute()
125
  current_count = count_res.count if hasattr(count_res, 'count') else 0
126
  if current_count + requested_posts > posts_limit:
127
  raise HTTPException(status_code=403, detail=f"Monthly post limit of {posts_limit} reached. Upgrade your plan.")
 
157
  "insight_data": insight,
158
  "opportunity_score": insight["opportunity_score"]
159
  }
160
+ # Insert into Supabase using service client
161
+ supabase_db.table("insights").insert(result).execute()
162
  all_results.append({
163
  "subreddit": sub,
164
  "post_title": post.get("title"),
 
171
 
172
  @app.get("/insights", response_model=List[InsightResponse])
173
  async def get_insights(user=Depends(get_current_user)):
174
+ res = supabase_db.table("insights").select("*").eq("user_id", user["id"]).order("created_at", desc=True).execute()
175
  insights = []
176
  for row in res.data:
177
  insights.append(InsightResponse(
 
188
  # ====================== Query / RAG ======================
189
  @app.post("/query", response_model=QueryResponse)
190
  async def query_insights(request: QueryRequest, user=Depends(get_current_user)):
191
+ insights = supabase_db.table("insights").select("*").eq("user_id", user["id"]).execute()
 
192
  relevant = []
193
  for row in insights.data:
194
  data = row["insight_data"]
195
  text = f"{data.get('burning_pain','')} {data.get('startup_idea','')} {data.get('customer_type','')}"
196
  if request.query.lower() in text.lower():
197
  relevant.append(row)
 
198
  if not relevant:
199
  relevant = sorted(insights.data, key=lambda x: x["opportunity_score"], reverse=True)[:request.n_results]
200
  else:
 
203
  if not relevant:
204
  raise HTTPException(status_code=404, detail="No relevant insights found")
205
 
 
206
  context = "\n\n".join([f"From r/{r['subreddit']}: {r['insight_data'].get('burning_pain','')} {r['insight_data'].get('startup_idea','')}" for r in relevant])
 
207
  from groq import Groq
208
  groq = Groq(api_key=GROQ_API_KEY)
209
  try:
 
260
  # ====================== Trends ======================
261
  @app.get("/trends", response_model=TrendResponse)
262
  async def trends(subreddit: str = None, user=Depends(get_current_user)):
263
+ query = supabase_db.table("insights").select("timestamp", "subreddit").eq("user_id", user["id"])
264
  if subreddit:
265
  query = query.eq("subreddit", subreddit)
266
  res = query.execute()