Dhruv-Ty commited on
Commit
ce7162f
·
verified ·
1 Parent(s): cedb6c8

Delete src/whatsapp_service.py

Browse files
Files changed (1) hide show
  1. src/whatsapp_service.py +0 -190
src/whatsapp_service.py DELETED
@@ -1,190 +0,0 @@
1
- import os
2
- import logging
3
- import base64
4
- import requests
5
- from twilio.rest import Client
6
- from twilio.base.exceptions import TwilioRestException
7
-
8
- # Configure logging
9
- logging.basicConfig(level=logging.INFO)
10
- logger = logging.getLogger(__name__)
11
-
12
- class WhatsAppService:
13
- def __init__(self):
14
- """Initialize WhatsApp service with Twilio credentials"""
15
- self.account_sid = os.getenv('TWILIO_ACCOUNT_SID')
16
- self.auth_token = os.getenv('TWILIO_AUTH_TOKEN')
17
- self.from_number = os.getenv('TWILIO_WHATSAPP_NUMBER') # Format: 'whatsapp:+1234567890'
18
-
19
- # Validate WhatsApp number format
20
- if self.from_number and not self.from_number.startswith('whatsapp:'):
21
- logger.warning(f"TWILIO_WHATSAPP_NUMBER should start with 'whatsapp:' - Current value: {self.from_number}")
22
- # Try to fix it automatically
23
- if self.from_number.startswith('+'):
24
- self.from_number = f"whatsapp:{self.from_number}"
25
- logger.info(f"Fixed WhatsApp number format: {self.from_number}")
26
-
27
- if not all([self.account_sid, self.auth_token, self.from_number]):
28
- missing = []
29
- if not self.account_sid: missing.append("TWILIO_ACCOUNT_SID")
30
- if not self.auth_token: missing.append("TWILIO_AUTH_TOKEN")
31
- if not self.from_number: missing.append("TWILIO_WHATSAPP_NUMBER")
32
- logger.warning(f"Twilio credentials not found in environment variables: {', '.join(missing)}")
33
-
34
- # Initialize Twilio client if credentials are available
35
- if all([self.account_sid, self.auth_token]):
36
- self.client = Client(self.account_sid, self.auth_token)
37
- else:
38
- self.client = None
39
-
40
- def validate_phone(self, phone_number):
41
- """
42
- Basic validation for phone numbers
43
-
44
- Args:
45
- phone_number (str): The phone number to validate
46
-
47
- Returns:
48
- bool: True if phone number format is valid
49
- """
50
- import re
51
- # Remove any non-digit characters except for leading +
52
- cleaned = re.sub(r'[^\d+]', '', phone_number)
53
-
54
- # Check if it starts with + followed by 7-15 digits
55
- if re.match(r'^\+\d{7,15}$', cleaned):
56
- return True, cleaned
57
- # Check if it's 7-15 digits without +
58
- elif re.match(r'^\d{7,15}$', cleaned):
59
- return True, f"+{cleaned}"
60
-
61
- return False, None
62
-
63
- def format_whatsapp_number(self, phone_number):
64
- """
65
- Format phone number for WhatsApp API
66
-
67
- Args:
68
- phone_number (str): Raw phone number
69
-
70
- Returns:
71
- str: Formatted WhatsApp number or None if invalid
72
- """
73
- is_valid, cleaned = self.validate_phone(phone_number)
74
- if is_valid:
75
- # WhatsApp numbers must be in format 'whatsapp:+1234567890'
76
- if not cleaned.startswith('+'):
77
- cleaned = f"+{cleaned}"
78
- return f"whatsapp:{cleaned}"
79
- return None
80
-
81
- def check_twilio_setup(self):
82
- """
83
- Diagnose Twilio setup issues
84
-
85
- Returns:
86
- tuple: (is_valid, error_message)
87
- """
88
- if not self.client:
89
- return False, "Twilio client not initialized. Check your TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN."
90
-
91
- if not self.from_number:
92
- return False, "WhatsApp number not specified. Set TWILIO_WHATSAPP_NUMBER environment variable."
93
-
94
- if not self.from_number.startswith('whatsapp:'):
95
- return False, f"TWILIO_WHATSAPP_NUMBER should be in format 'whatsapp:+1234567890'. Current: {self.from_number}"
96
-
97
- # Basic connectivity test
98
- try:
99
- # Try to fetch account info to verify credentials
100
- self.client.api.accounts(self.account_sid).fetch()
101
- return True, "Twilio setup looks correct"
102
- except TwilioRestException as e:
103
- return False, f"Twilio authentication failed: {str(e)}"
104
- except Exception as e:
105
- return False, f"Twilio connectivity error: {str(e)}"
106
-
107
- def send_report(self, to_phone, pdf_data, patient_name):
108
- """
109
- Send medical report via WhatsApp
110
-
111
- Args:
112
- to_phone (str): Recipient's phone number
113
- pdf_data (bytes): The PDF report as bytes
114
- patient_name (str): Patient name for personalization
115
-
116
- Returns:
117
- tuple[bool, str]: Success status and message
118
- """
119
- try:
120
- # Run diagnostic checks first
121
- is_setup_valid, setup_error = self.check_twilio_setup()
122
- if not is_setup_valid:
123
- logger.error(f"WhatsApp service setup error: {setup_error}")
124
- return False, f"WhatsApp service not properly configured: {setup_error}"
125
-
126
- # Format the recipient's phone number
127
- to_whatsapp = self.format_whatsapp_number(to_phone)
128
- if not to_whatsapp:
129
- return False, "Invalid phone number format. Please provide a valid number with country code."
130
-
131
- # Log the 'from' and 'to' numbers for debugging
132
- logger.info(f"Attempting to send WhatsApp message from {self.from_number} to {to_whatsapp}")
133
-
134
- # For Twilio sandbox, first check if the recipient is opted-in
135
- # Note: This is just a warning, it doesn't prevent sending
136
- logger.warning("For Twilio sandbox, recipients must first send the join code to your WhatsApp number")
137
-
138
- # For test purposes, use a publicly accessible PDF instead of trying to upload
139
- # In production, you would need to host the file somewhere publicly accessible
140
- try:
141
- # Send the WhatsApp message with test PDF
142
- message = self.client.messages.create(
143
- from_=self.from_number,
144
- body=f"Medical Report for {patient_name}\n\nPlease find attached your medical report from your recent consultation.\n\nNote: This report is for informational purposes only.",
145
- to=to_whatsapp,
146
- media_url=['https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf'] # Test PDF URL
147
- )
148
-
149
- logger.info(f"Successfully sent WhatsApp to {to_phone} (SID: {message.sid})")
150
- return True, "Report sent successfully via WhatsApp!"
151
-
152
- except TwilioRestException as e:
153
- # Specific error handling for Twilio API errors
154
- error_code = getattr(e, 'code', None)
155
- error_message = str(e)
156
-
157
- if error_code == 63018:
158
- # "To number is not currently opted in" error
159
- logger.error(f"Recipient not opted in: {error_message}")
160
- return False, "The recipient needs to opt in to your WhatsApp sandbox first. Please ask them to message your WhatsApp number with the join code."
161
- elif 'Channel' in error_message and 'From address' in error_message:
162
- # Channel not found error
163
- logger.error(f"WhatsApp channel not found: {error_message}")
164
- return False, "Your WhatsApp channel is not properly set up. Make sure you've completed the Twilio sandbox setup and your TWILIO_WHATSAPP_NUMBER is correct."
165
- else:
166
- # Other Twilio API errors
167
- logger.error(f"Twilio API error ({error_code}): {error_message}")
168
-
169
- # Try a fallback text-only message
170
- try:
171
- fallback_message = self.client.messages.create(
172
- from_=self.from_number,
173
- body=f"Medical Report for {patient_name}\n\nYour medical report is ready. Due to technical limitations, please download it from the app or request it via email.\n\nThis is a fallback message as we couldn't attach the PDF.",
174
- to=to_whatsapp
175
- )
176
- logger.info(f"Sent fallback WhatsApp message to {to_phone} (SID: {fallback_message.sid})")
177
- return True, "WhatsApp notification sent, but the PDF couldn't be attached. Please use email or download options instead."
178
- except Exception as e2:
179
- logger.error(f"Fallback message also failed: {str(e2)}")
180
- return False, f"WhatsApp sending failed. Error: {error_message}"
181
-
182
- except TwilioRestException as e:
183
- # General Twilio API errors
184
- logger.error(f"Twilio API error: {str(e)}")
185
- return False, f"WhatsApp sending failed: {str(e)}"
186
-
187
- except Exception as e:
188
- # Unexpected errors
189
- logger.error(f"Unexpected error sending WhatsApp: {str(e)}")
190
- return False, "An unexpected error occurred. Please try again later."