anushkab0602 commited on
Commit
5cd2da7
Β·
verified Β·
1 Parent(s): 22a81d7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +344 -285
app.py CHANGED
@@ -1,247 +1,284 @@
1
  import gradio as gr
2
- import torch
3
- from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig
4
  import requests
5
  import json
6
  import time
 
7
  from typing import List, Dict, Optional
8
- import threading
9
- import re
10
- # Configuration
11
- MCP_SERVER_URL = "https://your-mcp-server.hf.space/mcp" # Update this!
12
- MODEL_NAME = "TinyLlama/TinyLlama-1.1B-Chat-v1.0"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  # Global variables
14
- model = None
15
- tokenizer = None
16
- model_loaded = False
17
  user_profiles = {}
18
- class MCPKnowledgeBase:
19
- """Retrieves Ayurvedic knowledge from MCP server"""
20
-
21
- def __init__(self, server_url: str):
22
- self.server_url = server_url
23
- self.session = requests.Session()
24
- self.session.headers.update({'Content-Type': 'application/json'})
25
 
26
- def call_mcp_tool(self, tool_name: str, arguments: Dict) -> str:
27
- payload = {
28
- "jsonrpc": "2.0",
29
- "id": int(time.time()),
30
- "method": "tools/call",
31
- "params": {"name": tool_name, "arguments": arguments}
32
- }
33
 
 
 
34
  try:
35
- response = self.session.post(self.server_url, json=payload, timeout=10)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  if response.status_code == 200:
37
  result = response.json()
38
  if "result" in result and "content" in result["result"]:
39
  content = result["result"]["content"]
40
  if content and len(content) > 0:
41
  return content[0].get("text", "")
42
- return ""
43
  except:
44
- return ""
45
-
46
- def get_knowledge(self, query: str, user_profile: Dict) -> str:
47
- """Get relevant Ayurvedic knowledge based on query"""
48
- query_lower = query.lower()
49
- dosha = user_profile.get('constitution', '').lower()
50
- concerns = user_profile.get('concerns', '')
51
 
52
- # Smart knowledge retrieval based on query intent
53
- if any(word in query_lower for word in ['herb', 'medicine', 'remedy', 'treat']):
54
- condition = self.extract_condition(query) or concerns or 'stress'
55
- return self.call_mcp_tool("recommend_herbs", {
56
- "condition": condition,
57
- "dosha": dosha if dosha not in ['unknown', ''] else None,
58
- "severity": "moderate"
59
- })
 
 
 
 
 
 
 
60
 
61
- elif any(word in query_lower for word in ['diet', 'food', 'eat', 'nutrition']):
62
- if dosha and dosha not in ['unknown', '']:
63
- return self.call_mcp_tool("diet_recommendations", {
64
- "dosha": dosha,
65
- "season": "spring"
66
- })
67
-
68
- elif any(word in query_lower for word in ['routine', 'daily', 'schedule']):
69
- if dosha and dosha not in ['unknown', '']:
70
- return self.call_mcp_tool("daily_routine", {
71
- "dosha": dosha,
72
- "lifestyle": "active"
73
- })
74
-
75
- elif any(word in query_lower for word in ['yoga', 'exercise', 'asana']):
76
- if dosha and dosha not in ['unknown', '']:
77
- return self.call_mcp_tool("yoga_recommendations", {
78
- "dosha": dosha,
79
- "experience_level": "beginner"
80
- })
 
 
 
 
 
 
 
 
 
81
 
82
- elif any(word in query_lower for word in ['dosha', 'constitution', 'assessment']):
83
- return self.call_mcp_tool("seasonal_health_tips", {
84
- "season": "spring",
85
- "dosha": dosha if dosha not in ['unknown', ''] else None
86
- })
 
 
 
 
 
 
87
 
88
- return ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
 
90
- def extract_condition(self, query: str) -> Optional[str]:
91
- conditions = {
92
- 'stress': ['stress', 'anxiety', 'worry', 'tension'],
93
- 'digestion': ['digestion', 'stomach', 'acidity', 'bloating', 'gas'],
94
- 'sleep': ['sleep', 'insomnia', 'rest', 'tired'],
95
- 'joint pain': ['joint', 'pain', 'arthritis', 'stiff'],
96
- 'skin': ['skin', 'acne', 'rash', 'eczema'],
97
- 'weight': ['weight', 'obesity', 'fat', 'heavy']
98
- }
99
-
100
- query_lower = query.lower()
101
- for condition, keywords in conditions.items():
102
- if any(keyword in query_lower for keyword in keywords):
103
- return condition
104
- return None
105
- def load_tinyllama():
106
- """Load TinyLlama model optimized for HF Spaces"""
107
- global model, tokenizer, model_loaded
 
