!apt-get update !apt-get install -y portaudio19-dev !pip install pyaudio gradio datasets transformers torch pandas numpy matplotlib Pillow from datasets import load_dataset import gradio as gr import numpy as np import pandas as pd import matplotlib.pyplot as plt import torch from transformers import AutoImageProcessor, AutoModelForImageClassification from PIL import Image from difflib import get_close_matches from typing import Optional, Dict, Any import json import io import os import speech_recognition as sr # Configuration (unchanged) INSULIN_TYPES = { "Rapid-Acting": {"onset": 0.25, "duration": 4, "peak_time": 1.0}, "Long-Acting": {"onset": 2, "duration": 24, "peak_time": 8}, } DEFAULT_BASAL_RATES = { "00:00-06:00": 0.8, "06:00-12:00": 1.0, "12:00-18:00": 0.9, "18:00-24:00": 0.7 } GI_RANGES = { "low": (0, 55), "medium": (56, 69), "high": (70, 100) } HINDI_TO_ENGLISH = { "roti": "bread", "dal": "lentils", "chawal": "rice", "sabzi": "vegetable curry", "paneer": "paneer", "samosa": "samosa" } # Utility Functions (unchanged) def estimate_gi_timing(gi_value: Optional[int]) -> tuple[float, float]: if gi_value is None: return 1.0, 2.5 if gi_value <= 55: return 1.0, 3.0 elif 56 <= gi_value <= 69: return 0.75, 2.0 else: return 0.5, 1.5 def load_food_data(): try: ds = load_dataset("Anupam007/diabetic-food-analyzer") food_data = pd.DataFrame(ds['train']) food_data.columns = [col.lower().strip() for col in food_data.columns] food_data['food_name'] = food_data['food_name'].str.lower().str.strip() return food_data except Exception as e: print(f"Error loading food data: {e}") return pd.DataFrame() try: processor = AutoImageProcessor.from_pretrained("rajistics/finetuned-indian-food") model = AutoModelForImageClassification.from_pretrained("rajistics/finetuned-indian-food") model_loaded = True except Exception as e: print(f"Model Load Error: {e}") model_loaded = False processor = None model = None def classify_food(image): if not model_loaded or image is None: return "unknown" try: inputs = processor(images=image, return_tensors="pt") with torch.no_grad(): outputs = model(**inputs) predicted_idx = torch.argmax(outputs.logits, dim=-1).item() food_name = model.config.id2label.get(predicted_idx, "unknown").lower() return food_name except Exception as e: print(f"Classify food error: {e}") return "unknown" def get_food_nutrition(food_name: str, food_data: pd.DataFrame, weight_grams: Optional[float] = None) -> tuple[Optional[Dict[str, Any]], str]: food_name_lower = food_name.lower().strip() matches = get_close_matches(food_name_lower, food_data['food_name'].tolist(), n=1, cutoff=0.6) correction_note = "" if matches: corrected_name = matches[0] if corrected_name != food_name_lower: correction_note = f"Note: '{food_name}' corrected to '{corrected_name}'" matched_row = food_data[food_data['food_name'] == corrected_name].iloc[0] base_carbs = float(matched_row.get('unit_serving_carb_g', matched_row.get('carb_g', 0.0))) serving_size = matched_row.get('servings_unit', 'unknown') gi_value = matched_row.get('glycemic_index', None) if pd.isna(gi_value): gi_value = None else: try: gi_value = int(float(gi_value)) except (ValueError, TypeError): gi_value = None if weight_grams and serving_size != 'unknown': try: serving_weight = float(matched_row.get('serving_weight_grams', 100)) portion_size = weight_grams / serving_weight except (ValueError, TypeError): portion_size = 1.0 else: portion_size = 1.0 adjusted_carbs = base_carbs * portion_size nutrition_info = { 'matched_food': matched_row['food_name'], 'category': matched_row.get('primarysource', 'unknown'), 'subcategory': 'unknown', 'base_carbs': base_carbs, 'adjusted_carbs': adjusted_carbs, 'serving_size': f"1 {serving_size}", 'portion_multiplier': portion_size, 'notes': 'none', 'glycemic_index': gi_value } return nutrition_info, correction_note return None, f"No close match found for '{food_name}'" def determine_gi_level(gi_value: Optional[int]) -> str: if gi_value is None: return "Unknown" for level, (lower, upper) in GI_RANGES.items(): if lower <= gi_value <= upper: return level.capitalize() return "Unknown" def get_basal_rate(current_time_hour: float, basal_rates: Dict[str, float]) -> float: for interval, rate in basal_rates.items(): try: start, end = [int(x.split(':')[0]) for x in interval.split('-')] if start <= current_time_hour < end or (start <= current_time_hour and end == 24): return rate except Exception as e: print(f"Invalid basal interval {interval}: {e}") return 0.8 def insulin_activity(t: float, insulin_type: str, bolus_dose: float, bolus_duration: float = 0) -> float: insulin_data = INSULIN_TYPES.get(insulin_type, INSULIN_TYPES["Rapid-Acting"]) peak_time = insulin_data['peak_time'] duration = insulin_data['duration'] if bolus_duration > 0: if 0 <= t <= bolus_duration: return bolus_dose / bolus_duration return 0 if t < 0: return 0 elif t < peak_time: return bolus_dose * (t / peak_time) * np.exp(1 - t/peak_time) elif t < duration: return bolus_dose * np.exp((peak_time - t) / (duration - peak_time)) return 0 def calculate_active_insulin(insulin_history: list, current_time: float) -> float: return sum(insulin_activity(current_time - dose_time, insulin_type, dose_amount, bolus_duration) for dose_time, dose_amount, insulin_type, bolus_duration in insulin_history) def calculate_insulin_needs(carbs: float, glucose_current: float, glucose_target: float, tdd: float, weight: float, insulin_type: str = "Rapid-Acting", override_correction_dose: Optional[float] = None) -> Dict[str, Any]: if tdd <= 0 or weight <= 0: return {'error': 'TDD and weight must be positive'} insulin_data = INSULIN_TYPES.get(insulin_type, INSULIN_TYPES["Rapid-Acting"]) icr = 400 / tdd isf = 1700 / tdd correction_dose = (glucose_current - glucose_target) / isf if override_correction_dose is None else override_correction_dose carb_dose = carbs / icr total_bolus = max(0, carb_dose + correction_dose) basal_dose = weight * 0.5 return { 'icr': round(icr, 2), 'isf': round(isf, 2), 'correction_dose': round(correction_dose, 2), 'carb_dose': round(carb_dose, 2), 'total_bolus': round(total_bolus, 2), 'basal_dose': round(basal_dose, 2), 'insulin_type': insulin_type, 'insulin_onset': insulin_data['onset'], 'insulin_duration': insulin_data['duration'], 'peak_time': insulin_data['peak_time'] } def create_detailed_report(nutrition_info: Dict[str, Any], insulin_info: Dict[str, Any], current_basal_rate: float, correction_note: str) -> tuple[str, str, str]: gi_level = determine_gi_level(nutrition_info.get('glycemic_index')) peak_time, duration = estimate_gi_timing(nutrition_info.get('glycemic_index')) glucose_meal_details = f""" GLUCOSE & MEAL DETAILS: - Detected Food: {nutrition_info['matched_food']} - Category: {nutrition_info['category']} - Glycemic Index: {nutrition_info.get('glycemic_index', 'N/A')} ({gi_level}) - Peak Glucose Time: {peak_time} hours - Glucose Effect Duration: {duration} hours - Serving Size: {nutrition_info['serving_size']} - Carbs per Serving: {nutrition_info['base_carbs']}g - Portion Multiplier: {nutrition_info['portion_multiplier']}x - Total Carbs: {nutrition_info['adjusted_carbs']}g {correction_note} """ insulin_details = f""" INSULIN DETAILS: - ICR: 1:{insulin_info['icr']} - ISF: 1:{insulin_info['isf']} - Insulin Type: {insulin_info['insulin_type']} - Onset: {insulin_info['insulin_onset']}h - Duration: {insulin_info['insulin_duration']}h - Peak: {insulin_info['peak_time']}h - Correction Dose: {insulin_info['correction_dose']} units - Carb Dose: {insulin_info['carb_dose']} units - Total Bolus: {insulin_info['total_bolus']} units """ basal_details = f""" BASAL SETTINGS: - Basal Dose: {insulin_info['basal_dose']} units/day - Current Basal Rate: {current_basal_rate} units/h """ return glucose_meal_details, insulin_details, basal_details def speech_to_text(audio_file): recognizer = sr.Recognizer() try: with sr.AudioFile(audio_file) as source: audio = recognizer.record(source) try: text = recognizer.recognize_google(audio, language="hi-IN") return HINDI_TO_ENGLISH.get(text.lower(), text) except sr.UnknownValueError: text = recognizer.recognize_google(audio, language="en-US") return text except Exception as e: return f"Error processing audio: {e}" def diabetes_dashboard(initial_glucose, food_image, food_name_input, speech_input, weight_grams, insulin_type, override_correction_dose, extended_bolus_duration, weight, tdd, target_glucose, basal_rates_input, stress_level, sleep_hours, exercise_duration, exercise_intensity, time_hours): food_data = load_food_data() if food_data.empty: return "Error loading food data", None, None, None, None if speech_input: food_name = speech_to_text(speech_input) elif food_name_input and food_name_input.strip(): food_name = food_name_input.strip() else: food_name = classify_food(food_image) nutrition_info, correction_note = get_food_nutrition(food_name, food_data, weight_grams) if not nutrition_info: return correction_note, None, None, None, None try: basal_rates = json.loads(basal_rates_input) except: basal_rates = DEFAULT_BASAL_RATES insulin_info = calculate_insulin_needs( nutrition_info['adjusted_carbs'], initial_glucose, target_glucose, tdd, weight, insulin_type, override_correction_dose ) if 'error' in insulin_info: return insulin_info['error'], None, None, None, None current_basal_rate = get_basal_rate(12, basal_rates) glucose_meal_details, insulin_details, basal_details = create_detailed_report(nutrition_info, insulin_info, current_basal_rate, correction_note) hours = list(range(time_hours)) glucose_levels = [] current_glucose = initial_glucose insulin_history = [(0, insulin_info['total_bolus'], insulin_type, extended_bolus_duration)] for t in hours: carb_effect = nutrition_info['adjusted_carbs'] * 0.1 * np.exp(-(t - 1.5) ** 2 / 2) insulin_effect = calculate_active_insulin(insulin_history, t) basal_effect = get_basal_rate(t, basal_rates) stress_effect = stress_level * 2 sleep_effect = abs(8 - sleep_hours) * 5 exercise_effect = (exercise_duration / 60) * exercise_intensity * 2 current_glucose += carb_effect - insulin_effect - basal_effect + stress_effect + sleep_effect - exercise_effect glucose_levels.append(max(70, min(400, current_glucose))) fig, ax = plt.subplots(figsize=(10, 5)) ax.plot(hours, glucose_levels, 'b-', label='Predicted Glucose') ax.axhline(y=target_glucose, color='g', linestyle='--', label='Target') ax.fill_between(hours, 70, 180, alpha=0.1, color='g', label='Target Range') ax.set_xlabel('Hours') ax.set_ylabel('Glucose (mg/dL)') ax.legend() ax.grid(True) return glucose_meal_details, insulin_details, basal_details, insulin_info['total_bolus'], fig # Gradio Interface with gr.Blocks(title="Type 1 Diabetes Management Dashboard") as app: gr.Markdown("# Type 1 Diabetes Management Dashboard") with gr.Tab("Glucose & Meal"): initial_glucose = gr.Number(label="Current Glucose (mg/dL)", value=120) target_glucose = gr.Number(label="Target Glucose (mg/dL)", value=100) food_name_input = gr.Textbox(label="Food Name (optional)", placeholder="Enter food name manually") speech_input = gr.Audio(label="Upload Audio of Food Name (Hindi/English)", type="filepath") weight_grams = gr.Number(label="Weight (grams, optional)", value=None) food_image = gr.Image(label="Food Image (optional)", type="pil") glucose_meal_output = gr.Textbox(label="Glucose & Meal Details", lines=10) with gr.Tab("Insulin"): insulin_type = gr.Dropdown(list(INSULIN_TYPES.keys()), label="Insulin Type", value="Rapid-Acting") override_correction_dose = gr.Number(label="Override Correction Dose (units)", value=None) extended_bolus_duration = gr.Number(label="Extended Bolus Duration (h)", value=0) weight = gr.Number(label="Weight (kg)", value=70) tdd = gr.Number(label="Total Daily Dose (units)", value=40) insulin_output = gr.Textbox(label="Insulin Details", lines=10) bolus_output = gr.Number(label="Bolus Dose (units)") with gr.Tab("Basal Settings"): basal_rates_input = gr.Textbox(label="Basal Rates (JSON)", value=json.dumps(DEFAULT_BASAL_RATES), lines=2) basal_output = gr.Textbox(label="Basal Settings", lines=4) with gr.Tab("Other Factors"): stress_level = gr.Slider(1, 10, step=1, label="Stress Level", value=1) sleep_hours = gr.Number(label="Sleep Hours", value=7) exercise_duration = gr.Number(label="Exercise Duration (min)", value=0) exercise_intensity = gr.Slider(1, 10, step=1, label="Exercise Intensity", value=1) time_hours = gr.Slider(1, 24, step=1, label="Prediction Time (h)", value=6) plot_output = gr.Plot(label="Glucose Prediction") calculate_btn = gr.Button("Calculate") calculate_btn.click( diabetes_dashboard, inputs=[ initial_glucose, food_image, food_name_input, speech_input, weight_grams, insulin_type, override_correction_dose, extended_bolus_duration, weight, tdd, target_glucose, basal_rates_input, stress_level, sleep_hours, exercise_duration, exercise_intensity, time_hours ], outputs=[glucose_meal_output, insulin_output, basal_output, bolus_output, plot_output] ) app.launch(share=True) # Share=True generates a public URL