from datetime import datetime, timedelta from django.db.models import Count, Max, Min, Prefetch from rest_framework import status from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from rest_framework.views import APIView from rest_framework_simplejwt.authentication import JWTAuthentication from module_iam.models import IAmPrincipal from module_project import constants, date_utils from module_project.service import OneSignalNotificationService from module_project.utils import ApiResponse from ..models import (BeverageRecord, Bowel, ChronicCondition, FoodIngredientRecord, FoodIngredintDataset, FoodRecord, Intolerance, MealRecord, MealSymptomRecord, Medication, PastTreatment, PrincipalHealthData, Symptoms) from .serializers import (BowelSerializer, ChronicConditionSerializer, FoodDatasetSerializer, FoodIngredientDatasetSerializer, IAmPrincipalSerializer, IntoleranceSerializer, MealRecordSerializer, MealSymptomRecordSerializer, MedicationSerializer, PastTreatmentSerializer, PrincipalAndHealthSerializer, PrincipalHealthDataSerializer, SymptomsSerializer) class ProfileAPIView(APIView): authentication_classes = [JWTAuthentication] permission_classes = [IsAuthenticated] post_serializer_class = IAmPrincipalSerializer get_serializer_class = PrincipalAndHealthSerializer model = IAmPrincipal def get(self, request): try: obj = self.model.objects.prefetch_related("health_data_principal").get( pk=request.user.pk ) serializer = self.get_serializer_class(obj, context={"request": request}) except self.model.DoesNotExist: return ApiResponse.error( status=status.HTTP_404_NOT_FOUND, message=constants.RECORD_NOT_FOUND ) return ApiResponse.success(message=constants.SUCCESS, data=serializer.data) def post(self, request): data = request.data.copy() # Separate principal and health data principal_data = {} health_data = {} for key, value in data.items(): if key in self.post_serializer_class.Meta.fields: principal_data[key] = value else: health_data[key] = value principal_serializer = self.post_serializer_class( instance=request.user, data=principal_data ) health_serializer = PrincipalHealthDataSerializer(data=health_data) if not principal_serializer.is_valid(): return ApiResponse.error( message=constants.FAILURE, errors=principal_serializer.errors ) if not health_serializer.is_valid(): return ApiResponse.error( message=constants.FAILURE, errors=health_serializer.errors ) try: # with transaction.atomic(): # Ensure atomicity of database operations principal_instance = principal_serializer.save() principal_instance.register_complete = True principal_instance.save() # Check if health data already exists for the principal health_data_instance, created = PrincipalHealthData.objects.get_or_create( principal=principal_instance ) health_serializer.update(health_data_instance, health_data) except Exception as e: return ApiResponse.error(message=constants.FAILURE, errors=str(e)) return ApiResponse.success(message=constants.SUCCESS) class ProfileCompleteAPIView(APIView): authentication_classes = [JWTAuthentication] permission_classes = [IsAuthenticated] model = IAmPrincipal def get(self, request): user = IAmPrincipal.objects.filter(id=request.user.id).update(register_complete=True) return ApiResponse.success(message=constants.SUCCESS) class DailyRecordAPIView(APIView): def serialize_record(self, record): time_obj = datetime.strptime(str(record.time), "%H:%M:%S") return { "id": record.id, "date": record.date, "time": time_obj.strftime("%I:%M %p"), "sort_time": time_obj, # Add other fields as needed } def get(self, request): date = request.GET.get("date") # date = datetime.now().date() if not date: return ApiResponse.error( message=constants.FAILURE, errors="Date parameter is missing" ) try: # Convert the date string to a datetime object date_obj = datetime.strptime(date, "%Y-%m-%d").date() except ValueError: return ApiResponse.error( message=constants.FAILURE, errors="Invalid date format" ) # Define prefetch related queries for filtering the record of paticular date of all related models meal_records_prefetch = Prefetch( "meal_principal", queryset=MealRecord.objects.filter(date=date, deleted=False), to_attr="filtered_meal_record", ) medication_prefetch = Prefetch( "medication_principal", queryset=Medication.objects.filter(date=date, deleted=False), to_attr="filtered_medication", ) bowel_prefetch = Prefetch( "bowel_principal", queryset=Bowel.objects.filter(date=date, deleted=False), to_attr="filtered_bowel", ) meal_symptom_prefetch = Prefetch( "meal_symptom_principal", queryset=MealSymptomRecord.objects.filter(date=date, deleted=False), to_attr="filtered_meal_symptom", ) # Query the IAmPrincipal table of principal with prefetch_related to retrieve related records principal = IAmPrincipal.objects.prefetch_related( meal_records_prefetch, medication_prefetch, bowel_prefetch, meal_symptom_prefetch, ).get(id=request.user.id) serialized_meal_records = [ {"type": f"Meal - {record.meal_type}", **self.serialize_record(record)} for record in principal.filtered_meal_record ] serialized_medication = [ {"type": "Medication", **self.serialize_record(record)} for record in principal.filtered_medication ] serialized_bowel = [ {"type": "Bowel Movements", **self.serialize_record(record)} for record in principal.filtered_bowel ] serialized_symptom = [ {"type": "Symptom - Meal", **self.serialize_record(record)} for record in principal.filtered_meal_symptom ] all_records = ( serialized_symptom + serialized_meal_records + serialized_medication + serialized_bowel ) # all_records_sorted = sorted(all_records, key=lambda x: x["time"], reverse=True) all_records_sorted = sorted(all_records, key=lambda x: x["sort_time"], reverse=True) return ApiResponse.success(message=constants.SUCCESS, data=all_records_sorted) class IntoleranceListCreateAPIView(APIView): authentication_classes = [JWTAuthentication] permission_classes = [IsAuthenticated] serializer_class = IntoleranceSerializer model = Intolerance def get(self, request): obj = self.model.objects.filter(principal=request.user, active=True) serializer = self.serializer_class(obj, many=True) return ApiResponse.success(message=constants.SUCCESS, data=serializer.data) def post(self, request): print(f"request data for intolerance is {request.data}") serializer = self.serializer_class(data=request.data, many=True) if not serializer.is_valid(): return ApiResponse.error( message=constants.FAILURE, errors=serializer.errors ) try: self.model.objects.filter(principal=request.user).delete() instance = serializer.save(principal=request.user) saved_data_serializer = self.serializer_class(instance, many=True) return ApiResponse.success( message=constants.SUCCESS, data=saved_data_serializer.data ) except Exception as e: return ApiResponse.error(message=constants.FAILURE, errors=str(e)) class SymptomsListCreateAPIView(APIView): authentication_classes = [JWTAuthentication] permission_classes = [IsAuthenticated] serializer_class = SymptomsSerializer model = Symptoms def get(self, request): obj = self.model.objects.filter(principal=request.user, active=True) serializer = self.serializer_class(obj, many=True) return ApiResponse.success(message=constants.SUCCESS, data=serializer.data) def post(self, request): print(f"request data for Symptoms is {request.data}") serializer = self.serializer_class(data=request.data, many=True) if not serializer.is_valid(): return ApiResponse.error( message=constants.FAILURE, errors=serializer.errors ) try: self.model.objects.filter(principal=request.user).delete() instance = serializer.save(principal=request.user) saved_data_serializer = self.serializer_class(instance, many=True) return ApiResponse.success( message=constants.SUCCESS, data=saved_data_serializer.data ) except Exception as e: return ApiResponse.error(message=constants.FAILURE, errors=str(e)) class PastTreatmentListCreateAPIView(APIView): authentication_classes = [JWTAuthentication] permission_classes = [IsAuthenticated] serializer_class = PastTreatmentSerializer model = PastTreatment def get(self, request): obj = self.model.objects.filter(principal=request.user, active=True) serializer = self.serializer_class(obj, many=True) return ApiResponse.success(message=constants.SUCCESS, data=serializer.data) def post(self, request): print(f"request data for PastTreatment is {request.data}") serializer = self.serializer_class(data=request.data, many=True) if not serializer.is_valid(): return ApiResponse.error( message=constants.FAILURE, errors=serializer.errors ) try: self.model.objects.filter(principal=request.user).delete() instance = serializer.save(principal=request.user) saved_data_serializer = self.serializer_class(instance, many=True) return ApiResponse.success( message=constants.SUCCESS, data=saved_data_serializer.data ) except Exception as e: return ApiResponse.error(message=constants.FAILURE, errors=str(e)) class ChronicConditionListCreateAPIView(APIView): authentication_classes = [JWTAuthentication] permission_classes = [IsAuthenticated] serializer_class = ChronicConditionSerializer model = ChronicCondition def get(self, request): obj = self.model.objects.filter(principal=request.user, active=True) serializer = self.serializer_class(obj, many=True) return ApiResponse.success(message=constants.SUCCESS, data=serializer.data) def post(self, request): print(f"request data for PastTreatment is {request.data}") serializer = self.serializer_class(data=request.data, many=True) if not serializer.is_valid(): return ApiResponse.error( message=constants.FAILURE, errors=serializer.errors ) try: self.model.objects.filter(principal=request.user).delete() instance = serializer.save(principal=request.user) saved_data_serializer = self.serializer_class(instance, many=True) return ApiResponse.success( message=constants.SUCCESS, data=saved_data_serializer.data ) except Exception as e: return ApiResponse.error(message=constants.FAILURE, errors=str(e)) class MedicationAPIView(APIView): authentication_classes = [JWTAuthentication] permission_classes = [IsAuthenticated] serializer_class = MedicationSerializer model = Medication def get_objects(self, pk): try: return self.model.objects.get(pk=pk) except self.model.DoesNotExist: return ApiResponse.error( status=status.HTTP_404_NOT_FOUND, message=constants.RECORD_NOT_FOUND ) def get(self, request, pk): obj = self.get_objects(pk) if isinstance(obj, Response): return obj serializer = self.serializer_class(obj) return ApiResponse.success(message=constants.SUCCESS, data=serializer.data) def post(self, request): serializer = self.serializer_class(data=request.data) if not serializer.is_valid(): return ApiResponse.error( message=constants.FAILURE, errors=serializer.errors ) try: serializer.save(principal=request.user) except Exception as e: return ApiResponse.error(message=constants.FAILURE, errors=str(e)) return ApiResponse.success( status=status.HTTP_201_CREATED, message=constants.SUCCESS, data=serializer.data, ) def put(self, request, pk): obj = self.get_objects(pk) if isinstance(obj, Response): return obj serializer = self.serializer_class(obj, data=request.data) if not serializer.is_valid(): return ApiResponse.error(message=constants.FAILURE, errors=serializer.data) try: serializer.save() except Exception as e: return ApiResponse.error(message=constants.FAILURE, errors=str(e)) return ApiResponse.success( status=status.HTTP_201_CREATED, message=constants.SUCCESS, data=serializer.data, ) def delete(self, request, pk): obj = self.get_objects(pk) if isinstance(obj, Response): return obj try: obj.delete() except Exception as e: return ApiResponse.error(message=constants.FAILURE, errors=str(e)) return ApiResponse.success( message=constants.RECORD_DELETED, status=status.HTTP_204_NO_CONTENT ) class BowelAPIView(APIView): authentication_classes = [JWTAuthentication] permission_classes = [IsAuthenticated] serializer_class = BowelSerializer model = Bowel def get_objects(self, pk): try: return self.model.objects.get(pk=pk) except self.model.DoesNotExist: return ApiResponse.error( status=status.HTTP_404_NOT_FOUND, message=constants.RECORD_NOT_FOUND ) def get(self, request, pk): obj = self.get_objects(pk) if isinstance(obj, Response): return obj serializer = self.serializer_class(obj) return ApiResponse.success(message=constants.SUCCESS, data=serializer.data) def post(self, request): serializer = self.serializer_class(data=request.data) if not serializer.is_valid(): return ApiResponse.error( message=constants.FAILURE, errors=serializer.errors ) try: serializer.save(principal=request.user) except Exception as e: return ApiResponse.error(message=constants.FAILURE, errors=str(e)) return ApiResponse.success( status=status.HTTP_201_CREATED, message=constants.SUCCESS, data=serializer.data, ) def put(self, request, pk): obj = self.get_objects(pk) if isinstance(obj, Response): return obj serializer = self.serializer_class(obj, data=request.data) if not serializer.is_valid(): return ApiResponse.error(message=constants.FAILURE, errors=serializer.data) try: serializer.save() except Exception as e: return ApiResponse.error(message=constants.FAILURE, errors=str(e)) return ApiResponse.success( status=status.HTTP_201_CREATED, message=constants.SUCCESS, data=serializer.data, ) def delete(self, request, pk): obj = self.get_objects(pk) if isinstance(obj, Response): return obj try: obj.delete() except Exception as e: return ApiResponse.error(message=constants.FAILURE, errors=str(e)) return ApiResponse.success( message=constants.RECORD_DELETED, status=status.HTTP_204_NO_CONTENT ) class MealSymptomAPIView(APIView): authentication_classes = [JWTAuthentication] permission_classes = [IsAuthenticated] serializer_class = MealSymptomRecordSerializer model = MealSymptomRecord def get_objects(self, pk): try: return self.model.objects.get(pk=pk) except self.model.DoesNotExist: return ApiResponse.error( status=status.HTTP_404_NOT_FOUND, message=constants.RECORD_NOT_FOUND ) def get(self, request, pk): obj = self.get_objects(pk) if isinstance(obj, Response): return obj serializer = self.serializer_class(obj) return ApiResponse.success(message=constants.SUCCESS, data=serializer.data) def post(self, request): serializer = self.serializer_class(data=request.data) if not serializer.is_valid(): return ApiResponse.error( message=constants.FAILURE, errors=serializer.errors ) try: instance = serializer.save(principal=request.user) print(f"symptoms meal in put view {instance.id}") except Exception as e: return ApiResponse.error(message=constants.FAILURE, errors=str(e)) return ApiResponse.success( status=status.HTTP_201_CREATED, message=constants.SUCCESS, data=serializer.data, ) def put(self, request, pk): obj = self.get_objects(pk) if isinstance(obj, Response): return obj serializer = self.serializer_class(obj, data=request.data) if not serializer.is_valid(): return ApiResponse.error(message=constants.FAILURE, errors=serializer.data) try: instance = serializer.save() print(f"symptoms meal in put view {instance.id}") except Exception as e: return ApiResponse.error(message=constants.FAILURE, errors=str(e)) return ApiResponse.success( status=status.HTTP_201_CREATED, message=constants.SUCCESS, data=serializer.data, ) def delete(self, request, pk): obj = self.get_objects(pk) if isinstance(obj, Response): return obj try: obj.delete() except Exception as e: return ApiResponse.error(message=constants.FAILURE, errors=str(e)) return ApiResponse.success( message=constants.RECORD_DELETED, status=status.HTTP_204_NO_CONTENT ) class MealAPIView(APIView): authentication_classes = [JWTAuthentication] permission_classes = [IsAuthenticated] serializer_class = MealRecordSerializer model = MealRecord def get_objects(self, pk): try: return self.model.objects.get(pk=pk) except self.model.DoesNotExist: return ApiResponse.error( status=status.HTTP_404_NOT_FOUND, message=constants.RECORD_NOT_FOUND ) def get(self, request, pk): obj = self.get_objects(pk) if isinstance(obj, Response): return obj serializer = self.serializer_class(obj) return ApiResponse.success(message=constants.SUCCESS, data=serializer.data) def post(self, request): serializer = self.serializer_class(data=request.data) if not serializer.is_valid(): return ApiResponse.error( message=constants.FAILURE, errors=serializer.errors ) try: meal_id = serializer.save(principal=request.user) print(f"meal id in views {meal_id.id}") except Exception as e: return ApiResponse.error(message=constants.FAILURE, errors=str(e)) return ApiResponse.success( status=status.HTTP_201_CREATED, message=constants.SUCCESS, data=serializer.data, ) def put(self, request, pk): obj = self.get_objects(pk) if isinstance(obj, Response): return obj serializer = self.serializer_class(obj, data=request.data) if not serializer.is_valid(): return ApiResponse.error(message=constants.FAILURE, errors=serializer.data) try: instance = serializer.save() print(f"meal record id in put emthod {instance.id}") except Exception as e: return ApiResponse.error(message=constants.FAILURE, errors=str(e)) return ApiResponse.success( status=status.HTTP_201_CREATED, message=constants.SUCCESS, data=serializer.data, ) def delete(self, request, pk): obj = self.get_objects(pk) if isinstance(obj, Response): return obj try: obj.delete() except Exception as e: return ApiResponse.error(message=constants.FAILURE, errors=str(e)) return ApiResponse.success( message=constants.RECORD_DELETED, status=status.HTTP_204_NO_CONTENT ) class MealDuplicateAPIView(APIView): authentication_classes = [JWTAuthentication] permission_classes = [IsAuthenticated] serializer_class = MealRecordSerializer model = MealRecord def post(self, request): meal_id = request.data.get("id") meal_time = request.data.get("time") print(f"meal_id is {meal_id}, and time is {meal_time}, and type of {type(meal_time)}") try: original_meal = self.model.objects.get(pk=meal_id, principal=request.user) except Exception as e: return ApiResponse.error(message="Meal not found", errors=str(e)) instance = self.model( principal=original_meal.principal, date=original_meal.date, time=meal_time, meal_type=original_meal.meal_type ) print(f"record id is {original_meal}") instance.save() for food_obj in original_meal.food_records.all(): instance.food_records.add(food_obj) for beverage_obj in original_meal.beverage_records.all(): instance.beverage_records.add(beverage_obj) for ingredient_obj in original_meal.food_ingredient_records.all(): instance.food_ingredient_records.add(ingredient_obj) instance.save() serializer_obj = self.serializer_class(instance).data return ApiResponse.success(message=constants.SUCCESS, data=serializer_obj) class FoodDataAPIView(APIView): authentication_classes = [] permission_classes = [] model = FoodIngredintDataset serializer_class = FoodDatasetSerializer def get(self, request): obj = self.model.objects.all().order_by("food_name") serializer = self.serializer_class(obj, many=True) return ApiResponse.success(message=constants.SUCCESS, data=serializer.data) class FoodIngredientSearchAPIView(APIView): authentication_classes = [JWTAuthentication] permission_classes = [IsAuthenticated] model = FoodIngredintDataset serializer_class = FoodIngredientDatasetSerializer def get(self, request): query = request.query_params.getlist('query') print(f"Query : {query}") obj = self.model.objects.filter(food_name__in=query).values_list('ingredients', flat=True) unique_ingredients = set() for ingredients_list in obj: unique_ingredients.update(ingredients_list) # serializer = self.serializer_class(obj, many=True) return ApiResponse.success(message=constants.SUCCESS, data={'ingredients_list': list(unique_ingredients)}) class MealDateAPIView(APIView): authentication_classes = [JWTAuthentication] permission_classes = [IsAuthenticated] serializer_class = MealRecordSerializer model = MealRecord def get(self, request): date = request.GET.get("date") if not date: return ApiResponse.error( message=constants.FAILURE, errors="Date parameter is missing" ) try: # Convert the date string to a datetime object date_obj = datetime.strptime(date, "%Y-%m-%d").date() except ValueError: return ApiResponse.error( message=constants.FAILURE, errors="Invalid date format" ) obj = self.model.objects.filter(principal=request.user.id, date=date_obj) serializer = self.serializer_class(obj, many=True) return ApiResponse.success(message=constants.SUCCESS, data=serializer.data) from collections import defaultdict class ReportAPIView(APIView): authentication_classes = [JWTAuthentication] permission_classes = [IsAuthenticated] model = MealRecord def get_user(self): return self.request.user def enough_records_exist(self, start_date, end_date): """ Check if at least 7 days of records exist within the date range. This method calculates the minimum date by subtracting the required number of days (min_days_required - 1) from the end_date. It then filters the queryset based on the principal and date range. If any objects exist within this range, the method returns True, indicating that there are at least 7 days of records. :param start_date: The initial date in the date range :type start_date: datetime.date :param end_date: The final date in the date range :type end_date: datetime.date :return: True if at least 7 days of records exist, False otherwise :rtype: bool """ min_days_required = 7 current_date = start_date count = 0 while current_date <= end_date: if self.model.objects.filter(principal=self.get_user(), date=current_date).exists(): count += 1 if count >= min_days_required: return True else: count = 0 # Reset count if record is missing for any day current_date += timedelta(days=1) return False def get_top_food_avoid(self, start_date, end_date): """Get the top food to avoid.""" food_counts = defaultdict(int) ingredient_counts = defaultdict(int) beverage_counts = defaultdict(int) # symptom_records = MealSymptomRecord.objects.select_related("related_meal").filter( # principal=self.get_user(), date__range=(start_date, end_date) # ) # for symptom_record in symptom_records: # closest_meal = ( # MealRecord.objects.filter( # principal=symptom_record.principal, date__lte=symptom_record.date # ) # .order_by("-date", "-time") # .first() # ) # if closest_meal: # for food_record in closest_meal.food_records.all(): # food_counts[food_record.name] += 1 # for ingredient_record in closest_meal.food_ingredient_records.all(): # ingredient_counts[ingredient_record.name] += 1 # for beverage_record in closest_meal.beverage_records.all(): # beverage_counts[beverage_record.beverage_type] += 1 # Fetch symptom records with related meal records and related food/ingredient/beverage records symptom_records = MealSymptomRecord.objects.prefetch_related( Prefetch('related_meal__food_records', queryset=FoodRecord.objects.all()), Prefetch('related_meal__food_ingredient_records', queryset=FoodIngredientRecord.objects.all()), Prefetch('related_meal__beverage_records', queryset=BeverageRecord.objects.all()) ).filter( principal=self.get_user(), date__range=(start_date, end_date) ) # Loop through symptom records and count food, ingredient, and beverage occurrences for each related meal record for symptom_record in symptom_records: closest_meal = symptom_record.related_meal if closest_meal: for food_record in closest_meal.food_records.all(): food_counts[food_record.name] += 1 for ingredient_record in closest_meal.food_ingredient_records.all(): ingredient_counts[ingredient_record.name] += 1 for beverage_record in closest_meal.beverage_records.all(): beverage_counts[beverage_record.beverage_type] += 1 # Sort the dictionaries by their values in descending order and getting only top 3 record food_counts = dict( sorted(food_counts.items(), key=lambda x: x[1], reverse=True)[:3] ) ingredient_counts = dict( sorted(ingredient_counts.items(), key=lambda x: x[1], reverse=True)[:3] ) beverage_counts = dict( sorted(beverage_counts.items(), key=lambda x: x[1], reverse=True)[:3] ) food_avoid = next(iter(food_counts), None) return food_avoid, food_counts, ingredient_counts, beverage_counts def get_symptoms_frequency(self, start_date, end_date): """Get the frequency of symptoms.""" symptom_records = MealSymptomRecord.objects.filter( principal=self.get_user(), date__range=(start_date, end_date) ).annotate( before_meal_count=Count("symptoms_before_meal"), after_meal_count=Count("symptoms_after_meal"), ) symptoms_frequency = defaultdict(int) for record in symptom_records: for symptom in record.symptoms_before_meal.all(): symptoms_frequency[symptom.name] += record.before_meal_count for symptom in record.symptoms_after_meal.all(): symptoms_frequency[symptom.name] += record.after_meal_count sorted_symptoms_frequency = dict( sorted(symptoms_frequency.items(), key=lambda x: x[1], reverse=True)[:3] ) return sorted_symptoms_frequency def get_stool_type_counts(self, start_date, end_date): """Get the count of stool types.""" stool_type_counts = ( Bowel.objects.filter( principal=self.get_user(), date__range=(start_date, end_date) ) .values("stool_type") .annotate(stool_type_count=Count("stool_type")) ) stool_type_counts_dict = { item["stool_type"]: item["stool_type_count"] for item in stool_type_counts } stool_type_counts_sort = dict( sorted(stool_type_counts_dict.items(), key=lambda x: x[1], reverse=True)[:3] ) highest_stool = next(iter(stool_type_counts_sort), None) return stool_type_counts_sort, highest_stool def get(self, request): date_range = request.GET.get("date_range") start_date, end_date = date_utils.get_date_range(date_range) print(f"start date is {start_date}, end_date is {end_date}") print(f"is dats exist {self.enough_records_exist(start_date, end_date)}") if not self.enough_records_exist(start_date, end_date): return ApiResponse.error( message="No report is generated. Minimum Previous 7 days of records required." ) # Get top food to avoid food_avoid, food_counts, ingredient_counts, beverage_counts = ( self.get_top_food_avoid(start_date, end_date) ) # Get symptoms frequency sorted_symptoms_frequency = self.get_symptoms_frequency(start_date, end_date) # Get stool type counts stool_type_counts_sort, highest_stool = self.get_stool_type_counts( start_date, end_date ) nested_json = { "food_avoid": food_avoid, "same_food_avoid": { "food": food_counts, "ingredient": ingredient_counts, "beverage": beverage_counts, }, "symptoms_frequency": sorted_symptoms_frequency, "highest_stool": highest_stool, "stool_type": stool_type_counts_sort, } print(f"nested_json data is {nested_json}") return ApiResponse.success(message=constants.SUCCESS, data=nested_json)