Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -260,7 +260,7 @@ async def download_voice_file(media_url: str, filename: str) -> str:
|
|
| 260 |
return None
|
| 261 |
|
| 262 |
async def transcribe_voice_with_openai(file_path: str) -> str:
|
| 263 |
-
"""Transcribe voice file using OpenAI Whisper with
|
| 264 |
try:
|
| 265 |
# Check if file exists and has content
|
| 266 |
if not os.path.exists(file_path):
|
|
@@ -274,13 +274,82 @@ async def transcribe_voice_with_openai(file_path: str) -> str:
|
|
| 274 |
|
| 275 |
logger.info(f"[Transcribe] Transcribing file: {file_path} (size: {file_size} bytes)")
|
| 276 |
|
| 277 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 278 |
with open(file_path, 'rb') as audio_file:
|
| 279 |
transcript = openai.Audio.transcribe(
|
| 280 |
model="whisper-1",
|
| 281 |
file=audio_file,
|
| 282 |
-
language="en", #
|
| 283 |
-
prompt=
|
| 284 |
)
|
| 285 |
|
| 286 |
transcribed_text = transcript.text.strip()
|
|
@@ -290,12 +359,51 @@ async def transcribe_voice_with_openai(file_path: str) -> str:
|
|
| 290 |
if not transcribed_text or len(transcribed_text.strip()) < 2:
|
| 291 |
logger.warning(f"[Transcribe] First attempt failed, trying with Urdu-specific prompt")
|
| 292 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 293 |
with open(file_path, 'rb') as audio_file:
|
| 294 |
transcript = openai.Audio.transcribe(
|
| 295 |
model="whisper-1",
|
| 296 |
file=audio_file,
|
| 297 |
language="ur", # Force Urdu
|
| 298 |
-
prompt=
|
| 299 |
)
|
| 300 |
|
| 301 |
transcribed_text = transcript.text.strip()
|
|
@@ -305,11 +413,35 @@ async def transcribe_voice_with_openai(file_path: str) -> str:
|
|
| 305 |
if not transcribed_text or len(transcribed_text.strip()) < 2:
|
| 306 |
logger.warning(f"[Transcribe] Second attempt failed, trying with mixed language prompt")
|
| 307 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 308 |
with open(file_path, 'rb') as audio_file:
|
| 309 |
transcript = openai.Audio.transcribe(
|
| 310 |
model="whisper-1",
|
| 311 |
file=audio_file,
|
| 312 |
-
prompt=
|
| 313 |
)
|
| 314 |
|
| 315 |
transcribed_text = transcript.text.strip()
|
|
@@ -328,7 +460,7 @@ async def transcribe_voice_with_openai(file_path: str) -> str:
|
|
| 328 |
return None
|
| 329 |
|
| 330 |
def process_voice_input(text: str) -> str:
|
| 331 |
-
"""Process and clean voice input text with
|
| 332 |
if not text:
|
| 333 |
return ""
|
| 334 |
|
|
@@ -341,12 +473,9 @@ def process_voice_input(text: str) -> str:
|
|
| 341 |
# Basic punctuation cleanup
|
| 342 |
processed_text = processed_text.replace(' ,', ',').replace(' .', '.')
|
| 343 |
|
| 344 |
-
#
|
| 345 |
transcription_fixes = {
|
| 346 |
-
|
| 347 |
-
'goodbye': 'hello',
|
| 348 |
-
'good bye': 'hello',
|
| 349 |
-
'good by': 'hello',
|
| 350 |
'opium': 'option',
|
| 351 |
'opium numara': 'option number',
|
| 352 |
'opium number': 'option number',
|
|
@@ -365,6 +494,7 @@ def process_voice_input(text: str) -> str:
|
|
| 365 |
'numbra 1': 'number 1',
|
| 366 |
'numbra 2': 'number 2',
|
| 367 |
'numbra 3': 'number 3',
|
|
|
|
| 368 |
# Number fixes - only when they appear as standalone numbers
|
| 369 |
'aik': '1',
|
| 370 |
'ek': '1',
|
|
@@ -382,6 +512,7 @@ def process_voice_input(text: str) -> str:
|
|
| 382 |
'ath': '8',
|
| 383 |
'nau': '9',
|
| 384 |
'das': '10',
|
|
|
|
| 385 |
# Navigation command fixes
|
| 386 |
'man': 'main',
|
| 387 |
'men': 'main',
|
|
@@ -391,7 +522,34 @@ def process_voice_input(text: str) -> str:
|
|
| 391 |
'menu': 'main',
|
| 392 |
'home': 'main',
|
| 393 |
'back': 'main',
|
| 394 |
-
'return': 'main'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 395 |
}
|
| 396 |
|
| 397 |
# Apply transcription fixes - but be careful with Islamic greetings
|
|
@@ -1599,13 +1757,13 @@ async def process_incoming_message(from_number: str, msg: dict):
|
|
| 1599 |
send_whatsjet_message(from_number, response)
|
| 1600 |
|
| 1601 |
# Add to conversation history
|
| 1602 |
-
context_manager.add_to_history(from_number,
|
| 1603 |
|
| 1604 |
else:
|
| 1605 |
# Enhanced "not found" response with veterinary suggestions
|
| 1606 |
message = (
|
| 1607 |
"❌ *Product Not Found*\n\n"
|
| 1608 |
-
f"🔍 *We couldn't find '{
|
| 1609 |
"💡 *Try these alternatives:*\n"
|
| 1610 |
"• Check spelling (e.g., 'Hydropex' not 'Hydro pex')\n"
|
| 1611 |
"• Search by symptoms (e.g., 'respiratory', 'liver support')\n"
|
|
@@ -1631,8 +1789,111 @@ async def process_incoming_message(from_number: str, msg: dict):
|
|
| 1631 |
else:
|
| 1632 |
send_whatsjet_message(from_number, message)
|
| 1633 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1634 |
except Exception as e:
|
| 1635 |
-
logger.error(f"Error in
|
| 1636 |
# Instead of sending a generic error, return to main menu
|
| 1637 |
welcome_msg = generate_veterinary_welcome_message()
|
| 1638 |
send_whatsjet_message(from_number, welcome_msg)
|
|
@@ -3307,6 +3568,9 @@ async def send_product_image_with_caption(from_number: str, product: Dict[str, A
|
|
| 3307 |
send_whatsjet_message(from_number, details)
|
| 3308 |
|
| 3309 |
if __name__ == "__main__":
|
|
|
|
|
|
|
|
|
|
| 3310 |
# Launch FastAPI app
|
| 3311 |
import uvicorn
|
| 3312 |
-
uvicorn.run(app, host="0.0.0.0", port=7860)
|
|
|
|
| 260 |
return None
|
| 261 |
|
| 262 |
async def transcribe_voice_with_openai(file_path: str) -> str:
|
| 263 |
+
"""Transcribe voice file using OpenAI Whisper with comprehensive veterinary domain system prompt"""
|
| 264 |
try:
|
| 265 |
# Check if file exists and has content
|
| 266 |
if not os.path.exists(file_path):
|
|
|
|
| 274 |
|
| 275 |
logger.info(f"[Transcribe] Transcribing file: {file_path} (size: {file_size} bytes)")
|
| 276 |
|
| 277 |
+
# Comprehensive system prompt for veterinary WhatsApp assistant
|
| 278 |
+
system_prompt = """
|
| 279 |
+
You are transcribing voice messages for Apex Biotical Veterinary WhatsApp Assistant. This is a professional veterinary products chatbot.
|
| 280 |
+
|
| 281 |
+
CONTEXT: Users can speak product names, menu selections, numbers, and general queries in English or Urdu.
|
| 282 |
+
|
| 283 |
+
PRODUCT NAMES (Veterinary Products):
|
| 284 |
+
- Hydropex (electrolyte supplement)
|
| 285 |
+
- Respira Aid Plus (respiratory support)
|
| 286 |
+
- Heposel (liver tonic)
|
| 287 |
+
- Bromacid (respiratory/mucolytic)
|
| 288 |
+
- Hexatox (liver & kidney support)
|
| 289 |
+
- APMA Fort (mycotoxin binder)
|
| 290 |
+
- Para C.E (heat stress support)
|
| 291 |
+
- Tribiotic (antibiotic)
|
| 292 |
+
- PHYTO-SAL (phytogenic supplement)
|
| 293 |
+
- Mycopex Super (mycotoxin binder)
|
| 294 |
+
- Eflin KT-20 (antibiotic)
|
| 295 |
+
- Salcozine ST-30 (anticoccidial)
|
| 296 |
+
- Oftilex UA-10 (antibiotic)
|
| 297 |
+
- Biscomin 10 (injectable antibiotic)
|
| 298 |
+
- Apvita Plus (vitamin supplement)
|
| 299 |
+
- B-G Aspro-C (aspirin + vitamin C)
|
| 300 |
+
- EC-Immune (immune booster)
|
| 301 |
+
- Liverpex (liver tonic)
|
| 302 |
+
- Symodex (multivitamin)
|
| 303 |
+
- Respira Aid (respiratory support)
|
| 304 |
+
- Adek Gold (multivitamin)
|
| 305 |
+
- Immuno DX (immune enhancer)
|
| 306 |
+
|
| 307 |
+
MENU SELECTIONS:
|
| 308 |
+
- Main menu options: 1, 2, 3, 4
|
| 309 |
+
- Product numbers: 1-23
|
| 310 |
+
- Category numbers: 1-10
|
| 311 |
+
- Navigation: main, menu, back, home, start
|
| 312 |
+
|
| 313 |
+
NUMBERS (English & Urdu):
|
| 314 |
+
English: one, two, three, four, five, six, seven, eight, nine, ten, eleven, twelve, thirteen, fourteen, fifteen, sixteen, seventeen, eighteen, nineteen, twenty, twenty-one, twenty-two, twenty-three
|
| 315 |
+
Urdu (Roman): aik, ek, do, teen, char, panch, che, sat, ath, nau, das, gyara, bara, tera, choda, pandra, sola, satara, athara, unnees, bees, ikkees, baees, tees
|
| 316 |
+
Urdu (Script): ایک, دو, تین, چار, پانچ, چھ, سات, آٹھ, نو, دس, گیارہ, بارہ, تیرہ, چودہ, پندرہ, سولہ, سترہ, اٹھارہ, انیس, بیس, اکیس, بائیس, تئیس
|
| 317 |
+
|
| 318 |
+
COMMON GREETINGS:
|
| 319 |
+
English: hi, hello, hey, good morning, good afternoon, good evening, how are you
|
| 320 |
+
Urdu: salam, assalamu alaikum, adaab, namaste, khuda hafiz
|
| 321 |
+
|
| 322 |
+
MENU COMMANDS:
|
| 323 |
+
English: search, browse, download, catalog, contact, availability, main menu, option, number, choice
|
| 324 |
+
Urdu: تلاش, براؤز, ڈاؤن لوڈ, کیٹلاگ, رابطہ, دستیابی, مین مینو, آپشن, نمبر, اختیار
|
| 325 |
+
|
| 326 |
+
TRANSCRIPTION RULES:
|
| 327 |
+
1. Transcribe product names exactly as listed above
|
| 328 |
+
2. Convert spoken numbers to digits (1, 2, 3, etc.)
|
| 329 |
+
3. Handle both English and Urdu speech
|
| 330 |
+
4. Preserve exact spelling for product names
|
| 331 |
+
5. Convert menu selections to numbers
|
| 332 |
+
6. Handle common transcription errors (opium->option, numara->number)
|
| 333 |
+
7. Maintain context for veterinary domain
|
| 334 |
+
|
| 335 |
+
EXAMPLES:
|
| 336 |
+
- "hydropex" -> "hydropex"
|
| 337 |
+
- "respira aid plus" -> "respira aid plus"
|
| 338 |
+
- "option number one" -> "1"
|
| 339 |
+
- "aik" -> "1"
|
| 340 |
+
- "do" -> "2"
|
| 341 |
+
- "main menu" -> "main"
|
| 342 |
+
- "salam" -> "salam"
|
| 343 |
+
- "search products" -> "search products"
|
| 344 |
+
"""
|
| 345 |
+
|
| 346 |
+
# First attempt with comprehensive system prompt
|
| 347 |
with open(file_path, 'rb') as audio_file:
|
| 348 |
transcript = openai.Audio.transcribe(
|
| 349 |
model="whisper-1",
|
| 350 |
file=audio_file,
|
| 351 |
+
language="en", # Start with English
|
| 352 |
+
prompt=system_prompt
|
| 353 |
)
|
| 354 |
|
| 355 |
transcribed_text = transcript.text.strip()
|
|
|
|
| 359 |
if not transcribed_text or len(transcribed_text.strip()) < 2:
|
| 360 |
logger.warning(f"[Transcribe] First attempt failed, trying with Urdu-specific prompt")
|
| 361 |
|
| 362 |
+
urdu_system_prompt = """
|
| 363 |
+
You are transcribing Urdu voice messages for Apex Biotical Veterinary WhatsApp Assistant.
|
| 364 |
+
|
| 365 |
+
PRODUCT NAMES (Urdu/English):
|
| 366 |
+
- ہائیڈروپیکس (Hydropex)
|
| 367 |
+
- ریسپیرا ایڈ پلس (Respira Aid Plus)
|
| 368 |
+
- ہیپوسیل (Heposel)
|
| 369 |
+
- بروماسڈ (Bromacid)
|
| 370 |
+
- ہیکساٹوکس (Hexatox)
|
| 371 |
+
- اے پی ایم اے فورٹ (APMA Fort)
|
| 372 |
+
- پیرا سی ای (Para C.E)
|
| 373 |
+
- ٹرائی بیوٹک (Tribiotic)
|
| 374 |
+
- فائٹو سال (PHYTO-SAL)
|
| 375 |
+
- مائیکوپیکس سپر (Mycopex Super)
|
| 376 |
+
|
| 377 |
+
URDU NUMBERS:
|
| 378 |
+
- ایک (1), دو (2), تین (3), چار (4), پانچ (5)
|
| 379 |
+
- چھ (6), سات (7), آٹھ (8), نو (9), دس (10)
|
| 380 |
+
- گیارہ (11), بارہ (12), تیرہ (13), چودہ (14), پندرہ (15)
|
| 381 |
+
- سولہ (16), سترہ (17), اٹھارہ (18), انیس (19), بیس (20)
|
| 382 |
+
- اکیس (21), بائیس (22), تئیس (23)
|
| 383 |
+
|
| 384 |
+
URDU GREETINGS:
|
| 385 |
+
- سلام (salam), السلام علیکم (assalamu alaikum)
|
| 386 |
+
- آداب (adaab), نمستے (namaste), خدا حافظ (khuda hafiz)
|
| 387 |
+
|
| 388 |
+
URDU MENU COMMANDS:
|
| 389 |
+
- مین مینو (main menu), آپشن (option), نمبر (number)
|
| 390 |
+
- تلاش (search), براؤز (browse), ڈاؤن لوڈ (download)
|
| 391 |
+
- کیٹلاگ (catalog), رابطہ (contact), دستیابی (availability)
|
| 392 |
+
|
| 393 |
+
TRANSCRIPTION RULES:
|
| 394 |
+
1. Transcribe Urdu words in Urdu script
|
| 395 |
+
2. Convert Urdu numbers to digits
|
| 396 |
+
3. Handle mixed Urdu-English speech
|
| 397 |
+
4. Preserve product names exactly
|
| 398 |
+
5. Convert menu selections to numbers
|
| 399 |
+
"""
|
| 400 |
+
|
| 401 |
with open(file_path, 'rb') as audio_file:
|
| 402 |
transcript = openai.Audio.transcribe(
|
| 403 |
model="whisper-1",
|
| 404 |
file=audio_file,
|
| 405 |
language="ur", # Force Urdu
|
| 406 |
+
prompt=urdu_system_prompt
|
| 407 |
)
|
| 408 |
|
| 409 |
transcribed_text = transcript.text.strip()
|
|
|
|
| 413 |
if not transcribed_text or len(transcribed_text.strip()) < 2:
|
| 414 |
logger.warning(f"[Transcribe] Second attempt failed, trying with mixed language prompt")
|
| 415 |
|
| 416 |
+
mixed_system_prompt = """
|
| 417 |
+
You are transcribing voice messages for a veterinary products WhatsApp assistant. The user may speak in English, Urdu, or a mix of both languages.
|
| 418 |
+
|
| 419 |
+
PRODUCT NAMES (exact spelling required):
|
| 420 |
+
Hydropex, Respira Aid Plus, Heposel, Bromacid, Hexatox, APMA Fort, Para C.E, Tribiotic, PHYTO-SAL, Mycopex Super, Eflin KT-20, Salcozine ST-30, Oftilex UA-10, Biscomin 10, Apvita Plus, B-G Aspro-C, EC-Immune, Liverpex, Symodex, Respira Aid, Adek Gold, Immuno DX
|
| 421 |
+
|
| 422 |
+
NUMBERS (convert to digits):
|
| 423 |
+
English: one->1, two->2, three->3, etc.
|
| 424 |
+
Urdu: aik->1, ek->1, do->2, teen->3, etc.
|
| 425 |
+
|
| 426 |
+
MENU COMMANDS:
|
| 427 |
+
main, menu, back, home, start, option, number, search, browse, download, catalog, contact, availability
|
| 428 |
+
|
| 429 |
+
GREETINGS:
|
| 430 |
+
hi, hello, salam, assalamu alaikum, adaab, namaste
|
| 431 |
+
|
| 432 |
+
TRANSCRIPTION RULES:
|
| 433 |
+
1. Transcribe exactly what you hear
|
| 434 |
+
2. Convert numbers to digits
|
| 435 |
+
3. Preserve product names exactly
|
| 436 |
+
4. Handle both languages
|
| 437 |
+
5. Convert menu selections to numbers
|
| 438 |
+
"""
|
| 439 |
+
|
| 440 |
with open(file_path, 'rb') as audio_file:
|
| 441 |
transcript = openai.Audio.transcribe(
|
| 442 |
model="whisper-1",
|
| 443 |
file=audio_file,
|
| 444 |
+
prompt=mixed_system_prompt
|
| 445 |
)
|
| 446 |
|
| 447 |
transcribed_text = transcript.text.strip()
|
|
|
|
| 460 |
return None
|
| 461 |
|
| 462 |
def process_voice_input(text: str) -> str:
|
| 463 |
+
"""Process and clean voice input text with veterinary domain-specific transcription error correction"""
|
| 464 |
if not text:
|
| 465 |
return ""
|
| 466 |
|
|
|
|
| 473 |
# Basic punctuation cleanup
|
| 474 |
processed_text = processed_text.replace(' ,', ',').replace(' .', '.')
|
| 475 |
|
| 476 |
+
# Veterinary domain-specific transcription error corrections
|
| 477 |
transcription_fixes = {
|
| 478 |
+
# Common menu selection errors
|
|
|
|
|
|
|
|
|
|
| 479 |
'opium': 'option',
|
| 480 |
'opium numara': 'option number',
|
| 481 |
'opium number': 'option number',
|
|
|
|
| 494 |
'numbra 1': 'number 1',
|
| 495 |
'numbra 2': 'number 2',
|
| 496 |
'numbra 3': 'number 3',
|
| 497 |
+
|
| 498 |
# Number fixes - only when they appear as standalone numbers
|
| 499 |
'aik': '1',
|
| 500 |
'ek': '1',
|
|
|
|
| 512 |
'ath': '8',
|
| 513 |
'nau': '9',
|
| 514 |
'das': '10',
|
| 515 |
+
|
| 516 |
# Navigation command fixes
|
| 517 |
'man': 'main',
|
| 518 |
'men': 'main',
|
|
|
|
| 522 |
'menu': 'main',
|
| 523 |
'home': 'main',
|
| 524 |
'back': 'main',
|
| 525 |
+
'return': 'main',
|
| 526 |
+
|
| 527 |
+
# Veterinary product name corrections
|
| 528 |
+
'hydro pex': 'hydropex',
|
| 529 |
+
'hydro pex': 'hydropex',
|
| 530 |
+
'respira aid': 'respira aid plus',
|
| 531 |
+
'respira aid plus': 'respira aid plus',
|
| 532 |
+
'hepo sel': 'heposel',
|
| 533 |
+
'brom acid': 'bromacid',
|
| 534 |
+
'hexa tox': 'hexatox',
|
| 535 |
+
'apma fort': 'apma fort',
|
| 536 |
+
'para c': 'para c.e',
|
| 537 |
+
'para ce': 'para c.e',
|
| 538 |
+
'tribiotic': 'tribiotic',
|
| 539 |
+
'phyto sal': 'phyto-sal',
|
| 540 |
+
'mycopex': 'mycopex super',
|
| 541 |
+
'mycopex super': 'mycopex super',
|
| 542 |
+
'eflin': 'eflin kt-20',
|
| 543 |
+
'salcozine': 'salcozine st-30',
|
| 544 |
+
'oftilex': 'oftilex ua-10',
|
| 545 |
+
'biscomin': 'biscomin 10',
|
| 546 |
+
'apvita': 'apvita plus',
|
| 547 |
+
'bg aspro': 'b-g aspro-c',
|
| 548 |
+
'ec immune': 'ec-immune',
|
| 549 |
+
'liverpex': 'liverpex',
|
| 550 |
+
'symodex': 'symodex',
|
| 551 |
+
'adek': 'adek gold',
|
| 552 |
+
'immuno': 'immuno dx'
|
| 553 |
}
|
| 554 |
|
| 555 |
# Apply transcription fixes - but be careful with Islamic greetings
|
|
|
|
| 1757 |
send_whatsjet_message(from_number, response)
|
| 1758 |
|
| 1759 |
# Add to conversation history
|
| 1760 |
+
context_manager.add_to_history(from_number, message_body, response)
|
| 1761 |
|
| 1762 |
else:
|
| 1763 |
# Enhanced "not found" response with veterinary suggestions
|
| 1764 |
message = (
|
| 1765 |
"❌ *Product Not Found*\n\n"
|
| 1766 |
+
f"🔍 *We couldn't find '{message_body}' in our veterinary database.*\n\n"
|
| 1767 |
"💡 *Try these alternatives:*\n"
|
| 1768 |
"• Check spelling (e.g., 'Hydropex' not 'Hydro pex')\n"
|
| 1769 |
"• Search by symptoms (e.g., 'respiratory', 'liver support')\n"
|
|
|
|
| 1789 |
else:
|
| 1790 |
send_whatsjet_message(from_number, message)
|
| 1791 |
|
| 1792 |
+
# Handle menu state-based processing
|
| 1793 |
+
# Check if this is a menu selection
|
| 1794 |
+
if current_state in ['main_menu', 'category_selection_menu', 'category_products_menu', 'all_products_menu', 'product_inquiry']:
|
| 1795 |
+
# Validate menu selection
|
| 1796 |
+
is_valid, error_msg = validate_menu_selection(message_body, current_state, user_context)
|
| 1797 |
+
|
| 1798 |
+
if is_valid:
|
| 1799 |
+
# Handle valid menu selection
|
| 1800 |
+
if current_state == 'main_menu':
|
| 1801 |
+
if message_body == '1':
|
| 1802 |
+
# Search Products
|
| 1803 |
+
await display_all_products(from_number)
|
| 1804 |
+
elif message_body == '2':
|
| 1805 |
+
# Browse Categories
|
| 1806 |
+
categories = get_all_categories()
|
| 1807 |
+
if categories:
|
| 1808 |
+
context_manager.update_context(
|
| 1809 |
+
from_number,
|
| 1810 |
+
current_state='category_selection_menu',
|
| 1811 |
+
current_menu='category_selection_menu',
|
| 1812 |
+
current_menu_options=categories,
|
| 1813 |
+
available_categories=categories
|
| 1814 |
+
)
|
| 1815 |
+
message = "📁 *Select a Category:*\n\n"
|
| 1816 |
+
for i, category in enumerate(categories, 1):
|
| 1817 |
+
message += f"{format_number_with_emoji(i)} {category}\n"
|
| 1818 |
+
message += "\n💬 Type a category number or 'main' to return to main menu."
|
| 1819 |
+
send_whatsjet_message(from_number, message)
|
| 1820 |
+
else:
|
| 1821 |
+
send_whatsjet_message(from_number, "❌ No categories available. Type 'main' to return to main menu.")
|
| 1822 |
+
elif message_body == '3':
|
| 1823 |
+
# Download Catalog
|
| 1824 |
+
await send_catalog_pdf(from_number)
|
| 1825 |
+
elif message_body == '4':
|
| 1826 |
+
# AI Chat Mode
|
| 1827 |
+
context_manager.update_context(
|
| 1828 |
+
from_number,
|
| 1829 |
+
current_state='ai_chat_mode',
|
| 1830 |
+
current_menu='ai_chat_mode',
|
| 1831 |
+
current_menu_options=['main']
|
| 1832 |
+
)
|
| 1833 |
+
message = (
|
| 1834 |
+
"🤖 *Veterinary AI Assistant Activated*\n\n"
|
| 1835 |
+
"I'm now in AI chat mode. You can ask me:\n"
|
| 1836 |
+
"• Veterinary questions\n"
|
| 1837 |
+
"• Product recommendations\n"
|
| 1838 |
+
"• Treatment advice\n"
|
| 1839 |
+
"• General inquiries\n\n"
|
| 1840 |
+
"💬 *Type 'main' to return to main menu.*"
|
| 1841 |
+
)
|
| 1842 |
+
send_whatsjet_message(from_number, message)
|
| 1843 |
+
elif current_state == 'category_selection_menu':
|
| 1844 |
+
await handle_category_selection(message_body, from_number)
|
| 1845 |
+
elif current_state == 'category_products_menu':
|
| 1846 |
+
# Handle product selection from category
|
| 1847 |
+
available_products = user_context.get('available_products', [])
|
| 1848 |
+
if message_body.isdigit() and 1 <= int(message_body) <= len(available_products):
|
| 1849 |
+
selected_product = available_products[int(message_body) - 1]
|
| 1850 |
+
context_manager.update_context(
|
| 1851 |
+
from_number,
|
| 1852 |
+
current_product=selected_product,
|
| 1853 |
+
current_state='product_inquiry',
|
| 1854 |
+
current_menu='product_inquiry',
|
| 1855 |
+
current_menu_options=list(MENU_CONFIG['product_inquiry']['option_descriptions'].values())
|
| 1856 |
+
)
|
| 1857 |
+
response = generate_veterinary_product_response(selected_product, user_context)
|
| 1858 |
+
send_whatsjet_message(from_number, response)
|
| 1859 |
+
else:
|
| 1860 |
+
send_whatsjet_message(from_number, get_menu_validation_message(current_state, user_context))
|
| 1861 |
+
elif current_state == 'all_products_menu':
|
| 1862 |
+
# Handle product selection from all products
|
| 1863 |
+
if products_df is not None and not products_df.empty:
|
| 1864 |
+
all_products = products_df.to_dict('records')
|
| 1865 |
+
if message_body.isdigit() and 1 <= int(message_body) <= len(all_products):
|
| 1866 |
+
selected_product = all_products[int(message_body) - 1]
|
| 1867 |
+
context_manager.update_context(
|
| 1868 |
+
from_number,
|
| 1869 |
+
current_product=selected_product,
|
| 1870 |
+
current_state='product_inquiry',
|
| 1871 |
+
current_menu='product_inquiry',
|
| 1872 |
+
current_menu_options=list(MENU_CONFIG['product_inquiry']['option_descriptions'].values())
|
| 1873 |
+
)
|
| 1874 |
+
response = generate_veterinary_product_response(selected_product, user_context)
|
| 1875 |
+
send_whatsjet_message(from_number, response)
|
| 1876 |
+
else:
|
| 1877 |
+
send_whatsjet_message(from_number, get_menu_validation_message(current_state, user_context))
|
| 1878 |
+
else:
|
| 1879 |
+
send_whatsjet_message(from_number, "❌ No products available. Type 'main' to return to main menu.")
|
| 1880 |
+
elif current_state == 'product_inquiry':
|
| 1881 |
+
await handle_veterinary_product_followup(message_body, from_number)
|
| 1882 |
+
else:
|
| 1883 |
+
# Invalid menu selection
|
| 1884 |
+
send_whatsjet_message(from_number, error_msg)
|
| 1885 |
+
elif current_state == 'contact_request':
|
| 1886 |
+
await handle_contact_request_response(from_number, message_body)
|
| 1887 |
+
elif current_state == 'availability_request':
|
| 1888 |
+
await handle_availability_request_response(from_number, message_body)
|
| 1889 |
+
elif current_state == 'ai_chat_mode':
|
| 1890 |
+
await handle_ai_chat_mode(from_number, message_body, reply_language)
|
| 1891 |
+
else:
|
| 1892 |
+
# Default: treat as general query
|
| 1893 |
+
await handle_general_query_with_ai(from_number, message_body, user_context, reply_language)
|
| 1894 |
+
|
| 1895 |
except Exception as e:
|
| 1896 |
+
logger.error(f"Error in process_incoming_message: {e}")
|
| 1897 |
# Instead of sending a generic error, return to main menu
|
| 1898 |
welcome_msg = generate_veterinary_welcome_message()
|
| 1899 |
send_whatsjet_message(from_number, welcome_msg)
|
|
|
|
| 3568 |
send_whatsjet_message(from_number, details)
|
| 3569 |
|
| 3570 |
if __name__ == "__main__":
|
| 3571 |
+
# Load products data on startup
|
| 3572 |
+
load_products_data()
|
| 3573 |
+
|
| 3574 |
# Launch FastAPI app
|
| 3575 |
import uvicorn
|
| 3576 |
+
uvicorn.run(app, host="0.0.0.0", port=7860)
|