File size: 12,708 Bytes
4ef990b
e1fb3b2
f973312
e0bdeef
a548a89
 
25b6c4d
e0bdeef
f0cbaa0
70448af
 
 
 
e0bdeef
 
580f8c8
3522bb9
580f8c8
 
a548a89
f973312
3522bb9
a548a89
 
f973312
a548a89
 
580f8c8
 
 
54c24d5
e1fb3b2
e0bdeef
580f8c8
 
 
f973312
70448af
 
f973312
580f8c8
 
 
a548a89
f0cbaa0
70448af
 
f973312
580f8c8
c2a5b7b
580f8c8
 
c2a5b7b
f973312
580f8c8
 
f973312
 
 
 
580f8c8
 
f973312
70448af
580f8c8
 
70448af
f0cbaa0
a548a89
70448af
f0cbaa0
70448af
580f8c8
 
 
 
 
 
 
 
 
 
 
 
 
 
a548a89
 
580f8c8
 
 
 
 
 
f973312
 
580f8c8
f973312
 
 
 
 
580f8c8
 
 
f973312
 
580f8c8
f973312
731f155
e1fb3b2
c2a5b7b
70448af
a548a89
54c24d5
70448af
f973312
fe937b3
c2a5b7b
 
580f8c8
 
c2a5b7b
 
 
3522bb9
 
 
 
 
 
 
 
 
 
 
c2a5b7b
 
 
 
 
 
 
 
a548a89
580f8c8
 
 
 
fe937b3
e1fb3b2
580f8c8
 
fe937b3
580f8c8
 
 
 
4dbc7c0
a548a89
54c24d5
580f8c8
 
 
a548a89
 
 
 
 
 
 
 
 
e0bdeef
a548a89
 
580f8c8
 
 
a548a89
 
 
 
 
 
 
54c24d5
a548a89
 
fe937b3
a548a89
fe937b3
70448af
 
f973312
70448af
 
 
 
fe937b3
a548a89
 
fe937b3
 
580f8c8
 
3522bb9
 
 
580f8c8
 
 
 
 
 
 
3522bb9
 
 
 
fe937b3
a548a89
25b6c4d
a548a89
fe937b3
731f155
 
 
a548a89
731f155
 
 
 
a548a89
fe937b3
a548a89
fe937b3
a548a89
fe937b3
a548a89
731f155
 
 
 
 
a548a89
fe937b3
 
4dbc7c0
731f155
 
580f8c8
731f155
fe937b3
 
731f155
6ed2a87
f0cbaa0
580f8c8
3522bb9
 
6ed2a87
fe937b3
 
580f8c8
 
3522bb9
fe937b3
 
4dbc7c0
 
6ed2a87
fe937b3
580f8c8
fe937b3
580f8c8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6ed2a87
fe937b3
580f8c8
 
 
 
 
fe937b3
580f8c8
 
 
 
 
 
 
 
 
 
 
 
 
 
e1fb3b2
a548a89
 
6ed2a87
e1fb3b2
 
a548a89
e1fb3b2
a548a89
e1fb3b2
 
 
a548a89
e1fb3b2
a548a89
e1fb3b2
4ef990b
731f155
580f8c8
 
 
731f155
 
3522bb9
f0cbaa0
fe937b3
 
 
e0bdeef
a548a89
 
e0bdeef
3522bb9
580f8c8
 
e0bdeef
 
a548a89
70448af
4ef990b
fe937b3
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
import gradio as gr
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline
import logging
from typing import List, Dict
import gc
import os

# Setup logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

# Set environment variables for memory optimization
os.environ['TRANSFORMERS_CACHE'] = '/home/user/.cache/huggingface/hub'
os.environ['TOKENIZERS_PARALLELISM'] = 'false'

