Hamdy005 commited on
Commit
ca22acf
·
1 Parent(s): 6a2fe0d

refactor: decouple usage increment from rate limit checks, add session refresh error handling.

Browse files
quiz_generator/routes.py CHANGED
@@ -3,7 +3,7 @@ import logging
3
  from fastapi import APIRouter, HTTPException, Depends
4
  from typing import Optional
5
  from src.quiz_generator.quiz import smart_quiz_generator
6
- from src.store import get_material, get_chunks, get_summary, save_quiz, get_quizzes, save_quiz_result, get_quiz_results, check_and_increment_daily_limit
7
  from src.dependencies import get_current_user_id, get_current_user
8
  from src.config import settings
9
  from .schemas import QuizRequest, QuizResponse, SaveQuizResultRequest
@@ -35,7 +35,7 @@ async def generate_quiz(
35
  ):
36
  # Rate limit check
37
  user_email = current_user.get("email") if isinstance(current_user, dict) else getattr(current_user, "email", None)
38
- if not check_and_increment_daily_limit(user_id, email=user_email, limit=20):
39
  raise HTTPException(429, "Daily limit of 20 requests reached. Come back tomorrow!")
40
 
41
  body.difficulty = body.difficulty.capitalize()
@@ -109,6 +109,10 @@ async def generate_quiz(
109
  model_name=settings.model_name,
110
  )
111
 
 
 
 
 
112
  return QuizResponse(quiz=quiz, quiz_id=saved["id"])
113
  except ValueError as e:
114
  logger.warning(f"Validation error in generate_quiz: {str(e)}")
 
3
  from fastapi import APIRouter, HTTPException, Depends
4
  from typing import Optional
5
  from src.quiz_generator.quiz import smart_quiz_generator
6
+ from src.store import get_material, get_chunks, get_summary, save_quiz, get_quizzes, save_quiz_result, get_quiz_results, check_daily_limit, increment_daily_usage, ADMIN_EMAILS
7
  from src.dependencies import get_current_user_id, get_current_user
8
  from src.config import settings
9
  from .schemas import QuizRequest, QuizResponse, SaveQuizResultRequest
 
35
  ):
36
  # Rate limit check
37
  user_email = current_user.get("email") if isinstance(current_user, dict) else getattr(current_user, "email", None)
38
+ if not check_daily_limit(user_id, email=user_email, limit=20):
39
  raise HTTPException(429, "Daily limit of 20 requests reached. Come back tomorrow!")
40
 
41
  body.difficulty = body.difficulty.capitalize()
 
109
  model_name=settings.model_name,
110
  )
111
 
112
+ # Only increment limit if the quiz was generated successfully and saved without error
113
+ if not (user_email and user_email in ADMIN_EMAILS):
114
+ increment_daily_usage(user_id)
115
+
116
  return QuizResponse(quiz=quiz, quiz_id=saved["id"])
117
  except ValueError as e:
118
  logger.warning(f"Validation error in generate_quiz: {str(e)}")
rag/rag.py CHANGED
@@ -163,7 +163,7 @@ def get_quiz_llm():
163
  model=settings.model_name,
164
  api_key=settings.gemini_api_key,
165
  temperature=0.3,
166
- max_output_tokens=16000,
167
  timeout=300,
168
  )
169
 
 
163
  model=settings.model_name,
164
  api_key=settings.gemini_api_key,
165
  temperature=0.3,
166
+ max_output_tokens=12000,
167
  timeout=300,
168
  )
169
 
