varshakolanu commited on
Commit
4f65dd0
·
verified ·
1 Parent(s): 10e223f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +165 -71
app.py CHANGED
@@ -13,30 +13,65 @@ logging.basicConfig(level=logging.INFO, filename='app_log.txt',
13
  format='%(asctime)s - %(levelname)s - %(message)s')
14
 
15
  # Load environment variables (Hugging Face Spaces secrets)
16
- HF_API_TOKEN = os.getenv("HF_API_TOKEN")
17
- SALESFORCE_ACCESS_TOKEN = os.getenv("SALESFORCE_ACCESS_TOKEN")
18
- TWILIO_ACCOUNT_SID = os.getenv("TWILIO_ACCOUNT_SID")
19
- TWILIO_AUTH_TOKEN = os.getenv("TWILIO_AUTH_TOKEN")
20
- TWILIO_PHONE = os.getenv("TWILIO_PHONE")
21
- CALENDLY_API_TOKEN = os.getenv("CALENDLY_API_TOKEN")
22
- SALESFORCE_BASE_URL = os.getenv("SALESFORCE_INSTANCE_URL", "https://your_instance.salesforce.com/services/data/v60.0/")
 
23
 
24
  # Validate environment variables
25
- if not all([HF_API_TOKEN, SALESFORCE_ACCESS_TOKEN, TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN, TWILIO_PHONE, CALENDLY_API_TOKEN]):
 
 
26
  logging.error("Missing environment variables for API integrations.")
27
  raise ValueError("Missing environment variables. Configure API tokens in Hugging Face Spaces secrets.")
28
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  # Salesforce REST API Headers
 
 
 
 
 
30
  SALESFORCE_HEADERS = {
31
- "Authorization": f"Bearer {SALESFORCE_ACCESS_TOKEN}",
32
  "Content-Type": "application/json"
33
  }
34
 
35
- # Hugging Face Client
36
  class HuggingFaceClient:
37
- def __init__(self, api_token):
38
  self.api_url = "https://api-inference.huggingface.co/models/"
39
- self.headers = {"Authorization": f"Bearer {api_token}"}
40
  self.sentiment_model = "distilbert-base-uncased-finetuned-sst-2-english"
41
  self.severity_model = "bert-base-uncased" # Placeholder; use custom model
42
  self.translation_model = "facebook/m2m100_418M"
@@ -58,6 +93,8 @@ class HuggingFaceClient:
58
  response_text = self.translate(response_text, language_code, "en")
59
  sentiment_result = self.query(response_text, self.sentiment_model)
60
  severity_result = self.query(response_text, self.severity_model)
 
 
61
  sentiment_score = self.process_sentiment(sentiment_result)
62
  severity_score = self.process_severity(severity_result)
63
  risk_level = self.determine_risk_level(sentiment_score, severity_score)
@@ -70,7 +107,7 @@ class HuggingFaceClient:
70
  def translate(self, text, source_lang, target_lang):
71
  payload = {"inputs": text, "parameters": {"src_lang": source_lang, "tgt_lang": target_lang}}
72
  result = self.query(payload, self.translation_model)
73
- return result[0]["translation_text"] if result and isinstance(result, list) else text
74
 
75
  def process_sentiment(self, result):
76
  if result and isinstance(result, list) and len(result) > 0:
@@ -107,6 +144,9 @@ class SalesforceClient:
107
  record_id = response.json()["id"]
108
  logging.info(f"Created {object_name} record: {record_id}")
109
  return record_id
 
 
 
110
  except requests.exceptions.RequestException as e:
111
  logging.error(f"Failed to create {object_name} record: {str(e)}")
112
  return None
@@ -117,6 +157,9 @@ class SalesforceClient:
117
  response = requests.get(f"{self.base_url}query/?q={encoded_query}", headers=self.headers)
118
  response.raise_for_status()
119
  return response.json()["records"]
 
 
 