108
 
109
- try:
110
- print("Loading TinyLlama model...")
111
 
112
- # Use 4-bit quantization for memory efficiency
113
- quantization_config = BitsAndBytesConfig(
114
- load_in_4bit=True,
115
- bnb_4bit_compute_dtype=torch.float16,
116
- bnb_4bit_use_double_quant=True,
117
- bnb_4bit_quant_type="nf4"
118
- )
119
 
120
- tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
121
- if tokenizer.pad_token is None:
122
- tokenizer.pad_token = tokenizer.eos_token
 
123
 
124
- model = AutoModelForCausalLM.from_pretrained(
125
- MODEL_NAME,
126
- quantization_config=quantization_config,
127
- device_map="auto",
128
- torch_dtype=torch.float16,
129
- trust_remote_code=True
130
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
 
132
- model_loaded = True
133
- return "βœ… TinyLlama loaded successfully!"
 
 
 
134
 
135
- except Exception as e:
136
- model_loaded = False
137
- return f"❌ Failed to load model: {str(e)}"
138
- def generate_response(user_message: str, chat_history: List, user_profile: Dict) -> str:
139
- """Generate conversational response using TinyLlama + MCP knowledge"""
140
-
141
- if not model_loaded:
142
- return "⚠️ Please load the model first using the 'Load Model' button."
143
-
144
- # Get relevant Ayurvedic knowledge
145
- knowledge_base = MCPKnowledgeBase(MCP_SERVER_URL)
146
- ayurveda_knowledge = knowledge_base.get_knowledge(user_message, user_profile)
147
-
148
- # Build context from chat history
149
- context = ""
150
- if chat_history:
151
- recent_chat = chat_history[-2:] if len(chat_history) >= 2 else chat_history
152
- context = "\n".join([f"Human: {h[0]}\nDr. Ayur: {h[1]}" for h in recent_chat])
 
 
 
 
 
 
153
 
154
- # User profile context
155
- user_info = ""
156
- if user_profile:
157
  name = user_profile.get('name', 'friend')
158
- dosha = user_profile.get('constitution', '')
159
- concerns = user_profile.get('concerns', '')
160
- user_info = f"User: {name}, Constitution: {dosha}, Concerns: {concerns}"
161
-
162
- # Create TinyLlama optimized prompt
163
- system_prompt = """<|system|>
164
- You are Dr. Ayur, a wise and compassionate Ayurvedic doctor. You provide personalized guidance based on ancient Ayurvedic principles.
165
- Your personality:
166
- - Warm, caring, and knowledgeable
167
- - Always start responses with "Namaste"
168
- - Use simple, practical language
169
- - Include relevant Sanskrit terms with translations
170
- - Give actionable advice
171
- - Recommend consulting practitioners for serious issues
172
- Response style:
173
- - Keep responses 2-3 sentences for simple questions
174
- - Be more detailed for complex health advice
175
- - Always be encouraging and supportive
176
- <|user|>"""
177
- # Build the complete prompt
178
- if ayurveda_knowledge:
179
- knowledge_section = f"\n\nAyurvedic Knowledge:\n{ayurveda_knowledge[:800]}" # Limit knowledge
180
- else:
181
- knowledge_section = ""
182
-
183
- if user_info:
184
- user_section = f"\n\nUser Profile:\n{user_info}"
185
- else:
186
- user_section = ""
187
-
188
- if context:
189
- history_section = f"\n\nRecent conversation:\n{context}"
190
- else:
191
- history_section = ""
192
-
193
- prompt = f"""{system_prompt}{knowledge_section}{user_section}{history_section}
194
- Current question: {user_message}
195
- <|assistant|>
196
- Namaste! """
197
- try:
198
- # Tokenize with length limits for HF Spaces
199
- inputs = tokenizer.encode(prompt, return_tensors='pt', truncation=True, max_length=1500)
200
 
201
- with torch.no_grad():
202
- outputs = model.generate(
203
- inputs,
204
- max_new_tokens=200, # Reasonable limit for responses
205
- temperature=0.8,
206
- do_sample=True,
207
- top_p=0.9,
208
- top_k=50,
209
- repetition_penalty=1.1,
210
- pad_token_id=tokenizer.eos_token_id,
211
- eos_token_id=tokenizer.eos_token_id
212
- )
213
 
214
- # Decode response
215
- response = tokenizer.decode(outputs[0][inputs.shape[1]:], skip_special_tokens=True).strip()
216
 
217
- # Clean up response
218
- response = response.split("<|user|>")[0].split("<|system|>")[0].strip()
219
 
220
- # Ensure proper greeting
221
- if not response.startswith("Namaste"):
222
- response = "Namaste! " + response
223
 
224
- # Fallback for very short responses
225
- if len(response) < 20:
226
- return create_fallback_response(user_message, user_profile, ayurveda_knowledge)
227
 
228
- return response
 
229
 
230
- except Exception as e:
231
- print(f"Generation error: {e}")
232
- return create_fallback_response(user_message, user_profile, ayurveda_knowledge)
233
- def create_fallback_response(user_message: str, user_profile: Dict, knowledge: str) -> str:
234
- """Create fallback response when LLM fails"""
235
- name = user_profile.get('name', 'friend') if user_profile else 'friend'
236
-
237
- if knowledge:
238
- return f"Namaste {name}! Based on Ayurvedic principles:\n\n{knowledge[:500]}..."
239
- else:
240
- return f"Namaste {name}! I'd be happy to help with your Ayurveda question about {user_message}. Could you tell me more about your constitution or specific concerns?"
 
241
  def save_profile(name: str, age: int, constitution: str, concerns: str):
242
  """Save user profile"""
243
  if not name.strip():
244
- return "❌ Please enter your name"
245
 
246
  profile = {
247
  "name": name.strip(),
@@ -251,146 +288,168 @@ def save_profile(name: str, age: int, constitution: str, concerns: str):
251
  }
252
 
253
  user_profiles[name.lower()] = profile
254
- return f"βœ… Profile saved for {name}!"
255
- def get_user_profile(message: str) -> Dict:
256
- """Get user profile, prioritizing the most recent one"""
257
- # Try to find profile by name mention in message
258
- for name, profile in user_profiles.items():
259
- if name in message.lower():
260
- return profile
261
-
262
- # Return most recent profile if available
263
  if user_profiles:
264
  return list(user_profiles.values())[-1]
265
-
266
  return {}
267
  def chat_interface(message: str, history: List) -> tuple:
268
- """Main chat interface"""
269
  if not message.strip():
270
  return "", history
271
 
272
- user_profile = get_user_profile(message)
273
- response = generate_response(message.strip(), history, user_profile)
274
  history.append([message, response])
275
 
276
  return "", history
277
- def test_mcp_connection():
278
- """Test MCP server connection"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
279
  try:
280
- knowledge_base = MCPKnowledgeBase(MCP_SERVER_URL)
281
- test_result = knowledge_base.call_mcp_tool("seasonal_health_tips", {"season": "spring"})
282
- if test_result:
283
- return "βœ… MCP server connected successfully!"
284
  else:
285
- return "⚠️ MCP server responded but returned empty result"
286
- except Exception as e:
287
- return f"❌ MCP connection failed: {str(e)}"
288
- # Custom CSS
289
- css = """
290
- .gradio-container {
291
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
292
- }
293
- .chat-message {
294
- padding: 10px;
295
- margin: 5px 0;
296
- border-radius: 10px;
297
- }
298
- """
299
- # Create Gradio interface
300
- with gr.Blocks(title="Dr. Ayur - Conversational AI", css=css, theme=gr.themes.Soft()) as app:
301
 
302
  gr.HTML("""
303
  <div style="text-align: center; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
304
  color: white; padding: 20px; border-radius: 10px; margin-bottom: 20px;">
305
  <h1>πŸ•‰οΈ Dr. Ayur - Conversational Ayurvedic AI</h1>
306
- <p>Natural conversations about Ayurveda powered by TinyLlama and traditional wisdom</p>
307
  </div>
308
  """)
309
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
310
  with gr.Row():
311
  with gr.Column(scale=3):
312
  chatbot = gr.Chatbot(
313
  height=500,
314
- placeholder="Start chatting with Dr. Ayur about your health and wellness...",
315
  show_label=False
316
  )
317
 
318
  with gr.Row():
319
  msg_input = gr.Textbox(
320
- label="",
321
- placeholder="Ask Dr. Ayur anything about Ayurveda, health, or wellness...",
322
  scale=4,
323
  container=False
324
  )
325
  send_btn = gr.Button("Send", variant="primary", scale=1)
326
 
327
- with gr.Row():
328
- clear_btn = gr.Button("Clear Chat", variant="secondary")
329
-
330
- with gr.Column(scale=1):
331
- gr.Markdown("### πŸŽ›οΈ System Controls")
332
-
333
- load_model_btn = gr.Button("πŸ€– Load TinyLlama Model", variant="primary")
334
- test_mcp_btn = gr.Button("πŸ”Œ Test MCP Connection")
335
 
336
- system_status = gr.Textbox(
337
- label="System Status",
338
- value="Click 'Load TinyLlama Model' to start",
 
 
 
339
  interactive=False,
340
- lines=3
341
  )
342
 
343
- gr.Markdown("### πŸ‘€ User Profile")
344
-
345
  with gr.Group():
346
- profile_name = gr.Textbox(label="Name", placeholder="Your name")
347
  profile_age = gr.Number(label="Age", value=30, minimum=1, maximum=120)
348
  profile_constitution = gr.Dropdown(
349
- label="Constitution (if known)",
350
- choices=["Unknown", "Vata", "Pitta", "Kapha", "Vata-Pitta", "Pitta-Kapha", "Vata-Kapha"],
351
- value="Unknown"
352
  )
353
  profile_concerns = gr.Textbox(
354
- label="Health Concerns",
355
- placeholder="e.g., stress, digestion, sleep",
356
  lines=2
357
  )
358
- save_profile_btn = gr.Button("πŸ’Ύ Save Profile")
359
- profile_status = gr.Textbox(label="Profile Status", interactive=False)
360
 
361
- gr.Markdown("### πŸ’‘ Try asking:")
362
  gr.Markdown("""
363
- - "What's my dosha?"
364
- - "Help with stress and anxiety"
365
- - "Best foods for pitta constitution"
366
- - "Daily routine for better health"
367
- - "Yoga poses for beginners"
368
- - "Herbs for better sleep"
369
  """)
370
  # Event handlers
371
  msg_input.submit(chat_interface, [msg_input, chatbot], [msg_input, chatbot])
372
  send_btn.click(chat_interface, [msg_input, chatbot], [msg_input, chatbot])
373
  clear_btn.click(lambda: [], outputs=[chatbot])
374
 
375
- load_model_btn.click(load_tinyllama, outputs=[system_status])
376
- test_mcp_btn.click(test_mcp_connection, outputs=[system_status])
377
-
378
- save_profile_btn.click(
379
  save_profile,
380
  [profile_name, profile_age, profile_constitution, profile_concerns],
381
  [profile_status]
382
  )
383
  gr.HTML("""
384
  <div style="text-align: center; margin-top: 20px; padding: 15px;
385
- background: #f8f9fa; border-radius: 10px; font-size: 0.9em;">
386
- <p><strong>Disclaimer:</strong> Dr. Ayur provides educational information only.
387
- Always consult qualified Ayurvedic practitioners for personalized treatment.</p>
388
- <p>πŸ”— <strong>Powered by:</strong> TinyLlama + Model Context Protocol + Traditional Ayurvedic Wisdom</p>
389
  </div>
390
  """)
391
  if __name__ == "__main__":
392
- app.launch(
393
- share=True,
394
- server_name="0.0.0.0",
395
- server_port=7860
396
- )
 
1
  import gradio as gr
 
 
2
  import requests
3
  import json
4
  import time
5
+ import os
6
  from typing import List, Dict, Optional
7
+ import random
8
+ # Multiple free LLM API options
9
+ LLM_PROVIDERS = {
10
+ "huggingface": {
11
+ "url": "https://api-inference.huggingface.co/models/microsoft/DialoGPT-large",
12
+ "headers": {"Authorization": f"Bearer {os.getenv('HF_TOKEN', '')}"},
13
+ "free": True
14
+ },
15
+ "together": {
16
+ "url": "https://api.together.xyz/inference",
17
+ "model": "togethercomputer/RedPajama-INCITE-Chat-3B-v1",
18
+ "headers": {"Authorization": f"Bearer {os.getenv('TOGETHER_API_KEY', '')}"},
19
+ "free": True # Has free tier
20
+ },
21
+ "replicate": {
22
+ "model": "meta/llama-2-7b-chat",
23
+ "free": True # Has free tier
24
+ },
25
+ "groq": {
26
+ "url": "https://api.groq.com/openai/v1/chat/completions",
27
+ "model": "llama3-8b-8192",
28
+ "headers": {"Authorization": f"Bearer {os.getenv('GROQ_API_KEY', '')}"},
29
+ "free": True # Very generous free tier
30
+ }
31
+ }
32
+ # MCP Server for Ayurvedic knowledge
33
+ MCP_SERVER_URL = "https://your-mcp-server.hf.space/mcp"
34
  # Global variables
 
 
 
35
  user_profiles = {}
36
+ conversation_contexts = {}
37
+ class ConversationalAyurBot:
38
+ """Truly conversational Ayurvedic chatbot using free LLMs"""
 
 
 
 
39
 
40
+ def __init__(self):
41
+ self.provider = "groq" # Default to Groq (most reliable free option)
42
+ self.context_window = []
 
 
 
 
43
 
44
+ def get_ayurvedic_context(self, user_message: str, user_profile: Dict) -> str:
45
+ """Get relevant Ayurvedic context from MCP or built-in knowledge"""
46
  try:
47
+ # Try MCP server first
48
+ payload = {
49
+ "jsonrpc": "2.0",
50
+ "id": int(time.time()),
51
+ "method": "tools/call",
52
+ "params": {
53
+ "name": "recommend_herbs",
54
+ "arguments": {
55
+ "condition": user_message,
56
+ "dosha": user_profile.get('constitution', '').lower() if user_profile.get('constitution', '').lower() not in ['unknown', ''] else None
57
+ }
58
+ }
59
+ }
60
+
61
+ response = requests.post(MCP_SERVER_URL, json=payload, timeout=5)
62
  if response.status_code == 200:
63
  result = response.json()
64
  if "result" in result and "content" in result["result"]:
65
  content = result["result"]["content"]
66
  if content and len(content) > 0:
67
  return content[0].get("text", "")
 
68
  except:
69
+ pass
 
 
 
 
 
 
70
 
71
+ # Fallback to curated knowledge snippets
72
+ knowledge_snippets = [
73
+ "Ayurveda emphasizes that like increases like and opposites balance. If you're feeling hot and irritated, cooling foods and practices help.",
74
+ "The three doshas - Vata (air+space), Pitta (fire+water), and Kapha (earth+water) - govern all bodily functions.",
75
+ "Agni, the digestive fire, is central to health. Strong agni means good digestion and immunity.",
76
+ "Ama (toxins) accumulate when digestion is weak. Proper eating habits and detox help remove ama.",
77
+ "Daily routines (dinacharya) aligned with natural cycles promote balance and prevent disease.",
78
+ "Food is medicine in Ayurveda. The six tastes should be included in every meal for balance."
79
+ ]
80
+ return random.choice(knowledge_snippets)
81
+
82
+ def call_groq_api(self, messages: List[Dict]) -> str:
83
+ """Call Groq API (most reliable free option)"""
84
+ try:
85
+ import requests
86
 
87
+ # You can get a free API key from https://console.groq.com/
88
+ groq_api_key = os.getenv('GROQ_API_KEY') or 'your-groq-api-key-here'
89
+
90
+ if groq_api_key == 'your-groq-api-key-here':
91
+ return None # No API key provided
92
+
93
+ headers = {
94
+ "Authorization": f"Bearer {groq_api_key}",
95
+ "Content-Type": "application/json"
96
+ }
97
+
98
+ payload = {
99
+ "model": "llama3-8b-8192",
100
+ "messages": messages,
101
+ "temperature": 0.7,
102
+ "max_tokens": 512,
103
+ "top_p": 0.9
104
+ }
105
+
106
+ response = requests.post(
107
+ "https://api.groq.com/openai/v1/chat/completions",
108
+ headers=headers,
109
+ json=payload,
110
+ timeout=10
111
+ )
112
+
113
+ if response.status_code == 200:
114
+ result = response.json()
115
+ return result["choices"][0]["message"]["content"]
116
 
117
+ except Exception as e:
118
+ print(f"Groq API error: {e}")
119
+ return None
120
+
121
+ def call_huggingface_api(self, prompt: str) -> str:
122
+ """Call HuggingFace Inference API (free)"""
123
+ try:
124
+ hf_token = os.getenv('HF_TOKEN') or 'your-hf-token-here'
125
+
126
+ if hf_token == 'your-hf-token-here':
127
+ return None
128
 
129
+ headers = {"Authorization": f"Bearer {hf_token}"}
130
+
131
+ # Try different models
132
+ models = [
133
+ "microsoft/DialoGPT-large",
134
+ "facebook/blenderbot-400M-distill",
135
+ "microsoft/DialoGPT-medium"
136
+ ]
137
+
138
+ for model in models:
139
+ try:
140
+ response = requests.post(
141
+ f"https://api-inference.huggingface.co/models/{model}",
142
+ headers=headers,
143
+ json={"inputs": prompt, "parameters": {"max_length": 200}},
144
+ timeout=10
145
+ )
146
+
147
+ if response.status_code == 200:
148
+ result = response.json()
149
+ if isinstance(result, list) and len(result) > 0:
150
+ return result[0].get("generated_text", "").replace(prompt, "").strip()
151
+ elif isinstance(result, dict) and "generated_text" in result:
152
+ return result["generated_text"].replace(prompt, "").strip()
153
+ except:
154
+ continue
155
+
156
+ except Exception as e:
157
+ print(f"HuggingFace API error: {e}")
158
+ return None
159
 
160
+ def call_ollama_local(self, messages: List[Dict]) -> str:
161
+ """Call local Ollama if available"""
162
+ try:
163
+ # Check if Ollama is running locally
164
+ response = requests.post(
165
+ "http://localhost:11434/api/chat",
166
+ json={
167
+ "model": "llama2", # or "mistral", "codellama"
168
+ "messages": messages,
169
+ "stream": False
170
+ },
171
+ timeout=10
172
+ )
173
+
174
+ if response.status_code == 200:
175
+ return response.json()["message"]["content"]
176
+
177
+ except:
178
+ return None
179
 
180
+ def generate_conversational_response(self, user_message: str, chat_history: List, user_profile: Dict) -> str:
181
+ """Generate natural conversational response"""
182
 
183
+ # Get Ayurvedic context
184
+ ayur_context = self.get_ayurvedic_context(user_message, user_profile)
 
 
 
 
 
185
 
186
+ # Build conversation context
187
+ name = user_profile.get('name', 'friend')
188
+ dosha = user_profile.get('constitution', 'unknown')
189
+ concerns = user_profile.get('concerns', '')
190
 
191
+ # Create system prompt for conversational AI
192
+ system_prompt = f"""You are Dr. Ayur, a warm, wise, and conversational Ayurvedic doctor. You speak naturally like a caring friend who happens to be an expert in Ayurveda.
193
+ Your personality:
194
+ - Warm, empathetic, and genuinely caring
195
+ - Speaks naturally, not formally or robotically
196
+ - Uses "Namaste" as greeting but then talks like a normal person
197
+ - Gives practical, actionable advice
198
+ - Admits when you need more information
199
+ - Asks follow-up questions to understand better
200
+ - Shares relevant stories or analogies when helpful
201
+ User info: {name}, constitution: {dosha}, concerns: {concerns}
202
+ Ayurvedic context for this conversation: {ayur_context}
203
+ Remember:
204
+ - Have a natural conversation, don't lecture
205
+ - Ask questions to understand their specific situation
206
+ - Give personalized advice based on their constitution
207
+ - Be encouraging and supportive
208
+ - Keep responses conversational length (2-4 sentences usually)
209
+ - Only give longer responses when explaining complex concepts"""
210
+ # Build message history for API
211
+ messages = [{"role": "system", "content": system_prompt}]
212
 
213
+ # Add recent chat history
214
+ if chat_history:
215
+ for human_msg, ai_msg in chat_history[-3:]: # Last 3 exchanges
216
+ messages.append({"role": "user", "content": human_msg})
217
+ messages.append({"role": "assistant", "content": ai_msg})
218
 
219
+ # Add current message
220
+ messages.append({"role": "user", "content": user_message})
221
+
222
+ # Try different LLM providers
223
+ response = None
224
+
225
+ # 1. Try Groq (best free option)
226
+ response = self.call_groq_api(messages)
227
+ if response:
228
+ return response
229
+
230
+ # 2. Try local Ollama
231
+ response = self.call_ollama_local(messages)
232
+ if response:
233
+ return response
234
+
235
+ # 3. Try HuggingFace
236
+ prompt = f"{system_prompt}\n\nUser: {user_message}\nDr. Ayur:"
237
+ response = self.call_huggingface_api(prompt)
238
+ if response:
239
+ return response
240
+
241
+ # 4. Fallback to intelligent template response
242
+ return self.create_fallback_response(user_message, user_profile, ayur_context)
243
 
244
+ def create_fallback_response(self, user_message: str, user_profile: Dict, context: str) -> str:
245
+ """Create natural fallback response when APIs fail"""
 
246
  name = user_profile.get('name', 'friend')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
247
 
248
+ # Analyze user message for natural response
249
+ msg_lower = user_message.lower()
 
 
 
 
 
 
 
 
 
 
250
 
251
+ if any(word in msg_lower for word in ['hello', 'hi', 'hey', 'namaste']):
252
+ return f"Namaste {name}! How are you feeling today? What's been on your mind health-wise?"
253
 
254
+ elif any(word in msg_lower for word in ['thank', 'thanks']):
255
+ return f"You're so welcome, {name}! I'm here whenever you need guidance. How else can I support your wellness journey?"
256
 
257
+ elif any(word in msg_lower for word in ['stress', 'anxiety', 'worried']):
258
+ return f"I can hear that you're dealing with some stress, {name}. That's really common, and Ayurveda has wonderful ways to help. Can you tell me more about what's been triggering this for you? Understanding the root cause helps me suggest the best approach."
 
259
 
260
+ elif any(word in msg_lower for word in ['sleep', 'tired', 'insomnia']):
261
+ return f"Sleep issues can be so frustrating, {name}. Let's figure this out together. Are you having trouble falling asleep, staying asleep, or both? And how's your evening routine looking these days?"
 
262
 
263
+ elif any(word in msg_lower for word in ['diet', 'food', 'eat']):
264
+ return f"Ah, food as medicine - one of my favorite topics, {name}! What's your current relationship with food like? Are you dealing with any digestive concerns, or are you looking to optimize your energy and health?"
265
 
266
+ elif any(word in msg_lower for word in ['pain', 'hurt', 'ache']):
267
+ return f"I'm sorry you're experiencing pain, {name}. Where exactly are you feeling this discomfort, and have you noticed any patterns - like times of day when it's worse or better?"
268
+
269
+ else:
270
+ responses = [
271
+ f"That's a great question, {name}. Tell me a bit more about your situation so I can give you the most helpful guidance.",
272
+ f"I'd love to help with that, {name}. Can you share some more details about what you're experiencing?",
273
+ f"Interesting point, {name}. Let's explore this together - what made you think about this particular aspect of your health?"
274
+ ]
275
+ return random.choice(responses)
276
+ # Initialize the conversational bot
277
+ ayur_bot = ConversationalAyurBot()
278
  def save_profile(name: str, age: int, constitution: str, concerns: str):
279
  """Save user profile"""
280
  if not name.strip():
281
+ return "Please enter your name first!"
282
 
283
  profile = {
284
  "name": name.strip(),
 
288
  }
289
 
290
  user_profiles[name.lower()] = profile
291
+ return f"Great! I've got your profile saved, {name}. Now our conversations will be much more personalized."
292
+ def get_user_profile() -> Dict:
293
+ """Get the most recent user profile"""
 
 
 
 
 
 
294
  if user_profiles:
295
  return list(user_profiles.values())[-1]
 
296
  return {}
297
  def chat_interface(message: str, history: List) -> tuple:
298
+ """Main conversational interface"""
299
  if not message.strip():
300
  return "", history
301
 
302
+ user_profile = get_user_profile()
303
+ response = ayur_bot.generate_conversational_response(message.strip(), history, user_profile)
304
  history.append([message, response])
305
 
306
  return "", history
307
+ def test_llm_connections():
308
+ """Test available LLM connections"""
309
+ results = []
310
+
311
+ # Test Groq
312
+ groq_key = os.getenv('GROQ_API_KEY', 'your-groq-api-key-here')
313
+ if groq_key != 'your-groq-api-key-here':
314
+ try:
315
+ test_response = ayur_bot.call_groq_api([
316
+ {"role": "user", "content": "Hello"}
317
+ ])
318
+ if test_response:
319
+ results.append("βœ… Groq API: Connected")
320
+ else:
321
+ results.append("⚠️ Groq API: Available but failed test")
322
+ except:
323
+ results.append("❌ Groq API: Failed")
324
+ else:
325
+ results.append("⚠️ Groq API: No API key (add GROQ_API_KEY)")
326
+
327
+ # Test HuggingFace
328
+ hf_token = os.getenv('HF_TOKEN', 'your-hf-token-here')
329
+ if hf_token != 'your-hf-token-here':
330
+ results.append("βœ… HuggingFace: Token available")
331
+ else:
332
+ results.append("⚠️ HuggingFace: No token (add HF_TOKEN)")
333
+
334
+ # Test local Ollama
335
  try:
336
+ response = requests.get("http://localhost:11434/api/tags", timeout=2)
337
+ if response.status_code == 200:
338
+ results.append("βœ… Ollama: Running locally")
 
339
  else:
340
+ results.append("❌ Ollama: Not responding")
341
+ except:
342
+ results.append("❌ Ollama: Not available")
343
+
344
+ results.append("βœ… Fallback responses: Always available")
345
+
346
+ return "\n".join(results)
347
+ # Create the Gradio interface
348
+ with gr.Blocks(title="Dr. Ayur - Conversational AI", theme=gr.themes.Soft()) as app:
 
 
 
 
 
 
 
349
 
350
  gr.HTML("""
351
  <div style="text-align: center; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
352
  color: white; padding: 20px; border-radius: 10px; margin-bottom: 20px;">
353
  <h1>πŸ•‰οΈ Dr. Ayur - Conversational Ayurvedic AI</h1>
354
+ <p>Have natural conversations about your health and wellness with an AI Ayurvedic doctor</p>
355
  </div>
356
  """)
357
 
358
+ # API Key setup instructions
359
+ with gr.Accordion("πŸ”‘ Setup Instructions (Click to expand)", open=False):
360
+ gr.Markdown("""
361
+ ## Get Free API Access for Better Conversations:
362
+
363
+ **Option 1: Groq (Recommended - Very fast & generous free tier)**
364
+ 1. Go to [console.groq.com](https://console.groq.com/)
365
+ 2. Sign up for free
366
+ 3. Get your API key
367
+ 4. Add it as `GROQ_API_KEY` in your HuggingFace Space secrets
368
+
369
+ **Option 2: HuggingFace Token**
370
+ 1. Go to [huggingface.co/settings/tokens](https://huggingface.co/settings/tokens)
371
+ 2. Create a new token
372
+ 3. Add it as `HF_TOKEN` in your Space secrets
373
+
374
+ **Option 3: Local Ollama (For local development)**
375
+ 1. Install [Ollama](https://ollama.ai/)
376
+ 2. Run `ollama pull llama2`
377
+ 3. The app will automatically detect it
378
+
379
+ *Don't worry - the app works without API keys using intelligent fallback responses!*
380
+ """)
381
+
382
  with gr.Row():
383
  with gr.Column(scale=3):
384
  chatbot = gr.Chatbot(
385
  height=500,
386
+ placeholder="Start a natural conversation with Dr. Ayur about your health...",
387
  show_label=False
388
  )
389
 
390
  with gr.Row():
391
  msg_input = gr.Textbox(
392
+ placeholder="Just talk naturally - ask anything about your health, diet, stress, sleep...",
 
393
  scale=4,
394
  container=False
395
  )
396
  send_btn = gr.Button("Send", variant="primary", scale=1)
397
 
398
+ clear_btn = gr.Button("Clear Conversation", variant="secondary")
 
 
 
 
 
 
 
399
 
400
+ with gr.Column(scale=1):
401
+ gr.Markdown("### πŸ”§ System Status")
402
+ test_btn = gr.Button("πŸ”Œ Test LLM Connections")
403
+ status_display = gr.Textbox(
404
+ label="Connection Status",
405
+ value="Click 'Test LLM Connections' to check available services",
406
  interactive=False,
407
+ lines=6
408
  )
409
 
410
+ gr.Markdown("### πŸ‘€ Tell me about yourself")
 
411
  with gr.Group():
412
+ profile_name = gr.Textbox(label="Your name", placeholder="What should I call you?")
413
  profile_age = gr.Number(label="Age", value=30, minimum=1, maximum=120)
414
  profile_constitution = gr.Dropdown(
415
+ label="Your dosha (if you know it)",
416
+ choices=["I don't know", "Vata", "Pitta", "Kapha", "Mixed"],
417
+ value="I don't know"
418
  )
419
  profile_concerns = gr.Textbox(
420
+ label="What's on your mind health-wise?",
421
+ placeholder="e.g., stress, sleep issues, digestion...",
422
  lines=2
423
  )
424
+ save_btn = gr.Button("πŸ’Ύ Save My Info", variant="primary")
425
+ profile_status = gr.Textbox(label="", interactive=False, show_label=False)
426
 
427
+ gr.Markdown("### πŸ’­ Conversation starters:")
428
  gr.Markdown("""
429
+ - "I've been really stressed lately..."
430
+ - "I'm having trouble sleeping"
431
+ - "What foods should I eat for my body type?"
432
+ - "I get anxious a lot, can Ayurveda help?"
433
+ - "My digestion has been off"
434
+ - "I want to start eating healthier"
435
  """)
436
  # Event handlers
437
  msg_input.submit(chat_interface, [msg_input, chatbot], [msg_input, chatbot])
438
  send_btn.click(chat_interface, [msg_input, chatbot], [msg_input, chatbot])
439
  clear_btn.click(lambda: [], outputs=[chatbot])
440
 
441
+ test_btn.click(test_llm_connections, outputs=[status_display])
442
+ save_btn.click(
 
 
443
  save_profile,
444
  [profile_name, profile_age, profile_constitution, profile_concerns],
445
  [profile_status]
446
  )
447
  gr.HTML("""
448
  <div style="text-align: center; margin-top: 20px; padding: 15px;
449
+ background: #f8f9fa; border-radius: 10px;">
450
+ <p><strong>🌟 This is a truly conversational AI!</strong> It understands context, asks follow-up questions, and has natural conversations about your health.</p>
451
+ <p><strong>Disclaimer:</strong> Dr. Ayur provides educational information only. Always consult qualified practitioners for medical concerns.</p>
 
452
  </div>
453
  """)
454
  if __name__ == "__main__":
455
+ app.launch(share=True)