class HealthAssistant:
    def __init__(self):
        self.model_id = "microsoft/Phi-2"  # Using smaller Phi-2 model
        self.model = None
        self.tokenizer = None
        self.pipe = None
        self.metrics = []
        self.medications = []
        self.device = "cpu"
        self.is_model_loaded = False
        self.max_history_length = 2

    def initialize_model(self):
        try:
            if self.is_model_loaded:
                return True

            logger.info(f"Loading model: {self.model_id}")
            
            self.tokenizer = AutoTokenizer.from_pretrained(
                self.model_id,
                trust_remote_code=True,
                model_max_length=256,
                padding_side="left"
            )
            logger.info("Tokenizer loaded")

            self.model = AutoModelForCausalLM.from_pretrained(
                self.model_id,
                torch_dtype=torch.float32,
                trust_remote_code=True,
                device_map=None,
                low_cpu_mem_usage=True
            ).to(self.device)

            gc.collect()
            
            self.pipe = pipeline(
                "text-generation",
                model=self.model,
                tokenizer=self.tokenizer,
                device=self.device,
                model_kwargs={"low_cpu_mem_usage": True}
            )
            
            self.is_model_loaded = True
            logger.info("Model initialized successfully")
            return True
            
        except Exception as e:
            logger.error(f"Error in model initialization: {str(e)}")
            raise

    def unload_model(self):
        if hasattr(self, 'model') and self.model is not None:
            del self.model
            self.model = None
        if hasattr(self, 'pipe') and self.pipe is not None:
            del self.pipe
            self.pipe = None
        if hasattr(self, 'tokenizer') and self.tokenizer is not None:
            del self.tokenizer
            self.tokenizer = None
        self.is_model_loaded = False
        gc.collect()
        logger.info("Model unloaded successfully")

    def generate_response(self, message: str, history: List = None) -> str:
        try:
            if not self.is_model_loaded:
                self.initialize_model()
            
            message = message[:200]  # Truncate long messages
            
            prompt = self._prepare_prompt(message, history[-self.max_history_length:] if history else None)

            generation_args = {
                "max_new_tokens": 200,
                "return_full_text": False,
                "temperature": 0.7,
                "do_sample": True,
                "top_k": 50,
                "top_p": 0.9,
                "repetition_penalty": 1.1,
                "num_return_sequences": 1,
                "batch_size": 1
            }

            output = self.pipe(prompt, **generation_args)
            response = output[0]['generated_text']

            gc.collect()
            
            return response.strip()

        except Exception as e:
            logger.error(f"Error generating response: {str(e)}")
            return "I apologize, but I encountered an error. Please try again."

    def _prepare_prompt(self, message: str, history: List = None) -> str:
        prompt_parts = [
            "Medical AI assistant. Be professional, include disclaimers.",
            self._get_health_context()
        ]
        
        if history:
            for h in history:
                if isinstance(h, dict):  # New message format
                    if h['role'] == 'user':
                        prompt_parts.append(f"Human: {h['content'][:100]}")
                    else:
                        prompt_parts.append(f"Assistant: {h['content'][:100]}")
                else:  # Old format (tuple)
                    prompt_parts.extend([
                        f"Human: {h[0][:100]}",
                        f"Assistant: {h[1][:100]}"
                    ])
        
        prompt_parts.extend([
            f"Human: {message}",
            "Assistant:"
        ])
        
        return "\n".join(prompt_parts)

    def _get_health_context(self) -> str:
        if not self.metrics and not self.medications:
            return "No health data"
            
        context = []
        if self.metrics:
            latest = self.metrics[-1]
            context.append(f"Metrics: W:{latest['Weight']}kg S:{latest['Steps']} Sl:{latest['Sleep']}h")
        
        if self.medications:
            meds = [f"{m['Medication']}({m['Dosage']}@{m['Time']})" for m in self.medications[-2:]]
            context.append("Meds: " + ", ".join(meds))
            
        return " | ".join(context)

    def add_metrics(self, weight: float, steps: int, sleep: float) -> bool:
        try:
            if len(self.metrics) >= 5:
                self.metrics.pop(0)
                
            self.metrics.append({
                'Weight': weight,
                'Steps': steps,
                'Sleep': sleep
            })
            return True
        except Exception as e:
            logger.error(f"Error adding metrics: {e}")
            return False

    def add_medication(self, name: str, dosage: str, time: str, notes: str = "") -> bool:
        try:
            if len(self.medications) >= 5:
                self.medications.pop(0)
                
            self.medications.append({
                'Medication': name,
                'Dosage': dosage,
                'Time': time,
                'Notes': notes
            })
            return True
        except Exception as e:
            logger.error(f"Error adding medication: {e}")
            return False

