Files changed (1) hide show
  1. app.py +113 -90
app.py CHANGED
@@ -3,35 +3,32 @@ import tensorflow as tf
3
  import numpy as np
4
  from PIL import Image
5
  import json
6
- from datetime import datetime
7
- import tempfile
8
- import os
9
  from gtts import gTTS
10
- from fpdf import FPDF
 
11
  from health_logic import generate_advice
12
- from tensorflow.keras.applications.efficientnet import preprocess_input as efficientnet_preprocess
 
 
13
 
14
  # Load model
15
  model = tf.keras.models.load_model("food_vision_model.keras")
16
 
17
- class_names = [
18
- "akara", "banga_soup", "egusi_soup", "jollof_rice", "moi_moi",
19
- "nkwobi", "okpa", "suya", "tuwo", "yam_porridge"
20
- ]
21
-
22
- # Load food metadata
23
  with open("food_info.json", "r") as f:
24
  food_info = json.load(f)
25
 
26
- # Language map for TTS
 
 
27
  LANG_CODE = {
28
  "English": "en",
29
- "Hausa": "en", # gTTS doesn't support Hausa properly
30
- "Yoruba": "en",
31
- "Igbo": "en"
32
  }
33
 
34
- # Risk level helper
35
  def get_risk_level(score):
36
  if score <= 30:
37
  return "🟒 Low Risk"
@@ -40,121 +37,147 @@ def get_risk_level(score):
40
  else:
41
  return "πŸ”΄ High Risk"
42
 
43
- # PDF class with Unicode support
44
  class UnicodePDF(FPDF):