store.py CHANGED
@@ -646,16 +646,11 @@ def get_or_create_memory(memory_id: Optional[str] = None, seed_messages: list[di
646
  return mem, mid
647
 
648
 
649
- def check_and_increment_daily_limit(user_id: str, email: Optional[str] = None, limit: int = 20) -> bool:
650
  """
651
- Returns True if request is allowed, False if limit exceeded.
652
- Excludes Admin Emails from Limits.
653
-
654
- Bypasses the database RPC (which runs in UTC and resets at 3 AM Egypt time)
655
- to perform the date check in python using Egypt local timezone (UTC+3),
656
- ensuring limits reset exactly at 12 AM Egypt time.
657
  """
658
- # Guard: never apply limit to admin emails
659
  if email and email in ADMIN_EMAILS:
660
  return True
661
 
@@ -678,16 +673,51 @@ def check_and_increment_daily_limit(user_id: str, email: Optional[str] = None, l
678
  count = 0
679
  if count >= limit:
680
  return False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
681
 
682
  _robust_execute(
683
  _table_supabase("profiles")
684
  .update({"daily_requests": count + 1, "last_request_date": today})
685
  .eq("id", user_id)
686
  )
687
- return True
688
  except Exception as e:
689
- logger.error(f"Rate limit check failed: {e}")
690
- return True
 
 
 
 
 
 
 
 
 
691
 
692
 
693
  def get_usage(user_id: str) -> dict:
 
646
  return mem, mid
647
 
648
 
649
+ def check_daily_limit(user_id: str, email: Optional[str] = None, limit: int = 20) -> bool:
650
  """
651
+ Checks if the user is under the daily limit. Returns True if allowed, False if exceeded.
652
+ Does NOT increment the count.
 
 
 
 
653
  """
 
654
  if email and email in ADMIN_EMAILS:
655
  return True
656
 
 
673
  count = 0
674
  if count >= limit:
675
  return False
676
+ return True
677
+ except Exception as e:
678
+ logger.error(f"Rate limit check failed: {e}")
679
+ return True
680
+
681
+
682
+ def increment_daily_usage(user_id: str) -> None:
683
+ """
684
+ Increments the daily request count for the user.
685
+ """
686
+ today = _get_today_date_str()
687
+ try:
688
+ result = _robust_execute(
689
+ _table_supabase("profiles")
690
+ .select("daily_requests, last_request_date")
691
+ .eq("id", user_id)
692
+ )
693
+ if not result.data:
694
+ return
695
+ profile = result.data[0] if result.data else None
696
+ if not profile:
697
+ return
698
+
699
+ last_date = profile.get("last_request_date")
700
+ count = profile.get("daily_requests", 0) or 0
701
+ if last_date != today:
702
+ count = 0
703
 
704
  _robust_execute(
705
  _table_supabase("profiles")
706
  .update({"daily_requests": count + 1, "last_request_date": today})
707
  .eq("id", user_id)
708
  )
 
709
  except Exception as e:
710
+ logger.error(f"Failed to increment daily usage: {e}")
711
+
712
+
713
+ def check_and_increment_daily_limit(user_id: str, email: Optional[str] = None, limit: int = 20) -> bool:
714
+ """
715
+ Check limit and increment if allowed. Deprecated/kept for compatibility.
716
+ """
717
+ allowed = check_daily_limit(user_id, email, limit)
718
+ if allowed and not (email and email in ADMIN_EMAILS):
719
+ increment_daily_usage(user_id)
720
+ return allowed
721
 
722
 
723
  def get_usage(user_id: str) -> dict:
summary_generator/routes.py CHANGED
@@ -4,7 +4,7 @@ import logging
4
  from fastapi import APIRouter, HTTPException, Depends
5
 
6
  from src.summary_generator.summary import summarizer, web_summarizer
7
- from src.store import get_material, get_chunks, save_summary, get_summary as get_stored_summary, check_and_increment_daily_limit
8
  from src.dependencies import get_current_user_id, get_current_user
9
  from src.config import settings
10
  from .schemas import SummarizeRequest, SummarizeResponse
@@ -22,7 +22,7 @@ async def generate_summary(
22
  ):
23
  # Rate limit check
24
  user_email = current_user.get("email") if isinstance(current_user, dict) else getattr(current_user, "email", None)
25
- if not check_and_increment_daily_limit(user_id, email=user_email, limit=20):
26
  raise HTTPException(429, "Daily limit of 20 requests reached. Come back tomorrow!")
27
 
28
  mat = get_material(body.material_id)
@@ -58,6 +58,10 @@ async def generate_summary(
58
  model_name=settings.model_name,
59
  )
60
 
 
 
 
 
61
  return SummarizeResponse(summary=summary, time_taken=elapsed)
62
  except Exception as e:
63
  raise HTTPException(500, f"Summarization failed: {e}")
 
4
  from fastapi import APIRouter, HTTPException, Depends
5
 
6
  from src.summary_generator.summary import summarizer, web_summarizer
7
+ from src.store import get_material, get_chunks, save_summary, get_summary as get_stored_summary, check_daily_limit, increment_daily_usage
8
  from src.dependencies import get_current_user_id, get_current_user
9
  from src.config import settings
10
  from .schemas import SummarizeRequest, SummarizeResponse
 
22
  ):
23
  # Rate limit check
24
  user_email = current_user.get("email") if isinstance(current_user, dict) else getattr(current_user, "email", None)
25
+ if not check_daily_limit(user_id, email=user_email, limit=20):
26
  raise HTTPException(429, "Daily limit of 20 requests reached. Come back tomorrow!")
27
 
28
  mat = get_material(body.material_id)
 
58
  model_name=settings.model_name,
59
  )
60
 
61
+ # Only increment limit if the summary was generated successfully and saved without error
62
+ if not (user_email and user_email in settings.admin_emails if hasattr(settings, "admin_emails") else False):
63
+ increment_daily_usage(user_id)
64
+
65
  return SummarizeResponse(summary=summary, time_taken=elapsed)
66
  except Exception as e:
67
  raise HTTPException(500, f"Summarization failed: {e}")