import gradio as gr import joblib import re import contractions # Load model and encoder model = joblib.load("tfidf_baseline.pkl") le = joblib.load("label_encoder.pkl") # Signal categories signal_categories = { "Side Effects": ["side effect", "reaction", "rash", "nausea", "vomit", "dizzy", "dizziness", "headache", "itching", "swelling"], "Weight Changes": ["weight gain", "weight loss", "gained weight", "bloating"], "Mental Health": ["depression", "anxiety", "mood", "suicidal", "panic", "mental", "emotional", "crying", "mood swing"], "Sleep Issues": ["insomnia", "sleep", "tired", "fatigue", "exhausted", "drowsy", "can not sleep"], "Pain": ["pain", "cramps", "cramping", "ache", "burning", "soreness"], "Ineffectiveness": ["not work", "didn t work", "no effect", "useless", "ineffective", "did nothing"], "Withdrawal": ["withdrawal", "stopped", "quit", "discontinue", "coming off", "weaning"], "Hormonal Effects": ["period", "bleeding", "spotting", "hormonal", "menstrual", "libido", "sex drive"], "Digestive Issues": ["stomach", "diarrhea", "constipation", "nausea", "bowel", "gut", "acid", "heartburn"], "Access & Cost": ["expensive", "cost", "afford", "insurance", "price"] } def clean_text(text): if not isinstance(text, str): return "" text = contractions.fix(text) text = text.replace("'", "'").replace("&", "and") text = text.lower() text = re.sub(r"http\S+|www\S+", "", text) text = re.sub(r"[^a-z\s]", "", text) text = re.sub(r"\s+", " ", text).strip() return text def extract_signals(text): found = [] for category, keywords in signal_categories.items(): if any(kw in text for kw in keywords): found.append(category) return found def analyze_review(review_text, condition): if not review_text.strip(): return "Please enter a review.", "" condition = condition.strip().lower() if condition.strip() else "unknown" clean = clean_text(review_text) combined = condition + " " + clean pred_label = model.predict([combined])[0] sentiment = le.inverse_transform([pred_label])[0] proba = model.predict_proba([combined])[0] confidence = round(float(max(proba)) * 100, 1) emoji_map = {"Positive": "🟢", "Neutral": "🟡", "Negative": "🔴"} sentiment_output = f"{emoji_map[sentiment]} {sentiment} ({confidence}% confidence)" if sentiment == "Negative": signals = extract_signals(clean) if signals: signals_output = "⚠️ Detected Adverse Signals:\n" + "\n".join(f" • {s}" for s in signals) else: signals_output = "⚠️ Negative review — no specific signal category detected." else: signals_output = "No adverse signals flagged for non-negative reviews." return sentiment_output, signals_output # Gradio UI with gr.Blocks(title="MedReview Intelligence") as demo: gr.Markdown(""" # 🏥 MedReview Intelligence ### Clinical Feedback Analyzer — Adverse Signal Detection from Patient Drug Reviews *Built by Samuel Yaula Dutse* """) with gr.Row(): with gr.Column(): review_input = gr.Textbox( label="Patient Review", placeholder="Enter a patient drug review here...", lines=5 ) condition_input = gr.Textbox( label="Medical Condition (optional)", placeholder="e.g. Depression, Birth Control, Diabetes..." ) analyze_btn = gr.Button("Analyze Review", variant="primary") with gr.Column(): sentiment_output = gr.Textbox(label="Sentiment", interactive=False) signals_output = gr.Textbox(label="Adverse Signals Detected", lines=6, interactive=False) gr.Examples( examples=[ ["This medication has been a lifesaver. No side effects and my condition improved within weeks.", "Depression"], ["I gained 15 pounds in 2 months and the mood swings are unbearable. I had to stop taking it.", "Birth Control"], ["It works okay I guess. Not great but not terrible either. Still adjusting.", "Anxiety"], ], inputs=[review_input, condition_input] ) analyze_btn.click( fn=analyze_review, inputs=[review_input, condition_input], outputs=[sentiment_output, signals_output] ) demo.launch()