DreamStream-1 commited on
Commit
b8262c3
·
verified ·
1 Parent(s): ccc4a1b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +69 -403
app.py CHANGED
@@ -888,154 +888,66 @@ def split_message_for_whatsapp(message: str, max_length: int = 1000) -> list:
888
  return [message[i:i+max_length] for i in range(0, len(message), max_length)]
889
 
890
  def send_whatsjet_message(phone_number: str, message: str, media_type: str = None, media_path: str = None, filename: str = None) -> bool:
891
- """Send a message using WhatsJet API with optional media attachment. For images, send the image as a media message (no caption), then send the caption as a separate text message."""
892
  if not all([WHATSJET_API_URL, WHATSJET_VENDOR_UID, WHATSJET_API_TOKEN]):
893
  logger.error("[WhatsJet] Missing environment variables.")
894
  return False
895
 
896
  url = f"{WHATSJET_API_URL}/{WHATSJET_VENDOR_UID}/contact/send-message?token={WHATSJET_API_TOKEN}"
897
 
898
- # For images: use /contact/send-media-message endpoint with media_url, media_type, caption, and file_name
899
- if media_type in ["image/jpeg", "image/png"] and media_path:
900
  try:
901
- # Use direct public URL for WhatsJet (media_url)
902
- if media_path.startswith("http://") or media_path.startswith("https://"):
903
- image_url = media_path
904
- else:
905
- # If local file, upload to a public location or return False (not supported here)
906
- logger.error("[WhatsJet] Local file paths are not supported for media_url. Please provide a public URL.")
907
- return False
908
- media_api_url = f"{WHATSJET_API_URL}/{WHATSJET_VENDOR_UID}/contact/send-media-message"
909
  payload = {
910
- "phone_number": phone_number,
911
- "media_type": "image",
912
- "media_url": image_url,
913
- "caption": message,
914
- "file_name": filename or "image.jpg"
915
  }
916
- logger.info(f"[WhatsJet][DEBUG] Media API URL: {media_api_url}")
917
- logger.info(f"[WhatsJet][DEBUG] Media payload: {payload}")
918
- response = httpx.post(
919
- media_api_url,
920
- json=payload,
921
- timeout=30
922
- )
923
- logger.info(f"[WhatsJet][DEBUG] Media response status: {response.status_code}")
924
- logger.info(f"[WhatsJet][DEBUG] Media response headers: {dict(response.headers)}")
925
- logger.info(f"[WhatsJet][DEBUG] Media response body: {response.text}")
926
- response.raise_for_status()
927
- logger.info(f"[WhatsJet] Media image sent successfully via media_url to {phone_number}")
928
- return True
929
- except Exception as e:
930
- import traceback
931
- logger.error(f"[WhatsJet][ERROR] Exception sending image via media_url: {str(e)}\nTraceback: {traceback.format_exc()}")
932
- # Fallback: send text only
933
- return send_whatsjet_message(phone_number, message)
934
-
935
- # Handle other media messages (existing logic)
936
- if media_type and media_path:
937
- try:
938
- if isinstance(media_path, str) and (media_path.startswith("http://") or media_path.startswith("https://")):
939
- response = requests.get(media_path, stream=True, timeout=15)
940
- response.raise_for_status()
941
- media_content = response.content
942
- logger.info(f"[WhatsJet][DEBUG] Downloaded media content-type: {response.headers.get('Content-Type')}")
943
- logger.info(f"[WhatsJet][DEBUG] First 20 bytes: {media_content[:20]}")
944
- else:
945
- with open(media_path, 'rb') as f:
946
- media_content = f.read()
947
- # Try multipart first, then base64
948
  try:
