rakib72642 commited on
Commit
df718f6
ยท
1 Parent(s): 58fed26

changed voice and db mendatory points for appointment

Browse files
Files changed (4) hide show
  1. .env +1 -1
  2. core/backend.py +85 -32
  3. db_view/db.html +4 -0
  4. db_view/dbapi.py +2 -0
.env CHANGED
@@ -9,7 +9,7 @@ GOOGLE_API_KEY="AIzaSyA9sqz4YKQHKXR9TU1imw0DPOghzHOMiBo"
9
 
10
 
11
  ELEVENLABS_API_KEY="b3af3a938c8e15d5eae700ea47eea7d88dfe397f34fbd4b0c75c24f143b032b8"
12
- ELEVENLABS_VOICE_ID="rxvktZTNrsQlsGIpOQGz"
13
  ELEVENLABS_MODEL_ID="eleven_v3"
14
 
15
  # TWILIO_ACCOUNT_SID="ACfafc0d2d007bdf14b21bb3e14a7a7b31"
 
9
 
10
 
11
  ELEVENLABS_API_KEY="b3af3a938c8e15d5eae700ea47eea7d88dfe397f34fbd4b0c75c24f143b032b8"
12
+ ELEVENLABS_VOICE_ID="GrHQRXD136YZl3kbtri3"
13
  ELEVENLABS_MODEL_ID="eleven_v3"
14
 
15
  # TWILIO_ACCOUNT_SID="ACfafc0d2d007bdf14b21bb3e14a7a7b31"
core/backend.py CHANGED
@@ -577,6 +577,8 @@ async def book_appointment(
577
  patient_age: str = "",
578
  patient_num: str = "",
579
  visiting_date: str = "",
 
 
580
  patient_mail: str = ""
581
  ) -> str:
582
  """
@@ -588,8 +590,10 @@ async def book_appointment(
588
  patient_name: Full name of the patient.
589
  patient_age: Age of the patient (e.g. "32").
590
  patient_num: Contact phone number of the patient.
591
- visiting_date: Date of visit in YYYY-MM-DD format or natural text.
592
- patient_mail: Optional mail address for confirmation mail.
 
 
593
  """
594
  db_path = get_db_path()
595
  patient_num = format_bd_number(patient_num)