class GradioInterface:
    def __init__(self):
        try:
            logger.info("Initializing Health Assistant...")
            self.assistant = HealthAssistant()
            logger.info("Health Assistant initialized successfully")
        except Exception as e:
            logger.error(f"Failed to initialize Health Assistant: {e}")
            raise

    def chat_response(self, message: str, history: List) -> tuple:
        if not message.strip():
            return "", history
        
        try:
            response = self.assistant.generate_response(message, history)
            # Convert to new message format
            history.append({"role": "user", "content": message})
            history.append({"role": "assistant", "content": response})
            
            if len(history) % 3 == 0:
                self.assistant.unload_model()
                
            return "", history
        except Exception as e:
            logger.error(f"Error in chat response: {e}")
            return "", history + [
                {"role": "user", "content": message},
                {"role": "assistant", "content": "I apologize, but I encountered an error. Please try again."}
            ]

    def add_health_metrics(self, weight: float, steps: int, sleep: float) -> str:
        if not all([weight is not None, steps is not None, sleep is not None]):
            return "⚠️ Please fill in all metrics."
        
        if weight <= 0 or steps < 0 or sleep < 0:
            return "⚠️ Please enter valid positive numbers."
        
        if self.assistant.add_metrics(weight, steps, sleep):
            return f"""βœ… Health metrics saved successfully!
β€’ Weight: {weight} kg
β€’ Steps: {steps}
β€’ Sleep: {sleep} hours"""
        return "❌ Error saving metrics."

    def add_medication_info(self, name: str, dosage: str, time: str, notes: str) -> str:
        if not all([name, dosage, time]):
            return "⚠️ Please fill in all required fields."
        
        if self.assistant.add_medication(name, dosage, time, notes):
            return f"""βœ… Medication added successfully!
β€’ Medication: {name}
β€’ Dosage: {dosage}
β€’ Time: {time}
β€’ Notes: {notes if notes else 'None'}"""
        return "❌ Error adding medication."

    def create_interface(self):
        with gr.Blocks(title="Medical Health Assistant") as demo:
            gr.Markdown("""
            # πŸ₯ Medical Health Assistant
            This AI assistant provides general health information and guidance.
            """)
            
            with gr.Tabs():
                with gr.Tab("πŸ’¬ Medical Consultation"):
                    chatbot = gr.Chatbot(
                        value=[],
                        height=400,
                        label=False,
                        type="messages"  # Using new message format
                    )
                    with gr.Row():
                        msg = gr.Textbox(
                            placeholder="Ask your health question...",
                            lines=1,
                            label=False,
                            scale=9
                        )
                        send_btn = gr.Button("Send", scale=1)
                    clear_btn = gr.Button("Clear Chat")

                with gr.Tab("πŸ“Š Health Metrics"):
                    gr.Markdown("### Track Your Health Metrics")
                    with gr.Row():
                        weight_input = gr.Number(
                            label="Weight (kg)",
                            minimum=0,
                            maximum=500
                        )
                        steps_input = gr.Number(
                            label="Steps",
                            minimum=0,
                            maximum=100000
                        )
                        sleep_input = gr.Number(
                            label="Hours Slept",
                            minimum=0,
                            maximum=24
                        )
                    metrics_btn = gr.Button("Save Metrics")
                    metrics_status = gr.Markdown()

                with gr.Tab("πŸ’Š Medication Manager"):
                    gr.Markdown("### Track Your Medications")
                    med_name = gr.Textbox(
                        label="Medication Name",
                        placeholder="Enter medication name"
                    )
                    with gr.Row():
                        med_dosage = gr.Textbox(
                            label="Dosage",
                            placeholder="e.g., 500mg"
                        )
                        med_time = gr.Textbox(
                            label="Time",
                            placeholder="e.g., 9:00 AM"
                        )
                    med_notes = gr.Textbox(
                        label="Notes (optional)",
                        placeholder="Additional instructions or notes"
                    )
                    med_btn = gr.Button("Add Medication")
                    med_status = gr.Markdown()

            msg.submit(self.chat_response, [msg, chatbot], [msg, chatbot])
            send_btn.click(self.chat_response, [msg, chatbot], [msg, chatbot])
            clear_btn.click(lambda: [], None, chatbot)
            
            metrics_btn.click(
                self.add_health_metrics,
                inputs=[weight_input, steps_input, sleep_input],
                outputs=[metrics_status]
            )
            
            med_btn.click(
                self.add_medication_info,
                inputs=[med_name, med_dosage, med_time, med_notes],
                outputs=[med_status]
            )

            gr.Markdown("""
            ### ⚠️ Medical Disclaimer
            This AI assistant provides general health information only. Not a replacement for professional medical advice.
            Always consult healthcare professionals for medical decisions.
            """)

            demo.queue(max_size=5)
            
        return demo

def main():
    try:
        interface = GradioInterface()
        demo = interface.create_interface()
        demo.launch(
            server_name="0.0.0.0",
            show_error=True,
            share=True
        )
    except Exception as e:
        logger.error(f"Error starting application: {e}")
        raise

if __name__ == "__main__":
    main()