949
- files = {
950
- 'media': (filename or 'file.bin', media_content, media_type)
951
- }
952
- data = {
953
- 'phone_number': phone_number,
954
- 'message_body': message
955
- }
956
- # Enhanced logging
957
- logger.info(f"[WhatsJet][DEBUG] URL: {url}")
958
- logger.info(f"[WhatsJet][DEBUG] Multipart data: {data}")
959
- logger.info(f"[WhatsJet][DEBUG] Multipart files: {list(files.keys())}")
960
- response = httpx.post(
961
- url,
962
- data=data,
963
- files=files,
964
- timeout=30
965
- )
966
- logger.info(f"[WhatsJet][DEBUG] Multipart response status: {response.status_code}")
967
- logger.info(f"[WhatsJet][DEBUG] Multipart response headers: {dict(response.headers)}")
968
- try:
969
- response_text = response.text
970
- logger.info(f"[WhatsJet][DEBUG] Multipart response body: {response_text[:1000]}" + ("..." if len(response_text) > 1000 else ""))
971
- except Exception as e:
972
- logger.info(f"[WhatsJet][DEBUG] Multipart response body: Unable to read: {e}")
973
- response.raise_for_status()
974
- logger.info(f"[WhatsJet] Media message sent successfully via multipart to {phone_number}")
975
- return True
976
- except Exception as e:
977
- import traceback
978
- logger.warning(f"[WhatsJet][ERROR] Multipart upload failed for media, trying base64: {e}\nTraceback: {traceback.format_exc()}")
979
-
980
- media_b64 = base64.b64encode(media_content).decode('utf-8')
981
- payload = {
982
- "phone_number": phone_number,
983
- "message_body": message,
984
- 'media_type': media_type,
985
- 'media_content': media_b64,
986
- 'media_filename': filename or os.path.basename(media_path) if not media_path.startswith('http') else filename or 'file.bin'
987
- }
988
- # Enhanced logging
989
- logger.info(f"[WhatsJet][DEBUG] URL: {url}")
990
- logger.info(f"[WhatsJet][DEBUG] Base64 payload: {{'phone_number': payload['phone_number'], 'media_type': payload['media_type'], 'media_filename': payload['media_filename'], 'message_body': payload['message_body'][:50] + '...', 'media_content_length': len(payload['media_content'])}}")
991
  response = httpx.post(
992
  url,
993
  json=payload,
994
- timeout=30
995
  )
996
- logger.info(f"[WhatsJet][DEBUG] Base64 response status: {response.status_code}")
997
- logger.info(f"[WhatsJet][DEBUG] Base64 response headers: {dict(response.headers)}")
998
- try:
999
- response_text = response.text
1000
- logger.info(f"[WhatsJet][DEBUG] Base64 response body: {response_text[:1000]}" + ("..." if len(response_text) > 1000 else ""))
1001
- except Exception as e:
1002
- logger.info(f"[WhatsJet][DEBUG] Base64 response body: Unable to read: {e}")
1003
  response.raise_for_status()
1004
- logger.info(f"[WhatsJet] Media message sent successfully via base64 to {phone_number}")
1005
  return True
1006
  except Exception as e:
1007
- import traceback
1008
- logger.error(f"[WhatsJet][ERROR] Exception sending media message: {e}\nTraceback: {traceback.format_exc()}")
1009
  return False
1010
  except Exception as e:
1011
- import traceback
1012
- logger.error(f"[WhatsJet][ERROR] Exception preparing media message: {str(e)}\nTraceback: {traceback.format_exc()}")
1013
  return False
1014
 
1015
- # Handle text messages (existing logic)
1016
  if not message.strip():
1017
  return True # Don't send empty messages
1018
 
1019
  for chunk in split_message_for_whatsapp(message):
1020
  try:
1021
  payload = {"phone_number": phone_number, "message_body": chunk}
1022
- # Enhanced logging
1023
- logger.info(f"[WhatsJet][DEBUG] URL: {url}")
1024
- logger.info(f"[WhatsJet][DEBUG] Payload: {json.dumps(payload)}")
1025
- response = httpx.post(
1026
- url,
1027
- json=payload,
1028
- timeout=15
1029
- )
1030
- logger.info(f"[WhatsJet][DEBUG] Response status: {response.status_code}")
1031
- logger.info(f"[WhatsJet][DEBUG] Response headers: {dict(response.headers)}")
1032
- logger.info(f"[WhatsJet][DEBUG] Response body: {response.text}")
1033
- response.raise_for_status()
1034
- logger.info(f"[WhatsJet] Text chunk sent successfully to {phone_number}")
1035
  except Exception as e:
