| import gradio as gr |
| import numpy as np |
| from transformers import WhisperProcessor, WhisperForConditionalGeneration |
| import json |
| import hashlib |
| import os |
| import logging |
|
|
| |
| logging.basicConfig(level=logging.INFO) |
| logger = logging.getLogger(__name__) |
|
|
| |
| try: |
| logger.info("Preloading Whisper model...") |
| processor = WhisperProcessor.from_pretrained("openai/whisper-small") |
| speech_model = WhisperForConditionalGeneration.from_pretrained("openai/whisper-small") |
| logger.info("Whisper model preloaded successfully") |
| except Exception as e: |
| logger.error(f"Error preloading Whisper model: {e}") |
| processor = WhisperProcessor.from_pretrained("openai/whisper-small") |
| speech_model = WhisperForConditionalGeneration.from_pretrained("openai/whisper-small") |
|
|
| |
| LOCAL_FOODS = [ |
| {"name": "Rice", "price_per_unit": 60, "unit": "kg", "source": "Local Mandi"}, |
| {"name": "Dal", "price_per_unit": 120, "unit": "kg", "source": "Farmers' Market"}, |
| {"name": "Potatoes", "price_per_unit": 30, "unit": "kg", "source": "Local Vendor"}, |
| {"name": "Chicken", "price_per_unit": 300, "unit": "kg", "source": "Poultry Farm"} |
| ] |
|
|
| |
| custom_theme = gr.themes.Base( |
| primary_hue=gr.themes.colors.teal, |
| secondary_hue=gr.themes.colors.yellow, |
| neutral_hue=gr.themes.colors.gray, |
| text_size=gr.themes.sizes.text_lg, |
| font=[gr.themes.GoogleFont("Noto Sans")] |
| ) |
|
|
| |
| def format_height(height_ft): |
| feet = int(height_ft) |
| inches = round((height_ft - feet) * 12) |
| return f"{feet} ft {inches} in" |
|
|
| |
| def encrypt_data(data): |
| return hashlib.sha256(data.encode()).hexdigest() |
|
|
| |
| def transcribe_audio(audio): |
| if audio is None: |
| return "Farmer" |
| try: |
| audio_data = np.frombuffer(audio, dtype=np.int16) |
| input_features = processor(audio_data, sampling_rate=16000, return_tensors="pt").input_features |
| predicted_ids = speech_model.generate(input_features, max_new_tokens=30) |
| transcription = processor.decode(predicted_ids[0], skip_special_tokens=True) |
| logger.info(f"Transcribed audio to: {transcription}") |
| return transcription[:50] |
| except Exception as e: |
| logger.error(f"Audio transcription failed: {e}") |
| return "Farmer" |
|
|
| |
| def translate_output(text, lang): |
| translations = { |
| "en": { |
| "app_title": "Personalized Diet Generator", |
| "dietitian_review": "Dietitian Review", |
| "your_feedback": "Your Feedback", |
| "age": "Age (years)", |
| "gender": "Gender", |
| "weight": "Weight (kg)", |
| "height": "Height (ft)", |
| "occupation": "Occupation", |
| "activity_level": "Activity Level", |
| "health_conditions": "Health Conditions (e.g., diabetes)", |
| "dietary_preferences": "Dietary Preferences (e.g., vegetarian)", |
| "allergies": "Allergies", |
| "weekly_budget": "Weekly Budget (₹)", |
| "pincode": "Pincode", |
| "cultural_preferences": "Cultural Preferences", |
| "consent": "I consent to data processing", |
| "status_success": "Diet plan generated successfully", |
| "status_cached": "Loaded cached diet plan (offline mode)", |
| "status_error": "Error: Please consent to data processing", |
| "feedback_dietitian": "Feedback submitted successfully!", |
| "feedback_user": "Thank you for your feedback!", |
| "monday": "Monday", "tuesday": "Tuesday", "wednesday": "Wednesday", |
| "thursday": "Thursday", "friday": "Friday", "saturday": "Saturday", "sunday": "Sunday", |
| "breakfast": "Breakfast", "lunch": "Lunch", "dinner": "Dinner" |
| }, |
| "hi": { |
| "app_title": "वैयक्तिकृत आहार जनरेटर", |
| "dietitian_review": "डायटिशियन समीक्षा", |
| "your_feedback": "आपकी प्रतिक्रिया", |
| "age": "आयु (वर्ष)", |
| "gender": "लिंग", |
| "weight": "वजन (किग्रा)", |
| "height": "ऊंचाई (फीट)", |
| "occupation": "पेशा", |
| "activity_level": "गतिविधि स्तर", |
| "health_conditions": "स्वास्थ्य स्थितियाँ (जैसे, मधुमेह)", |
| "dietary_preferences": "आहार प्राथमिकताएँ (जैसे, शाकाहारी)", |
| "allergies": "एलर्जी", |
| "weekly_budget": "साप्ताहिक बजट (₹)", |
| "pincode": "पिनकोड", |
| "cultural_preferences": "सांस्कृतिक प्राथमिकताएँ", |
| "consent": "मैं डेटा प्रसंस्करण के लिए सहमति देता हूँ", |
| "status_success": "आहार योजना सफलतापूर्वक उत्पन्न की गई", |
| "status_cached": "संरक्षित आहार योजना लोड की गई (ऑफलाइन मोड)", |
| "status_error": "त्रुटि: कृपया डेटा प्रसंस्करण के लिए सहमति दें", |
| "feedback_dietitian": "प्रतिक्रिया सफलतापूर्वक जमा की गई!", |
| "feedback_user": "आपकी प्रतिक्रिया के लिए धन्यवाद!", |
| "monday": "सोमवार", "tuesday": "मंगलवार", "wednesday": "बुधवार", |
| "thursday": "गुरुवार", "friday": "शुक्रवार", "saturday": "शनिवार", "sunday": "रविवार", |
| "breakfast": "नाश्ता", "lunch": "दोपहर का भोजन", "dinner": "रात का भोजन" |
| } |
| } |
| lang_map = {"English": "en", "Hindi": "hi"} |
| lang_code = lang_map.get(lang, "en") |
| return translations.get(lang_code, translations["en"]) |
|
|
| |
| def generate_diet_plan(age, gender, weight, height, occupation, activity_level, health_conditions, |
| dietary_preferences, allergies, budget, zip_code, cultural_preferences, consent, lang, audio=None): |
| logger.info("Generating diet plan with inputs: age=%s, gender=%s, weight=%s, height=%s, occupation=%s, consent=%s", |
| age, gender, weight, height, occupation, consent) |
| if not consent: |
| return translate_output("status_error", lang), [], "" |
| if audio is not None: |
| occupation = transcribe_audio(audio) |
| user_data = { |
| "age": age, "gender": gender, "weight": weight, "height": height, "occupation": occupation, |
| "activity_level": activity_level, "health_conditions": health_conditions, |
| "dietary_preferences": dietary_preferences, "allergies": allergies, "budget": budget, |
| "cultural_preferences": cultural_preferences |
| } |
| user_id = encrypt_data(json.dumps(user_data)) |
|
|
| cached_plan = load_cached_plan(user_id) |
| if cached_plan: |
| logger.info("Loaded cached diet plan for user_id: %s", user_id) |
| diet_plan_output = format_diet_plan(cached_plan, lang) |
| local_foods_output = format_local_foods(LOCAL_FOODS, lang) |
| return translate_output("status_cached", lang), local_foods_output, diet_plan_output |
|
|
| formatted_height = format_height(height) |
| diet_plan = { |
| "Monday": {"breakfast": "Roti with dal", "lunch": "Rice and potato curry", "dinner": "Chicken curry"}, |
| "Tuesday": {"breakfast": "Poha", "lunch": "Dal and roti", "dinner": "Vegetable stir-fry"}, |
| "Wednesday": {"breakfast": "Upma", "lunch": "Rice and sambar", "dinner": "Chicken gravy"}, |
| "Thursday": {"breakfast": "Idli with chutney", "lunch": "Roti and dal", "dinner": "Potato sabzi"}, |
| "Friday": {"breakfast": "Dosa", "lunch": "Rice and chicken curry", "dinner": "Dal and roti"}, |
| "Saturday": {"breakfast": "Puri with aloo", "lunch": "Vegetable pulao", "dinner": "Chicken fry"}, |
| "Sunday": {"breakfast": "Paratha", "lunch": "Rice and sambar", "dinner": "Dal tadka"} |
| } |
| if "South Indian" in cultural_preferences.lower(): |
| diet_plan.update({"Monday": {"breakfast": "Idli with sambar", "lunch": "Rice and rasam", "dinner": "Vegetable curry"}, |
| "Friday": {"breakfast": "Dosa with chutney", "lunch": "Rice and fish curry", "dinner": "Dal"}}) |
| elif "North Indian" in cultural_preferences.lower(): |
| diet_plan.update({"Monday": {"breakfast": "Paratha with curd", "lunch": "Roti and paneer", "dinner": "Dal makhani"}, |
| "Friday": {"breakfast": "Puri with aloo", "lunch": "Roti and chole", "dinner": "Vegetable pulao"}}) |
|
|
| cache_diet_plan(user_id, diet_plan) |
| logger.info("Diet plan generated and cached for user_id: %s", user_id) |
| diet_plan_output = format_diet_plan(diet_plan, lang) |
| local_foods_output = format_local_foods(LOCAL_FOODS, lang) |
| return translate_output("status_success", lang), local_foods_output, diet_plan_output |
|
|
| |
| def format_diet_plan(diet_plan, lang): |
| trans = translate_output("", lang) |
| output = "" |
| for day, meals in diet_plan.items(): |
| output += f"### {trans[day.lower()]}\n" |
| output += f"- **{trans['breakfast']}**: {meals['breakfast']}\n" |
| output += f"- **{trans['lunch']}**: {meals['lunch']}\n" |
| output += f"- **{trans['dinner']}**: {meals['dinner']}\n\n" |
| return output |
|
|
| def format_local_foods(local_foods, lang): |
| return [f"{food['name']} - ₹{food['price_per_unit']}/{food['unit']} from {food['source']}" for food in local_foods] |
|
|
| |
| def cache_diet_plan(user_id, diet_plan): |
| logger.info(f"Caching diet plan for user: {user_id}") |
| try: |
| with open(f"cache_{user_id}.json", "w") as f: |
| json.dump(diet_plan, f) |
| except Exception as e: |
| logger.error(f"Error caching diet plan: {e}") |
|
|
| def load_cached_plan(user_id): |
| logger.info(f"Loading cached diet plan for user: {user_id}") |
| try: |
| with open(f"cache_{user_id}.json", "r") as f: |
| return json.load(f) |
| except: |
| return None |
|
|
| |
| def submit_dietitian_feedback(feedback, lang): |
| logger.info(f"Submitting dietitian feedback: {feedback}") |
| if not feedback or feedback.strip() == "": |
| return "Error: Please provide feedback" |
| try: |
| with open("dietitian_feedback.json", "a") as f: |
| f.write(json.dumps({"feedback": feedback, "lang": lang}) + "\n") |
| except Exception as e: |
| logger.error(f"Error saving dietitian feedback: {e}") |
| return translate_output("feedback_dietitian", lang) |
|
|
| def submit_user_feedback(feedback, lang): |
| logger.info(f"Submitting user feedback: {feedback}") |
| if not feedback or feedback.strip() == "": |
| return "Error: Please provide feedback" |
| try: |
| with open("user_feedback.json", "a") as f: |
| f.write(json.dumps({"feedback": feedback, "lang": lang}) + "\n") |
| except Exception as e: |
| logger.error(f"Error saving user feedback: {e}") |
| return translate_output("feedback_user", lang) |
|
|
| |
| def main(): |
| with gr.Blocks(title="Personalized Diet Generator", theme=custom_theme, css=""" |
| .container { max-width: 900px; margin: 20px auto; padding: 25px; background: #00695C; border-radius: 15px; box-shadow: 0 4px 8px rgba(0,0,0,0.1); } |
| .card { background: #BF360C; padding: 20px; margin-bottom: 25px; border-radius: 10px; box-shadow: 0 2px 6px rgba(0,0,0,0.1); color: #FFFFFF; } |
| .diet-plan { min-height: 400px; font-size: 18px; color: #FFFFFF; } |
| .gr-button { background: #FFCA28; color: #000000; padding: 12px 25px; border: none; border-radius: 8px; font-size: 16px; } |
| .gr-button:hover { background: #FFB300; } |
| .gr-textbox { font-size: 16px; padding: 10px; border: 2px solid #FFCA28; border-radius: 5px; background: #FFFFFF; color: #000000; } |
| .gr-slider { width: 100%; } |
| .gr-dropdown { font-size: 16px; padding: 10px; background: #FFFFFF; color: #000000; } |
| h3 { color: #FFCA28; font-size: 24px; } |
| """) as demo: |
| language = gr.Dropdown( |
| choices=["English", "Hindi"], |
| value="English", |
| label="Select Language" |
| ) |
|
|
| def update_interface(lang): |
| trans = translate_output("", lang) |
| return gr.Markdown(f"### {trans['app_title']}", elem_classes="container"), \ |
| gr.Markdown(f"### {trans['dietitian_review']}", visible=True), \ |
| gr.Markdown(f"### {trans['your_feedback']}", visible=True), \ |
| gr.Slider(minimum=18, maximum=80, value=35, label=trans["age"], step=1), \ |
| gr.Dropdown(choices=["Male", "Female", "Other"], value="Male", label=trans["gender"]), \ |
| gr.Slider(minimum=20, maximum=150, value=60, label=trans["weight"], step=0.5), \ |
| gr.Slider(minimum=4.0, maximum=6.5, value=5.2, step=0.01, label=trans["height"]), \ |
| gr.Textbox(label=trans["occupation"], value="Farmer"), \ |
| gr.Microphone(label=trans["occupation"] + " (Optional)"), \ |
| gr.Dropdown(choices=["Low", "Moderate", "High"], value="Moderate", label=trans["activity_level"]), \ |
| gr.Textbox(label=trans["health_conditions"], value="None"), \ |
| gr.Textbox(label=trans["dietary_preferences"], value="None"), \ |
| gr.Textbox(label=trans["allergies"], value="None"), \ |
| gr.Slider(minimum=830, maximum=41500, value=5000, label=trans["weekly_budget"]), \ |
| gr.Textbox(label=trans["pincode"], value="500075"), \ |
| gr.Textbox(label=trans["cultural_preferences"], value="South Indian"), \ |
| gr.Checkbox(label=trans["consent"], value=False) |
|
|
| language.change( |
| fn=update_interface, |
| inputs=[language], |
| outputs=[ |
| gr.Markdown(elem_classes="container"), |
| gr.Markdown(visible=True), |
| gr.Markdown(visible=True), |
| gr.Slider(), |
| gr.Dropdown(), |
| gr.Slider(), |
| gr.Slider(), |
| gr.Textbox(), |
| gr.Microphone(), |
| gr.Dropdown(), |
| gr.Textbox(), |
| gr.Textbox(), |
| gr.Textbox(), |
| gr.Slider(), |
| gr.Textbox(), |
| gr.Textbox(), |
| gr.Checkbox() |
| ] |
| ) |
|
|
| trans_init = translate_output("", "English") |
| with gr.Row(elem_classes="container"): |
| with gr.Column(scale=1, elem_classes="card"): |
| age = gr.Slider(minimum=18, maximum=80, value=35, label=trans_init["age"], step=1) |
| gender = gr.Dropdown(choices=["Male", "Female", "Other"], value="Male", label=trans_init["gender"]) |
| weight = gr.Slider(minimum=20, maximum=150, value=60, label=trans_init["weight"], step=0.5) |
| height = gr.Slider(minimum=4.0, maximum=6.5, value=5.2, step=0.01, label=trans_init["height"]) |
| occupation = gr.Textbox(label=trans_init["occupation"], value="Farmer") |
| audio_input = gr.Microphone(label=trans_init["occupation"] + " (Optional)") |
| with gr.Column(scale=1, elem_classes="card"): |
| activity_level = gr.Dropdown(choices=["Low", "Moderate", "High"], value="Moderate", label=trans_init["activity_level"]) |
| health_conditions = gr.Textbox(label=trans_init["health_conditions"], value="None") |
| dietary_preferences = gr.Textbox(label=trans_init["dietary_preferences"], value="None") |
| allergies = gr.Textbox(label=trans_init["allergies"], value="None") |
| budget = gr.Slider(minimum=830, maximum=41500, value=5000, label=trans_init["weekly_budget"]) |
|
|
| with gr.Row(elem_classes="container"): |
| with gr.Column(scale=1, elem_classes="card"): |
| zip_code = gr.Textbox(label=trans_init["pincode"], value="500075") |
| cultural_preferences = gr.Textbox(label=trans_init["cultural_preferences"], value="South Indian") |
| consent = gr.Checkbox(label=trans_init["consent"], value=False) |
| submit_button = gr.Button("Generate Diet Plan") |
|
|
| with gr.Row(elem_classes="container"): |
| with gr.Column(scale=1, elem_classes="card"): |
| status = gr.Textbox(label="Status") |
| local_foods = gr.Textbox(label="Local Food Sources", lines=4) |
| diet_plan = gr.Markdown(label="Weekly Diet Plan", elem_classes="diet-plan") |
|
|
| with gr.Row(elem_classes="container"): |
| with gr.Column(scale=1, elem_classes="card"): |
| gr.Markdown(f"### {trans_init['dietitian_review']}") |
| dietitian_feedback = gr.Textbox(label="Dietitian Feedback", value="Plan looks balanced. Suggest adding more greens.") |
| dietitian_submit = gr.Button("Submit Feedback") |
| dietitian_output = gr.Textbox(label="Feedback Status") |
|
|
| with gr.Row(elem_classes="container"): |
| with gr.Column(scale=1, elem_classes="card"): |
| gr.Markdown(f"### {trans_init['your_feedback']}") |
| user_feedback = gr.Textbox(label="Your Feedback") |
| user_submit = gr.Button("Submit Feedback") |
| user_output = gr.Textbox(label="Feedback Status") |
|
|
| |
| submit_button.click( |
| fn=generate_diet_plan, |
| inputs=[age, gender, weight, height, occupation, activity_level, health_conditions, |
| dietary_preferences, allergies, budget, zip_code, cultural_preferences, consent, language, audio_input], |
| outputs=[status, local_foods, diet_plan] |
| ) |
| dietitian_submit.click( |
| fn=submit_dietitian_feedback, |
| inputs=[dietitian_feedback, language], |
| outputs=dietitian_output |
| ) |
| user_submit.click( |
| fn=submit_user_feedback, |
| inputs=[user_feedback, language], |
| outputs=user_output |
| ) |
|
|
| return demo |
|
|
| if __name__ == "__main__": |
| demo = main() |
| demo.launch(server_name="0.0.0.0", server_port=7860) |