CoolFace
Apppublic

UZMAilyas/CSReview

sourceHugging Facemitupdated 17d agoView on Hugging Face
1likes
app.py1430 linesDownload Raw Back to root
1#from langchain_ollama import ChatOllama   #IMPORT2from dotenv import load_dotenv3from langchain_core.tools import tool4import math5from datetime import datetime, timedelta6from langchain_core.tools import tool7import matplotlib.pyplot as plt8from langchain.agents import create_agent   #IMPORT9from langchain_core.tools import tool10from datetime import datetime11from typing import Dict, Union12from langchain_google_genai import ChatGoogleGenerativeAI  #IMPORT13import math   14import random15import os16import gradio as gr17 18from datetime import datetime, timedelta19 20def parse_date(date_text):21    for fmt in ("%d-%m-%Y", "%d/%m/%Y", "%Y-%m-%d"):22        try:23            return datetime.strptime(date_text.strip(), fmt)24        except ValueError:25            continue26 27    raise ValueError(28        f"Invalid date '{date_text}'. Use DD-MM-YYYY."29    )30#load 31load_dotenv()32 33#*******MODAL PROVIDE*************************34 35#api_key = os.getenv("GEMINI_API_KEY")36#llm = ChatGoogleGenerativeAI(model= "gemini-flash-lite-latest" , api_key=api_key) #model="gemini-2.5-flash",api_key=api_key)37#CORRECT_PASSWORD =os.getenv("passCS")38api_key = os.getenv("GEMINI_API_KEY")39 40MODEL_PROVIDER = os.getenv("MODEL_PROVIDER", "gemini").lower().strip()41 42#OLLAMA_MODEL = os.getenv("OLLAMA_MODEL", "deepseek-r1:1.5b")43 44CORRECT_PASSWORD = os.getenv("passCS")45 46# ==========================================================47# MEDPHY-NEXUS DUAL LLM CONFIGURATION48# ==========================================================49 50# Gemini Cloud LLM51gemini_llm = ChatGoogleGenerativeAI(52    model="gemini-flash-lite-latest",53    api_key=api_key54)55 56# Local Ollama LLM57#ollama_llm = ChatOllama(58#    model=OLLAMA_MODEL,59#    temperature=060#)61 62# Select active LLM63if MODEL_PROVIDER == "ollama":64    llm = ollama_llm65    print(f"πŸ–₯️ MEDPHY-NEXUS running with LOCAL OLLAMA: {OLLAMA_MODEL}")66else:67    llm = gemini_llm68    print("☁️ MEDPHY-NEXUS running with GEMINI")69 70# Dictionary of dose limits (units in mSv)71OCCUPATIONAL_LIMITS = {72        "Annual dose limit to Workers": 50,  # mSv per year73        "Annual Exposure Limit to Workers (5-year avg)": 20,  # mSv per year74        "Monthly dose Limit to Worker": 4.16,  # mSv per month (approx.)75        "Lens of Eye Dose Limit to Worker": 50,  # mSv per year76        "Extremity Dose Limit to Worker": 500,  # mSv per year77        "Annual Dose Limit to Public": 1,  # mSv per year78        "Lens of Eye Dose Limit to Public": 15,  # mSv per year79        "Extremity Dose Limit to Public": 50,  # mSv per year80        "Annual Dose Limit to Caregivers": 5,  # mSv per year81        "Annual Dose Limit to Comforter": 5,  # mSv per year82        "PNRA release limit(dose)": 50,  # USv 83        "PNRA release limit(activity)": 30,  # mci 84 85        "Discharge TEDE Threshold":0.5, #rem86        "Occupancy factor (6/24)":0.25, #if patient expose 6hr public a day87        "Occupancy factor (3/24)":0.125, #if public expose 3hr a day from patient88 89    }90# βœ… Dictionary of Radioactive Nuclide & Their Half-Lives (in Days)91from datetime import datetime92import math93RADIOACTIVE_NUCLIDES = {94    "Uranium-238": 4.47e9 * 365,  # Billion years converted to days95    "Uranium-235": 704e6 * 365,   # Million years converted to days96    "Thorium-232": 14.05e9 * 365,97    "Plutonium-239": 24100,98    "Plutonium-238": 87.7,99    "Radon-222": 3.8,100    "Radium-226": 1600,101    "Polonium-210": 138,102    "Americium-241": 432,103    "Carbon-14": 5730,104    "Strontium-90": 28.8 * 365,105    "Iodine-131 (I-131)": 8.02,106    "I-131": 8.02,107    "Iodine-125(I-125)": 59.4,108    "I-125": 59.4,109    "Cesium-137": 30.2 * 365,110     "Cs-137": 30.2 * 365,111    "Technetium-99m": 0.25,  # 6 hours converted to days112    "Tc-99m": 0.25,  # 6 hours converted to days113    "Cobalt-60": 5.27 * 365,114    "Co-60": 5.27 * 365,115    "Cobalt-57": 271.8,116    "Co-57": 271.8,117    "Tritium (H-3)": 12.32 * 365,118    "Krypton-85": 10.76 * 365,119    "Ruthenium-106": 373.6,120    "Molybdenum (MO-99)": 66/24,121    "Cesium Cs-137": 10950,  # ~30 years122    "Cobalt Co-60": 1925,    # ~5.3 years123    "Cobalt Co-57": 271.8,   # ~9 months124    "Barium Ba-133": 3843,   # ~10.5 years125}126# Half-life values (in days)127HALF_LIFE = {128    "Cs-137": 10950,  # ~30 years129    "Co-60": 1925,    # ~5.3 years130    "Co-57": 271.8,   # ~9 months131    "Ba-133": 3843,   # ~10.5 years132}133 134# Source purchase dates (YYYY-MM-DD)135SOURCE_PURCHASE = {136    "Cs-137": "2019-09-20",137    "Co-60": "2019-09-20",138    "Co-57": "2022-04-21",139    "Ba-133": "2019-09-20",140}141 142# Initial activities (in MBq) at the time of purchase (Example Values)143INITIAL_ACTIVITY = {144    "Cs-137": 370,   # Example values, replace with actual145    "Co-60": 1000,146    "Co-57": 740,147    "Ba-133": 500,148}149 150 151#   Tool 1: Unit Conversion152@tool153def unit_conversion_tool(value, from_unit, to_unit):154    """155    Converts radiation measurement units.156    """157    value = float(value)158    conversion_factors = {159        "Gy_to_rad": 100, "rad_to_Gy": 0.01,160        "Sv_to_rem": 100, "rem_to_Sv": 0.01,161        "Bq_to_Ci": 2.7e-11, "Ci_to_Bq": 3.7e10,162        "C/kg_to_R": 2.58e-4, "R_to_C/kg": 0.387e4,163    }164    key = f"{from_unit}_to_{to_unit}"165    if key in conversion_factors:166        result = value * conversion_factors[key]167        return f"**Conversion:** {value} {from_unit} β†’ {to_unit}\n**Result:** {result:.4f} {to_unit}"168    else:169        return "⚠️ Invalid conversion request."170 171#  Tool 2: Radioactive Decay Calculation172@tool173# Function to Calculate Radioactive Decay174def radioactive_decay_tool(nuclide, initial_activity, elapsed_days):175    """176    Computes remaining radioactive activity based on the nuclide, initial activity, and elapsed time.177    Generates a Medical Physics (MP) report in Google Doc style.178    Args:179        nuclide (str): Name of the radioactive nuclide.180        initial_activity (float): Initial activity in Bq or Ci or mCi.181        elapsed_days (float): Time elapsed in days .182    Returns:183        str: A formatted Google Doc-style report with computed decay results.184    """185    try:186        initial_activity = float(initial_activity)187        elapsed_days = float(elapsed_days)188    except (TypeError, ValueError):189        return "⚠️ Invalid decay input. Activity and elapsed time must be numeric."190 191    if initial_activity <= 0 or elapsed_days < 0:192        return "⚠️ Initial activity must be positive and elapsed time cannot be negative."193 194    initial_activity = float(initial_activity)  195    elapsed_days = int(elapsed_days)  196 197    # Now comparisons will work correctly198    if initial_activity <= 0 or elapsed_days < 0:199        return "Error: Initial activity must be positive, and elapsed days cannot be negative."200    # Retrieve half-life from the dictionary201    half_life = RADIOACTIVE_NUCLIDES.get(nuclide, None)202    H_L=HALF_LIFE.get(nuclide,None)203 204    #if half_life is None:205    if H_L is None:206        return f"⚠️ Error: Nuclide '{nuclide}' not found in database. Please check spelling or add it."207 208    # Compute decay constant209    #decay_constant = math.log(2) / half_life210    decay_constant = math.log(2) / H_L211 212 213    # Compute remaining activity214    remaining_activity = initial_activity * math.exp(-decay_constant * elapsed_days)215 216    # Generate Google Doc-style Report217    current_date = datetime.now().strftime("%Y-%m-%d")218 219    report = f"""220# πŸ“Š **Medical Physics Report**221### πŸ“… Date: {current_date}222---223## **πŸ”Ή Radioactive Decay Calculation**224πŸ”¬ **Radionuclide:** {nuclide}  225πŸ“ˆ **Initial Activity:** {initial_activity} Bq  or Ci or mCi226⏳  227   **HalfLife:**{H_L}228πŸ•°οΈ **Elapsed Time:** {elapsed_days} days  229βš›οΈ **Remaining Activity:** {remaining_activity:.4f} Bq or Ci or mCi230---231πŸ”š **End of Report**232"""233    #**Half-life:** {half_life:.2f} days234#return report235 #  Tool 3: print list of exposure limits236@tool237def print_exposure_limits(query: str = "all") -> str:238    """239    Returns a SNIF Google Doc–style report of exposure/dose limits for workers, public, or caregivers.240    Args:241        query (str): A string indicating which limits to display. Acceptable values:"workers", "public", "caregivers","comforter" or "all" (default prints all limits).242    Returns:243        str: A formatted report with the requested dose limits.244    """245    query_lower = query.lower().strip()246    247    # Filter keys based on the query248    if query_lower == "workers":249        # Include keys related to workers (e.g., any key with "worker")250        keys = [k for k in OCCUPATIONAL_LIMITS if "worker" in k.lower()]251    elif query_lower == "public":252        keys = [k for k in OCCUPATIONAL_LIMITS if "public" in k.lower()]253    elif query_lower == "caregivers":254        keys = [k for k in OCCUPATIONAL_LIMITS if "caregiver" in k.lower()]255    elif query_lower == "comforter":256        keys = [k for k in OCCUPATIONAL_LIMITS if "comforter" in k.lower()]257    else:258        # If query is "all" or unrecognized, print all limits.259        keys = list(OCCUPATIONAL_LIMITS.keys())260    261    # Generate a SNIF Google Doc-style report262    current_date = datetime.now().strftime("%Y-%m-%d")263    report = f"""264#  **Exposure/Dose Limits Report**265### πŸ“… Date: {current_date}266---267"""268    for key in keys:269        report += f"\n- **{key}**: {OCCUPATIONAL_LIMITS[key]} mSv\n"270    271    report += "\n---\nπŸ”š **End of Report**"272    return report273# Tool 4:patient release criteria274@tool275 276def patient_release_decision(neck_dose_microSv_hr: float, exposure_duration_hr: float, initial_activity_mCi: float, sef: str) -> str:277    """278    Evaluates whether a patient treated with I-131 can be released based on their neck dose,279    remaining activity, and Socio-Economic Factor (SEF). Generates a structured SNIF Google Doc-style report.280    281    Args:282        neck_dose_microSv_hr (float): Measured neck dose in ΞΌSv/hr.283        exposure_duration_hr (float): Elapsed time in hours since administration.284        initial_activity_mCi (float): Administered activity in mCi.285        sef (str): Socio-Economic Factor, which should be either "good" or "bad".286        287    Returns:288        str: A formatted SNIF Google Doc-style report with the calculated TEDE and release recommendation.289    """290    # Validate input291    if neck_dose_microSv_hr < 0 or exposure_duration_hr < 0 or initial_activity_mCi <= 0:292        return "⚠️ Invalid input! Neck dose, exposure duration, and initial activity must be positive numbers."293    294    sef = sef.lower().strip()295    if sef not in ["good", "bad"]:296        return "⚠️ Invalid SEF! Please provide 'GOOD' or 'BAD' for the socio-economic factor."297    298    # Retrieve Constants299    occupancy_factor = OCCUPATIONAL_LIMITS.get("Occupancy factor (6/24)", 0.25)300    discharge_threshold = OCCUPATIONAL_LIMITS.get("Discharge TEDE Threshold", 0.5)301    pnra_limit = OCCUPATIONAL_LIMITS.get("PNRA release limit(dose)", 50)  # Default 50 Β΅Sv302    pnra_limit1= OCCUPATIONAL_LIMITS.get("PNRA release limit(activity)", 30)#default 30 mci303    half_life_days = RADIOACTIVE_NUCLIDES.get("I-131", 8.02)  # Half-life in days304 305    # Convert exposure duration to days306    exposure_duration_days = exposure_duration_hr / 24307 308    # Calculate Decay Constant (Ξ») in per day309    decay_constant = math.log(2) / half_life_days  # Ξ» = ln(2) / T_half310 311    # Compute Remaining Activity After Decay312    remaining_activity_mCi = initial_activity_mCi * math.exp(-decay_constant * exposure_duration_days)313 314    # Compute TEDE (Dose-Based) from Measured Neck Dose315    tede_dose_rem = (neck_dose_microSv_hr * 1.44 * 24 * half_life_days * occupancy_factor) / 1000 * 0.1  # Convert to rem316 317    # Compute TEDE (Activity-Based) from Remaining I-131 Activity318    tede_activity_rem = (remaining_activity_mCi * 1.44 * 24 * 2.2 * half_life_days * occupancy_factor) / 1000 * 0.1  # Convert to rem319 320    # Debugging Print Statements321    print(f"Remaining Activity (mCi): {remaining_activity_mCi:.3f}")322    print(f"TEDE from Dose Measurement (rem): {tede_dose_rem:.3f}")323    print(f"TEDE from Activity Calculation (rem): {tede_activity_rem:.3f}")324    print(f"PNRA release Limit: on Measured Dose{pnra_limit} Β΅Sv")325    print(f"PNRA release Limit: on Residual Activity{pnra_limit1} mCi") 326 327    # **Decision-Making Based on NRC Guidelines**328    if tede_dose_rem < discharge_threshold and tede_activity_rem < discharge_threshold:329        recommendation = "βœ… Immediate release recommended."330    elif tede_dose_rem < discharge_threshold and tede_activity_rem > discharge_threshold:331        if sef == "good":332            recommendation = "⚠️ Discharge allowed with strict home isolation guidelines."333        else:334            recommendation = "❌ Hospital stay recommended until TEDE (activity) < 0.5 rem."335    else:336        recommendation = "❌ Patient should remain hospitalized until both TEDE values are below 0.5 rem."337 338    # Generate SNIF Google Doc-style Report339    current_date = datetime.now().strftime("%Y-%m-%d")340    report = f"""341# πŸ“Š **Medical Physics Patient Release Report**342### πŸ“… Date: {current_date}343---344## **πŸ”Ή Patient Exposure Assessment**345- **Neck Dose Rate:** {neck_dose_microSv_hr:.2f} ΞΌSv/hr  346- **Total Effective Dose Equivalent (TEDE from Measured Dose):** {tede_dose_rem:.3f} rem347- **Total Effective Dose Equivalent (TEDE from Activity Calculation):** {tede_activity_rem:.3f} rem348- **PNRA Release Limit:** on Measured dose {pnra_limit} Β΅Sv and on Residual Activity {pnra_limit1}mCi349- **Remaining Activity After {exposure_duration_days:.2f} Days:** {remaining_activity_mCi:.3f} mCi350## **πŸ”Έ Definitions**351- **TEDE (Activity-Based):** Estimated radiation exposure based on the remaining I-131 activity in the body which contribute to exposure to public.352- **TEDE (Dose-Based):** Radiation exposure measured from the patient's emitted dose using a survey meter.353## **πŸ”Ή Discharge Recommendation**354- **Threshold for Release:** {discharge_threshold} rem355- **Occupancy Factor:** {occupancy_factor}356- **Half-Life (I-131):** {half_life_days} days357- **Decision:** {recommendation}358---359πŸ”š **End of Report**360"""361    return report362 363# βœ… Example Function Call364#print(patient_release_decision(12.5, 48, 30, "good"))  # Example with 30 mCi initial dose, 48 hours exposure365 366# Tool-5:AI Agent to Call Tools367@tool368def medical_physics_agent(query):369    """370    An AI agent that takes user queries and calls the appropriate MP tool.371    """372    current_date = datetime.now().strftime("%Y-%m-%d")373    374    # Identify Query Type375    if "convert" in query:376        value = float(query.split()[1])  # Extract first number377        from_unit, to_unit = query.split()[2], query.split()[4]  # Extract units378        result = unit_conversion_tool(value, from_unit, to_unit)379        title = "Unit Conversion"380    381    elif "decay" in query:382        values = [float(i) for i in query.split() if i.replace('.', '', 1).isdigit()]383        if len(values) == 3:384            result = radioactive_decay_tool(values[0], values[1], values[2])385            title = "Radioactive Decay Calculation"386        else:387            return "⚠️ Invalid input format for decay calculation."388    389    elif "dose" in query:390        dose = float(query.split()[1])391        result = radiation_protection_advice(dose)392        title = "Occupational Dose Assessment"393    elif "predicted yield" in query:394        activity = float(query.split()[1])395        result = predict_tc99m_yield(datetime,activity)396        title = "Predicted Yield of Tc-99m"    397        398    elif "nm_test_protocol" in query:399        nm_test = float(query.split()[1])400        result = nm_test_protocol(nmTest,weight,height)401        title = "nm_test_protocol"   402    elif "QC Tests DOSE CALIBRATOR" in query:403        # Example Usage404 405        QC_test = float(query.split()[1])406        result = get_qc_test_details (QC_test)407        title = "QC_test_protocol"     408    elif "QC Tests GAMMA CAMERA" in query:409        # Example Usage410 411        QC_test = float(query.split()[1])412        result = get_gammaqc_test_details (QC_test)413        title = "QC_test_protocol"     414    else:415        return "⚠️ Sorry, I didn't understand your request."416    # Format Response in Google Doc SNIF Style417    report = f"""418# **πŸ“Š Medical Physics (MP) Report**419### **πŸ“… Date:** {current_date}420---421## **{title}**422{result}423---424**End of Report**425"""426    return report427 428    429#Tool-6 RP-Advice430@tool431def radiation_protection_advice(daily_exposure_microSv: Union[float, int, str]) -> str:432    """433    Provides radiation protection advice based on daily occupational434    radiation exposure in microSv.435    """436 437    try:438        # Convert LLM-provided string/number to float439        daily_exposure_microSv = float(daily_exposure_microSv)440 441    except (ValueError, TypeError):442        return (443            "❌ Invalid exposure value. "444            "Please provide the daily exposure as a numeric value in Β΅Sv."445        )446 447    # Convert Β΅Sv to mSv448    daily_exposure_mSv = daily_exposure_microSv / 1000449 450    # Annualized estimate451    annual_exposure_mSv = daily_exposure_mSv * 365452 453    # Radiation protection assessment454    if daily_exposure_mSv < 0.08:455        assessment = "LOW"456        advice = (457            "Daily exposure is relatively low. Continue routine radiation "458            "protection practices, ALARA principles and personnel monitoring."459        )460 461    elif daily_exposure_mSv < 0.17:462        assessment = "MODERATE"463        advice = (464            "Exposure is moderate. Review work practices, distance, shielding "465            "and time spent near radiation sources. Continue dosimetry monitoring."466        )467 468    else:469        assessment = "HIGH"470        advice = (471            "Exposure is relatively high. Review the radiation work practice "472            "immediately, investigate the source of exposure and consult the "473            "Radiation Protection Officer/Medical Physicist."474        )475 476    return f"""477### ☒️ Radiation Protection Assessment478 479**Daily Exposure:** {daily_exposure_microSv:.2f} Β΅Sv  480**Daily Exposure:** {daily_exposure_mSv:.4f} mSv  481**Estimated Annual Exposure:** {annual_exposure_mSv:.2f} mSv  482 483**Assessment:** **{assessment}**484 485**Advice:**  486{advice}487 488**Important:** This is a screening assessment. Personnel dose records,489dosimeter results, work patterns and applicable PNRA/institutional490requirements should be reviewed for formal radiation-protection decisions.491"""492# Tool7-Predicted Yield Tc-99m493@tool494def predict_tc99m_yield(arrival_date: str, initial_activity: float) -> str:495    """496    Predicts the daily yield of a Tc-99m generator for the next 7 days.497    Parameters:498    arrival_date (str): Date when the generator arrives (format: "DD-MM-YYYY").499    initial_activity (float): Initial activity of Mo-99 in mCi.500    Returns:501    dict: Dictionary with dates as keys and predicted yields as values.502    """503    received_date = parse_date(arrival_date)504    try:505        initial_activity = float(initial_activity)506    except (TypeError, ValueError):507        return "❌ Generator activity must be a numeric value in mCi."508    # Constants509    #half_life_Mo99 = 66  # Mo-99 half-life in hours510    half_life_Mo99=RADIOACTIVE_NUCLIDES["Molybdenum (MO-99)"]*24511    #print(f"half life ofMo-99{half_life_Mo99}")512    decay_constant = math.log(2) / half_life_Mo99  # Decay constant513    extraction_efficiency = 0.87  # Typical Tc-99m extraction efficiency514    515    # Convert string date to datetime object516    arrival_datetime = datetime.strptime(arrival_date, "%d-%m-%Y")517    518    # Predict yield for the next 7 days519    predicted_yields = {}520    521    for day in range(1, 8):  # Next 7 days522        current_date = arrival_datetime + timedelta(days=day)523        time_elapsed = day * 24  # Convert days to hours524        remaining_activity = initial_activity * math.exp(-decay_constant * time_elapsed)525        tc99m_yield = remaining_activity * extraction_efficiency  # Apply efficiency526        predicted_yields[current_date.strftime("%d-%m-%Y")] = round(tc99m_yield, 2)527    528    return predicted_yields529###TOOL8NM-SCAN PROTOCOL as per SNMMI530@tool531def nm_test_protocol(test_name, weight=None, height=None, age=None):532    """533    Function to return the nuclear medicine test protocol based on user query.534    535    Parameters:536    - test_name (str): Name of the NM test537    - weight (float): Patient weight in kg (for pediatric cases)538    - height (float): Patient height in cm (optional, not used for dosing)539    - age (int): Patient age in years (to determine adult vs pediatric dose)540    541    Returns:542    - A formatted string with test details.543    """544 545    # Database of NM test protocols546    nm_tests = {547        "bone scan": {548            "radiopharmaceutical": "99mTc-MDP/HDP",549            "dose_adult": "10–25 mCi (370–925 MBq)",550            "dose_pediatric": lambda w: f"{round(min(0.3 * w, 25), 2)} mCi ({round(min(11.1 * w, 925), 2)} MBq)",551            "imaging_time": "2–4 hrs",552            "preparation": "Hydrate well",553            "max_ped_dose": "25 mCi"554        },555        "mag3 renal scan": {556            "radiopharmaceutical": "99mTc-MAG3",557            "dose_adult": "3–10 mCi (111–370 MBq)",558            "dose_pediatric": lambda w: f"{round(min(0.1 * w, 10), 2)} mCi ({round(min(3.7 * w, 370), 2)} MBq)",559            "imaging_time": "Immediate",560            "preparation": "Hydrate well",561            "max_ped_dose": "10 mCi"562        },563        "dtpa renal scan": {564            "radiopharmaceutical": "99mTc-DTPA",565            "dose_adult": "3–10 mCi (111–370 MBq)",566            "dose_pediatric": lambda w: f"{round(min(0.2 * w, 10), 2)} mCi ({round(min(7.4 * w, 370), 2)} MBq)",567            "imaging_time": "Immediate",568            "preparation": "Hydrate well",569            "max_ped_dose": "10 mCi"570        },571        "dmsa renal scan": {572            "radiopharmaceutical": "99mTc-DMSA",573            "dose_adult": "1–5 mCi (37–185 MBq)",574            "dose_pediatric": lambda w: f"{round(min(0.3 * w, 5), 2)} mCi ({round(min(11.1 * w, 185), 2)} MBq)",575            "imaging_time": "2–4 hrs",576            "preparation": "None",577            "max_ped_dose": "5 mCi"578        },579        "hida scan": {580            "radiopharmaceutical": "99mTc-DISIDA/MeBrofenin",581            "dose_adult": "3–8 mCi (111–296 MBq)",582            "dose_pediatric": lambda w: f"{round(min(0.1 * w, 8), 2)} mCi ({round(min(3.7 * w, 296), 2)} MBq)",583            "imaging_time": "Immediate",584            "preparation": "NPO 4–6 hrs",585            "max_ped_dose": "8 mCi"586        },587        "cardiac MIBI scan": {588            "radiopharmaceutical": "99mTc-MIBI/Tetrofosmin",589            "dose_adult": "8–36 mCi (296–1332 MBq)",590            "dose_pediatric": lambda w: f"{round(min(0.3 * w, 36), 2)} mCi ({round(min(11.1 * w, 1332), 2)} MBq)",591            "imaging_time": "15–60 min",592            "preparation": "NPO 4–6 hrs, Avoid caffeine",593            "max_ped_dose": "36 mCi"594        }595    }596 597    # Normalize the test name to lowercase for matching598    test_name = test_name.lower()599 600    # Check if the test exists601    if test_name not in nm_tests:602        return "❌ Test not found. Please enter a valid NM test name."603 604    # Get test details605    test_details = nm_tests[test_name]606 607    # Determine dose based on age608    if age is None or age >= 18:609        dose_info = f"**Dose (Adult):** {test_details['dose_adult']}"610    elif weight is not None:611        dose_info = f"**Dose (Pediatric - Weight {weight} kg):** {test_details['dose_pediatric'](weight)} (Max: {test_details['max_ped_dose']})"612    else:613        dose_info = "**Pediatric dose requires weight input.**"614 615    # Format output616    result = f"""617    πŸ”¬**Nuclear Medicine Test Protocol at AEMCK: {test_name.title()}**  618    ______As per SNMMI619    - **Radiopharmaceutical:** {test_details['radiopharmaceutical']}620    {dose_info}621    - **Imaging Time:** {test_details['imaging_time']}622    - **Patient Preparation:** {test_details['preparation']}623    """624 625    return result.strip()626 627# Example Usage628#print(nm_test_protocol("Bone Scan", weight=15, age=5))629#print(nm_test_protocol("Cardiac MIBI Scan", age=25))630#print(nm_test_protocol("HIDA Scan", weight=30, age=10))631 632 633#Curent activity Tool9634@tool635def calculate_current_activity(source_name):636    """637    Calculates the current activity of a radioactive source based on the decay formula.638    Args:639        source_name (str): Name of the isotope (e.g., "Cs-137", "Co-60").640    Returns:641        float: Current activity in MBq.642    """643    if source_name not in HALF_LIFE or source_name not in SOURCE_PURCHASE:644        return "Unknown Source"645 646    # Get today's date and calculate decay647    today = datetime.today()648    purchase_date = datetime.strptime(SOURCE_PURCHASE[source_name], "%Y-%m-%d")649    days_elapsed = (today - purchase_date).days650    651    # Decay formula: A = A0 * (1/2)^(t/T)652    A0 = INITIAL_ACTIVITY[source_name]653    T = HALF_LIFE[source_name]654    A = A0 * math.pow(0.5, days_elapsed / T)655 656    return round(A, 2)  # Return current activity in MBq657 658 659#For QC-TESTTOOL#10660 661@tool662def get_qc_test_details(test_name: str) -> str:663    """664    Retrieves Dose Calibrator CRC-25R QC test details including665    frequency, acceptance criteria, instructions and good practices.666 667    The tool accepts flexible test names such as:668    Accuracy669    Accuracy QC670    Dose Calibrator Accuracy671    Constancy Test672    Zero Adjustment673    Background674    Contamination675    Linearity676    Geometry677    Chamber Voltage678    Data Check679    Introduction680    """681 682    # ---------------------------------------------------------683    # 1. Validate input684    # ---------------------------------------------------------685 686    if test_name is None:687        return "❌ Please specify the Dose Calibrator QC test."688 689    test_name = str(test_name).strip()690 691    if not test_name:692        return "❌ Please specify the Dose Calibrator QC test."693 694    # ---------------------------------------------------------695    # 2. Normalize test name696    # ---------------------------------------------------------697 698    normalized = (699        test_name700        .lower()701        .replace("-", " ")702        .replace("_", " ")703        .replace(",", " ")704        .replace(".", " ")705    )706 707    normalized = " ".join(normalized.split())708 709    # ---------------------------------------------------------710    # 3. Identify requested QC test711    # ---------------------------------------------------------712 713    if "introduction" in normalized:714        selected_test = "Introduction"715 716    elif "chamber voltage" in normalized or "voltage" in normalized:717        selected_test = "Chamber Voltage"718 719    elif "accuracy" in normalized:720        selected_test = "Accuracy"721 722    elif "constancy" in normalized:723        selected_test = "Constancy Test"724 725    elif "zero adjustment" in normalized or "zero" in normalized:726        selected_test = "Zero Adjustment"727 728    elif "background" in normalized:729        selected_test = "Background"730 731    elif "data check" in normalized or "data" in normalized:732        selected_test = "Data Check"733 734    elif "contamination" in normalized or "wipe" in normalized:735        selected_test = "Contamination"736 737    elif "linearity" in normalized:738        selected_test = "Linearity"739 740    elif "geometry" in normalized:741        selected_test = "Geometry"742 743    else:744        return f"""745### ❌ QC Test Not Found746 747I could not identify **"{test_name}"** as a Dose Calibrator CRC-25R748QC test.749 750### Available QC Tests751 752- Chamber Voltage753- Accuracy754- Constancy Test755- Zero Adjustment756- Background757- Data Check758- Contamination759- Linearity760- Geometry761- Introduction762 763Please specify one of the above tests.764"""765 766    # ---------------------------------------------------------767    # 4. QC DATABASE768    # ---------------------------------------------------------769 770    qc_tests = {771 772        "Introduction": {773            "title": "Dose Calibrator CRC-25R β€” QC Program",774            "description": [775                "AEMCK (Atomic Energy Medical Centre Karachi) has one CRC-25R Dose Calibrator.",776                "The centre also has three Gamma Cameras used for diagnostic and therapeutic Nuclear Medicine applications.",777                "Dose Calibrator QC should be performed according to the approved institutional QC program, applicable regulatory requirements and manufacturer's recommendations."778            ],779            "good_practices": [780                "Maintain documented QC schedules and records.",781                "Use appropriate calibrated and traceable reference sources.",782                "Perform QC under consistent environmental and operating conditions.",783                "Investigate abnormal trends rather than relying only on individual pass/fail results.",784                "Ensure corrective actions are documented.",785                "Keep QC records available for audit and regulatory inspection."786            ]787        },788 789        "Chamber Voltage": {790            "Frequency": "Daily",791            "Acceptance Value": "Β±1%",792            "Instructions": [793                "Turn on the dose calibrator and allow it to warm up according to the manufacturer's instructions.",794                "Check the chamber voltage reading on the display.",795                "Compare the observed value with the approved reference/nominal value.",796                "If the deviation exceeds the approved acceptance criterion, investigate the cause and take corrective action."797            ],798            "Good Practices": [799                "Ensure a stable power supply.",800                "Perform the measurement under consistent operating conditions.",801                "Record the result in the QC log.",802                "Investigate abnormal trends promptly."803            ]804        },805 806        "Accuracy": {807            "Frequency": "Quarterly",808            "Acceptance Value": "Β±5%",809            "Instructions": [810                "Use an appropriate certified or traceable reference source.",811                "Select the correct radionuclide setting on the dose calibrator.",812                "Allow the dose calibrator to stabilize before measurement.",813                "Place the reference source in the appropriate and reproducible position.",814                "Record the measured activity.",815                "Calculate the percentage deviation from the expected/reference activity.",816                "Compare the result with the approved acceptance criterion.",817                "If the result is outside the acceptance criterion, investigate the cause and perform corrective action according to the approved procedure."818            ],819            "Good Practices": [820                "Use calibrated and traceable reference sources.",821                "Use appropriate radionuclides covering the clinical measurement range where required.",822                "Record source identification, reference activity, calibration date and measurement date.",823                "Use consistent source positioning and geometry.",824                "Perform measurements under stable environmental conditions.",825                "Trend results over time to identify gradual deterioration.",826                "Do not rely only on a single measurement when investigating an abnormal result.",827                "Document all corrective actions and repeat measurements when required."828            ]829        },830 831        "Constancy Test": {832            "Frequency": "Daily",833            "Acceptance Value": "Β±5% of reference value",834            "Instructions": [835                "Use the designated reference source for constancy testing.",836                "Verify the source identification and reference activity.",837                "Place the source in a reproducible position in the dose calibrator.",838                "Measure the activity.",839                "Compare the result with the established reference value.",840                "Record the result and investigate deviations outside the approved acceptance criterion."841            ],842            "Good Practices": [843                "Perform the test under consistent environmental conditions.",844                "Use the same source, geometry and positioning whenever possible.",845                "Allow the dose calibrator to warm up before testing.",846                "Maintain a historical QC trend.",847                "Investigate unexpected changes for possible contamination, source positioning errors, electronic drift or equipment malfunction."848            ]849        },850 851        "Zero Adjustment": {852            "Frequency": "Daily",853            "Acceptance Value": "Β±0.3 mV",854            "Instructions": [855                "Ensure that no radioactive source is present in the measurement chamber.",856                "Check the zero indication according to the manufacturer's procedure.",857                "Perform zero adjustment only according to the approved equipment procedure."858            ],859            "Good Practices": [860                "Ensure no external radiation source is influencing the measurement.",861                "Perform the check before routine measurements.",862                "Keep the chamber clean and free from contamination.",863                "Document abnormal zero readings."864            ]865        },866 867        "Background": {868            "Frequency": "Daily",869            "Acceptance Value": "Β±20% of current mean (<530 ΞΌCi)",870            "Instructions": [871                "Ensure that no radioactive source is inside or immediately adjacent to the chamber.",872                "Measure the background according to the approved procedure.",873                "Compare the result with the established baseline/current mean.",874                "Investigate significant changes in background."875            ],876            "Good Practices": [877                "Check for radioactive contamination in and around the measurement chamber.",878                "Ensure no radioactive source is nearby during the measurement.",879                "Maintain a historical background trend.",880                "Investigate sudden increases before using the calibrator for patient doses."881            ]882        },883 884        "Data Check": {885            "Frequency": "Daily",886            "Acceptance Value": "Correct and consistent readings",887            "Instructions": [888                "Verify that the correct radionuclide setting is selected.",889                "Check displayed activity and measurement units.",890                "Compare readings with the expected/reference value where applicable.",891                "Verify correct date/time and QC documentation."892            ],893            "Good Practices": [894                "Verify radionuclide selection before every measurement.",895                "Check units carefully to avoid mCi/MBq/ΞΌCi conversion errors.",896                "Maintain accurate QC documentation.",897                "Report discrepancies immediately."898            ]899        },900 901        "Contamination": {902            "Frequency": "Weekly",903            "Acceptance Value": "<3 ΞΌCi (0.12 MBq)",904            "Instructions": [905                "Perform contamination monitoring using the approved wipe-test procedure.",906                "Check accessible surfaces of the dose calibrator and measurement area.",907                "Measure the wipe sample using the appropriate radiation detection system.",908                "Compare the result with the approved contamination limit.",909                "Decontaminate and investigate if contamination is detected above the approved criterion."910            ],911            "Good Practices": [912                "Perform routine wipe testing according to the institutional radiation-safety program.",913                "Keep the measurement chamber and surrounding area clean.",914                "Prevent radioactive material from entering the chamber.",915                "Document contamination results and corrective actions."916            ]917        },918 919        "Linearity": {920            "Frequency": "Quarterly",921            "Acceptance Value": "Within 5% of expected value",922            "Instructions": [923                "Use the approved linearity testing method.",924                "Measure a suitable range of activities.",925                "Record measured activity at each level/time point.",926                "Compare measured values with expected values.",927                "Evaluate the deviation across the measurement range.",928                "Investigate and correct unacceptable deviations."929            ],930            "Good Practices": [931                "Cover the clinically relevant activity range.",932                "Use appropriate decay-based or other approved linearity methodology.",933                "Maintain consistent source geometry.",934                "Record all measurements.",935                "Trend linearity results over time."936            ]937        },938 939        "Geometry": {940            "Frequency": "Acceptance Test / After Major Repair / Periodically as specified by the approved QC program",941            "Acceptance Value": "Within Β±5% of expected/reference value",942            "Instructions": [943                "Ensure that the dose calibrator is properly installed and warmed up.",944                "Select the appropriate radionuclide setting.",945                "Prepare samples with different volumes using the same activity concentration.",946                "Use representative syringes and/or vials applicable to clinical practice.",947                "Measure each sample using reproducible positioning.",948                "Compare readings across different volumes and geometries.",949                "Evaluate whether geometry-dependent variation is within the approved acceptance criterion.",950                "Apply correction factors only when authorized by the approved procedure."951            ],952            "Good Practices": [953                "Use a well-mixed radioactive solution.",954                "Maintain consistent sample positioning.",955                "Avoid air bubbles where they could affect geometry.",956                "Use clinically representative syringes and vials.",957                "Document the geometry configuration used.",958                "Retain results as a baseline for future comparison."959            ]960        }961    }962 963    # ---------------------------------------------------------964    # 5. Get selected test965    # ---------------------------------------------------------966 967    test = qc_tests[selected_test]968 969    # ---------------------------------------------------------970    # 6. Introduction971    # ---------------------------------------------------------972 973    if selected_test == "Introduction":974 975        response = f"""976# ☒️ Dose Calibrator CRC-25R β€” QC Program977 978### Facility979 980{chr(10).join("- " + item for item in test["description"])}981 982### Recommended Good Practices983 984{chr(10).join(f"{i+1}. {item}" for i, item in enumerate(test["good_practices"]))}985 986> **Note:** QC frequencies and acceptance criteria should be verified987> against the current manufacturer's specifications, applicable988> regulatory requirements and the approved institutional QC procedure.989"""990 991        return response992 993    # ---------------------------------------------------------994    # 7. Format normal QC test995    # ---------------------------------------------------------996 997    response = f"""998# ☒️ Dose Calibrator CRC-25R β€” {selected_test}999 1000### QC Parameters1001 1002**Frequency:** {test.get("Frequency", "Not specified")}1003 1004**Acceptance Value:** {test.get("Acceptance Value", "Not specified")}1005 1006### Instructions1007 1008"""1009 1010    for i, instruction in enumerate(test.get("Instructions", []), 1):1011        response += f"{i}. {instruction}\n"1012 1013    response += "\n### Good Practices\n\n"1014 1015    for i, practice in enumerate(test.get("Good Practices", []), 1):1016        response += f"{i}. {practice}\n"1017 1018    # ---------------------------------------------------------1019    # 8. Add source information only when Accuracy is requested1020    # ---------------------------------------------------------1021 1022    if selected_test == "Accuracy":1023 1024        response += """1025 1026### Reference Sources1027 1028The following reference sources may be used where available and1029appropriate to the approved QC procedure:1030 1031- Cs-1371032- Co-601033- Co-571034- Ba-1331035 1036**Important:** Reference-source activity should be decay-corrected to1037the measurement date using the source certificate/reference date.1038Source identity, reference activity, calibration date and traceability1039should be documented.1040 1041### QC Documentation1042 1043Record at minimum:1044 1045- Date and time1046- Operator1047- Dose calibrator identification1048- Radionuclide1049- Reference source identification1050- Reference activity1051- Measurement result1052- Percentage deviation1053- Acceptance criterion1054- Pass/Fail status1055- Corrective action, if required1056"""1057 1058    response += """1059 1060---1061 1062**Medical Physics Note:** Acceptance criteria and QC frequency should1063be confirmed against the current CRC-25R manufacturer's documentation,1064applicable regulatory requirements and the approved institutional1065Medical Physics/QC procedure before being used for formal compliance1066decisions.1067"""1068 1069    return response1070@tool1071def get_gammaqc_test_details(test_name):1072    """1073    Retrieves QC test details of Gamma Camera, including Peak positioning, Energy Resolution etc.1074    1075    Args:1076        test_name (str): The name of the QC test (e.g, "Peak Positioning", "Energy Resolution,").1077    Returns:1078        dict: A dictionary containing test details or an error message if the test is invalid.1079    Example Usage:1080        >>> get_qc_test_details("Peak positioning")1081    """1082    1083    qc_tests = {1084        "Introduction":["AEMCK (Atomic Energy Medical Centre Karachi) has three Gamma Cameras for Diagnosis and Therapies.",1085        "Daily QC includes Peak Position , Energy Resolution, Background Test, and Image Quality Test.",1086        "Monthly QC includes Centre of Rotation (COR) and Intrinsic Uniformity Test."],1087        1088        "Peak Position": {1089            "Frequency": "Daily",1090            "Acceptance Value": "Tc-99m: 140 Β± 3 keV, Co-57: 122 Β± 3 keV",1091            "Instructions": [1092                "Ensure proper calibration of the Gamma camera.",1093                "Place the Tc-99m or Co-57 source appropriately.",1094                "Verify that the peak position falls within the acceptable range."1095            ],1096            "Good Practices": [1097                "Always use a well-calibrated source for Gamma cam.",1098                "Check for any sudden peak shifts indicating detector issues."1099            ]1100        },1101        "Energy Resolution": {1102            "Frequency": "Daily",1103            "Acceptance Value": "Tc-99m: < 11.0%, Co-57: < 12.0%",1104            "Instructions": [1105                "Acquire a spectrum using the Gamma camera.",1106                "Calculate the full-width at half maximum (FWHM).",1107                "Ensure that the energy resolution falls within the acceptance criteria."1108            ],1109            "Good Practices": [1110                "Use a high-quality energy calibration source.",1111                "Avoid fluctuations in environmental conditions."1112            ]1113        },1114        "Intrinsic Uniformity": {1115            "Frequency": "Monthly",1116            "Acceptance Value": "CFOV Integral Uniformity < 5%",1117            "Instructions": [1118                "Perform an intrinsic uniformity scan using Tc-99m for Gamma Cam",1119                "Analyze the image uniformity using processing software.",1120                "Ensure that uniformity deviations remain within the threshold."1121            ],1122            "Good Practices": [1123                "Use a uniform flood source.",1124                "Regularly check for detector malfunctions."1125            ]1126        },1127        "Centre of Rotation (COR)": {1128            "Frequency": "Monthly",1129            "Instructions": [1130                "Use a point source of Tc-99m at the center of rotation for Gamma cam.",1131                "Acquire multiple views and analyze COR deviation.",1132                "Ensure that misalignment does not exceed acceptable limits."1133            ],1134            "Good Practices": [1135                "Perform COR analysis after maintenance or detector adjustments.",1136                "Verify consistency over multiple acquisitions."1137            ]1138        }               1139               1140    }1141    1142    #return qc_tests.get(test_name, {"Error": "Invalid QC Test Name"})1143    return qc_tests.get(test_name, {"Error": "Invalid test name. Please choose a valid QC test."})1144 1145# Example Usage1146#if __name__ == "__main__":1147#    test_name = input("Enter the QC test name: ")1148#    result = get_qc_test_details(test_name)1149# #   print(result)1150 1151 1152 1153def random_prompt():1154    return random.choice([1155        "Convert 1Gy into rem.",1156        "Tell me the half life of Iodine I-131.",1157        "A patient with 50mci administered on 27-2-2025 after 1 day he has neckdose 25USv with good SEF, can I release patient?.",1158        "List me all radiation dose limits for workers.",1159        "Tell me the radiation dose limits for General Public as per PNRA.",1160        "What is the  predicted yield for next seven days of 600mci of Tc-99m generator which received on 10-2-2025.",1161        "A cobalt-57 (Co-57) source of 10mCi,what will be the remaining activity after 100days?",1162        "If a worker got 2mSv daily in working hours, what will be the advice of RPO in ALARA context.",1163        "What is the dose protocol of HIDA scan for Pedriatic patient of 7kg weight and 3 years age.",1164        "Tell me the good practices of Accuracy Qc test of Dose Callibrator.",1165        "Geometry Qc test for Dose Callibrator instructions",1166 1167 1168        1169    ])1170tools=[get_gammaqc_test_details,get_qc_test_details,calculate_current_activity,nm_test_protocol,radiation_protection_advice,predict_tc99m_yield,print_exposure_limits,patient_release_decision,unit_conversion_tool,radioactive_decay_tool]1171 1172#agent=initialize_agent(tools,llm,agent=AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION)1173#************************************Change2***************************************1174agent = create_agent(1175    model=llm,1176    tools=tools,1177    system_prompt="""1178You are MEDPHY-NEXUS, an AI Medical Physics and Radiation Protection assistant.1179 1180You assist qualified Medical Physicists and Radiation Protection Officers1181with Medical Physics, Nuclear Medicine, radiation protection, radioactive1182materials, dosimetry, QC, radiation surveys and related calculations.1183 1184Use the available tools whenever a calculation, lookup or technical1185assessment requires them.1186 1187Do not invent regulatory limits or clinical values. Clearly identify1188assumptions and recommend verification against applicable PNRA regulations,1189institutional SOPs and approved protocols where appropriate.1190"""1191)1192 1193#response=agent.invoke({"input":" Neck dose of iodine treated patient is 20 microSv he is staying 24 hrs and his sef is BAD.  "})1194#print(f"\n{response}\n")1195# Define the function that handles user input1196#******************Change3********************************1197def process_input(user_input):1198    try:1199        response = agent.invoke({1200            "messages": [

Showing the first 1,200 of 1430 lines. Download the file for the rest.