45
- def header(self):
46
- self.set_font("DejaVu", "B", 16)
47
- self.cell(0, 10, "HoodHealth Pro+ Report", ln=True)
48
-
49
- def footer(self):
50
- self.set_y(-15)
51
- self.set_font("DejaVu", "I", 8)
52
- self.cell(0, 10, f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M')}", align="C")
53
 
54
  def generate_pdf(info, advice, risk_score, risk_level, flags, conditions, lang, display_name, image_path):
55
  pdf = UnicodePDF()
56
- pdf.add_font("DejaVu", "", "DejaVuSans.ttf", uni=True)
57
- pdf.add_font("DejaVu", "B", "DejaVuSans.ttf", uni=True)
58
- pdf.add_font("DejaVu", "I", "DejaVuSans.ttf", uni=True)
59
  pdf.add_page()
60
- pdf.set_font("DejaVu", "", 12)
 
 
 
 
 
 
 
 
61
 
62
- pdf.image(image_path, x=10, y=40, w=60)
63
  pdf.set_xy(75, 40)
64
- pdf.multi_cell(0, 10, f"Food: {display_name}\nEthnicity: {info['ethnicity']}\nIngredients: {info['ingredients']}")
 
 
 
 
65
 
66
  pdf.ln(35)
67
- pdf.multi_cell(0, 10, f"Calories: {info['calories']} kcal\nCarbs: {info['carbs']}g\nProtein: {info['protein']}g\nFat: {info['fat']}g")
 
 
 
 
 
 
68
  pdf.ln(5)
69
- pdf.multi_cell(0, 10, f"Diet Type: {info['diet_type']}\nSubstitute: {info.get('substitute', 'None')}")
70
- pdf.ln(10)
 
 
71
 
 
72
  pdf.set_font("DejaVu", "B", 14)
73
  pdf.cell(0, 10, "Health Analysis", ln=True)
74
- pdf.set_font("DejaVu", "", 12)
75
- pdf.multi_cell(0, 10, f"Conditions: {', '.join(conditions)}\nRisk Score: {risk_score}% ({risk_level})\nRisk Factors: {', '.join(flags) if flags else 'None'}\nAdvice: {advice}")
 
 
 
 
 
 
 
76
  pdf.ln(5)
77
  pdf.set_font("DejaVu", "I", 10)
78
- pdf.multi_cell(0, 10, "*Note: This advice is not a medical diagnosis.*")
79
 
80
- path = os.path.join(tempfile.gettempdir(), "report.pdf")
81
- pdf.output(path)
82
- return path
83
 
84
- # Main function
 
 
85
  def classify_food(image, conditions, language):
86
  if not conditions:
87
  return "⚠️ Please select at least one health condition.", None, None, None
88
 
89
- # Preprocess image
90
  image = image.convert("RGB").resize((224, 224))
91
- img = tf.keras.preprocessing.image.img_to_array(image)
92
- img = efficientnet_preprocess(img)
93
- img = np.expand_dims(img, axis=0)
94
 
95
- # Predict
96
- preds = model.predict(img)[0]
97
- idx = np.argmax(preds)
98
- predicted_class = class_names[idx]
99
- confidence = round(float(preds[idx]) * 100, 2)
100
 
101
  info = food_info[predicted_class]
102
- display_name = info.get("display_name", predicted_class.replace("_", " ").title())
103
 
104
- # Advice logic
105
  advice, risk_score, flags = generate_advice(info, conditions)
106
  risk_level = get_risk_level(risk_score)
107
 
108
- # Save audio
109
- audio_path = os.path.join(tempfile.gettempdir(), "tts.mp3")
110
- tts = gTTS(text=advice, lang=LANG_CODE.get(language, "en"))
111
- tts.save(audio_path)
112
-
113
- # Save image
114
- image_path = os.path.join(tempfile.gettempdir(), "upload.jpg")
115
- image.save(image_path)
116
-
117
- # Generate PDF
118
- pdf_path = generate_pdf(info, advice, risk_score, risk_level, flags, conditions, language, display_name, image_path)
119
-
120
- # Output summary
 
 
 
 
 
 
 
 
 
 
 
 
121
  result = (
122
- f"🍽️ Food: {display_name}\n"
123
- f"🌍 Ethnicity: {info['ethnicity']}\n"
124
- f"πŸ₯¦ Ingredients: {info['ingredients']}\n"
125
- f"πŸ”₯ Calories: {info['calories']} kcal\n"
126
- f"🍞 Carbs: {info['carbs']}g\n"
127
- f"πŸ₯© Protein: {info['protein']}g\n"
128
- f"🧈 Fat: {info['fat']}g\n"
129
- f"🌱 Diet Type: {info['diet_type']}\n"
130
- f"πŸ” Substitute: {info.get('substitute', 'None')}\n\n"
131
- f"πŸ“ˆ Confidence: {confidence}%\n"
132
- f"πŸ“Š Risk Score: {risk_score}% ({risk_level})\n"
133
- f"⚠️ Risk Factors: {', '.join(flags) if flags else 'None'}\n"
134
- f"βœ… Advice: {advice}\n\n"
135
- f"πŸ“ *Generated by HoodHealth Pro+.*"
136
  )
137
 
138
- return result, audio_path, f"πŸ—£οΈ Language: {language}", pdf_path
139
 
140
- # Gradio interface
141
  interface = gr.Interface(
142
  fn=classify_food,
143
  inputs=[
144
  gr.Image(type="pil", label="Upload Food Image"),
145
- gr.CheckboxGroup(label="Select Health Conditions", choices=[
146
- "Normal", "Diabetic", "Hypertensive", "Weight Loss", "Malnourished", "Pregnant/Nursing", "Cholesterol Watch"]),
147
- gr.Dropdown(label="Language for TTS", choices=["English", "Hausa", "Yoruba", "Igbo"], value="English")
 
 
148
  ],
149
  outputs=[
150
- gr.Textbox(label="Prediction and Advice"),
151
  gr.Audio(label="Hear Advice"),
152
- gr.Textbox(label="Language Info"),
153
- gr.File(label="Download PDF Report")
154
  ],
155
- title="🍲 FoodHealth Pro+",
156
- description="Upload a food image and get nutrition details, health risk, personalized advice, audio guidance, and a downloadable PDF report."
157
  )
158
 
159
  if __name__ == "__main__":
160
- interface.launch()
 
3
  import numpy as np
4
  from PIL import Image
5
  import json
 
 
 
6
  from gtts import gTTS
7
+ import os
8
+ import tempfile
9
  from health_logic import generate_advice
10
+ from deep_translator import GoogleTranslator
11
+ from datetime import datetime
12
+ from fpdf import FPDF
13
 
14
  # Load model
15
  model = tf.keras.models.load_model("food_vision_model.keras")
16
 
17
+ # Load metadata
 
 
 
 
 
18
  with open("food_info.json", "r") as f:
19
  food_info = json.load(f)
20
 
21
+ class_names = list(food_info.keys())
22
+
23
+ # Language code mapping for gTTS
24
  LANG_CODE = {
25
  "English": "en",
26
+ "Hausa": "ha",
27
+ "Yoruba": "yo",
28
+ "Igbo": "ig"
29
  }
30
 
31
+ # Risk color level
32
  def get_risk_level(score):
33
  if score <= 30:
34
  return "🟒 Low Risk"
 
37
  else:
38
  return "πŸ”΄ High Risk"
39
 
40
+ # PDF Generator using Unicode-safe font
41
  class UnicodePDF(FPDF):
42
+ def __init__(self):
43
+ super().__init__()
44
+ self.add_font("DejaVu", "", "DejaVuSans.ttf", uni=True)
45
+ self.add_font("DejaVu", "B", "DejaVuSans.ttf", uni=True)
46
+ self.set_font("DejaVu", size=12)
 
 
 
47
 
48
  def generate_pdf(info, advice, risk_score, risk_level, flags, conditions, lang, display_name, image_path):
49
  pdf = UnicodePDF()
 
 
 
50
  pdf.add_page()
51
+ pdf.set_font("DejaVu", "B", 16)
52
+ pdf.cell(0, 10, "HoodHealth Pro+ Report", ln=True)
53
+
54
+ pdf.set_font("DejaVu", size=12)
55
+ pdf.cell(0, 10, f"Date: {datetime.now().strftime('%Y-%m-%d %H:%M')}", ln=True)
56
+ pdf.ln(10)
57
+
58
+ if os.path.exists(image_path):
59
+ pdf.image(image_path, x=10, y=40, w=60)
60
 
 
61
  pdf.set_xy(75, 40)
62
+ pdf.multi_cell(0, 10,
63
+ f"🍽️ Food: {display_name}\n"
64
+ f"🌍 Ethnicity: {info['ethnicity']}\n"
65
+ f"πŸ₯¦ Ingredients: {info['ingredients']}"
66
+ )
67
 
68
  pdf.ln(35)
69
+ pdf.multi_cell(0, 10,
70
+ f"πŸ”₯ Calories: {info['calories']} kcal\n"
71
+ f"🍞 Carbs: {info['carbs']}g\n"
72
+ f"πŸ₯© Protein: {info['protein']}g\n"
73
+ f"🧈 Fat: {info['fat']}g"
74
+ )
75
+
76
  pdf.ln(5)
77
+ pdf.multi_cell(0, 10,
78
+ f"🌱 Diet Type: {info['diet_type']}\n"
79
+ f"πŸ” Substitute: {info.get('substitute', 'None')}"
80
+ )
81
 
82
+ pdf.ln(10)
83
  pdf.set_font("DejaVu", "B", 14)
84
  pdf.cell(0, 10, "Health Analysis", ln=True)
85
+ pdf.set_font("DejaVu", size=12)
86
+
87
+ pdf.multi_cell(0, 10,
88
+ f"πŸ“‹ Selected Conditions: {', '.join(conditions)}\n"
89
+ f"πŸ“Š Risk Score: {risk_score}% ({risk_level})\n"
90
+ f"⚠️ Risk Factors: {', '.join(flags) if flags else 'None'}\n"
91
+ f"βœ… Advice: {advice}"
92
+ )
93
+
94
  pdf.ln(5)
95
  pdf.set_font("DejaVu", "I", 10)
96
+ pdf.multi_cell(0, 10, "*Note: This advice is generated using simplified nutritional rules and is not a medical diagnosis.*")
97
 
98
+ temp_pdf = os.path.join(tempfile.gettempdir(), "report.pdf")
99
+ pdf.output(temp_pdf)
 
100
 
101
+ return temp_pdf
102
+
103
+ # Main logic
104
  def classify_food(image, conditions, language):
105
  if not conditions:
106
  return "⚠️ Please select at least one health condition.", None, None, None
107
 
 
108
  image = image.convert("RGB").resize((224, 224))
109
+ img_array = tf.keras.preprocessing.image.img_to_array(image) / 255.0
110
+ img_array = np.expand_dims(img_array, axis=0)
 
111
 
112
+ predictions = model.predict(img_array)[0]
113
+ predicted_index = np.argmax(predictions)
114
+ predicted_class = class_names[predicted_index]
115
+ confidence = round(float(predictions[predicted_index]) * 100, 2)
 
116
 
117
  info = food_info[predicted_class]
118
+ display_name = info.get("display_name", predicted_class.title())
119
 
 
120
  advice, risk_score, flags = generate_advice(info, conditions)
121
  risk_level = get_risk_level(risk_score)
122
 
123
+ # Translate
124
+ if language != "English":
125
+ try:
126
+ translated = GoogleTranslator(source="auto", target=LANG_CODE[language]).translate(advice)
127
+ advice = translated
128
+ except:
129
+ advice += " (⚠️ Translation failed)"
130
+
131
+ # TTS with fallback
132
+ tts_audio = None
133
+ try:
134
+ tts_lang = LANG_CODE.get(language, "en")
135
+ tts = gTTS(text=advice, lang=tts_lang)
136
+ tts_audio = os.path.join(tempfile.gettempdir(), "tts.mp3")
137
+ tts.save(tts_audio)
138
+ except Exception as e:
139
+ print(f"TTS error: {e}")
140
+ advice += " (⚠️ Voice advice unavailable)"
141
+
142
+ # Save image and PDF
143
+ tmp_img = os.path.join(tempfile.gettempdir(), "upload.jpg")
144
+ image.save(tmp_img)
145
+ pdf_path = generate_pdf(info, advice, risk_score, risk_level, flags, conditions, language, display_name, tmp_img)
146
+
147
+ # Output
148
  result = (
149
+ f"🧠 *Predictions*:\n"
150
+ f"🍲 {display_name} – {confidence}%\n\n"
151
+ f"πŸ“‰ *Top Confidence*: {confidence}%\n"
152
+ f"πŸ“Š *Risk Score*: {risk_score}% ({risk_level})\n"
153
+ f"⚠️ *Risk Factors*: {', '.join(flags) if flags else 'None'}\n"
154
+ f"βœ… *Advice*: {advice}\n"
155
+ f"πŸ” *Substitute*: {info.get('substitute', 'None')}\n\n"
156
+ f"πŸ“ This advice is generated using simple nutrition rules and is not a medical diagnosis."
 
 
 
 
 
 
157
  )
158
 
159
+ return result, tts_audio, f"πŸ—£οΈ Language: {language}", pdf_path
160
 
161
+ # Interface
162
  interface = gr.Interface(
163
  fn=classify_food,
164
  inputs=[
165
  gr.Image(type="pil", label="Upload Food Image"),
166
+ gr.CheckboxGroup(
167
+ label="Select Health Conditions",
168
+ choices=["Normal", "Diabetic", "Hypertensive", "Weight Loss", "Malnourished", "Pregnant/Nursing", "Cholesterol Watch"]
169
+ ),
170
+ gr.Dropdown(label="Language for TTS", choices=list(LANG_CODE.keys()), value="English")
171
  ],
172
  outputs=[
173
+ gr.Textbox(label="Result", lines=10),
174
  gr.Audio(label="Hear Advice"),
175
+ gr.Textbox(label="TTS Language"),
176
+ gr.File(label="Download Health Report (PDF)")
177
  ],
178
+ title="πŸ₯— FoodHealth Pro+",
179
+ description="Upload a food image. Get full nutrition info, risk score, health advice with voice support in your language and download a detailed PDF."
180
  )
181
 
182
  if __name__ == "__main__":
183
+ interface.launch()