Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
@@ -12,8 +12,183 @@ from datasets import load_dataset
|
|
12 |
from gtts import gTTS
|
13 |
import os
|
14 |
import speech_recognition as sr
|
|
|
15 |
|
16 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
|
18 |
# Main Dashboard with Voice Input
|
19 |
def diabetes_dashboard(initial_glucose, food_audio, food_image, portion_size,
|
@@ -84,12 +259,13 @@ def diabetes_dashboard(initial_glucose, food_audio, food_image, portion_size,
|
|
84 |
speech_output = f"Food detected: {nutrition_info['matched_food']}. " \
|
85 |
f"Total carbs: {nutrition_info['adjusted_carbs']} grams. " \
|
86 |
f"Recommended bolus dose: {insulin_info['total_bolus']} units."
|
|
|
|
|
87 |
tts = gTTS(text=speech_output, lang='en')
|
88 |
-
audio_file
|
89 |
-
tts.save(audio_file)
|
90 |
|
91 |
-
return (glucose_meal_details + insulin_details + basal_details,
|
92 |
-
|
93 |
audio_file,
|
94 |
glucose_meal_details,
|
95 |
insulin_details,
|
@@ -98,7 +274,7 @@ def diabetes_dashboard(initial_glucose, food_audio, food_image, portion_size,
|
|
98 |
# Gradio Interface
|
99 |
with gr.Blocks(title="Diabetes Management Dashboard") as demo:
|
100 |
gr.Markdown("# Diabetes Management Dashboard")
|
101 |
-
|
102 |
with gr.Row():
|
103 |
with gr.Column():
|
104 |
# Input Components
|
@@ -116,13 +292,13 @@ with gr.Blocks(title="Diabetes Management Dashboard") as demo:
|
|
116 |
value=json.dumps(DEFAULT_BASAL_RATES),
|
117 |
label="Basal Rates (JSON format)"
|
118 |
)
|
119 |
-
|
120 |
with gr.Accordion("Lifestyle Factors"):
|
121 |
stress = gr.Slider(0, 10, value=3, label="Stress Level")
|
122 |
sleep = gr.Slider(0, 12, value=8, label="Sleep Hours")
|
123 |
exercise_dur = gr.Slider(0, 240, value=0, label="Exercise Duration (min)")
|
124 |
exercise_int = gr.Slider(0, 10, value=0, label="Exercise Intensity")
|
125 |
-
|
126 |
time_horizon = gr.Slider(1, 24, value=6, step=1, label="Prediction Time (hours)")
|
127 |
submit_btn = gr.Button("Calculate")
|
128 |
|
|
|
12 |
from gtts import gTTS
|
13 |
import os
|
14 |
import speech_recognition as sr
|
15 |
+
import soundfile as sf # Import soundfile
|
16 |
|
17 |
+
# Define constants and data structures
|
18 |
+
INSULIN_TYPES = {
|
19 |
+
"Rapid-Acting": 1.0,
|
20 |
+
"Short-Acting": 0.8,
|
21 |
+
"Intermediate-Acting": 0.6,
|
22 |
+
"Long-Acting": 0.4
|
23 |
+
}
|
24 |
+
|
25 |
+
DEFAULT_BASAL_RATES = {
|
26 |
+
"00:00": 0.8,
|
27 |
+
"03:00": 0.7,
|
28 |
+
"06:00": 0.9,
|
29 |
+
"09:00": 1.0,
|
30 |
+
"12:00": 0.9,
|
31 |
+
"15:00": 0.8,
|
32 |
+
"18:00": 0.9,
|
33 |
+
"21:00": 0.8
|
34 |
+
}
|
35 |
+
|
36 |
+
# Load food data from CSV
|
37 |
+
def load_food_data():
|
38 |
+
try:
|
39 |
+
food_data = pd.read_csv("food_data.csv")
|
40 |
+
return food_data
|
41 |
+
except FileNotFoundError:
|
42 |
+
print("Error: food_data.csv not found.")
|
43 |
+
return pd.DataFrame()
|
44 |
+
|
45 |
+
# Save audio to a temporary file
|
46 |
+
def save_audio(filepath, audio_data):
|
47 |
+
sf.write(filepath, audio_data[0], audio_data[1])
|
48 |
+
|
49 |
+
# Recognize food name from audio
|
50 |
+
def recognize_food_from_voice(food_audio):
|
51 |
+
try:
|
52 |
+
audio_path = "audio_temp.wav"
|
53 |
+
save_audio(audio_path, food_audio)
|
54 |
+
|
55 |
+
r = sr.Recognizer()
|
56 |
+
with sr.AudioFile(audio_path) as source:
|
57 |
+
audio = r.record(source)
|
58 |
+
|
59 |
+
food_name = r.recognize_google(audio)
|
60 |
+
os.remove(audio_path) # Clean up the temp file
|
61 |
+
return food_name
|
62 |
+
except Exception as e:
|
63 |
+
print(f"Error recognizing food from voice: {e}")
|
64 |
+
return None
|
65 |
+
|
66 |
+
# Classify food from image (replace with your image classification model)
|
67 |
+
def classify_food(image):
|
68 |
+
# Load pre-trained image classification model
|
69 |
+
image_processor = AutoImageProcessor.from_pretrained("google/vit-base-patch16-224")
|
70 |
+
model = AutoModelForImageClassification.from_pretrained("google/vit-base-patch16-224")
|
71 |
+
|
72 |
+
try:
|
73 |
+
inputs = image_processor(images=image, return_tensors="pt")
|
74 |
+
outputs = model(**inputs)
|
75 |
+
logits = outputs.logits
|
76 |
+
predicted_class_idx = logits.argmax(-1).item()
|
77 |
+
predicted_label = model.config.id2label[predicted_class_idx]
|
78 |
+
return predicted_label
|
79 |
+
except Exception as e:
|
80 |
+
print(f"Error classifying image: {e}")
|
81 |
+
return "Unknown Food"
|
82 |
+
|
83 |
+
# Get nutrition information for a given food (fuzzy matching)
|
84 |
+
def get_food_nutrition(food_name, food_data, portion_size):
|
85 |
+
if food_data.empty:
|
86 |
+
return None
|
87 |
+
|
88 |
+
food_names = food_data["Food"].tolist()
|
89 |
+
closest_match = get_close_matches(food_name, food_names, n=1, cutoff=0.6)
|
90 |
+
|
91 |
+
if closest_match:
|
92 |
+
matched_food = closest_match[0]
|
93 |
+
food_info = food_data[food_data["Food"] == matched_food].iloc[0]
|
94 |
+
|
95 |
+
carbs_per_portion = food_info["Carbs"]
|
96 |
+
fat_per_portion = food_info["Fat"]
|
97 |
+
protein_per_portion = food_info["Protein"]
|
98 |
+
fiber_per_portion = food_info["Fiber"]
|
99 |
+
|
100 |
+
adjusted_carbs = max(0, carbs_per_portion - (fiber_per_portion / 2)) * portion_size
|
101 |
+
|
102 |
+
return {
|
103 |
+
"matched_food": matched_food,
|
104 |
+
"portion_size": portion_size,
|
105 |
+
"carbs_per_portion": carbs_per_portion * portion_size,
|
106 |
+
"fat_per_portion": fat_per_portion * portion_size,
|
107 |
+
"protein_per_portion": protein_per_portion * portion_size,
|
108 |
+
"fiber_per_portion": fiber_per_portion * portion_size,
|
109 |
+
"adjusted_carbs": adjusted_carbs
|
110 |
+
}
|
111 |
+
else:
|
112 |
+
return None
|
113 |
+
|
114 |
+
# Calculate Insulin Needs
|
115 |
+
def calculate_insulin_needs(adjusted_carbs, initial_glucose, target_glucose, tdd, weight, insulin_type, override_correction_dose=None):
|
116 |
+
try:
|
117 |
+
isf = 1800 / tdd # Insulin Sensitivity Factor
|
118 |
+
carb_ratio = 500 / tdd # Carb Ratio
|
119 |
+
|
120 |
+
# Correction Dose Calculation
|
121 |
+
if override_correction_dose is not None:
|
122 |
+
correction_dose = override_correction_dose
|
123 |
+
else:
|
124 |
+
correction_dose = (initial_glucose - target_glucose) / isf
|
125 |
+
|
126 |
+
# Carb Dose Calculation
|
127 |
+
carb_dose = adjusted_carbs / carb_ratio
|
128 |
+
|
129 |
+
# Total Bolus Dose
|
130 |
+
total_bolus = correction_dose + carb_dose
|
131 |
+
|
132 |
+
# ISF Modifier based on Insulin Type
|
133 |
+
isf_modifier = INSULIN_TYPES.get(insulin_type, 1.0) # Default to 1.0 if insulin type not found
|
134 |
+
total_bolus *= isf_modifier
|
135 |
+
|
136 |
+
return {
|
137 |
+
"isf": isf,
|
138 |
+
"carb_ratio": carb_ratio,
|
139 |
+
"correction_dose": correction_dose,
|
140 |
+
"carb_dose": carb_dose,
|
141 |
+
"total_bolus": total_bolus,
|
142 |
+
"insulin_type": insulin_type,
|
143 |
+
"target_glucose": target_glucose,
|
144 |
+
"initial_glucose": initial_glucose
|
145 |
+
}
|
146 |
+
|
147 |
+
except Exception as e:
|
148 |
+
return {"error": f"Error calculating insulin: {e}"}
|
149 |
+
|
150 |
+
# Get Basal Rate
|
151 |
+
def get_basal_rate(time_hours, basal_rates):
|
152 |
+
time_str = "{:02d}:00".format(time_hours % 24) # Format as HH:00
|
153 |
+
for t in sorted(basal_rates.keys()):
|
154 |
+
if time_str >= t:
|
155 |
+
current_basal_rate = basal_rates[t]
|
156 |
+
else:
|
157 |
+
break
|
158 |
+
return current_basal_rate
|
159 |
+
|
160 |
+
# Active Insulin Calculation (Simple Exponential Decay Model)
|
161 |
+
def calculate_active_insulin(insulin_history, time):
|
162 |
+
active_insulin = 0
|
163 |
+
for bolus_time, bolus_amount, insulin_type, duration in insulin_history:
|
164 |
+
time_elapsed = time - bolus_time
|
165 |
+
if time_elapsed < duration:
|
166 |
+
# Using exponential decay for simplicity
|
167 |
+
active_insulin += bolus_amount * np.exp(-time_elapsed / (duration / np.log(2)))
|
168 |
+
return active_insulin
|
169 |
+
|
170 |
+
def create_detailed_report(nutrition_info, insulin_info, current_basal_rate):
|
171 |
+
# Format the report string
|
172 |
+
glucose_meal_details = f"### Glucose & Meal Details\n\n" \
|
173 |
+
f"- **Detected Food:** {nutrition_info['matched_food']}\n" \
|
174 |
+
f"- **Portion Size:** {nutrition_info['portion_size']}\n" \
|
175 |
+
f"- **Carbohydrates:** {nutrition_info['carbs_per_portion']} g\n" \
|
176 |
+
f"- **Adjusted Carbs:** {nutrition_info['adjusted_carbs']} g\n"
|
177 |
+
|
178 |
+
insulin_details = f"### Insulin Details\n\n" \
|
179 |
+
f"- **Blood Glucose Target:** {insulin_info['target_glucose']} mg/dL\n" \
|
180 |
+
f"- **Current Glucose Level:** {insulin_info['initial_glucose']} mg/dL\n" \
|
181 |
+
f"- **Insulin Sensitivity Factor (ISF):** {insulin_info['isf']:.2f}\n" \
|
182 |
+
f"- **Carb Ratio:** {insulin_info['carb_ratio']:.2f} g/U\n" \
|
183 |
+
f"- **Correction Dose:** {insulin_info['correction_dose']:.2f} U\n" \
|
184 |
+
f"- **Carb Dose:** {insulin_info['carb_dose']:.2f} U\n" \
|
185 |
+
f"- **Total Bolus Dose:** {insulin_info['total_bolus']:.2f} U\n" \
|
186 |
+
f"- **Insulin Type:** {insulin_info['insulin_type']}"
|
187 |
+
|
188 |
+
basal_details = f"### Basal Settings\n\n" \
|
189 |
+
f"- **Current Basal Rate:** {current_basal_rate} U/hr\n"
|
190 |
+
|
191 |
+
return glucose_meal_details, insulin_details, basal_details
|
192 |
|
193 |
# Main Dashboard with Voice Input
|
194 |
def diabetes_dashboard(initial_glucose, food_audio, food_image, portion_size,
|
|
|
259 |
speech_output = f"Food detected: {nutrition_info['matched_food']}. " \
|
260 |
f"Total carbs: {nutrition_info['adjusted_carbs']} grams. " \
|
261 |
f"Recommended bolus dose: {insulin_info['total_bolus']} units."
|
262 |
+
audio_file = "recommendation.mp3" # relative path
|
263 |
+
|
264 |
tts = gTTS(text=speech_output, lang='en')
|
265 |
+
tts.save(audio_file) # save it in the app directory
|
|
|
266 |
|
267 |
+
return (glucose_meal_details + insulin_details + basal_details,
|
268 |
+
fig, # Pass the matplotlib figure object
|
269 |
audio_file,
|
270 |
glucose_meal_details,
|
271 |
insulin_details,
|
|
|
274 |
# Gradio Interface
|
275 |
with gr.Blocks(title="Diabetes Management Dashboard") as demo:
|
276 |
gr.Markdown("# Diabetes Management Dashboard")
|
277 |
+
|
278 |
with gr.Row():
|
279 |
with gr.Column():
|
280 |
# Input Components
|
|
|
292 |
value=json.dumps(DEFAULT_BASAL_RATES),
|
293 |
label="Basal Rates (JSON format)"
|
294 |
)
|
295 |
+
|
296 |
with gr.Accordion("Lifestyle Factors"):
|
297 |
stress = gr.Slider(0, 10, value=3, label="Stress Level")
|
298 |
sleep = gr.Slider(0, 12, value=8, label="Sleep Hours")
|
299 |
exercise_dur = gr.Slider(0, 240, value=0, label="Exercise Duration (min)")
|
300 |
exercise_int = gr.Slider(0, 10, value=0, label="Exercise Intensity")
|
301 |
+
|
302 |
time_horizon = gr.Slider(1, 24, value=6, step=1, label="Prediction Time (hours)")
|
303 |
submit_btn = gr.Button("Calculate")
|
304 |
|