Files
LLM_Engineering_OLD/community-contributions/clinic_booking_bot.ipynb
Sabine Fonderson | CEO b840ea6b58 Add files via upload
Hi Ed,
2025-06-27 16:46:48 +02:00

345 lines
12 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"cells": [
{
"cell_type": "code",
"execution_count": 170,
"id": "a1aa1b43-7a47-4aca-ae5f-94a9d4ba2d89",
"metadata": {},
"outputs": [],
"source": [
"## Clinic Booking Bot\n",
"\n",
"##Easily book your clinic visit available only on weekdays between **14:00 and 15:00**. \n",
"##Speak or type, and get instant confirmation.\n"
]
},
{
"cell_type": "code",
"execution_count": 171,
"id": "fe798c6a-f8da-46aa-8c0e-9d2623def3d2",
"metadata": {},
"outputs": [],
"source": [
"# import library\n",
"\n",
"import os\n",
"import json\n",
"from dotenv import load_dotenv\n",
"from openai import OpenAI\n",
"import gradio as gr\n",
"import base64\n",
"from io import BytesIO\n",
"from datetime import date\n",
"from PIL import Image, ImageDraw, ImageFont\n"
]
},
{
"cell_type": "code",
"execution_count": 172,
"id": "0ad4e526-e95d-4e70-9faa-b4236b105dd5",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"OpenAI API Key exists and begins sk-proj-\n"
]
}
],
"source": [
"# Save keys\n",
"\n",
"load_dotenv(override=True)\n",
"\n",
"openai_api_key = os.getenv('OPENAI_API_KEY')\n",
"if openai_api_key:\n",
" print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
"else:\n",
" print(\"OpenAI API Key not set\")\n",
" \n",
"MODEL = \"gpt-4o-mini\"\n",
"openai = OpenAI()"
]
},
{
"cell_type": "code",
"execution_count": 173,
"id": "ae95308e-0002-4017-9f2c-fcb1ddb248fa",
"metadata": {},
"outputs": [],
"source": [
"# --- CONFIG ---\n",
"BOOKING_START = 14\n",
"BOOKING_END = 15\n",
"WEEKDAYS = [\"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\"]\n",
"PHONE = \"010-1234567\"\n",
"confirmed_bookings = []\n"
]
},
{
"cell_type": "code",
"execution_count": 174,
"id": "e21b0fd0-4cda-4938-8867-dc2c6e7af4b1",
"metadata": {},
"outputs": [],
"source": [
"# --- TTS ---\n",
"def generate_tts(text, voice=\"fable\", filename=\"output.mp3\"):\n",
" response = openai.audio.speech.create(\n",
" model=\"tts-1\",\n",
" voice=\"fable\",\n",
" input=text\n",
" )\n",
" with open(filename, \"wb\") as f:\n",
" f.write(response.content)\n",
" return filename"
]
},
{
"cell_type": "code",
"execution_count": 175,
"id": "e28a5c3b-bd01-4845-a41e-87823f6bb078",
"metadata": {},
"outputs": [],
"source": [
"# --- Translate Booking Confirmation ---\n",
"def translate_text(text, target_language=\"nl\"):\n",
" prompt = f\"Translate this message to {target_language}:\\n{text}\"\n",
" response = openai.chat.completions.create(\n",
" model=\"gpt-4\",\n",
" messages=[\n",
" {\"role\": \"system\", \"content\": \"You are a helpful translator.\"},\n",
" {\"role\": \"user\", \"content\": prompt}\n",
" ]\n",
" )\n",
" return response.choices[0].message.content.strip()\n"
]
},
{
"cell_type": "code",
"execution_count": 176,
"id": "8ed57cc9-7d54-4a5d-831b-0efcc5b7a7a9",
"metadata": {},
"outputs": [],
"source": [
"# --- Booking Logic ---\n",
"def book_appointment(name, time_str):\n",
" try:\n",
" booking_time = datetime.strptime(time_str, \"%H:%M\")\n",
" except ValueError:\n",
" return \"Invalid time format. Use HH:MM.\", None, None\n",
"\n",
" hour = booking_time.hour\n",
" weekday = datetime.today().strftime(\"%A\")\n",
"\n",
" if weekday not in WEEKDAYS:\n",
" response = \"Bookings are only available on weekdays.\"\n",
" elif BOOKING_START <= hour < BOOKING_END:\n",
" confirmation = f\"Booking confirmed for {name} at {time_str}.\"\n",
" confirmed_bookings.append((name, time_str))\n",
" translated = translate_text(confirmation)\n",
" audio = generate_tts(translated)\n",
" image = generate_booking_image(name, time_str)\n",
" return translated, audio, image\n",
" else:\n",
" response = \"Sorry, bookings are only accepted between 14:00 and 15:00 on weekdays.\"\n",
" translated = translate_text(response)\n",
" audio = generate_tts(translated)\n",
" return translated, audio, None"
]
},
{
"cell_type": "code",
"execution_count": 177,
"id": "19b52115-f0f3-4d63-a463-886163d4cfd1",
"metadata": {},
"outputs": [],
"source": [
"# --- Booking Card ---\n",
"def generate_booking_image(name, time_str):\n",
" img = Image.new(\"RGB\", (500, 250), color=\"white\")\n",
" draw = ImageDraw.Draw(img)\n",
" msg = f\"\\u2705 Booking Confirmed\\nName: {name}\\nTime: {time_str}\"\n",
" draw.text((50, 100), msg, fill=\"black\")\n",
" return img"
]
},
{
"cell_type": "code",
"execution_count": 178,
"id": "2c446b6c-d410-4ba1-b0c7-c475e5259ff5",
"metadata": {},
"outputs": [],
"source": [
"# --- Voice Booking ---\n",
"def voice_booking(audio_path, name):\n",
" with open(audio_path, \"rb\") as f:\n",
" response = openai.audio.transcriptions.create(model=\"whisper-1\", file=f)\n",
" transcription = response.text.strip()\n",
"\n",
" system_prompt = \"\"\"\n",
" You are a clinic assistant. Extract only the appointment time from the user's sentence in 24-hour HH:MM format.\n",
" If no time is mentioned, respond with 'No valid time found.'\n",
" \"\"\"\n",
"\n",
" response = openai.chat.completions.create(\n",
" model=\"gpt-4\",\n",
" messages=[\n",
" {\"role\": \"system\", \"content\": system_prompt},\n",
" {\"role\": \"user\", \"content\": transcription}\n",
" ]\n",
" )\n",
" extracted_time = response.choices[0].message.content.strip()\n",
"\n",
" if \":\" in extracted_time:\n",
" return book_appointment(name, extracted_time)\n",
" else:\n",
" message = \"Sorry, I couldn't understand the time. Please try again.\"\n",
" translated = translate_text(message)\n",
" audio_path = generate_tts(translated)\n",
" return translated, audio_path, None"
]
},
{
"cell_type": "code",
"execution_count": 179,
"id": "121d2907-7fa8-4248-b2e7-83617ea66ff0",
"metadata": {},
"outputs": [],
"source": [
"# --- Chat Bot Handler ---\n",
"def chat_bot(messages):\n",
" system_prompt = \"\"\"\n",
" You are a clinic booking assistant. Your job is to:\n",
" - Greet the patient and explain your role\n",
" - Only assist with making appointments\n",
" - Accept bookings only on weekdays between 14:00 and 15:00\n",
" - Do not provide medical advice\n",
" - Always respond with empathy and clarity\n",
" \"\"\"\n",
" response = openai.chat.completions.create(\n",
" model=\"gpt-4\",\n",
" messages=[{\"role\": \"system\", \"content\": system_prompt}] + messages\n",
" )\n",
" reply = response.choices[0].message.content.strip()\n",
" audio = generate_tts(reply)\n",
" return reply, audio"
]
},
{
"cell_type": "code",
"execution_count": 180,
"id": "2427b694-8c57-40cb-b202-4a8989547925",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"* Running on local URL: http://127.0.0.1:7898\n",
"* To create a public link, set `share=True` in `launch()`.\n"
]
},
{
"data": {
"text/html": [
"<div><iframe src=\"http://127.0.0.1:7898/\" width=\"100%\" height=\"500\" allow=\"autoplay; camera; microphone; clipboard-read; clipboard-write;\" frameborder=\"0\" allowfullscreen></iframe></div>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Gradio interface\n",
"with gr.Blocks(theme=gr.themes.Soft()) as demo:\n",
" gr.Markdown(\"\"\"## 🩺 GP Booking Assistant \n",
"Only available weekdays between **14:00 and 15:00** \n",
"☎️ Contact: {PHONE}\n",
"---\"\"\")\n",
"\n",
" name_global = gr.Textbox(label=\"Your Name\", placeholder=\"Enter your name\", interactive=True)\n",
"\n",
" with gr.Tab(\"💬 Chat Mode\"):\n",
" chatbot = gr.Chatbot(label=\"Booking Chat\", type=\"messages\", height=400)\n",
" text_input = gr.Textbox(label=\"Type your message or use your voice below\")\n",
" audio_input = gr.Audio(type=\"filepath\", label=\"🎙️ Or speak your request\")\n",
" chat_audio_output = gr.Audio(label=\"🔊 Assistant's Reply\", type=\"filepath\")\n",
" send_btn = gr.Button(\"Send\")\n",
"\n",
" def handle_chat(user_message, chat_history):\n",
" chat_history = chat_history or []\n",
" chat_history.append({\"role\": \"user\", \"content\": user_message})\n",
" reply, audio = chat_bot(chat_history)\n",
" chat_history.append({\"role\": \"assistant\", \"content\": reply})\n",
" return chat_history, \"\", audio\n",
"\n",
" def handle_audio_chat(audio_path, chat_history):\n",
" with open(audio_path, \"rb\") as f:\n",
" transcription = openai.audio.transcriptions.create(model=\"whisper-1\", file=f).text.strip()\n",
" return handle_chat(transcription, chat_history)\n",
"\n",
" send_btn.click(handle_chat, [text_input, chatbot], [chatbot, text_input, chat_audio_output])\n",
" text_input.submit(handle_chat, [text_input, chatbot], [chatbot, text_input, chat_audio_output])\n",
" audio_input.change(handle_audio_chat, [audio_input, chatbot], [chatbot, text_input, chat_audio_output])\n",
"\n",
"\n",
" \n",
" with gr.Tab(\"📝 Text Booking\"):\n",
" time_text = gr.Textbox(label=\"Preferred Time (HH:MM)\", placeholder=\"e.g., 14:30\")\n",
" btn_text = gr.Button(\"📅 Book via Text\")\n",
"\n",
" with gr.Tab(\"🎙️ Voice Booking\"):\n",
" voice_input = gr.Audio(type=\"filepath\", label=\"Say your preferred time\")\n",
" btn_voice = gr.Button(\"📅 Book via Voice\")\n",
"\n",
" output_text = gr.Textbox(label=\"Response\", interactive=False)\n",
" output_audio = gr.Audio(label=\"Audio Reply\", type=\"filepath\")\n",
" output_image = gr.Image(label=\"Booking Confirmation\")\n",
"\n",
" btn_text.click(fn=book_appointment, inputs=[name_global, time_text], outputs=[output_text, output_audio, output_image])\n",
" btn_voice.click(fn=voice_booking, inputs=[voice_input, name_global], outputs=[output_text, output_audio, output_image])\n",
"\n",
" gr.Markdown(\"\"\"---\n",
"<small>This assistant does **not** give medical advice. It only books appointments within allowed hours.</small>\n",
"\"\"\")\n",
"\n",
" demo.launch()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f359de0a-28b1-4895-b21d-91d79e494a0d",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.12"
}
},
"nbformat": 4,
"nbformat_minor": 5
}