120
  except requests.exceptions.RequestException as e:
121
  logging.error(f"Failed to query records: {str(e)}")
122
  return []
@@ -130,42 +173,71 @@ class TwilioClient:
130
 
131
  def send_message(self, to_number, body):
132
  try:
 
 
133
  data = {"From": self.from_number, "To": to_number, "Body": body}
134
  response = requests.post(self.api_url, auth=self.auth, data=data, timeout=10)
135
  response.raise_for_status()
136
  logging.info(f"Sent message to {to_number}")
137
  return True
 
 
 
138
  except requests.exceptions.RequestException as e:
139
  logging.error(f"Failed to send message: {str(e)}")
140
- return False
141
 
142
  # Calendly Client
143
  class CalendlyClient:
144
  def __init__(self, api_token):
145
  self.api_url = "https://api.calendly.com/scheduled_events"
 
146
  self.headers = {"Authorization": f"Bearer {api_token}"}
147
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
  def create_event(self, patient_email, event_type_uuid):
149
  try:
150
- response = requests.post(self.api_url, headers=self.headers,
151
- json={"event_type": f"https://api.calendly.com/event_types/{event_type_uuid}",
152
- "invitee_email": patient_email})
 
 
 
 
153
  response.raise_for_status()
154
  logging.info(f"Scheduled Calendly event for {patient_email}")
155
  return response.json()["resource"]["start_time"]
 
 
 
156
  except requests.exceptions.RequestException as e:
157
  logging.error(f"Failed to schedule Calendly event: {str(e)}")
158
  return None
159
 
160
  # Gradio Interface Functions
161
- hf_client = HuggingFaceClient(HF_API_TOKEN)
162
  sf_client = SalesforceClient(SALESFORCE_BASE_URL, SALESFORCE_HEADERS)
163
  twilio_client = TwilioClient(TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN, TWILIO_PHONE)
164
  calendly_client = CalendlyClient(CALENDLY_API_TOKEN)
165
 
166
  def register_patient(phone, email, language, consent_status):
 
 
167
  try:
168
- name = f"PAT-{str(uuid.uuid4())[:6]}" # Auto-generated
169
  patient_data = {
170
  "Name": name, "Phone__c": phone, "Email__c": email,
171
  "Language__c": language, "ConsentGiven__c": consent_status
@@ -173,20 +245,22 @@ def register_patient(phone, email, language, consent_status):
173
  patient_id = sf_client.create_record("Patient__c", patient_data)
174
  if patient_id:
175
  logging.info(f"Registered patient: {name}")
176
- return f"Patient {name} registered successfully!"
177
- return "Failed to register patient."
178
  except Exception as e:
179
  logging.error(f"Error registering patient: {str(e)}")
180
  return f"Error: {str(e)}"
181
 
182
- def submit_consent(patient_phone, method):
 
 
183
  try:
184
- patients = sf_client.query_records(f"SELECT Id FROM Patient__c WHERE Phone__c = '{patient_phone}'")
185
  if patients:
186
- consent_data = {"Method__c": method, "GivenOn__c": date.today().isoformat()}
187
  consent_id = sf_client.create_record("Consent__c", consent_data)
188
  if consent_id:
189
- logging.info("Consent recorded.")
190
  return "Consent recorded successfully!"
191
  return "Failed to record consent."
192
  return "Patient not found."
@@ -195,25 +269,33 @@ def submit_consent(patient_phone, method):
195
  return f"Error: {str(e)}"
196
 
197
  def schedule_followup(patient_phone, message_template, follow_up_date):
 
 
198
  try:
199
- patients = sf_client.query_records(f"SELECT Id, ConsentGiven__c, Language__c FROM Patient__c WHERE Phone__c = '{patient_phone}'")
200
- if patients and patients[0]["ConsentGiven__c"] == "Approved":
201
- followup_data = {
202
- "Patient__c": patients[0]["Id"], "FollowUpDate__c": follow_up_date.isoformat(),
203
- "MessageTemplate__c": message_template, "Status__c": "Scheduled"
204
- }
205
- followup_id = sf_client.create_record("FollowUpPlan__c", followup_data)
206
- if followup_id:
207
- if twilio_client.send_message(patient_phone, message_template):
208
- sf_client.create_record("MessageLog__c", {
209
- "Patient__c": patients[0]["Id"], "MessageText__c": message_template,
210
- "Direction__c": "Outbound", "Timestamp__c": datetime.utcnow().isoformat()
211
- })
212
- logging.info(f"Follow-up scheduled for patient: {patients[0]['Id']}")
213
- return "Follow-up scheduled and message sent!"
214
- return "Failed to send message."
215
  return "Failed to schedule follow-up."
216
- return "Patient not found or consent not approved."
 
 
 
 
 
 
 
 
 
 
217
  except Exception as e:
218
  logging.error(f"Error scheduling follow-up: {str(e)}")
219
  return f"Error: {str(e)}"
@@ -228,13 +310,18 @@ def view_risk_dashboard():
228
  "Sentiment": log["Sentiment__c"]} for log in symptom_logs
