import gradio as gr import numpy as np from transformers import pipeline from sentence_transformers import SentenceTransformer # ------------------------------------------------------------------------ # Load smaller, valid models # ------------------------------------------------------------------------ # Zero-shot NLI classifier (≈120 MB) intent_classifier = pipeline( "zero-shot-classification", model="valhalla/distilbart-mnli-12-1" ) # Lightweight sentence‐embedding model (≈60 MB) model = SentenceTransformer("paraphrase-MiniLM-L3-v2") # ------------------------------------------------------------------------ # Define intent labels # ------------------------------------------------------------------------ intents = [ "schedule appointment", "clinic hours", "insurance inquiry", "test results", "appointment cancellation", "prescription refill", "covid protocols", "update personal info", "services offered", "telehealth availability", "contact support" ] # ------------------------------------------------------------------------ # Updated FAQ data and corresponding intent tags # ------------------------------------------------------------------------ faq_data = { "questions": [ "How do I schedule an appointment?", "Can I book an appointment online?", "What is the process to make a doctor's appointment?", "What are your clinic hours?", "Are you open on weekends?", "When does the clinic open and close?", "Do you accept my insurance?", "Which insurance plans do you accept?", "Can I use my insurance for treatment?", "How can I get my test results?", "When will my lab results be ready?", "How do I access my blood test results?", "How do I cancel or reschedule my appointment?", "Can I change my appointment time?", "What is the cancellation policy?", "How do I refill my prescription?", "Can I get a refill for my medication online?", "What is the process to renew my prescription?", "What COVID-19 protocols are in place?", "Do I need to wear a mask to my appointment?", "How is your clinic handling COVID-19 safety?", "How do I update my personal information?", "Can I change my address or phone number online?", "Where do I update my contact details?", "What services do you offer?", "Do you provide pediatric care?", "What types of medical services are available?", "Are telehealth visits available?", "Can I book a virtual doctor visit?", "Do you offer video consultations?", "How can I contact customer service?", "What is your support phone number?", "Who do I talk to for more help?" ], "answers": [ "You can schedule an appointment by calling our clinic or using our online booking system.", "Yes, appointments can be booked online via our website or patient portal.", "To make a doctor's appointment, call our front desk or use the online scheduler.", "Our clinic is open Monday to Friday from 8 AM to 6 PM, and Saturdays from 9 AM to 1 PM.", "Yes, we are open on Saturdays from 9 AM to 1 PM but closed on Sundays.", "We open at 8 AM and close at 6 PM on weekdays.", "We accept most major insurance providers. Please contact us to verify your coverage.", "Our clinic accepts a variety of insurance plans including Aetna, Blue Cross, and United Healthcare.", "Yes, your insurance can be used for most treatments at our clinic.", "Test results are usually available within 3-5 business days and can be accessed through your patient portal.", "Lab results are typically ready within 3-5 days after testing.", "You can view your blood test results online through the patient portal.", "To cancel or reschedule, please call us at least 24 hours before your appointment or use the patient portal.", "You can change your appointment time by contacting our front desk.", "Our cancellation policy requires 24-hour notice to avoid fees.", "You can request prescription refills by contacting our pharmacy or through the patient portal.", "Refills can be requested online via your patient account.", "To renew your prescription, contact your doctor or use the online refill service.", "We follow all recommended COVID-19 safety protocols, including mask mandates and social distancing.", "Masks are required for all visitors during appointments.", "Our clinic enforces strict COVID-19 guidelines to ensure patient safety.", "You can update your personal information by logging into your patient account or contacting our front desk.", "Changes to your address or phone number can be made online.", "Please update your contact details through the patient portal or by calling us.", "Our services include primary care, pediatrics, lab testing, immunizations, and wellness checkups.", "Yes, we offer pediatric care as part of our services.", "We provide a wide range of medical services including preventive care and diagnostics.", "Telehealth visits are available for many of our services.", "You can book a virtual doctor visit online through our patient portal.", "Video consultations are offered for appropriate medical concerns.", "You can contact customer service via phone at 1-800-123-4567 or email support@clinic.com.", "Our support phone number is 1-800-123-4567.", "For more help, please contact our support team by phone or email." ] } intent_tags = [ "schedule appointment", "schedule appointment", "schedule appointment", "clinic hours", "clinic hours", "clinic hours", "insurance inquiry", "insurance inquiry", "insurance inquiry", "test results", "test results", "test results", "appointment cancellation", "appointment cancellation", "appointment cancellation", "prescription refill", "prescription refill", "prescription refill", "covid protocols", "covid protocols", "covid protocols", "update personal info", "update personal info", "update personal info", "services offered", "services offered", "services offered", "telehealth availability", "telehealth availability", "telehealth availability", "contact support", "contact support", "contact support" ] # ------------------------------------------------------------------------ # Precompute embeddings for all FAQ questions once # ------------------------------------------------------------------------ faq_embeddings = model.encode(faq_data["questions"]) def chatbot_response(user_question, threshold_intent=0.2, threshold_faq=0.3): """ Two‐stage matching: 1) Zero‐shot intent classification. If confidence < threshold_intent, do a direct cosine‐similarity search across all FAQs. 2) Otherwise, filter FAQs by predicted intent, then cosine‐similarity among that subset. If score < threshold_faq, return fallback. """ # 1) Encode the user question user_emb = model.encode([user_question])[0] # 2) Intent prediction intent_result = intent_classifier(user_question, candidate_labels=intents) predicted_intent = intent_result["labels"][0] intent_confidence = intent_result["scores"][0] # 3) If low confidence, match across all FAQs if intent_confidence < threshold_intent: cos_sims = np.dot(faq_embeddings, user_emb) / ( np.linalg.norm(faq_embeddings, axis=1) * np.linalg.norm(user_emb) ) best_idx = np.argmax(cos_sims) if cos_sims[best_idx] >= threshold_faq: return faq_data["answers"][best_idx] return "Sorry, I didn't understand your question. Please try rephrasing." # 4) Otherwise, filter by that intent indices = [i for i, tag in enumerate(intent_tags) if tag == predicted_intent] if not indices: return "Sorry, I don't have an answer for that topic yet." filtered_embs = faq_embeddings[indices] cos_sims = np.dot(filtered_embs, user_emb) / ( np.linalg.norm(filtered_embs, axis=1) * np.linalg.norm(user_emb) ) best_idx_within = np.argmax(cos_sims) if cos_sims[best_idx_within] < threshold_faq: return "Sorry, I couldn't find a good match for your question." return faq_data["answers"][indices[best_idx_within]] # ------------------------------------------------------------------------ # Gradio interface # ------------------------------------------------------------------------ def respond(user_input): return chatbot_response(user_input) iface = gr.Interface( fn=respond, inputs=gr.Textbox(lines=2, placeholder="Ask a health-related question..."), outputs="text", title="Healthcare Support Chatbot", description="Ask about appointments, test results, COVID protocols, telehealth, and more." ) if __name__ == "__main__": iface.launch()