@@ -598,16 +602,32 @@ async def book_appointment(
598
  doctor_name = _clean_text(doctor_name)
599
  category = _clean_text(category)
600
  visiting_date = _clean_text(visiting_date)
 
 
601
  patient_mail = _clean_text(patient_mail)
602
- parsed_date = _parse_visit_date(visiting_date)
603
- if parsed_date:
604
- visiting_date = parsed_date
605
-
606
- if not patient_name or not patient_age or not patient_num or not visiting_date:
607
- return (
608
- "Missing booking details. Need patient name, age, phone number, "
609
- "and visit date."
610
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
611
 
612
  async with aiosqlite.connect(db_path) as db:
613
  db.row_factory = aiosqlite.Row
@@ -640,7 +660,23 @@ async def book_appointment(
640
  doctor_data = dict(doctor)
641
  doctor_name = doctor_data.get("doctor_name", "Unknown")
642
  doctor_category = doctor_data.get("category", "Unknown")
643
- visiting_time = doctor_data.get("visiting_time", "Unknown")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
644
 
645
  cursor = await db.execute(
646
  """SELECT id FROM patients
@@ -653,35 +689,33 @@ async def book_appointment(
653
  f"on {visiting_date} already exists."
654
  )
655
 
 
656
  await db.execute(
657
  """INSERT INTO patients
658
- (doctor_name, doctor_category, patient_name, patient_age, patient_num, visiting_date, patient_mail)
659
- VALUES (?, ?, ?, ?, ?, ?, ?)""",
660
- (doctor_name, doctor_category, patient_name, patient_age, patient_num, visiting_date, patient_mail),
661
  )
662
  await db.commit()
663
 
664
- # Mail confirmation is optional. Book first, then try to send email if available.
665
  mail_message = (
666
  f"Doctor : {doctor_name}\n"
667
  f"Patient : {patient_name}\n"
668
  f"Visit Date : {visiting_date}\n"
 
669
  f"Visit Time : {visiting_time}\n"
670
  f"Please arrive on time."
671
  )
672
- mail_status = ""
673
- if patient_mail:
674
- try:
675
- await send_mail(
676
- to_mail=patient_mail,
677
- subject="โœ… Appointment Confirmed!",
678
- body=mail_message,
679
- )
680
- mail_status = "\n๐Ÿ“ง Mail confirmation sent."
681
- except Exception as e:
682
- mail_status = f"\nโš ๏ธ Mail failed: {str(e)}"
683
- else:
684
- mail_status = "\n๐Ÿ“ง No email provided, so email confirmation was skipped."
685
 
686
  return (
687
  f"โœ… Appointment Booked!\n"
@@ -690,7 +724,10 @@ async def book_appointment(
690
  f"Patient : {patient_name}\n"
691
  f"Age : {patient_age}\n"
692
  f"Date : {visiting_date}\n"
 
 
693
  f"Contact : {patient_num}\n"
 
694
  f"โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n"
695
  f"Please arrive on time."
696
  f"{mail_status}"
@@ -800,7 +837,7 @@ TOOL RULES:
800
  - Use `book_appointment` only after identifying the doctor and required patient details.
801
  - Never invent `doctor_id`. Get it from tool results or resolve by doctor_name/category.
802
  - If the user gives a Bangla date like "เฆ†เฆ—เฆพเฆฎเง€เฆ•เฆพเฆฒ" or "เฆชเฆฐเฆถเง", convert it to a real date before booking.
803
- - Do not block booking on email. If email is missing, book the appointment and skip email confirmation.
804
  - If the user already provided name, age, phone, and date and then confirms, call `book_appointment` immediately.
805
  - If the user asks to cancel and only gives a phone number, cancel the single matching appointment if there is exactly one.
806
 
@@ -838,8 +875,9 @@ You must now choose the correct tool instead of answering in prose:
838
  - Use `delete_appointment` when the user is cancelling a booking.
839
 
840
  Important booking rules:
841
- - Email is optional. If the user did not provide email, book without it.
842
- - If the user already gave name, age, phone, and visit date, do not ask for those again.
 
843
  - If the user has already confirmed the details, book immediately.
844
 
845
  Important cancellation rules:
@@ -923,11 +961,26 @@ class AIBackend:
923
  patient_age TEXT,
924
  patient_num TEXT,
925
  visiting_date TEXT,
 
 
926
  patient_mail TEXT
927
  )
928
  """)
929
  await self.conn.commit()
930
 
 
 
 
 
 
 
 
 
 
 
 
 
 
931
  # โ”€โ”€ Summarise node โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
932
  async def summarize_conversation(self, state: ChatState):
933
  existing = state.get("summary", "")
 
577
  patient_age: str = "",
578
  patient_num: str = "",
579
  visiting_date: str = "",
580
+ visiting_day: str = "",
581
+ visiting_time: str = "",
582
  patient_mail: str = ""
583
  ) -> str:
584
  """
 
590
  patient_name: Full name of the patient.
591
  patient_age: Age of the patient (e.g. "32").
592
  patient_num: Contact phone number of the patient.
593
+ visiting_date: Date of visit in YYYY-MM-DD format or natural text (optional if visiting_day is provided).
594
+ visiting_day: Day of visit (e.g. "Sunday", "เฆฐเฆฌเฆฟเฆฌเฆพเฆฐ", "today") โ€” required if visiting_date is not provided.
595
+ visiting_time: Time of visit (e.g. "6pm-9pm") โ€” required (can be auto-filled from doctor record if missing).
596
+ patient_mail: Required email address for confirmation mail.
597
  """
598
  db_path = get_db_path()
599
  patient_num = format_bd_number(patient_num)
 
602
  doctor_name = _clean_text(doctor_name)
603
  category = _clean_text(category)
604
  visiting_date = _clean_text(visiting_date)
605
+ visiting_day = _clean_text(visiting_day)
606
+ visiting_time = _clean_text(visiting_time)
607
  patient_mail = _clean_text(patient_mail)
608
+
609
+ if visiting_date:
610
+ parsed_date = _parse_visit_date(visiting_date)
611
+ if parsed_date:
612
+ visiting_date = parsed_date
613
+ elif visiting_day:
614
+ parsed_date = _parse_visit_date(visiting_day)
615
+ if parsed_date:
616
+ visiting_date = parsed_date
617
+
618
+ # Mandatory fields
619
+ if not patient_name:
620
+ return "Missing booking details. Need patient name."
621
+ if not patient_age:
622
+ return "Missing booking details. Need patient age."
623
+ if not patient_num:
624
+ return "Missing booking details. Need patient phone number."
625
+ if not (doctor_id or doctor_name):
626
+ return "Missing booking details. Need doctor name."
627
+ if not visiting_date:
628
+ return "Missing booking details. Need day/date to visit the doctor."
629
+ if not patient_mail:
630
+ return "Missing booking details. Need email address for confirmation."
631
 
632
  async with aiosqlite.connect(db_path) as db:
633
  db.row_factory = aiosqlite.Row
 
660
  doctor_data = dict(doctor)
661
  doctor_name = doctor_data.get("doctor_name", "Unknown")
662
  doctor_category = doctor_data.get("category", "Unknown")
663
+ doctor_visiting_days = doctor_data.get("visiting_days", "") or ""
664
+ doctor_visiting_time = doctor_data.get("visiting_time", "") or ""
665
+
666
+ # Auto-fill visiting_time from doctor record if caller didn't provide it
667
+ if not visiting_time:
668
+ visiting_time = doctor_visiting_time.strip()
669
+ if not visiting_time:
670
+ return "Missing booking details. Need time to visit the doctor."
671
+
672
+ # Keep visiting_day if provided; otherwise derive from date (English day)
673
+ if not visiting_day and visiting_date:
674
+ try:
675
+ import datetime as _dt
676
+ y, m, d = [int(x) for x in visiting_date.split("-")]
677
+ visiting_day = _dt.date(y, m, d).strftime("%A")
678
+ except Exception:
679
+ visiting_day = ""
680
 
681
  cursor = await db.execute(
682
  """SELECT id FROM patients
 
689
  f"on {visiting_date} already exists."
690
  )
691
 
692
+ # Create booking
693
  await db.execute(
694
  """INSERT INTO patients
695
+ (doctor_name, doctor_category, patient_name, patient_age, patient_num, visiting_date, visiting_day, visiting_time, patient_mail)
696
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)""",
697
+ (doctor_name, doctor_category, patient_name, patient_age, patient_num, visiting_date, visiting_day, visiting_time, patient_mail),
698
  )
699
  await db.commit()
700
 
701
+ # Mail confirmation is mandatory.
702
  mail_message = (
703
  f"Doctor : {doctor_name}\n"
704
  f"Patient : {patient_name}\n"
705
  f"Visit Date : {visiting_date}\n"
706
+ f"Visit Day : {visiting_day}\n"
707
  f"Visit Time : {visiting_time}\n"
708
  f"Please arrive on time."
709
  )
710
+ try:
711
+ await send_mail(
712
+ to_mail=patient_mail,
713
+ subject="โœ… Appointment Confirmed!",
714
+ body=mail_message,
715
+ )
716
+ mail_status = "\n๐Ÿ“ง Confirmation mail sent."
717
+ except Exception as e:
718
+ mail_status = f"\nโš ๏ธ Mail failed: {str(e)}"
 
 
 
 
719
 
720
  return (
721
  f"โœ… Appointment Booked!\n"
 
724
  f"Patient : {patient_name}\n"
725
  f"Age : {patient_age}\n"
726
  f"Date : {visiting_date}\n"
727
+ f"Day : {visiting_day}\n"
728
+ f"Time : {visiting_time}\n"
729
  f"Contact : {patient_num}\n"
730
+ f"Email : {patient_mail}\n"
731
  f"โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n"
732
  f"Please arrive on time."
733
  f"{mail_status}"
 
837
  - Use `book_appointment` only after identifying the doctor and required patient details.
838
  - Never invent `doctor_id`. Get it from tool results or resolve by doctor_name/category.
839
  - If the user gives a Bangla date like "เฆ†เฆ—เฆพเฆฎเง€เฆ•เฆพเฆฒ" or "เฆชเฆฐเฆถเง", convert it to a real date before booking.
840
+ - Email is REQUIRED for booking and must be used to send a confirmation mail.
841
  - If the user already provided name, age, phone, and date and then confirms, call `book_appointment` immediately.
842
  - If the user asks to cancel and only gives a phone number, cancel the single matching appointment if there is exactly one.
843
 
 
875
  - Use `delete_appointment` when the user is cancelling a booking.
876
 
877
  Important booking rules:
878
+ - Email is REQUIRED. Do not book without an email address.
879
+ - Visiting time is REQUIRED. If the doctor record has a visiting_time, use it and confirm it with the user.
880
+ - If the user already gave name, age, phone, doctor name, visit day/date, visit time, and email, do not ask again.
881
  - If the user has already confirmed the details, book immediately.
882
 
883
  Important cancellation rules:
 
961
  patient_age TEXT,
962
  patient_num TEXT,
963
  visiting_date TEXT,
964
+ visiting_day TEXT,
965
+ visiting_time TEXT,
966
  patient_mail TEXT
967
  )
968
  """)
969
  await self.conn.commit()
970
 
971
+ # Lightweight migrations for older DBs
972
+ async def _ensure_column(table: str, col: str, col_type: str) -> None:
973
+ async with self.conn.execute(f"PRAGMA table_info({table})") as cur:
974
+ rows = await cur.fetchall()
975
+ existing = {r[1] for r in rows} # (cid,name,type,notnull,dflt,pk)
976
+ if col in existing:
977
+ return
978
+ await self.conn.execute(f"ALTER TABLE {table} ADD COLUMN {col} {col_type}")
979
+ await self.conn.commit()
980
+
981
+ await _ensure_column("patients", "visiting_day", "TEXT")
982
+ await _ensure_column("patients", "visiting_time", "TEXT")
983
+
984
  # โ”€โ”€ Summarise node โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
985
  async def summarize_conversation(self, state: ChatState):
986
  existing = state.get("summary", "")
db_view/db.html CHANGED
@@ -114,6 +114,8 @@
114
  <th>Doctor</th>
115
  <th>Category</th>
116
  <th>Visiting Date</th>
 
 
117
  </tr>
118
  </thead>
119
  <tbody></tbody>
@@ -186,6 +188,8 @@
186
  <td>${patient.doctor_name}</td>
187
  <td>${patient.doctor_category}</td>
188
  <td>${patient.visiting_date}</td>
 
 
189
  </tr>`).join('');
190
 
191
  loading.style.display = 'none';
 
114
  <th>Doctor</th>
115
  <th>Category</th>
116
  <th>Visiting Date</th>
117
+ <th>Visiting Day</th>
118
+ <th>Visiting Time</th>
119
  </tr>
120
  </thead>
121
  <tbody></tbody>
 
188
  <td>${patient.doctor_name}</td>
189
  <td>${patient.doctor_category}</td>
190
  <td>${patient.visiting_date}</td>
191
+ <td>${patient.visiting_day || ''}</td>
192
+ <td>${patient.visiting_time || ''}</td>
193
  </tr>`).join('');
194
 
195
  loading.style.display = 'none';
db_view/dbapi.py CHANGED
@@ -45,6 +45,8 @@ class Patient(BaseModel):
45
  patient_age: str
46
  patient_num: str
47
  visiting_date: str
 
 
48
  patient_mail: str
49
 
50
  class AllDataResponse(BaseModel):
 
45
  patient_age: str
46
  patient_num: str
47
  visiting_date: str
48
+ visiting_day: str | None = ""
49
+ visiting_time: str | None = ""
50
  patient_mail: str
51
 
52
  class AllDataResponse(BaseModel):