From 8212dbbc21282c887015a5118c409f1bea25d054 Mon Sep 17 00:00:00 2001 From: Vira Kasprova Date: Thu, 14 Nov 2024 16:26:58 -0600 Subject: [PATCH] added error handling --- ai_ta_backend/database/sql.py | 86 ++++++++++------- ai_ta_backend/service/retrieval_service.py | 104 ++++++++++++--------- 2 files changed, 113 insertions(+), 77 deletions(-) diff --git a/ai_ta_backend/database/sql.py b/ai_ta_backend/database/sql.py index d0972cb0..9e154ab4 100644 --- a/ai_ta_backend/database/sql.py +++ b/ai_ta_backend/database/sql.py @@ -159,42 +159,64 @@ def getPreAssignedAPIKeys(self, email: str): return self.supabase_client.table("pre_authorized_api_keys").select("*").contains("emails", '["' + email + '"]').execute() def getConversationsCreatedAtByCourse(self, course_name: str): - count_response = self.supabase_client.table("llm-convo-monitor")\ - .select("created_at", count="exact")\ - .eq("course_name", course_name)\ - .execute() - - total_count = count_response.count - - if total_count <= 0: - return [], 0 - - all_data = [] - batch_size = 1000 - start = 0 - - while start < total_count: - end = min(start + batch_size - 1, total_count - 1) - - response = self.supabase_client.table("llm-convo-monitor")\ - .select("created_at")\ + try: + count_response = self.supabase_client.table("llm-convo-monitor")\ + .select("created_at", count="exact")\ .eq("course_name", course_name)\ - .range(start, end)\ .execute() - - if not response.data: - print(f"No data returned for range {start} to {end}.") - break - - all_data.extend(response.data) - start += batch_size - - return all_data, total_count + + total_count = count_response.count if hasattr(count_response, 'count') else 0 + + if total_count <= 0: + print(f"No conversations found for course: {course_name}") + return [], 0 + + all_data = [] + batch_size = 1000 + start = 0 + + while start < total_count: + end = min(start + batch_size - 1, total_count - 1) + + try: + response = self.supabase_client.table("llm-convo-monitor")\ + .select("created_at")\ + .eq("course_name", course_name)\ + .range(start, end)\ + .execute() + + if not response or not hasattr(response, 'data') or not response.data: + print(f"No data returned for range {start} to {end}.") + break + + all_data.extend(response.data) + start += batch_size + + except Exception as batch_error: + print(f"Error fetching batch {start}-{end}: {str(batch_error)}") + continue + + if not all_data: + print(f"No conversation data could be retrieved for course: {course_name}") + return [], 0 + + return all_data, len(all_data) + + except Exception as e: + print(f"Error in getConversationsCreatedAtByCourse for {course_name}: {str(e)}") + return [], 0 def getProjectStats(self, project_name: str): - response = self.supabase_client.table("project_stats").select("total_messages, total_conversations, unique_users")\ - .eq("project_name", project_name).execute() + try: + response = self.supabase_client.table("project_stats").select("total_messages, total_conversations, unique_users")\ + .eq("project_name", project_name).execute() + + if response and hasattr(response, 'data') and response.data: + return response.data[0] + except Exception as e: + print(f"Error fetching project stats for {project_name}: {str(e)}") - return response.data[0] if response.data else {"total_messages": 0, "total_conversations": 0, "unique_users": 0} + # Return default values if anything fails + return {"total_messages": 0, "total_conversations": 0, "unique_users": 0} \ No newline at end of file diff --git a/ai_ta_backend/service/retrieval_service.py b/ai_ta_backend/service/retrieval_service.py index 28bc4561..68f91a1c 100644 --- a/ai_ta_backend/service/retrieval_service.py +++ b/ai_ta_backend/service/retrieval_service.py @@ -526,54 +526,68 @@ def format_for_json(self, found_docs: List[Document]) -> List[Dict]: def getConversationStats(self, course_name: str): """ Fetches conversation data from the database and groups them by day, hour, and weekday. - - Args: - course_name (str) - - Returns: - dict: A dictionary containing: - - 'per_day': Counts of conversations by date (YYYY-MM-DD). - - 'per_hour': Counts of conversations by hour (0-23). - - 'per_weekday': Counts of conversations by weekday (Monday-Sunday). - - 'heatmap': A nested dictionary for heatmap data (days of the week as keys, hours as inner keys). """ - # print(f"Received course_name: {course_name}") - - conversations, total_count = self.sqlDb.getConversationsCreatedAtByCourse(course_name) - - central_tz = pytz.timezone('America/Chicago') - - grouped_data = { - 'per_day': defaultdict(int), - 'per_hour': defaultdict(int), - 'per_weekday': defaultdict(int), - 'heatmap': defaultdict(lambda: defaultdict(int)), - } + try: + conversations, total_count = self.sqlDb.getConversationsCreatedAtByCourse(course_name) + + # Initialize with empty data (all zeros) + response_data = { + 'per_day': {}, + 'per_hour': {str(hour): 0 for hour in range(24)}, # Convert hour to string for consistency + 'per_weekday': {day: 0 for day in ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']}, + 'heatmap': {day: {str(hour): 0 for hour in range(24)} for day in ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']}, + 'total_count': 0 + } + + if not conversations: + return response_data + + central_tz = pytz.timezone('America/Chicago') + grouped_data = { + 'per_day': defaultdict(int), + 'per_hour': defaultdict(int), + 'per_weekday': defaultdict(int), + 'heatmap': defaultdict(lambda: defaultdict(int)), + } - if conversations: for record in conversations: - created_at = record['created_at'] - parsed_date = parser.parse(created_at).astimezone(central_tz) - - day = parsed_date.date() - hour = parsed_date.hour - day_of_week = parsed_date.strftime('%A') - - grouped_data['per_day'][str(day)] += 1 - grouped_data['per_hour'][hour] += 1 - grouped_data['per_weekday'][day_of_week] += 1 - grouped_data['heatmap'][day_of_week][hour] += 1 - - else: - print("No valid response data. Check if the query is correct or if the response is empty.") - return {} - - return { - 'per_day': dict(grouped_data['per_day']), - 'per_hour': dict(grouped_data['per_hour']), - 'per_weekday': dict(grouped_data['per_weekday']), - 'heatmap': {day: dict(hours) for day, hours in grouped_data['heatmap'].items()}, - } + try: + created_at = record['created_at'] + parsed_date = parser.parse(created_at).astimezone(central_tz) + + day = parsed_date.date() + hour = parsed_date.hour + day_of_week = parsed_date.strftime('%A') + + grouped_data['per_day'][str(day)] += 1 + grouped_data['per_hour'][str(hour)] += 1 # Convert hour to string + grouped_data['per_weekday'][day_of_week] += 1 + grouped_data['heatmap'][day_of_week][str(hour)] += 1 # Convert hour to string + except Exception as e: + print(f"Error processing record: {str(e)}") + continue + + return { + 'per_day': dict(grouped_data['per_day']), + 'per_hour': {str(k): v for k, v in grouped_data['per_hour'].items()}, + 'per_weekday': dict(grouped_data['per_weekday']), + 'heatmap': {day: {str(h): count for h, count in hours.items()} + for day, hours in grouped_data['heatmap'].items()}, + 'total_count': total_count + } + + except Exception as e: + print(f"Error in getConversationStats for course {course_name}: {str(e)}") + self.sentry.capture_exception(e) + # Return empty data structure on error + return { + 'per_day': {}, + 'per_hour': {str(hour): 0 for hour in range(24)}, + 'per_weekday': {day: 0 for day in ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']}, + 'heatmap': {day: {str(hour): 0 for hour in range(24)} + for day in ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']}, + 'total_count': 0 + } def getProjectStats(self, project_name: str) -> Dict[str, int]: """