1036
- import traceback
1037
- logger.error(f"[WhatsJet][ERROR] Exception sending text chunk: {e}\nTraceback: {traceback.format_exc()}")
1038
  return False
 
1039
  logger.info(f"[WhatsJet] Successfully sent complete text message to {phone_number}")
1040
  return True
1041
 
@@ -3454,38 +3366,35 @@ load_products_data()
3454
 
3455
  def get_product_image_path(product_name: str) -> str:
3456
  """
3457
- Get the public URL for a product image if it exists in the uploads directory.
3458
- Returns the public URL if found, otherwise falls back to static/images or None.
3459
  """
3460
  try:
3461
- # Check uploads directory for exact match (case and spaces preserved)
3462
- uploads_dir = "uploads"
3463
- image_extensions = ['.jpg', '.jpeg', '.png']
3464
- for ext in image_extensions:
3465
- filename = f"{product_name}{ext}"
3466
- local_path = os.path.join(uploads_dir, filename)
3467
- if os.path.exists(local_path):
3468
- # Construct the public URL for Hugging Face Space
3469
- # (Assumes the Space is named dreamstream-1-chatbot)
3470
- public_url = f"https://dreamstream-1-chatbot.hf.space/uploads/{filename.replace(' ', '%20')}"
3471
- logger.info(f"[Image] Found product image in uploads: {public_url}")
3472
- return public_url
3473
- # Fallback to static/images (old logic)
3474
  images_dir = "static/images"
3475
  os.makedirs(images_dir, exist_ok=True)
 
 
3476
  safe_name = re.sub(r'[^\w\s-]', '', product_name).replace(' ', '_').lower()
 
 
3477
  image_extensions = ['.jpg', '.jpeg', '.png', '.webp', '.gif']
 
3478
  for ext in image_extensions:
3479
  image_path = os.path.join(images_dir, f"{safe_name}{ext}")
3480
  if os.path.exists(image_path):
3481
  logger.info(f"[Image] Found product image: {image_path}")
3482
  return image_path
 
 
3483
  default_image_path = os.path.join(images_dir, "default_product.jpg")
3484
  if os.path.exists(default_image_path):
3485
  logger.info(f"[Image] Using default product image: {default_image_path}")
3486
  return default_image_path
 
3487
  logger.warning(f"[Image] No image found for product: {product_name}")
3488
  return None
 
3489
  except Exception as e:
3490
  logger.error(f"[Image] Error getting product image path: {e}")
3491
  return None