229
  ])
230
  high_risk = df[df["Severity"] == "High"]
231
- return df, high_risk.to_dict('records') if not high_risk.empty else "No high-risk cases."
 
 
 
232
  return pd.DataFrame(), "No symptom logs available."
233
  except Exception as e:
234
  logging.error(f"Error loading risk dashboard: {str(e)}")
235
  return pd.DataFrame(), f"Error: {str(e)}"
236
 
237
  def escalate_case(patient_id, response_text):
 
 
238
  try:
239
  case_data = {
240
  "RelatedPatient__c": patient_id, "Priority__c": "High",
@@ -249,8 +336,13 @@ def escalate_case(patient_id, response_text):
249
  logging.error(f"Error escalating case: {str(e)}")
250
  return f"Error: {str(e)}"
251
 
252
- def schedule_appointment(patient_email, event_type_uuid):
 
 
253
  try:
 
 
 
254
  event_time = calendly_client.create_event(patient_email, event_type_uuid)
255
  if event_time:
256
  appointment_data = {"DateTime__c": event_time, "Status__c": "Scheduled"}
@@ -265,31 +357,33 @@ def schedule_appointment(patient_email, event_type_uuid):
265
  return f"Error: {str(e)}"
266
 
267
  def submit_survey(patient_phone, question, answer):
 
 
268
  try:
269
- patients = sf_client.query_records(f"SELECT Id, Language__c FROM Patient__c WHERE Phone__c = '{patient_phone}'")
270
- if patients:
271
- survey_data = {"Question__c": question, "Answer__c": answer}
272
- survey_id = sf_client.create_record("Survey__c", survey_data)
273
- if survey_id:
274
- analysis = hf_client.analyze_response(answer, patients[0]["Language__c"])
275
- if analysis:
276
- symptom_data = {
277
- "Patient__c": patients[0]["Id"], "ResponseText__c": answer,
278
- "RiskScore__c": analysis["risk_level"], "Severity__c": analysis["severity_score"],
279
- "Sentiment__c": analysis["sentiment_score"]
280
- }
281
- symptom_id = sf_client.create_record("SymptomLog__c", symptom_data)
282
- if symptom_id and analysis["risk_level"] == "High":
283
- case_data = {
284
- "RelatedPatient__c": patients[0]["Id"], "Priority__c": "High",
285
- "Description__c": f"High-risk survey response: {answer}"
286
- }
287
- sf_client.create_record("Case__c", case_data)
288
- logging.info(f"Survey submitted for patient: {patients[0]['Id']}")
289
- return "Survey submitted and analyzed!"
290
- return "Failed to analyze survey response."
291
  return "Failed to submit survey."
292
- return "Patient not found."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
293
  except Exception as e:
294
  logging.error(f"Error submitting survey: {str(e)}")
295
  return f"Error: {str(e)}"
@@ -346,22 +440,22 @@ with gr.Blocks(theme=gr.themes.Soft(), title="AI-Powered Patient Follow-up Agent
346
  with gr.Row():
347
  escalate_id_input = gr.Textbox(label="Patient ID (for escalation)")
348
  escalate_response_input = gr.Textbox(label="Response Text")
349
- escalate_button = gr.Button("Submit Case Escalation")
350
  escalate_output = gr.Textbox(label="Result")
351
  escalate_button.click(
352
- fn=escribe_case,
353
  inputs=[escalate_id_input, escalate_response_input],
354
  outputs=escalate_output
355
  )
356
 
357
  with gr.Tab("Appointment Scheduling"):
358
  appt_email_input = gr.Textbox(label="Patient Email", placeholder="patient@example.com")
359
- event_type_input = gr.Textbox(label="Calendly Event Type UUID", placeholder="your_event_type_uuid")
360
  appt_button = gr.Button("Schedule Appointment")
361
  appt_output = gr.Textbox(label="Result")
362
  appt_button.click(
363
  fn=schedule_appointment,
364
- inputs=[appt_email_input, event_type_input],
365
  outputs=appt_output
366
  )
367
 
 
13
  format='%(asctime)s - %(levelname)s - %(message)s')
14
 
15
  # Load environment variables (Hugging Face Spaces secrets)
16
+ SALESFORCE_USERNAME = os.getenv("SF_USERNAME", "app41@clinic.com")
17
+ SALESFORCE_PASSWORD = os.getenv("SF_PASSWORD", "text@12345")
18
+ SALESFORCE_SECURITY_TOKEN = os.getenv("SF_SECURITY_TOKEN", "6JgPkW3K5MPPGXDgc2JNxCUdB")
19
+ SALESFORCE_INSTANCE_URL = os.getenv("SF_INSTANCE_URL", "https://clinic3-dev-ed.develop.lightning.force.com/")
20
+ TWILIO_ACCOUNT_SID = os.getenv("TWILIO_ACCOUNT_SID", "AC80ba89ceecaa0f3058326f5c86d63f18")
21
+ TWILIO_AUTH_TOKEN = os.getenv("TWILIO_AUTH_TOKEN", "13d8416e924902b19f8181b77c968060")
22
+ TWILIO_PHONE = os.getenv("TWILIO_PHONE", "+13304226436")
23
+ CALENDLY_API_TOKEN = os.getenv("CALENDLY_API_TOKEN", "eyJraWQiOiIxY2UxZTEzNjE3ZGNmNzY2YjNjZWJjY2Y4ZGM1YmFmYThhNjVlNjg0MDIzZjdjMzJiZTgzNDliMjM4MDEzNWI0IiwidHlwIjoiUEFUIiwiYWxnIjoiRVMyNTYifQ.eyJpc3MiOiJodHRwczovL2F1dGguY2FsZW5kbHkuY29tIiwiaWF0IjoxNzUwODQ5MDc3LCJqdGkiOiI2Njk2N2NjOC1lODk3LTRjZWQtOGM1NS03MGZlNzk5MGRhNTAiLCJ1c2VyX3V1aWQiOiIxYWNjMTMwZS1kN2MzLTQyOTAtYTBjNy1mMzZkYTYxMjMwMDQifQ.BexmuW5XR8wk4_FsROEv5eH7deUSSetNwjCaNiNeBLBYnbJDiG4Hfzbg2qNbUNR0Q8Nb-6-3uU3UuwXex-CgHQ")
24
 
25
  # Validate environment variables
26
+ required_vars = [SALESFORCE_USERNAME, SALESFORCE_PASSWORD, SALESFORCE_SECURITY_TOKEN, SALESFORCE_INSTANCE_URL,
27
+ TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN, TWILIO_PHONE, CALENDLY_API_TOKEN]
28
+ if not all(required_vars):
29
  logging.error("Missing environment variables for API integrations.")
30
  raise ValueError("Missing environment variables. Configure API tokens in Hugging Face Spaces secrets.")
31
 
32
+ # Salesforce Authentication
33
+ def get_salesforce_access_token():
34
+ try:
35
+ login_url = "https://login.salesforce.com/services/Soap/u/60.0"
36
+ payload = f"""<?xml version="1.0" encoding="utf-8" ?>
37
+ <env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
38
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
39
+ xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
40
+ <env:Body>
41
+ <n1:login xmlns:n1="urn:partner.soap.sforce.com">
42
+ <n1:username>{SALESFORCE_USERNAME}</n1:username>
43
+ <n1:password>{SALESFORCE_PASSWORD}{SALESFORCE_SECURITY_TOKEN}</n1:password>
44
+ </n1:login>
45
+ </env:Body>
46
+ </env:Envelope>"""
47
+ headers = {"Content-Type": "text/xml", "SOAPAction": "login"}
48
+ response = requests.post(login_url, data=payload, headers=headers, timeout=10)
49
+ response.raise_for_status()
50
+ response_text = response.text
51
+ session_id = response_text.split("<sessionId>")[1].split("</sessionId>")[0]
52
+ server_url = response_text.split("<serverUrl>")[1].split("</serverUrl>")[0]
53
+ instance_url = server_url.split("/services")[0]
54
+ return {"access_token": session_id, "instance_url": instance_url}
55
+ except Exception as e:
56
+ logging.error(f"Salesforce authentication failed: {str(e)}")
57
+ return None
58
+
59
  # Salesforce REST API Headers
60
+ sf_auth = get_salesforce_access_token()
61
+ if not sf_auth:
62
+ logging.error("Failed to authenticate with Salesforce.")
63
+ raise ValueError("Salesforce authentication failed.")
64
+ SALESFORCE_BASE_URL = sf_auth["instance_url"] + "/services/data/v60.0/"
65
  SALESFORCE_HEADERS = {
66
+ "Authorization": f"Bearer {sf_auth['access_token']}",
67
  "Content-Type": "application/json"
68
  }
69
 
70
+ # Hugging Face Client (No token needed in Hugging Face Spaces)
71
  class HuggingFaceClient:
72
+ def __init__(self):
73
  self.api_url = "https://api-inference.huggingface.co/models/"
74
+ self.headers = {} # Token is implicit in Hugging Face Spaces
75
  self.sentiment_model = "distilbert-base-uncased-finetuned-sst-2-english"
76
  self.severity_model = "bert-base-uncased" # Placeholder; use custom model
77
  self.translation_model = "facebook/m2m100_418M"
 
93
  response_text = self.translate(response_text, language_code, "en")
94
  sentiment_result = self.query(response_text, self.sentiment_model)
95
  severity_result = self.query(response_text, self.severity_model)
96
+ if not sentiment_result or not severity_result:
97
+ return None
98
  sentiment_score = self.process_sentiment(sentiment_result)
99
  severity_score = self.process_severity(severity_result)
100
  risk_level = self.determine_risk_level(sentiment_score, severity_score)
 
107
  def translate(self, text, source_lang, target_lang):
108
  payload = {"inputs": text, "parameters": {"src_lang": source_lang, "tgt_lang": target_lang}}
109
  result = self.query(payload, self.translation_model)
110
+ return result[0].get("translation_text", text) if result and isinstance(result, list) else text
111
 
112
  def process_sentiment(self, result):
113
  if result and isinstance(result, list) and len(result) > 0:
 
144
  record_id = response.json()["id"]
145
  logging.info(f"Created {object_name} record: {record_id}")
146
  return record_id
147
+ except requests.exceptions.HTTPError as e:
148
+ logging.error(f"HTTP error creating {object_name} record: {e.response.status_code} - {e.response.text}")
149
+ return None
150
  except requests.exceptions.RequestException as e:
151
  logging.error(f"Failed to create {object_name} record: {str(e)}")
152
  return None
 
157
  response = requests.get(f"{self.base_url}query/?q={encoded_query}", headers=self.headers)
158
  response.raise_for_status()
159
  return response.json()["records"]
160
+ except requests.exceptions.HTTPError as e:
161
+ logging.error(f"HTTP error querying records: {e.response.status_code} - {e.response.text}")
162
+ return []
163
  except requests.exceptions.RequestException as e:
164
  logging.error(f"Failed to query records: {str(e)}")
165
  return []
 
173
 
174
  def send_message(self, to_number, body):
175
  try:
176
+ if not to_number.startswith("+"):
177
+ return "Invalid phone number format. Must start with +country_code."
178
  data = {"From": self.from_number, "To": to_number, "Body": body}
179
  response = requests.post(self.api_url, auth=self.auth, data=data, timeout=10)
180
  response.raise_for_status()
181
  logging.info(f"Sent message to {to_number}")
182
  return True
183
+ except requests.exceptions.HTTPError as e:
184
+ logging.error(f"Twilio HTTP error: {e.response.status_code} - {e.response.text}")
185
+ return f"Twilio error: {e.response.text}"
186
  except requests.exceptions.RequestException as e:
187
  logging.error(f"Failed to send message: {str(e)}")
188
+ return str(e)
189
 
190
  # Calendly Client
191
  class CalendlyClient:
192
  def __init__(self, api_token):
193
  self.api_url = "https://api.calendly.com/scheduled_events"
194
+ self.event_types_url = "https://api.calendly.com/event_types"
195
  self.headers = {"Authorization": f"Bearer {api_token}"}
196
 
197
+ def get_event_type_uuid(self, event_slug="30min"):
198
+ try:
199
+ response = requests.get(self.event_types_url, headers=self.headers, timeout=5)
200
+ response.raise_for_status()
201
+ event_types = response.json()["collection"]
202
+ for event in event_types:
203
+ if event["slug"].endswith(event_slug):
204
+ return event["uuid"]
205
+ logging.error(f"Event type {event_slug} not found.")
206
+ return None
207
+ except requests.exceptions.RequestException as e:
208
+ logging.error(f"Failed to fetch event types: {str(e)}")
209
+ return None
210
+
211
  def create_event(self, patient_email, event_type_uuid):
212
  try:
213
+ if not event_type_uuid:
214
+ return None
215
+ event_data = {
216
+ "event_type": f"https://api.calendly.com/event_types/{event_type_uuid}",
217
+ "invitee_email": patient_email
218
+ }
219
+ response = requests.post(self.api_url, headers=self.headers, json=event_data, timeout=10)
220
  response.raise_for_status()
221
  logging.info(f"Scheduled Calendly event for {patient_email}")
222
  return response.json()["resource"]["start_time"]
223
+ except requests.exceptions.HTTPError as e:
224
+ logging.error(f"Calendly HTTP error: {e.response.status_code} - {e.response.text}")
225
+ return None
226
  except requests.exceptions.RequestException as e:
227
  logging.error(f"Failed to schedule Calendly event: {str(e)}")
228
  return None
229
 
230
  # Gradio Interface Functions
231
+ hf_client = HuggingFaceClient()
232
  sf_client = SalesforceClient(SALESFORCE_BASE_URL, SALESFORCE_HEADERS)
233
  twilio_client = TwilioClient(TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN, TWILIO_PHONE)
234
  calendly_client = CalendlyClient(CALENDLY_API_TOKEN)
235
 
236
  def register_patient(phone, email, language, consent_status):
237
+ if not phone or not email or not language or not consent_status:
238
+ return "All fields are required."
239
  try:
240
+ name = f"PAT-{str(uuid4())[:7]}" # Unique patient ID
241
  patient_data = {
242
  "Name": name, "Phone__c": phone, "Email__c": email,
243
  "Language__c": language, "ConsentGiven__c": consent_status
 
245
  patient_id = sf_client.create_record("Patient__c", patient_data)
246
  if patient_id:
247
  logging.info(f"Registered patient: {name}")
248
+ return f"Patient {name} registered successfully! ID: {patient_id}"
249
+ return "Failed to register patient. Check Salesforce logs."
250
  except Exception as e:
251
  logging.error(f"Error registering patient: {str(e)}")
252
  return f"Error: {str(e)}"
253
 
254
+ def submit_consent(patient_phone, consent_method):
255
+ if not patient_phone or not consent_method:
256
+ return "All fields are required."
257
  try:
258
+ patients = sf_client.query_records(f"SELECT Id, Name FROM Patient__c WHERE Phone__c = '{patient_phone}'")
259
  if patients:
260
+ consent_data = {"Method__c": consent_method, "GivenOn__c": date.today().isoformat()}
261
  consent_id = sf_client.create_record("Consent__c", consent_data)
262
  if consent_id:
263
+ logging.info(f"Consent recorded for patient: {patients[0]['Name']}")
264
  return "Consent recorded successfully!"
265
  return "Failed to record consent."
266
  return "Patient not found."
 
269
  return f"Error: {str(e)}"
270
 
271
  def schedule_followup(patient_phone, message_template, follow_up_date):
272
+ if not patient_phone or not message_template or not follow_up_date:
273
+ return "All fields are required."
274
  try:
275
+ follow_up_date = datetime.strptime(follow_up_date, "%Y-%m-%d").date()
276
+ patients = sf_client.query_records(f"SELECT Id, ConsentGiven__c, Language__c, Name FROM Patient__c WHERE Phone__c = '{patient_phone}'")
277
+ if not patients:
278
+ return "Patient not found."
279
+ if patients[0]["ConsentGiven__c"] != "Approved":
280
+ return "Consent not approved for messaging."
281
+ followup_data = {
282
+ "Patient__c": patients[0]["Id"], "FollowUpDate__c": follow_up_date.isoformat(),
283
+ "MessageTemplate__c": message_template, "Status__c": "Scheduled"
284
+ }
285
+ followup_id = sf_client.create_record("FollowUpPlan__c", followup_data)
286
+ if not followup_id:
 
 
 
 
287
  return "Failed to schedule follow-up."
288
+ send_result = twilio_client.send_message(patient_phone, message_template)
289
+ if send_result is True:
290
+ sf_client.create_record("MessageLog__c", {
291
+ "Patient__c": patients[0]["Id"], "MessageText__c": message_template,
292
+ "Direction__c": "Outbound", "Timestamp__c": datetime.utcnow().isoformat()
293
+ })
294
+ logging.info(f"Follow-up scheduled and message sent for patient: {patients[0]['Name']}")
295
+ return "Follow-up scheduled and message sent!"
296
+ return f"Failed to send message: {send_result}"
297
+ except ValueError:
298
+ return "Invalid date format. Use YYYY-MM-DD."
299
  except Exception as e:
300
  logging.error(f"Error scheduling follow-up: {str(e)}")
301
  return f"Error: {str(e)}"
 
310
  "Sentiment": log["Sentiment__c"]} for log in symptom_logs
311
  ])
