From d892ab3174e0fb4d3265594dd3bae8a4fd337586 Mon Sep 17 00:00:00 2001 From: Debanjum Date: Sat, 9 Nov 2024 11:30:55 -0800 Subject: [PATCH] Fix handling of command rate limit and improve rate limit messages Command rate limit wouldn't be shown to user as server wouldn't be able to handle HTTP exception in the middle of streaming. Catch exception and render it as LLM response message instead for visibility into command rate limiting to user on client Log rate limmit messages for all rate limit events on server as info messages Convert exception messages into first person responses by Khoj to prevent breaking the third wall and provide more details on wht happened and possible ways to resolve them. --- src/khoj/routers/api_chat.py | 13 ++++---- src/khoj/routers/helpers.py | 63 ++++++++++++++++++++++++------------ 2 files changed, 50 insertions(+), 26 deletions(-) diff --git a/src/khoj/routers/api_chat.py b/src/khoj/routers/api_chat.py index a20982ea..8646a695 100644 --- a/src/khoj/routers/api_chat.py +++ b/src/khoj/routers/api_chat.py @@ -738,8 +738,13 @@ async def chat( conversation_commands.append(mode) for cmd in conversation_commands: - await conversation_command_rate_limiter.update_and_check_if_valid(request, cmd) - q = q.replace(f"/{cmd.value}", "").strip() + try: + await conversation_command_rate_limiter.update_and_check_if_valid(request, cmd) + q = q.replace(f"/{cmd.value}", "").strip() + except HTTPException as e: + async for result in send_llm_response(str(e.detail)): + yield result + return defiltered_query = defilter_query(q) @@ -775,10 +780,6 @@ async def chat( # researched_results = await extract_relevant_info(q, researched_results, agent) logger.info(f"Researched Results: {researched_results}") - for cmd in conversation_commands: - await conversation_command_rate_limiter.update_and_check_if_valid(request, cmd) - q = q.replace(f"/{cmd.value}", "").strip() - used_slash_summarize = conversation_commands == [ConversationCommand.Summarize] file_filters = conversation.file_filters if conversation else [] # Skip trying to summarize if diff --git a/src/khoj/routers/helpers.py b/src/khoj/routers/helpers.py index 990fa33f..c7a90fc3 100644 --- a/src/khoj/routers/helpers.py +++ b/src/khoj/routers/helpers.py @@ -1306,25 +1306,28 @@ class ApiUserRateLimiter: # Check if the user has exceeded the rate limit if subscribed and count_requests >= self.subscribed_requests: logger.info( - f"Rate limit: {count_requests} requests in {self.window} seconds for user: {user}. Limit is {self.subscribed_requests} requests." - ) - raise HTTPException(status_code=429, detail="Slow down! Too Many Requests") - if not subscribed and count_requests >= self.requests: - if self.requests >= self.subscribed_requests: - logger.info( - f"Rate limit: {count_requests} requests in {self.window} seconds for user: {user}. Limit is {self.subscribed_requests} requests." - ) - raise HTTPException( - status_code=429, - detail="Slow down! Too Many Requests", - ) - - logger.info( - f"Rate limit: {count_requests} requests in {self.window} seconds for user: {user}. Limit is {self.subscribed_requests} requests." + f"Rate limit: {count_requests}/{self.subscribed_requests} requests not allowed in {self.window} seconds for subscribed user: {user}." ) raise HTTPException( status_code=429, - detail="I'm glad you're enjoying interacting with me! But you've exceeded your usage limit for today. Come back tomorrow or subscribe to increase your usage limit via [your settings](https://app.khoj.dev/settings).", + detail="I'm glad you're enjoying interacting with me! You've unfortunately exceeded your usage limit for today. But let's chat more tomorrow?", + ) + if not subscribed and count_requests >= self.requests: + if self.requests >= self.subscribed_requests: + logger.info( + f"Rate limit: {count_requests}/{self.subscribed_requests} requests not allowed in {self.window} seconds for user: {user}." + ) + raise HTTPException( + status_code=429, + detail="I'm glad you're enjoying interacting with me! You've unfortunately exceeded your usage limit for today. But let's chat more tomorrow?", + ) + + logger.info( + f"Rate limit: {count_requests}/{self.requests} requests not allowed in {self.window} seconds for user: {user}." + ) + raise HTTPException( + status_code=429, + detail="I'm glad you're enjoying interacting with me! You've unfortunately exceeded your usage limit for today. You can subscribe to increase your usage limit via [your settings](https://app.khoj.dev/settings) or we can continue our conversation tomorrow?", ) # Add the current request to the cache @@ -1350,6 +1353,7 @@ class ApiImageRateLimiter: # Check number of images if len(body.images) > self.max_images: + logger.info(f"Rate limit: {len(body.images)}/{self.max_images} images not allowed per message.") raise HTTPException( status_code=429, detail=f"Those are way too many images for me! I can handle up to {self.max_images} images per message.", @@ -1370,6 +1374,7 @@ class ApiImageRateLimiter: total_size_mb += len(image_bytes) / (1024 * 1024) # Convert bytes to MB if total_size_mb > self.max_combined_size_mb: + logger.info(f"Data limit: {total_size_mb}MB/{self.max_combined_size_mb}MB size not allowed per message.") raise HTTPException( status_code=429, detail=f"Those images are way too large for me! I can handle up to {self.max_combined_size_mb}MB of images per message.", @@ -1405,13 +1410,19 @@ class ConversationCommandRateLimiter: if subscribed and count_requests >= self.subscribed_rate_limit: logger.info( - f"Rate limit: {count_requests} requests in 24 hours for user: {user}. Limit is {self.subscribed_rate_limit} requests." + f"Rate limit: {count_requests}/{self.subscribed_rate_limit} requests not allowed in 24 hours for subscribed user: {user}." ) - raise HTTPException(status_code=429, detail="Slow down! Too Many Requests") - if not subscribed and count_requests >= self.trial_rate_limit: raise HTTPException( status_code=429, - detail=f"We're glad you're enjoying Khoj! You've exceeded your `/{conversation_command.value}` command usage limit for today. Subscribe to increase your usage limit via [your settings](https://app.khoj.dev/settings).", + detail=f"I'm glad you're enjoying interacting with me! You've unfortunately exceeded your `/{conversation_command.value}` command usage limit for today. Maybe we can talk about something else for today?", + ) + if not subscribed and count_requests >= self.trial_rate_limit: + logger.info( + f"Rate limit: {count_requests}/{self.trial_rate_limit} requests not allowed in 24 hours for user: {user}." + ) + raise HTTPException( + status_code=429, + detail=f"I'm glad you're enjoying interacting with me! You've unfortunately exceeded your `/{conversation_command.value}` command usage limit for today. You can subscribe to increase your usage limit via [your settings](https://app.khoj.dev/settings) or we can talk about something else for today?", ) await UserRequests.objects.acreate(user=user, slug=command_slug) return @@ -1457,16 +1468,28 @@ class ApiIndexedDataLimiter: logger.info(f"Deleted {num_deleted_entries} entries for user: {user}.") if subscribed and incoming_data_size_mb >= self.subscribed_num_entries_size: + logger.info( + f"Data limit: {incoming_data_size_mb}MB incoming will exceed {self.subscribed_num_entries_size}MB allowed for subscribed user: {user}." + ) raise HTTPException(status_code=429, detail="Too much data indexed.") if not subscribed and incoming_data_size_mb >= self.num_entries_size: + logger.info( + f"Data limit: {incoming_data_size_mb}MB incoming will exceed {self.num_entries_size}MB allowed for user: {user}." + ) raise HTTPException( status_code=429, detail="Too much data indexed. Subscribe to increase your data index limit." ) user_size_data = EntryAdapters.get_size_of_indexed_data_in_mb(user) if subscribed and user_size_data + incoming_data_size_mb >= self.subscribed_total_entries_size: + logger.info( + f"Data limit: {incoming_data_size_mb}MB incoming + {user_size_data}MB existing will exceed {self.subscribed_total_entries_size}MB allowed for subscribed user: {user}." + ) raise HTTPException(status_code=429, detail="Too much data indexed.") if not subscribed and user_size_data + incoming_data_size_mb >= self.total_entries_size_limit: + logger.info( + f"Data limit: {incoming_data_size_mb}MB incoming + {user_size_data}MB existing will exceed {self.subscribed_total_entries_size}MB allowed for non subscribed user: {user}." + ) raise HTTPException( status_code=429, detail="Too much data indexed. Subscribe to increase your data index limit." )