@@ -3667,20 +3576,11 @@ async def send_product_image_with_caption(from_number: str, product: Dict[str, A
3667
  product_name = product.get('Product Name', 'Unknown Product')
3668
  details = generate_veterinary_product_response(product, user_context)
3669
  image_url = product.get('Images', '').strip() if 'Images' in product else ''
3670
-
3671
- # Force image URL for Respira Aid Plus (use cPanel public URL)
3672
- if product_name.lower().strip() == "respira aid plus":
3673
- image_url = "https://amgocus.com/uploads/images/Respira%20Aid%20Plus.jpg"
3674
-
3675
- logger.info(f"[Product] Processing image for product: {product_name}")
3676
- logger.info(f"[Product] Image URL from CSV: {image_url}")
3677
-
3678
  try:
3679
- # First, check if we have an image URL from CSV
3680
  if image_url:
3681
  # Convert Google Drive link to direct download if needed
3682
  if 'drive.google.com' in image_url:
3683
- logger.info(f"[Product] Converting Google Drive link: {image_url}")
3684
  if '/d/' in image_url:
3685
  file_id = image_url.split('/d/')[1].split('/')[0]
3686
  elif 'id=' in image_url:
@@ -3689,97 +3589,58 @@ async def send_product_image_with_caption(from_number: str, product: Dict[str, A
3689
  file_id = ''
3690
  if file_id:
3691
  image_url = f"https://drive.google.com/uc?export=download&id={file_id}"
3692
- logger.info(f"[Product] Converted to direct download URL: {image_url}")
3693
-
3694
- # Use the public URL directly for WhatsApp API
3695
- media_type = 'image/jpeg'
3696
- filename = f"{product_name.replace(' ', '_')}.jpg"
3697
-
3698
- # Test the image URL first
3699
- try:
3700
- logger.info(f"[Product] Testing image URL accessibility: {image_url}")
3701
- test_response = requests.head(image_url, timeout=10)
3702
- if test_response.status_code != 200:
3703
- logger.warning(f"[Product] Image URL not accessible (status {test_response.status_code}): {image_url}")
3704
- raise Exception(f"Image URL not accessible: {test_response.status_code}")
3705
- logger.info(f"[Product] Image URL is accessible")
3706
- except Exception as e:
3707
- logger.warning(f"[Product] Failed to test image URL {image_url}: {e}")
3708
- image_url = None
3709
-
3710
- # Send using public URL (not local file)
3711
- if image_url:
3712
- logger.info(f"[Product] Attempting to send image from CSV URL for: {product_name}")
3713
  success = send_whatsjet_message(
3714
  from_number,
3715
  details,
3716
  media_type=media_type,
3717
- media_path=image_url, # Use public URL directly
3718
  filename=filename
3719
  )
3720
-
3721
  if success:
3722
- logger.info(f"[Product] Successfully sent image from CSV link with caption for product: {product_name}")
3723
  return
3724
  else:
3725
- logger.warning(f"[Product] Failed to send image from CSV link, trying fallback: {product_name}")
3726
-
3727
- # Fallback 1: Try with a known public test image
3728
- logger.info(f"[Product] Trying public test image for: {product_name}")
3729
- test_image_url = "https://www.w3schools.com/w3images/lights.jpg"
3730
- media_type = 'image/jpeg'
3731
- filename = f"{product_name.replace(' ', '_')}.jpg"
3732
-
3733
- success = send_whatsjet_message(
3734
- from_number,
3735
- details,
3736
- media_type=media_type,
3737
- media_path=test_image_url,
3738
- filename=filename
3739
- )
3740
-
3741
- if success:
3742
- logger.info(f"[Product] Successfully sent test image with caption for product: {product_name}")
3743
- return
3744
-
3745
- # Fallback 2: Try local uploads directory (public URL)
3746
- logger.info(f"[Product] Trying local uploads directory for: {product_name}")
3747
  image_path = get_product_image_path(product_name)
3748
- if image_path and (image_path.startswith('http') or os.path.exists(image_path)):
3749
  media_type = get_product_image_media_type(image_path)
3750
  filename = f"{product_name.replace(' ', '_')}.jpg"
3751
-
3752
- # If it's already a public URL, use it directly
3753
- if image_path.startswith('http'):
3754
- media_path = image_path
3755
- logger.info(f"[Product] Using existing public URL: {media_path}")
3756
- else:
3757
- # Convert local path to public URL
3758
- media_path = f"https://dreamstream-1-chatbot.hf.space/uploads/{os.path.basename(image_path).replace(' ', '%20')}"
3759
- logger.info(f"[Product] Converted local path to public URL: {media_path}")
3760
-
3761
  success = send_whatsjet_message(
3762
  from_number,
3763
  details,
3764
  media_type=media_type,
3765
- media_path=media_path, # Use public URL
3766
  filename=filename
3767
  )
3768
-
3769
  if success:
3770
- logger.info(f"[Product] Successfully sent image with caption for product: {product_name}")
3771
  else:
3772
  logger.warning(f"[Product] Failed to send image, sending text only: {product_name}")
3773
  send_whatsjet_message(from_number, details)
3774
  else:
3775
- # No image available, send text only
3776
- logger.info(f"[Product] No image available, sending text only for: {product_name}")
3777
  send_whatsjet_message(from_number, details)
3778
-
3779
  except Exception as e:
3780
  logger.error(f"[Product] Error sending product image with caption: {e}")
3781
- logger.info(f"[Product] Falling back to text-only message for: {product_name}")
3782
  send_whatsjet_message(from_number, details)
 
 
 
 
 
 
3783
 
3784
  @app.get("/test-product-image-with-caption")
3785
  async def test_product_image_with_caption(phone: str):
@@ -3799,201 +3660,6 @@ async def test_product_image_with_caption(phone: str):
3799
  except Exception as e:
3800
  return {"error": str(e)}
3801
 
3802
- @app.get("/test-image-sending")
3803
- async def test_image_sending(phone: str, image_url: str = "https://www.w3schools.com/w3images/lights.jpg"):
3804
- """
3805
- Test endpoint to send a test image with caption to debug image sending functionality.
3806
- """
3807
- try:
3808
- test_message = f"""🧪 *Test Image Message*
3809
-
3810
- This is a test message to verify image sending functionality.
3811
-
3812
- 📸 *Image Details:*
3813
- • URL: {image_url}
3814
- • Type: JPEG
3815
- • Purpose: Testing WhatsJet API
3816
-
3817
- 💬 *Test Options:*
3818
- 1️⃣ Send another test image
3819
- 2️⃣ Test with different URL
3820
- 3️⃣ Back to main menu
3821
-
3822
- Please confirm if you received both the image and this text message."""
3823
-
3824
- success = send_whatsjet_message(
3825
- phone,
3826
- test_message,
3827
- media_type="image/jpeg",
3828
- media_path=image_url,
3829
- filename="test_image.jpg"
3830
- )
3831
-
3832
- if success:
3833
- return {
3834
- "status": "success",
3835
- "phone": phone,
3836
- "image_url": image_url,
3837
- "message": "Test image and caption sent successfully"
3838
- }
3839
- else:
3840
- return {
3841
- "status": "failed",
3842
- "phone": phone,
3843
- "image_url": image_url,
3844
- "message": "Failed to send test image"
3845
- }
3846
- except Exception as e:
3847
- return {"error": str(e), "phone": phone, "image_url": image_url}
3848
-
3849
- @app.get("/debug-whatsjet")
3850
- async def debug_whatsjet():
3851
- """
3852
- Debug endpoint to check WhatsJet configuration and test basic functionality.
3853
- """
3854
- try:
3855
- # Check environment variables
3856
- config_status = {
3857
- "WHATSJET_API_URL": bool(WHATSJET_API_URL),
3858
- "WHATSJET_VENDOR_UID": bool(WHATSJET_VENDOR_UID),
3859
- "WHATSJET_API_TOKEN": bool(WHATSJET_API_TOKEN),
3860
- "all_configured": all([WHATSJET_API_URL, WHATSJET_VENDOR_UID, WHATSJET_API_TOKEN])
3861
- }
3862
-
3863
- # Test basic text message if configured
3864
- test_result = None
3865
- if config_status["all_configured"]:
3866
- try:
3867
- # Test with a simple text message
3868
- test_phone = "1234567890" # Dummy phone for testing
3869
- test_success = send_whatsjet_message(
3870
- test_phone,
3871
- "🧪 WhatsJet API Test Message\n\nThis is a test to verify API connectivity.",
3872
- )
3873
- test_result = {
3874
- "success": test_success,
3875
- "message": "API test completed (dummy phone number used)"
3876
- }
3877
- except Exception as e:
3878
- test_result = {
3879
- "success": False,
3880
- "error": str(e)
3881
- }
3882
-
3883
- return {
3884
- "timestamp": datetime.now().isoformat(),
3885
- "config_status": config_status,
3886
- "test_result": test_result,
3887
- "api_url": WHATSJET_API_URL if config_status["all_configured"] else "Not configured",
3888
- "vendor_uid": WHATSJET_VENDOR_UID if config_status["all_configured"] else "Not configured"
3889
- }
3890
- except Exception as e:
3891
- return {"error": str(e), "timestamp": datetime.now().isoformat()}
3892
-
3893
- @app.get("/test-whatsjet-payloads")
3894
- async def test_whatsjet_payloads(phone: str):
3895
- """
3896
- Test different WhatsJet API payload formats to identify the correct one for image sending.
3897
- """
3898
- if not all([WHATSJET_API_URL, WHATSJET_VENDOR_UID, WHATSJET_API_TOKEN]):
3899
- return {"error": "WhatsJet not configured"}
3900
-
3901
- url = f"{WHATSJET_API_URL}/{WHATSJET_VENDOR_UID}/contact/send-message?token={WHATSJET_API_TOKEN}"
3902
- test_image_url = "https://www.w3schools.com/w3images/lights.jpg"
3903
-
3904
- # Download test image
3905
- try:
3906
- response = requests.get(test_image_url, timeout=10)
3907
- response.raise_for_status()
3908
- image_content = response.content
3909
- image_b64 = base64.b64encode(image_content).decode('utf-8')
3910
- except Exception as e:
3911
- return {"error": f"Failed to download test image: {e}"}
3912
-
3913
- results = {}
3914
-
3915
- # Test different payload formats
3916
- test_payloads = [
3917
- {
3918
- "name": "Format 1: Standard with media_content",
3919
- "payload": {
3920
- "phone_number": phone,
3921
- "media_type": "image/jpeg",
3922
- "media_content": image_b64,
3923
- "media_filename": "test.jpg",
3924
- "message_body": ""
3925
- }
3926
- },
3927
- {
3928
- "name": "Format 2: With media_url instead of media_content",
3929
- "payload": {
3930
- "phone_number": phone,
3931
- "media_type": "image/jpeg",
3932
- "media_url": test_image_url,
3933
- "media_filename": "test.jpg",
3934
- "message_body": ""
3935
- }
3936
- },
3937
- {
3938
- "name": "Format 3: With file field",
3939
- "payload": {
3940
- "phone_number": phone,
3941
- "file": image_b64,
3942
- "file_type": "image/jpeg",
3943
- "filename": "test.jpg",
3944
- "message_body": ""
3945
- }
3946
- },
3947
- {
3948
- "name": "Format 4: With attachment field",
3949
- "payload": {
3950
- "phone_number": phone,
3951
- "attachment": image_b64,
3952
- "attachment_type": "image/jpeg",
3953
- "attachment_name": "test.jpg",
3954
- "message_body": ""
3955
- }
3956
- },
3957
- {
3958
- "name": "Format 5: With image field",
3959
- "payload": {
3960
- "phone_number": phone,
3961
- "image": image_b64,
3962
- "image_type": "image/jpeg",
3963
- "image_name": "test.jpg",
3964
- "message_body": ""
3965
- }
3966
- }
3967
- ]
3968
-
3969
- for test in test_payloads:
3970
- try:
3971
- logger.info(f"[WhatsJet] Testing payload format: {test['name']}")
3972
- response = httpx.post(url, json=test['payload'], timeout=30)
3973
-
3974
- results[test['name']] = {
3975
- "status_code": response.status_code,
3976
- "success": response.status_code == 200,
3977
- "response_body": response.text[:200] if response.text else "No response body"
3978
- }
3979
-
3980
- logger.info(f"[WhatsJet] {test['name']} - Status: {response.status_code}")
3981
-
3982
- except Exception as e:
3983
- results[test['name']] = {
3984
- "status_code": "Error",
3985
- "success": False,
3986
- "error": str(e)
3987
- }
3988
- logger.error(f"[WhatsJet] {test['name']} - Error: {e}")
3989
-
3990
- return {
3991
- "timestamp": datetime.now().isoformat(),
3992
- "phone": phone,
3993
- "test_image_url": test_image_url,
3994
- "results": results
3995
- }
3996
-
3997
  if __name__ == "__main__":
3998
  # Launch FastAPI app
3999
  import uvicorn
 
888
  return [message[i:i+max_length] for i in range(0, len(message), max_length)]
889
 
890
  def send_whatsjet_message(phone_number: str, message: str, media_type: str = None, media_path: str = None, filename: str = None) -> bool:
891
+ """Send a message using WhatsJet API with optional media attachment"""
892
  if not all([WHATSJET_API_URL, WHATSJET_VENDOR_UID, WHATSJET_API_TOKEN]):
893
  logger.error("[WhatsJet] Missing environment variables.")
894
  return False
895
 
896
  url = f"{WHATSJET_API_URL}/{WHATSJET_VENDOR_UID}/contact/send-message?token={WHATSJET_API_TOKEN}"
897
 
898
+ # Handle media messages
899
+ if media_type and media_path:
900
  try:
901
+ with open(media_path, 'rb') as f:
902
+ media_content = f.read()
903
+ media_b64 = base64.b64encode(media_content).decode('utf-8')
 
 
 
 
 
904
  payload = {
905
+ "phone_number": phone_number,
906
+ "message_body": message,
907
+ 'media_type': media_type,
908
+ 'media_content': media_b64,
909
+ 'media_filename': filename or os.path.basename(media_path)
910
  }
911
+ # Send message with increased timeout
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
912
  try:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
913
  response = httpx.post(
914
  url,
915
  json=payload,
916
+ timeout=15
917
  )
 
 
 
 
 
 
 
918
  response.raise_for_status()
919
+ logger.info(f"[WhatsJet] Media message sent successfully to {phone_number}")
920
  return True
921
  except Exception as e:
922
+ logger.error(f"[WhatsJet] Exception sending media message: {e}")
 
923
  return False
924
  except Exception as e:
925
+ logger.error(f"[WhatsJet] Exception preparing media message: {str(e)}")
 
926
  return False
927
 
928
+ # Handle text messages
929
  if not message.strip():
930
  return True # Don't send empty messages
931
 
932
  for chunk in split_message_for_whatsapp(message):
933
  try:
934
  payload = {"phone_number": phone_number, "message_body": chunk}
935
+ # Send message with increased timeout
936
+ try:
937
+ response = httpx.post(
938
+ url,
939
+ json=payload,
940
+ timeout=15
941
+ )
942
+ response.raise_for_status()
943
+ logger.info(f"[WhatsJet] Text chunk sent successfully to {phone_number}")
944
+ except Exception as e:
945
+ logger.error(f"[WhatsJet] Exception sending text chunk: {e}")
946
+ return False
 
947
  except Exception as e:
948
+ logger.error(f"[WhatsJet] Exception preparing text chunk: {str(e)}")
 
949
  return False
950
+
951
  logger.info(f"[WhatsJet] Successfully sent complete text message to {phone_number}")
952
  return True
953
 
 
3366
 
3367
  def get_product_image_path(product_name: str) -> str:
3368
  """
3369
+ Get the image path for a product
3370
+ Returns the path to the product image if it exists, otherwise None
3371
  """
3372
  try:
3373
+ # Create images directory if it doesn't exist
 
 
 
 
 
 
 
 
 
 
 
 
3374
  images_dir = "static/images"
3375
  os.makedirs(images_dir, exist_ok=True)
3376
+
3377
+ # Clean product name for filename
3378
  safe_name = re.sub(r'[^\w\s-]', '', product_name).replace(' ', '_').lower()
3379
+
3380
+ # Check for common image extensions
3381
  image_extensions = ['.jpg', '.jpeg', '.png', '.webp', '.gif']
3382
+
3383
  for ext in image_extensions:
3384
  image_path = os.path.join(images_dir, f"{safe_name}{ext}")
3385
  if os.path.exists(image_path):
3386
  logger.info(f"[Image] Found product image: {image_path}")
3387
  return image_path
3388
+
3389
+ # If no specific product image found, check for a default image
3390
  default_image_path = os.path.join(images_dir, "default_product.jpg")
3391
  if os.path.exists(default_image_path):
3392
  logger.info(f"[Image] Using default product image: {default_image_path}")
3393
  return default_image_path
3394
+
3395
  logger.warning(f"[Image] No image found for product: {product_name}")
3396
  return None
3397
+
3398
  except Exception as e:
3399
  logger.error(f"[Image] Error getting product image path: {e}")
3400
  return None
 
3576
  product_name = product.get('Product Name', 'Unknown Product')
3577
  details = generate_veterinary_product_response(product, user_context)
3578
  image_url = product.get('Images', '').strip() if 'Images' in product else ''
3579
+ temp_file_path = None
 
 
 
 
 
 
 
3580
  try:
 
3581
  if image_url:
3582
  # Convert Google Drive link to direct download if needed
3583
  if 'drive.google.com' in image_url:
 
3584
  if '/d/' in image_url:
3585
  file_id = image_url.split('/d/')[1].split('/')[0]
3586
  elif 'id=' in image_url:
 
3589
  file_id = ''
3590
  if file_id:
3591
  image_url = f"https://drive.google.com/uc?export=download&id={file_id}"
3592
+ # Download the image to a temp file
3593
+ response = requests.get(image_url, stream=True, timeout=10)
3594
+ if response.status_code == 200:
3595
+ with tempfile.NamedTemporaryFile(delete=False, suffix='.jpg') as tmp:
3596
+ for chunk in response.iter_content(1024):
3597
+ tmp.write(chunk)
3598
+ temp_file_path = tmp.name
3599
+ media_type = 'image/jpeg'
3600
+ filename = f"{product_name.replace(' ', '_')}.jpg"
 
 
 
 
 
 
 
 
 
 
 
 
3601
  success = send_whatsjet_message(
3602
  from_number,
3603
  details,
3604
  media_type=media_type,
3605
+ media_path=temp_file_path,
3606
  filename=filename
3607
  )
 
3608
  if success:
3609
+ logger.info(f"[Product] Sent image from CSV link with caption for product: {product_name}")
3610
  return
3611
  else:
3612
+ logger.warning(f"[Product] Failed to send image from CSV link, sending text only: {product_name}")
3613
+ else:
3614
+ logger.warning(f"[Product] Could not download image from CSV link: {image_url}")
3615
+ # Fallback to local static/images
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3616
  image_path = get_product_image_path(product_name)
3617
+ if image_path and os.path.exists(image_path):
3618
  media_type = get_product_image_media_type(image_path)
3619
  filename = f"{product_name.replace(' ', '_')}.jpg"
 
 
 
 
 
 
 
 
 
 
3620
  success = send_whatsjet_message(
3621
  from_number,
3622
  details,
3623
  media_type=media_type,
3624
+ media_path=image_path,
3625
  filename=filename
3626
  )
 
3627
  if success:
3628
+ logger.info(f"[Product] Sent image with caption for product: {product_name}")
3629
  else:
3630
  logger.warning(f"[Product] Failed to send image, sending text only: {product_name}")
3631
  send_whatsjet_message(from_number, details)
3632
  else:
 
 
3633
  send_whatsjet_message(from_number, details)
3634
+ logger.info(f"[Product] Sent product info without image: {product_name}")
3635
  except Exception as e:
3636
  logger.error(f"[Product] Error sending product image with caption: {e}")
 
3637
  send_whatsjet_message(from_number, details)
3638
+ finally:
3639
+ if temp_file_path and os.path.exists(temp_file_path):
3640
+ try:
3641
+ os.remove(temp_file_path)
3642
+ except Exception:
3643
+ pass
3644
 
3645
  @app.get("/test-product-image-with-caption")
3646
  async def test_product_image_with_caption(phone: str):
 
3660
  except Exception as e:
3661
  return {"error": str(e)}
3662
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3663
  if __name__ == "__main__":
3664
  # Launch FastAPI app
3665
  import uvicorn