feat: Enforce Automatic Token Limits in AI Handlers

CMS Service:
- generate_quiz: Check 2000 tokens limit
- generate_course: Check 5000 tokens limit
- generate_hotspots: Check 2000 tokens limit
- generate_role_play: Check 2500 tokens limit
- summarize_lesson: Check 1500 tokens limit

LMS Service:
- chat_with_tutor: Check 1000 tokens limit
- evaluate_audio_response: Check 1500 tokens limit

Behavior:
- Returns HTTP 429 Too Many Requests when limit exceeded
- Error message indicates monthly limit exceeded
- Users must contact admin for limit increase
- Works with automatic alert system (Phase 3)

Total Functions Protected: 7

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
2026-03-23 17:18:04 -03:00
parent 173ddfae53
commit 6ef2860b26
2 changed files with 40 additions and 5 deletions
+11 -1
View File
@@ -2102,9 +2102,14 @@ pub async fn get_recommendations(
pub async fn evaluate_audio_response(
Org(_org_ctx): Org,
_claims: Claims,
claims: Claims,
Json(payload): Json<AudioGradingPayload>,
) -> Result<Json<AudioGradingResponse>, (StatusCode, String)> {
// Check token limit before proceeding (estimate 1500 tokens for audio evaluation)
if let Err(_) = common::token_limits::check_ai_token_limit(&pool, claims.sub, 1500).await {
return Err((StatusCode::TOO_MANY_REQUESTS, "Token limit exceeded".to_string()));
}
let client = reqwest::Client::new();
let provider = env::var("AI_PROVIDER").unwrap_or_else(|_| "openai".to_string());
@@ -2496,6 +2501,11 @@ pub async fn chat_with_tutor(
Path(lesson_id): Path<Uuid>,
Json(payload): Json<ChatPayload>,
) -> Result<Json<ChatResponse>, (StatusCode, String)> {
// Check token limit before proceeding (estimate 1000 tokens for chat)
if let Err(_) = common::token_limits::check_ai_token_limit(&pool, claims.sub, 1000).await {
return Err((StatusCode::TOO_MANY_REQUESTS, "Monthly AI token limit exceeded. Please contact your administrator.".to_string()));
}
// 1. Fetch lesson context with access check (matches get_lesson_content)
let is_preview = claims.token_type.as_deref() == Some("preview");