312
  high_risk = df[df["Severity"] == "High"]
313
+ high_risk_info = high_risk.to_dict('records') if not high_risk.empty else "No high-risk cases."
314
+ logging.info("Risk dashboard loaded successfully.")
315
+ return df, high_risk_info
316
+ logging.info("No symptom logs found.")
317
  return pd.DataFrame(), "No symptom logs available."
318
  except Exception as e:
319
  logging.error(f"Error loading risk dashboard: {str(e)}")
320
  return pd.DataFrame(), f"Error: {str(e)}"
321
 
322
  def escalate_case(patient_id, response_text):
323
+ if not patient_id or not response_text:
324
+ return "All fields are required."
325
  try:
326
  case_data = {
327
  "RelatedPatient__c": patient_id, "Priority__c": "High",
 
336
  logging.error(f"Error escalating case: {str(e)}")
337
  return f"Error: {str(e)}"
338
 
339
+ def schedule_appointment(patient_email, event_type_slug="30min"):
340
+ if not patient_email or not event_type_slug:
341
+ return "All fields are required."
342
  try:
343
+ event_type_uuid = calendly_client.get_event_type_uuid(event_type_slug)
344
+ if not event_type_uuid:
345
+ return f"Event type '{event_type_slug}' not found."
346
  event_time = calendly_client.create_event(patient_email, event_type_uuid)
347
  if event_time:
348
  appointment_data = {"DateTime__c": event_time, "Status__c": "Scheduled"}
 
357
  return f"Error: {str(e)}"
358
 
359
  def submit_survey(patient_phone, question, answer):
360
+ if not patient_phone or not question or not answer:
361
+ return "All fields are required."
362
  try:
363
+ patients = sf_client.query_records(f"SELECT Id, Language__c, Name FROM Patient__c WHERE Phone__c = '{patient_phone}'")
364
+ if not patients:
365
+ return "Patient not found."
366
+ survey_data = {"Question__c": question, "Answer__c": answer}
367
+ survey_id = sf_client.create_record("Survey__c", survey_data)
368
+ if not survey_id:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
369
  return "Failed to submit survey."
370
+ analysis = hf_client.analyze_response(answer, patients[0]["Language__c"])
371
+ if analysis:
372
+ symptom_data = {
373
+ "Patient__c": patients[0]["Id"], "ResponseText__c": answer,
374
+ "RiskScore__c": analysis["risk_level"], "Severity__c": analysis["severity_score"],
375
+ "Sentiment__c": analysis["sentiment_score"]
376
+ }
377
+ symptom_id = sf_client.create_record("SymptomLog__c", symptom_data)
378
+ if symptom_id and analysis["risk_level"] == "High":
379
+ case_data = {
380
+ "RelatedPatient__c": patients[0]["Id"], "Priority__c": "High",
381
+ "Description__c": f"High-risk survey response: {answer}"
382
+ }
383
+ sf_client.create_record("Case__c", case_data)
384
+ logging.info(f"Survey submitted for patient: {patients[0]['Name']}")
385
+ return f"Survey submitted and analyzed! Risk Level: {analysis['risk_level']}"
386
+ return "Failed to analyze survey response."
387
  except Exception as e:
388
  logging.error(f"Error submitting survey: {str(e)}")
389
  return f"Error: {str(e)}"
 
440
  with gr.Row():
441
  escalate_id_input = gr.Textbox(label="Patient ID (for escalation)")
442
  escalate_response_input = gr.Textbox(label="Response Text")
443
+ escalate_button = gr.Button("Escalate Case")
444
  escalate_output = gr.Textbox(label="Result")
445
  escalate_button.click(
446
+ fn=escalate_case,
447
  inputs=[escalate_id_input, escalate_response_input],
448
  outputs=escalate_output
449
  )
450
 
451
  with gr.Tab("Appointment Scheduling"):
452
  appt_email_input = gr.Textbox(label="Patient Email", placeholder="patient@example.com")
453
+ appt_event_input = gr.Textbox(label="Event Type Slug", value="30min", placeholder="e.g., 30min")
454
  appt_button = gr.Button("Schedule Appointment")
455
  appt_output = gr.Textbox(label="Result")
456
  appt_button.click(
457
  fn=schedule_appointment,
458
+ inputs=[appt_email_input, appt_event_input],
459
  outputs=appt_output
460
  )
461