HealthAssistant / app.py
reedmayhew's picture
Update app.py
f2d2182 verified
raw
history blame
18 kB
import os
import gradio as gr
from openai import OpenAI
# Configure the OpenAI client with your custom API endpoint and API key.
client = OpenAI(base_url="http://home.mayhew.cloud:1234/v1", api_key="lm-studio")
medical_recommendations = "MEDICAL RECOMMENDATIONS:\n\n" + "Below is an overview of common birth control options, sorted from most effective to least effective based on typical-use failure rates. Keep in mind that “typical use” reflects real-world use (including human error), while “perfect use” may show slightly better rates. The information below includes average prevention rates, along with pros, cons, and possible side effects.\n\n---\n\n## 1. Highly Effective Methods (<1% Failure Rate)\n\n### **Sterilization**\n- **Average Prevention Rate:** >99% effective\n- **Pros:**\n - **Permanent:** Ideal for those who are sure they do not want future pregnancies.\n - **Low Maintenance:** No ongoing effort or daily attention required.\n- **Cons:**\n - **Irreversible:** Difficult or impossible to reverse in most cases.\n - **Surgical Procedure:** Involves risks related to surgery.\n- **Side Effects/Risks:**\n - Surgical risks such as infection or complications.\n - For **vasectomy**: Minor swelling, bruising, or pain.\n - For **tubal ligation**: Possibility of regret if family planning changes.\n\n### **Intrauterine Devices (IUDs)**\n- **Types:** \n - **Hormonal IUD (e.g., Mirena, Skyla)**\n - **Copper IUD (Paragard)**\n- **Average Prevention Rate:** >99% effective\n- **Pros:**\n - **Long-Term Protection:** Lasts between 3–10 years depending on the type.\n - **Low Maintenance:** One-time insertion with immediate high efficacy.\n - **Reversible:** Fertility typically returns quickly after removal.\n- **Cons:**\n - **Insertion Required:** Must be inserted (and later removed) by a healthcare provider.\n - **Initial Discomfort:** Some users experience pain or cramping during insertion.\n- **Side Effects/Risks:**\n - **Hormonal IUD:** May cause irregular bleeding initially; often reduces menstrual cramps over time.\n - **Copper IUD:** Can lead to heavier periods and increased cramping.\n - **Rare Risks:** Possibility of expulsion or uterine perforation.\n\n### **Implant (e.g., Nexplanon)**\n- **Average Prevention Rate:** >99% effective\n- **Pros:**\n - **Long-Lasting:** Effective for up to 3 years.\n - **Low Maintenance:** Once inserted, requires little to no user attention.\n - **Reversible:** Fertility typically returns after removal.\n- **Cons:**\n - **Insertion/Removal Procedure:** Minor procedure required for both.\n - **Irregular Bleeding:** May cause unpredictable menstrual bleeding.\n- **Side Effects/Risks:**\n - Possible mood changes, headaches, or weight gain.\n - Insertion site pain or, rarely, infection.\n\n---\n\n## 2. Moderately Effective Methods (Approximately 1–9% Failure Rate with Typical Use)\n\n### **Injectable Birth Control (e.g., Depo-Provera)**\n- **Average Prevention Rate:** ~96% effective (about 4% failure rate typical use)\n- **Pros:**\n - **Convenient:** Only requires an injection every 3 months.\n - **High Efficacy:** Very effective when injections are on schedule.\n- **Cons:**\n - **Irregular Bleeding:** Some users experience spotting or amenorrhea (absence of periods).\n - **Fertility Delay:** Return to fertility may take several months after stopping.\n- **Side Effects/Risks:**\n - Possible weight gain and mood swings.\n - Long-term use may affect bone density.\n - Injection site reactions.\n\n### **Oral Contraceptive Pills (Combined or Progestin-Only)**\n- **Average Prevention Rate:** ~91% effective (about 7–9% failure rate typical use)\n- **Pros:**\n - **Cycle Regulation:** Can help regulate menstrual cycles and reduce cramps.\n - **Additional Benefits:** Some formulations help with acne and other hormonal issues.\n - **Quick Reversal:** Fertility typically returns quickly after discontinuation.\n- **Cons:**\n - **Daily Commitment:** Must be taken at the same time each day.\n - **User Error:** Missing pills reduces effectiveness.\n- **Side Effects/Risks:**\n - Increased risk of blood clots, especially in smokers or women over 35.\n - Nausea, breast tenderness, and mood changes.\n - Possible increased blood pressure.\n\n### **Transdermal Patch (e.g., Ortho Evra)**\n- **Average Prevention Rate:** ~91% effective (similar to the pill)\n- **Pros:**\n - **Weekly Application:** Requires changing only once a week.\n - **Steady Hormone Delivery:** Provides a consistent dose over time.\n- **Cons:**\n - **Skin Irritation:** May cause irritation at the application site.\n - **Visibility:** The patch is noticeable on the skin.\n- **Side Effects/Risks:**\n - Similar risks to combined oral contraceptives, including blood clots.\n - Nausea, breast tenderness, and headaches.\n - Reduced effectiveness if the patch becomes detached.\n\n### **Vaginal Ring (e.g., NuvaRing)**\n- **Average Prevention Rate:** ~91% effective\n- **Pros:**\n - **Monthly Maintenance:** Inserted once a month, reducing daily hassle.\n - **Low Systemic Hormone Levels:** Delivers hormones locally, which may reduce some systemic side effects.\n- **Cons:**\n - **Insertion Required:** Must be comfortable with inserting and removing the ring.\n - **Vaginal Discomfort:** Some may experience irritation or discomfort.\n- **Side Effects/Risks:**\n - Similar to other hormonal methods: risk of blood clots, mood changes, and headaches.\n - Possible vaginal irritation.\n\n---\n\n## 3. Less Effective Methods (Failure Rate 10% or Higher with Typical Use)\n\n### **Barrier Methods**\n\n#### **Male Condoms**\n- **Average Prevention Rate:** ~87% effective (about 13% failure rate typical use)\n- **Pros:**\n - **STI Protection:** Also reduce the risk of sexually transmitted infections.\n - **Non-Hormonal:** Suitable for those who prefer or require non-hormonal options.\n - **Widely Accessible:** Easily available without a prescription.\n- **Cons:**\n - **User-Dependent:** Effectiveness depends on correct and consistent use.\n - **Potential for Breakage:** Can break or slip if not used properly.\n- **Side Effects/Risks:**\n - Possible latex allergy (alternatives available, e.g., polyurethane).\n - Reduced sensation for some users.\n\n#### **Female Condoms**\n- **Average Prevention Rate:** ~79% effective with typical use\n- **Pros:**\n - **STI Protection:** Offers protection against sexually transmitted infections.\n - **Female-Controlled:** Provides an option for women to initiate protection.\n- **Cons:**\n - **Cost and Availability:** Often more expensive and less widely available.\n - **Learning Curve:** Can be less intuitive to use than male condoms.\n- **Side Effects/Risks:**\n - Potential irritation or allergic reaction to the materials used.\n\n#### **Diaphragms and Cervical Caps**\n- **Average Prevention Rate:** Approximately 83–88% effective with typical use\n- **Pros:**\n - **Reusable:** Can be cleaned and reused over multiple cycles.\n - **Non-Hormonal:** Good option for those avoiding hormones.\n- **Cons:**\n - **Requires Spermicide:** Must be used with a spermicide to improve effectiveness.\n - **Proper Fit Needed:** Must be correctly fitted by a healthcare provider.\n - **Timing:** Must be inserted prior to intercourse and left in place for a prescribed duration.\n- **Side Effects/Risks:**\n - Potential for irritation or allergic reactions to the spermicide.\n - Increased risk of urinary tract infections in some users.\n\n### **Spermicides (Used Alone)**\n- **Average Prevention Rate:** ~79% effective with typical use\n- **Pros:**\n - **Accessibility:** Can be purchased over-the-counter.\n - **Enhances Other Methods:** Can be combined with barrier methods to improve efficacy.\n- **Cons:**\n - **Lower Effectiveness Alone:** Much less effective when used as the sole method.\n - **Frequent Application:** Must be used with every act of intercourse.\n- **Side Effects/Risks:**\n - Can cause vaginal or penile irritation.\n - Potential allergic reactions.\n\n### **Fertility Awareness Methods (Natural Family Planning)**\n- **Average Prevention Rate:** ~76% effective with typical use (highly variable)\n- **Pros:**\n - **No Hormones or Devices:** Relies on tracking natural fertility signs.\n - **Increases Body Awareness:** Helps users understand their menstrual cycle.\n- **Cons:**\n - **High Commitment:** Requires daily tracking and strict adherence.\n - **Variable Effectiveness:** Efficacy can vary widely based on the method and diligence.\n- **Side Effects/Risks:**\n - No direct medical side effects, but higher risk of unintended pregnancy if not followed meticulously.\n\n### **Withdrawal (Coitus Interruptus)**\n- **Average Prevention Rate:** ~78% effective with typical use\n- **Pros:**\n - **No Cost:** Free and does not involve medications or devices.\n - **No Hormonal Side Effects:** Completely non-hormonal.\n- **Cons:**\n - **High Reliance on Timing:** Requires significant self-control and perfect timing.\n - **Risk from Pre-Ejaculate:** Pre-ejaculate can contain sperm, increasing failure risk.\n- **Side Effects/Risks:**\n - No direct medical risks, but potential for stress or relationship strain if unsuccessful.\n\n---\n\n> **Note:** \n> The effectiveness percentages mentioned above are approximate values and may vary based on individual use, adherence, and specific product variations."
SYSTEM_PROMPT = "You are a medical professional. Provide clear, detailed empathetic, and accurate information about healthcare topics. **You must always use markdown and bullet points.** Do not state to consult with a healthcare provider, as you are a healthcare provider. Only refer patients to an outside provider for physical resources, such as prescriptions, tests, bloodwork, x-rays, ultrasounds, CT scans, MRIs, and other in-person needs, since you provide services via telehealth, and do not have a license to call in orders for such requests.\n\n" + medical_recommendations
# UI text and styling
DESCRIPTION = '''
<div>
<div style="display: flex; align-items: center;">
<img src="https://aihealthcare.gay/icon96.png" alt="HealthAssistant Logo" width="96" height="96">
<h1 style="margin-left: 20px;">HealthAssistant</h1>
</div>
'''
LICENSE = """
<p>
Disclaimer: This Health Assistant is designed to provide helpful healthcare information; however, it may contain errors and is not intended to replace professional medical care. It does not diagnose any condition or disease. Always consult with a qualified healthcare provider for any medical concerns. Given the nature of AI models, there is a minimal risk of generating harmful or offensive content. Please exercise caution and use common sense.
User Acknowledgment: I hereby confirm that I am at least 18 years of age (or accompanied by a legal guardian who is at least 18 years old), understand that the information provided by this service is for informational purposes only and is not intended to diagnose or treat any medical condition, and acknowledge that I am solely responsible for verifying any information provided.</p>
"""
PLACEHOLDER = """
<div style="padding: 30px; text-align: center; display: flex; flex-direction: column; align-items: center;">
<h1 style="font-size: 28px; margin-bottom: 2px; opacity: 0.55;">The "Doctor" is in.</h1>
<p style="font-size: 18px; margin-bottom: 2px; opacity: 0.65;">Available for free. Always verify responses with outside information.</p>
</div>
"""
css = """
h1 {
text-align: center;
display: block;
}
#duplicate-button {
margin: auto;
color: white;
background: #1565c0;
border-radius: 100vh;
}
"""
# List of (phrase, replacement) pairs.
replacements = [
("a healthcare provider", "me"),
("a healthcare professional", "me"),
("a doctor", "me")
# Add more pairs as needed.
]
# Calculate the maximum length of any phrase.
max_phrase_length = max(len(phrase) for phrase, _ in replacements)
MIN_FLUSH_SIZE = max(50, max_phrase_length * 2)
print(MIN_FLUSH_SIZE)
def apply_replacements(text):
"""
Replace all specified phrases in the text.
"""
print(text)
for phrase, replacement in replacements:
text = text.replace(phrase, replacement)
return text
def chat_with_openai(message: str, history: list, temperature: float, max_new_tokens: int):
"""
Call the OpenAI ChatCompletion endpoint using the new client and yield streaming responses.
Implements <think> logic:
- The assistant is forced to begin its answer with "<think> ".
- We then wait until a closing "</think>" marker is received.
- Only text after "</think>" is displayed as the final answer.
Args:
message (str): The latest user message.
history (list): Conversation history as a list of (user, assistant) tuples.
temperature (float): Sampling temperature.
max_new_tokens (int): Maximum tokens to generate.
Yields:
str: Partial cumulative output from the assistant.
"""
conversation = []
if not history:
# Add a system prompt and initial assistant confirmation.
conversation.append({"role": "system", "content": SYSTEM_PROMPT})
conversation.append({"role": "assistant", "content": "Understood!"})
for user_msg, assistant_msg in history:
conversation.append({"role": "user", "content": user_msg})
conversation.append({"role": "assistant", "content": assistant_msg})
conversation.append({"role": "user", "content": message})
# Force the model to begin its answer with a "<think>" block.
conversation.append({"role": "assistant", "content": "<think> "})
# Immediately yield a "thinking" status message.
yield "HealthAssistant is Thinking! Please wait, your response will output shortly...\n\n"
# Call the API with streaming enabled.
response = client.chat.completions.create(
model="model-identifier", # Replace with your actual model identifier.
messages=conversation,
temperature=temperature,
max_tokens=max_new_tokens,
stream=True,
)
# Initialize buffers and state flags.
buffer = "" # Accumulates tokens until the </think> marker is found.
pending_buffer = "" # Holds the tail end of text that may contain a partial phrase.
display_text = "" # Cumulative text that has been finalized and yielded.
think_detected = False
full_response = "" # Accumulates the full raw response (without replacements applied).
# Process streaming responses.
for chunk in response:
# Extract the new token text from the current chunk.
delta = chunk.choices[0].delta
token_text = delta.content or ""
full_response += token_text
if not think_detected:
# Accumulate tokens until we see the closing </think> marker.
buffer += token_text
if "</think>" in buffer:
think_detected = True
# Discard everything up to and including the "</think>" marker.
after_think = buffer.split("</think>", 1)[1]
pending_buffer += after_think
# Only flush if we have at least MIN_FLUSH_SIZE characters.
if len(pending_buffer) >= MIN_FLUSH_SIZE:
# Flush all but the last max_phrase_length characters.
safe_portion = pending_buffer[:-max_phrase_length] if len(pending_buffer) > max_phrase_length else ""
if safe_portion:
display_text += apply_replacements(safe_portion)
yield display_text
pending_buffer = pending_buffer[-max_phrase_length:]
else:
# After the </think> marker, add tokens to pending_buffer.
pending_buffer += token_text
if len(pending_buffer) >= MIN_FLUSH_SIZE:
safe_portion = pending_buffer[:-max_phrase_length] if len(pending_buffer) > max_phrase_length else ""
if safe_portion:
display_text += apply_replacements(safe_portion)
yield display_text
pending_buffer = pending_buffer[-max_phrase_length:]
# After processing all tokens, flush any remaining text.
if pending_buffer:
safe_portion = pending_buffer # flush whatever remains
display_text += apply_replacements(safe_portion)
yield display_text
# Append the full (raw) response, including the <think> section, to the conversation history.
# If you want the history to reflect the replacements, apply them here.
modified_full_response = apply_replacements(full_response)
history.append((message, modified_full_response))
# Create the Chatbot component.
chatbot = gr.Chatbot(height=450, placeholder=PLACEHOLDER, label='HealthAssistant')
# Build the Gradio interface.
with gr.Blocks(css=css) as demo:
gr.HTML(DESCRIPTION)
gr.ChatInterface(
fn=chat_with_openai,
chatbot=chatbot,
fill_height=True,
additional_inputs_accordion=gr.Accordion(label="⚙️ Parameters", open=False, render=False, visible=False),
additional_inputs=[
gr.Slider(minimum=0.6, maximum=0.6, step=0.1, value=0.6, label="Temperature", render=False, visible=False),
gr.Slider(minimum=1024, maximum=4096, step=128, value=2048, label="Max new tokens", render=False, visible=False),
],
examples=[
['What is PrEP, and how do I know if I need it?'],
['What medications help manage being undetectable with HIV?'],
['How do I know if an abortion is the right option?'],
['How can I access birth-control in states where it is regulated?'],
],
cache_examples=False,
)
gr.Markdown(LICENSE)
if __name__ == "__main__":
demo.launch()