Spaces:
Build error
Build error
| """ | |
| π§ Autism Spectrum Disorder Screening System | |
| Professional Explainable AI Web Application with SHAP | |
| """ | |
| import streamlit as st | |
| import pandas as pd | |
| import numpy as np | |
| import pickle | |
| import shap | |
| import matplotlib.pyplot as plt | |
| import seaborn as sns | |
| from sklearn.preprocessing import StandardScaler | |
| import warnings | |
| warnings.filterwarnings('ignore') | |
| # ============================================================================ | |
| # PAGE CONFIGURATION | |
| # ============================================================================ | |
| st.set_page_config( | |
| page_title="π§ Autism Spectrum Screening | AI-Powered", | |
| page_icon="π§ ", | |
| layout="wide", | |
| initial_sidebar_state="expanded" | |
| ) | |
| # ============================================================================ | |
| # PROFESSIONAL STYLING | |
| # ============================================================================ | |
| st.markdown(""" | |
| <style> | |
| /* Main theme colors */ | |
| :root { | |
| --primary: #6366f1; | |
| --secondary: #ec4899; | |
| --success: #10b981; | |
| --warning: #f59e0b; | |
| --danger: #ef4444; | |
| --info: #3b82f6; | |
| } | |
| /* Global styles */ | |
| body { | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| } | |
| /* Metric cards */ | |
| .metric-card { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| color: white; | |
| padding: 20px; | |
| border-radius: 12px; | |
| box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3); | |
| text-align: center; | |
| margin: 10px 0; | |
| } | |
| .metric-value { | |
| font-size: 2.5em; | |
| font-weight: bold; | |
| margin: 10px 0; | |
| } | |
| /* Risk boxes */ | |
| .risk-high { | |
| background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); | |
| } | |
| .risk-medium { | |
| background: linear-gradient(135deg, #fa709a 0%, #fee140 100%); | |
| } | |
| .risk-low { | |
| background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); | |
| } | |
| .risk-box { | |
| color: white; | |
| padding: 30px; | |
| border-radius: 15px; | |
| text-align: center; | |
| box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15); | |
| margin: 20px 0; | |
| } | |
| .risk-percentage { | |
| font-size: 3.5em; | |
| font-weight: 900; | |
| margin: 15px 0; | |
| text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); | |
| } | |
| .risk-label { | |
| font-size: 1.5em; | |
| font-weight: bold; | |
| margin-top: 10px; | |
| } | |
| /* Info boxes */ | |
| .info-box { | |
| background-color: #eff6ff; | |
| border-left: 4px solid #3b82f6; | |
| padding: 15px; | |
| border-radius: 8px; | |
| margin: 15px 0; | |
| color: #000 !important; | |
| } | |
| .success-box { | |
| background-color: #ecfdf5; | |
| border-left: 4px solid #10b981; | |
| padding: 15px; | |
| border-radius: 8px; | |
| margin: 15px 0; | |
| color: #000 !important; | |
| } | |
| .warning-box { | |
| background-color: #fffbeb; | |
| border-left: 4px solid #f59e0b; | |
| padding: 15px; | |
| border-radius: 8px; | |
| margin: 15px 0; | |
| color: #000 !important; | |
| } | |
| .danger-box { | |
| background-color: #fef2f2; | |
| border-left: 4px solid #ef4444; | |
| padding: 15px; | |
| border-radius: 8px; | |
| margin: 15px 0; | |
| color: #000 !important; | |
| } | |
| .demographic-label { | |
| color: white !important; | |
| font-weight: 600; | |
| } | |
| .question-label { | |
| color: white !important; | |
| font-weight: 500; | |
| } | |
| /* Section styling */ | |
| .section-header { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| color: white !important; | |
| padding: 20px; | |
| border-radius: 10px; | |
| margin: 20px 0 15px 0; | |
| font-size: 1.8em; | |
| font-weight: bold; | |
| } | |
| .section-subheader { | |
| color: white !important; | |
| font-size: 1.2em; | |
| font-weight: bold; | |
| margin: 15px 0 10px 0; | |
| } | |
| .section-instructions { | |
| background-color: rgba(102, 126, 234, 0.1); | |
| color: white !important; | |
| padding: 10px 15px; | |
| border-left: 4px solid #667eea; | |
| border-radius: 5px; | |
| margin-bottom: 15px; | |
| } | |
| /* Buttons */ | |
| .stButton > button { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| color: white; | |
| border: none; | |
| border-radius: 8px; | |
| padding: 12px 24px; | |
| font-size: 16px; | |
| font-weight: 600; | |
| width: 100%; | |
| transition: all 0.3s ease; | |
| box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3); | |
| } | |
| .stButton > button:hover { | |
| box-shadow: 0 8px 24px rgba(102, 126, 234, 0.5); | |
| transform: translateY(-2px); | |
| } | |
| /* Header styling */ | |
| h1 { | |
| color: #1f2937; | |
| text-align: center; | |
| margin-bottom: 30px; | |
| font-size: 2.5em; | |
| font-weight: 900; | |
| } | |
| h2 { | |
| color: #374151; | |
| border-bottom: 3px solid #667eea; | |
| padding-bottom: 10px; | |
| margin-top: 30px; | |
| } | |
| h3 { | |
| color: #4b5563; | |
| } | |
| /* Tabs styling */ | |
| .stTabs [data-baseweb="tab-list"] { | |
| gap: 10px; | |
| } | |
| .stTabs [data-baseweb="tab-list"] button { | |
| background-color: #f3f4f6; | |
| border-radius: 8px; | |
| padding: 10px 20px; | |
| } | |
| .stTabs [data-baseweb="tab-list"] button[aria-selected="true"] { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| color: white; | |
| } | |
| /* Form styling */ | |
| .stForm { | |
| background-color: #f9fafb; | |
| padding: 20px; | |
| border-radius: 12px; | |
| border: 1px solid #e5e7eb; | |
| } | |
| /* Sidebar */ | |
| .sidebar .sidebar-content { | |
| background-color: #f8f9fa; | |
| } | |
| /* Footer */ | |
| .footer { | |
| text-align: center; | |
| padding: 20px; | |
| border-top: 1px solid #e5e7eb; | |
| color: #6b7280; | |
| font-size: 0.9em; | |
| margin-top: 40px; | |
| } | |
| </style> | |
| """, unsafe_allow_html=True) | |
| # ============================================================================ | |
| # LOAD MODELS AND DATA | |
| # ============================================================================ | |
| def load_models(): | |
| try: | |
| with open('models/rf_model.pkl', 'rb') as f: | |
| model = pickle.load(f) | |
| with open('models/scaler.pkl', 'rb') as f: | |
| scaler = pickle.load(f) | |
| with open('models/le_dict.pkl', 'rb') as f: | |
| le_dict = pickle.load(f) | |
| with open('models/feature_names.pkl', 'rb') as f: | |
| feature_names = pickle.load(f) | |
| with open('models/shap_explainer.pkl', 'rb') as f: | |
| explainer = pickle.load(f) | |
| with open('models/shap_values.pkl', 'rb') as f: | |
| shap_values_data = pickle.load(f) | |
| return model, scaler, le_dict, feature_names, explainer, shap_values_data | |
| except Exception as e: | |
| st.error(f"β Error loading models: {str(e)}") | |
| return None, None, None, None, None, None | |
| model, scaler, le_dict, feature_names, explainer, shap_values_data = load_models() | |
| models_ready = model is not None | |
| # ============================================================================ | |
| # HEADER | |
| # ============================================================================ | |
| st.markdown(""" | |
| <div style="text-align: center; margin-bottom: 40px;"> | |
| <h1>π§ Autism Spectrum Disorder Screening</h1> | |
| <p style="font-size: 1.2em; color: #6b7280; margin-top: -20px;"> | |
| <strong>AI-Powered Screening with Explainable Intelligence</strong> | |
| </p> | |
| <hr style="margin: 20px 0;"> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| # ============================================================================ | |
| # SIDEBAR NAVIGATION | |
| # ============================================================================ | |
| with st.sidebar: | |
| st.markdown("### π― Navigation Menu") | |
| page = st.radio( | |
| "Select Option:", | |
| ["π Home", "π Screening", "π Analytics", "β FAQ", "π About"], | |
| label_visibility="collapsed" | |
| ) | |
| st.markdown("---") | |
| st.markdown(""" | |
| ### βΉοΈ Quick Info | |
| - **Status**: β Production Ready | |
| - **Model**: Random Forest | |
| - **Accuracy**: 92.5% | |
| - **Features**: 18 | |
| - **Training Data**: 704 records | |
| """) | |
| # ============================================================================ | |
| # HOME PAGE | |
| # ============================================================================ | |
| if page == "π Home": | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| st.markdown(""" | |
| ### π Welcome! | |
| This is a professional autism spectrum screening tool powered by | |
| **Artificial Intelligence** and **Explainable AI (SHAP)**. | |
| #### β¨ Key Features: | |
| - π€ **AI-Powered**: Trained on 704 patient records | |
| - π **Explainable**: SHAP values explain every prediction | |
| - π― **Accurate**: 92.5% model accuracy | |
| - π **Private**: No data stored | |
| - β‘ **Fast**: Instant results | |
| - π» **Professional**: Healthcare-grade interface | |
| """) | |
| with col2: | |
| # Display metrics | |
| col2a, col2b = st.columns(2) | |
| with col2a: | |
| st.markdown(""" | |
| <div class="metric-card"> | |
| <div>π Training Samples</div> | |
| <div class="metric-value">704</div> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| st.markdown(""" | |
| <div class="metric-card"> | |
| <div>π― Accuracy</div> | |
| <div class="metric-value">92.5%</div> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| with col2b: | |
| st.markdown(""" | |
| <div class="metric-card"> | |
| <div>π§ Features</div> | |
| <div class="metric-value">18</div> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| st.markdown(""" | |
| <div class="metric-card"> | |
| <div>β‘ Response</div> | |
| <div class="metric-value"><1s</div> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| st.markdown("---") | |
| # Workflow explanation | |
| st.markdown("### π How It Works") | |
| col1, col2, col3, col4 = st.columns(4) | |
| with col1: | |
| st.markdown(""" | |
| #### 1οΈβ£ Input | |
| Fill out the screening questionnaire with AQ-10 assessment and demographic info | |
| """) | |
| with col2: | |
| st.markdown(""" | |
| #### 2οΈβ£ Process | |
| AI model processes your responses and generates prediction | |
| """) | |
| with col3: | |
| st.markdown(""" | |
| #### 3οΈβ£ Analysis | |
| SHAP explainability shows which factors influenced the result | |
| """) | |
| with col4: | |
| st.markdown(""" | |
| #### 4οΈβ£ Report | |
| Get clear risk assessment with professional recommendations | |
| """) | |
| st.markdown("---") | |
| # Important disclaimers | |
| st.markdown(""" | |
| <div class="danger-box"> | |
| β οΈ <strong>IMPORTANT DISCLAIMER</strong><br> | |
| This tool is for SCREENING purposes ONLY and NOT for clinical diagnosis. | |
| Always consult with qualified healthcare professionals for: | |
| - Accurate diagnosis | |
| - Treatment decisions | |
| - Clinical recommendations | |
| </div> | |
| """, unsafe_allow_html=True) | |
| # ============================================================================ | |
| # SCREENING PAGE | |
| # ============================================================================ | |
| elif page == "π Screening": | |
| if not models_ready: | |
| st.error("β Models not loaded. Please check model files.") | |
| else: | |
| st.markdown("# π AUTISM SPECTRUM QUOTIENT SCREENING") | |
| st.markdown("## Complete Assessment & Demographics") | |
| st.markdown("---") | |
| st.markdown(''' | |
| <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| color: white; | |
| padding: 20px; | |
| border-radius: 10px; | |
| margin: 20px 0 15px 0; | |
| font-size: 1.8em; | |
| font-weight: bold; | |
| text-align: left;"> | |
| π§ AQ-10 ASSESSMENT QUESTIONS | |
| </div> | |
| ''', unsafe_allow_html=True) | |
| st.markdown(''' | |
| <div style="background-color: rgba(102, 126, 234, 0.1); | |
| color: white; | |
| padding: 10px 15px; | |
| border-left: 4px solid #667eea; | |
| border-radius: 5px; | |
| margin-bottom: 15px;"> | |
| <strong>Instructions:</strong> Rate each statement on a scale of 0 (Disagree) to 1 (Agree) | |
| </div> | |
| ''', unsafe_allow_html=True) | |
| st.markdown("") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| st.markdown('<div class="section-subheader">Questions 1-5</div>', unsafe_allow_html=True) | |
| st.markdown('<p class="question-label">1. Prefer focusing on details</p>', unsafe_allow_html=True) | |
| A1 = st.slider("1. Prefer focusing on details", 0, 1, 0, key="A1", label_visibility="collapsed") | |
| st.markdown('<p class="question-label">2. Must have sameness and routine</p>', unsafe_allow_html=True) | |
| A2 = st.slider("2. Must have sameness and routine", 0, 1, 0, key="A2", label_visibility="collapsed") | |
| st.markdown('<p class="question-label">3. Prefer reading systematically</p>', unsafe_allow_html=True) | |
| A3 = st.slider("3. Prefer reading systematically", 0, 1, 0, key="A3", label_visibility="collapsed") | |
| st.markdown('<p class="question-label">4. Feel anxious in social situations</p>', unsafe_allow_html=True) | |
| A4 = st.slider("4. Feel anxious in social situations", 0, 1, 0, key="A4", label_visibility="collapsed") | |
| st.markdown('<p class="question-label">5. Prefer one-to-one conversation</p>', unsafe_allow_html=True) | |
| A5 = st.slider("5. Prefer one-to-one conversation", 0, 1, 0, key="A5", label_visibility="collapsed") | |
| with col2: | |
| st.markdown('<div class="section-subheader">Questions 6-10</div>', unsafe_allow_html=True) | |
| st.markdown('<p class="question-label">6. Notice small environmental changes</p>', unsafe_allow_html=True) | |
| A6 = st.slider("6. Notice small environmental changes", 0, 1, 0, key="A6", label_visibility="collapsed") | |
| st.markdown('<p class="question-label">7. Trouble focusing while changing activities</p>', unsafe_allow_html=True) | |
| A7 = st.slider("7. Trouble focusing while changing activities", 0, 1, 0, key="A7", label_visibility="collapsed") | |
| st.markdown('<p class="question-label">8. Often daydream</p>', unsafe_allow_html=True) | |
| A8 = st.slider("8. Often daydream", 0, 1, 0, key="A8", label_visibility="collapsed") | |
| st.markdown('<p class="question-label">9. Focused on one topic at a time</p>', unsafe_allow_html=True) | |
| A9 = st.slider("9. Focused on one topic at a time", 0, 1, 0, key="A9", label_visibility="collapsed") | |
| st.markdown('<p class="question-label">10. Difficult having small talk</p>', unsafe_allow_html=True) | |
| A10 = st.slider("10. Difficult having small talk", 0, 1, 0, key="A10", label_visibility="collapsed") | |
| st.markdown("---") | |
| # ============= DEMOGRAPHIC INFORMATION SECTION ============= | |
| st.markdown(''' | |
| <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| color: white; | |
| padding: 20px; | |
| border-radius: 10px; | |
| margin: 20px 0 15px 0; | |
| font-size: 1.8em; | |
| font-weight: bold; | |
| text-align: left;"> | |
| π DEMOGRAPHIC INFORMATION | |
| </div> | |
| ''', unsafe_allow_html=True) | |
| st.markdown(''' | |
| <div style="background-color: rgba(102, 126, 234, 0.1); | |
| color: white; | |
| padding: 10px 15px; | |
| border-left: 4px solid #667eea; | |
| border-radius: 5px; | |
| margin-bottom: 15px;"> | |
| <strong>Instructions:</strong> Please provide the following details about yourself | |
| </div> | |
| ''', unsafe_allow_html=True) | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| st.markdown('<p class="demographic-label">Age</p>', unsafe_allow_html=True) | |
| age = st.number_input("Age", min_value=1, max_value=120, value=30, label_visibility="collapsed") | |
| st.markdown('<p class="demographic-label">Ethnicity</p>', unsafe_allow_html=True) | |
| ethnicity = st.selectbox("Ethnicity", [ | |
| "white European", "latino", "asian", "black", | |
| "middle eastern", "mixed", "others" | |
| ], label_visibility="collapsed") | |
| st.markdown('<p class="demographic-label">Jaundice at Birth</p>', unsafe_allow_html=True) | |
| jundice = st.selectbox("Jaundice at Birth", ["no", "yes"], label_visibility="collapsed") | |
| st.markdown('<p class="demographic-label">Used App Before</p>', unsafe_allow_html=True) | |
| used_app = st.selectbox("Used App Before", ["no", "yes"], label_visibility="collapsed") | |
| with col2: | |
| st.markdown('<p class="demographic-label">Gender</p>', unsafe_allow_html=True) | |
| gender = st.selectbox("Gender", ["m", "f"], label_visibility="collapsed") | |
| st.markdown('<p class="demographic-label">Country</p>', unsafe_allow_html=True) | |
| country = st.selectbox("Country", [ | |
| "United States", "United Kingdom", "Canada", "Australia", | |
| "India", "Brazil", "others" | |
| ], label_visibility="collapsed") | |
| st.markdown('<p class="demographic-label">Family History of Autism</p>', unsafe_allow_html=True) | |
| autism_family = st.selectbox("Family History of Autism", ["no", "yes"], label_visibility="collapsed") | |
| st.markdown('<p class="demographic-label">Screening Type</p>', unsafe_allow_html=True) | |
| screening_type = st.selectbox("Screening Type", ["adult", "clinical"], label_visibility="collapsed") | |
| st.markdown("---") | |
| # Display live score (NOT inside form - updates in real-time) | |
| current_score = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8 + A9 + A10 | |
| col_score1, col_score2 = st.columns(2) | |
| with col_score1: | |
| st.metric("Your AQ-10 Score", f"{current_score}/10", delta=None) | |
| with col_score2: | |
| if current_score >= 7: | |
| risk_text = "π΄ HIGH RISK PROFILE" | |
| risk_color = "#ef4444" | |
| elif current_score >= 5: | |
| risk_text = "π‘ MEDIUM RISK PROFILE" | |
| risk_color = "#f59e0b" | |
| else: | |
| risk_text = "π’ LOW RISK PROFILE" | |
| risk_color = "#10b981" | |
| st.markdown(f'<p style="font-size: 18px; color: {risk_color}; font-weight: bold;">{risk_text}</p>', unsafe_allow_html=True) | |
| st.markdown("---") | |
| st.markdown(''' | |
| <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| color: white; | |
| padding: 20px; | |
| border-radius: 10px; | |
| margin: 20px 0 15px 0; | |
| font-size: 1.8em; | |
| font-weight: bold; | |
| text-align: left;"> | |
| π€ Submit Assessment | |
| </div> | |
| ''', unsafe_allow_html=True) | |
| # Use regular button instead of form | |
| if st.button("ANALYZE & GET RESULTS", use_container_width=True, key="submit_btn"): | |
| try: | |
| # Prepare input data | |
| input_dict = { | |
| 'A1_prefer_detail_not_big_picture': A1, | |
| 'A2_must_have_sameness': A2, | |
| 'A3_prefer_reading_systematically': A3, | |
| 'A4_feel_anxious_in_social': A4, | |
| 'A5_prefer_talking_one_to_one': A5, | |
| 'A6_notice_small_changes': A6, | |
| 'A7_trouble_focus_on_changing': A7, | |
| 'A8_often_daydream': A8, | |
| 'A9_focused_on_one_topic': A9, | |
| 'A10_difficult_small_talk': A10, | |
| 'age': age, | |
| 'gender': gender, | |
| 'ethnicity': ethnicity, | |
| 'jundice': jundice, | |
| 'autism_family_member': autism_family, | |
| 'country': country, | |
| 'used_app_before': used_app, | |
| 'screening_type': screening_type | |
| } | |
| input_df = pd.DataFrame([input_dict]) | |
| # Encode categorical variables | |
| input_encoded = input_df.copy() | |
| # Define value mappings for categorical fields - case insensitive lookup | |
| value_mappings = { | |
| 'gender': { | |
| 'm': 'M', 'f': 'F', 'male': 'M', 'female': 'F' | |
| }, | |
| 'ethnicity': { | |
| 'white european': 'White', 'white': 'White', | |
| 'latino': 'Others', 'latin american': 'Others', | |
| 'asian': 'Asian', | |
| 'black': 'Black', 'african american': 'Black', | |
| 'middle eastern': 'Others', 'middle eastern/north african': 'Others', | |
| 'mixed': 'Others', | |
| 'others': 'Others', 'other': 'Others' | |
| }, | |
| 'country': { | |
| 'united states': 'USA', 'usa': 'USA', 'us': 'USA', | |
| 'united kingdom': 'UK', 'uk': 'UK', | |
| 'canada': 'Canada', | |
| 'australia': 'USA', # Map to USA as default for unknown countries | |
| 'india': 'India', | |
| 'brazil': 'USA', | |
| 'others': 'USA', 'other': 'USA' | |
| }, | |
| 'screening_type': { | |
| 'adult': 'Questionnaire', 'questionnaire': 'Questionnaire', | |
| 'clinical': 'Interview', 'interview': 'Interview' | |
| }, | |
| 'jundice': { | |
| 'yes': 'yes', 'no': 'no', | |
| 'y': 'yes', 'n': 'no' | |
| }, | |
| 'autism_family_member': { | |
| 'yes': 'yes', 'no': 'no', | |
| 'y': 'yes', 'n': 'no' | |
| }, | |
| 'used_app_before': { | |
| 'yes': 'yes', 'no': 'no', | |
| 'y': 'yes', 'n': 'no' | |
| } | |
| } | |
| # Handle categorical encoding with robust error handling | |
| for col in input_df.columns: | |
| if col in le_dict: | |
| try: | |
| input_encoded[col] = le_dict[col].transform(input_df[col]) | |
| except ValueError as e: | |
| original_val = str(input_df[col].values[0]).strip() | |
| # Get encoder's valid classes | |
| valid_classes = le_dict[col].classes_ | |
| # Try mapping if available | |
| if col in value_mappings: | |
| mapped_val = value_mappings[col].get(original_val.lower(), None) | |
| if mapped_val and mapped_val in valid_classes: | |
| input_encoded[col] = le_dict[col].transform([mapped_val]) | |
| else: | |
| # If mapping didn't work, try exact case match | |
| if original_val in valid_classes: | |
| input_encoded[col] = le_dict[col].transform([original_val]) | |
| else: | |
| # Last resort: case-insensitive search in valid classes | |
| for vc in valid_classes: | |
| if vc.lower() == original_val.lower(): | |
| input_encoded[col] = le_dict[col].transform([vc]) | |
| break | |
| else: | |
| raise ValueError(f"No valid mapping for '{original_val}' in {col}. Valid options: {list(valid_classes)}") | |
| else: | |
| # For columns without mapping, try case-insensitive match | |
| for vc in valid_classes: | |
| if vc.lower() == original_val.lower(): | |
| input_encoded[col] = le_dict[col].transform([vc]) | |
| break | |
| else: | |
| raise ValueError(f"Invalid value '{original_val}' for {col}. Valid options: {list(valid_classes)}") | |
| # Scale numeric features | |
| # Only scale the 11 numeric columns that were scaled during training | |
| numeric_cols = ['A1_prefer_detail_not_big_picture', 'A2_must_have_sameness', | |
| 'A3_prefer_reading_systematically', 'A4_feel_anxious_in_social', | |
| 'A5_prefer_talking_one_to_one', 'A6_notice_small_changes', | |
| 'A7_trouble_focus_on_changing', 'A8_often_daydream', | |
| 'A9_focused_on_one_topic', 'A10_difficult_small_talk', 'age'] | |
| input_scaled = input_encoded.copy() | |
| input_scaled[numeric_cols] = scaler.transform(input_encoded[numeric_cols]) | |
| # Reorder columns to match feature_names exactly | |
| input_scaled = input_scaled[feature_names] | |
| # Verify shape before prediction | |
| if input_scaled.shape[1] != len(feature_names): | |
| raise ValueError(f"Feature count mismatch: got {input_scaled.shape[1]}, expected {len(feature_names)}") | |
| # Get prediction | |
| pred_proba = model.predict_proba(input_scaled)[0] | |
| autism_prob = pred_proba[1] | |
| # DEBUG: Show what we're sending to model | |
| st.write("π **DEBUG INFO:**") | |
| st.write(f"AQ-10 Score: {A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8 + A9 + A10}/10") | |
| st.write(f"Age: {age}, Gender: {gender}, Ethnicity: {ethnicity}") | |
| st.write(f"Model Input Shape: {input_scaled.shape}") | |
| st.write(f"Prediction Probabilities: Class 0 (No Autism)={pred_proba[0]:.4f}, Class 1 (Autism)={pred_proba[1]:.4f}") | |
| # Risk classification | |
| if autism_prob >= 0.7: | |
| risk_level = "π΄ HIGH RISK" | |
| risk_class = "risk-high" | |
| recommendation = "high" | |
| elif autism_prob >= 0.5: | |
| risk_level = "π‘ MEDIUM RISK" | |
| risk_class = "risk-medium" | |
| recommendation = "medium" | |
| else: | |
| risk_level = "π’ LOW RISK" | |
| risk_class = "risk-low" | |
| recommendation = "low" | |
| # Display results | |
| st.markdown("---") | |
| st.markdown("### π― Screening Results") | |
| # Main risk box | |
| st.markdown(f""" | |
| <div class="risk-box {risk_class}"> | |
| <div class="risk-percentage">{autism_prob*100:.1f}%</div> | |
| <div class="risk-label">{risk_level}</div> | |
| <div style="margin-top: 15px; font-size: 0.95em; opacity: 0.95;"> | |
| Autism Spectrum Screening Score | |
| </div> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| # Metrics | |
| col1, col2, col3 = st.columns(3) | |
| with col1: | |
| st.metric("π§ Autism Probability", f"{autism_prob*100:.1f}%") | |
| with col2: | |
| st.metric("β No Autism Probability", f"{pred_proba[0]*100:.1f}%") | |
| with col3: | |
| st.metric("π Model Confidence", f"{max(pred_proba)*100:.1f}%") | |
| # ============================================================ | |
| # CLINICAL RECOMMENDATIONS SECTION | |
| # ============================================================ | |
| st.markdown("---") | |
| st.markdown("### π Recommended Next Steps") | |
| if recommendation == "high": | |
| st.markdown("<div style='background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); color: black; padding: 25px; border-radius: 12px; border-left: 5px solid #dc2626; box-shadow: 0 4px 12px rgba(245, 87, 108, 0.3);'><h3 style='margin-top: 0; color: black;'>π΄ HIGH RISK PROFILE</h3><h4 style='color: black;'>Recommended Actions:</h4><ul><li><strong>Schedule consultation with autism specialist</strong> within 1-2 weeks</li><li><strong>Prepare documentation:</strong> Family history, symptom timeline, developmental milestones</li><li><strong>Share this report</strong> with your healthcare provider</li><li><strong>Request formal diagnostic evaluation</strong> using DSM-5 criteria</li></ul><h4 style='color: black;'>Clinical Indicators Noted:</h4><ul><li>Strong autism spectrum traits detected</li><li>Recommend urgent professional assessment</li><li>Multiple screening factors present</li></ul><p style='margin-bottom: 0; font-style: italic; font-size: 0.9em;'>β οΈ <strong>Important:</strong> This is a screening tool, not a diagnosis. Only a qualified medical professional can diagnose autism.</p></div>", unsafe_allow_html=True) | |
| elif recommendation == "medium": | |
| st.markdown("<div style='background: linear-gradient(135deg, #fa709a 0%, #fee140 100%); color: black; padding: 25px; border-radius: 12px; border-left: 5px solid #f59e0b; box-shadow: 0 4px 12px rgba(245, 158, 11, 0.3);'><h3 style='margin-top: 0; color: black;'>π‘ MEDIUM RISK PROFILE</h3><h4 style='color: black;'>Recommended Actions:</h4><ul><li><strong>Schedule follow-up assessment</strong> within 6-12 months</li><li><strong>Monitor for symptom changes</strong> over next 3-6 months</li><li><strong>Consider clinical evaluation</strong> if symptoms worsen or new concerns arise</li><li><strong>Discuss results</strong> with your primary healthcare provider</li></ul><h4 style='color: black;'>Clinical Indicators Noted:</h4><ul><li>Moderate autism spectrum traits present</li><li>Pattern suggests further assessment may be beneficial</li><li>Consider evaluation based on symptom severity</li></ul><p style='margin-bottom: 0; font-style: italic; font-size: 0.9em;'>β οΈ <strong>Important:</strong> This is a screening tool, not a diagnosis. Consult healthcare professionals for clinical decisions.</p></div>", unsafe_allow_html=True) | |
| else: # LOW RISK | |
| st.markdown("<div style='background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); color: black; padding: 25px; border-radius: 12px; border-left: 5px solid #10b981; box-shadow: 0 4px 12px rgba(16, 185, 129, 0.3);'><h3 style='margin-top: 0; color: black;'>π’ LOW RISK PROFILE</h3><h4 style='color: black;'>Recommended Actions:</h4><ul><li><strong>No immediate clinical concern</strong> based on current screening</li><li><strong>Rescreen</strong> if new symptoms develop in future</li><li><strong>Contact healthcare provider</strong> only if symptoms emerge</li><li><strong>Routine monitoring</strong> through regular health check-ups</li></ul><h4 style='color: black;'>Clinical Indicators Noted:</h4><ul><li>Minimal autism spectrum traits detected</li><li>Screening suggests low probability of autism spectrum disorder</li><li>Current presentation does not warrant urgent referral</li></ul><p style='margin-bottom: 0; font-style: italic; font-size: 0.9em;'>β <strong>Note:</strong> Negative screening does not completely rule out autism. Consult professionals if concerns arise.</p></div>", unsafe_allow_html=True) | |
| # Disclaimer | |
| st.markdown("---") | |
| st.markdown(""" | |
| <div style="background-color: #fee2e2; | |
| border-left: 4px solid #dc2626; | |
| padding: 15px; | |
| border-radius: 8px; | |
| color: #7f1d1d;"> | |
| <strong>β οΈ IMPORTANT MEDICAL DISCLAIMER</strong><br> | |
| This tool provides screening assistance only and should NOT be used for self-diagnosis. | |
| Autism Spectrum Disorder diagnosis requires comprehensive evaluation by qualified healthcare professionals including psychiatrists, psychologists, or neurologists. | |
| Always consult with medical professionals for accurate diagnosis and treatment recommendations. | |
| </div> | |
| """, unsafe_allow_html=True) | |
| # Visualization | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| fig, ax = plt.subplots(figsize=(8, 6)) | |
| colors = ['#10b981', '#ef4444'] | |
| ax.pie([pred_proba[0], pred_proba[1]], labels=['No ASD', 'ASD'], | |
| autopct='%1.1f%%', colors=colors, explode=(0.05, 0.05), startangle=90) | |
| ax.set_title('Prediction Probability Distribution', fontweight='bold', fontsize=12) | |
| st.pyplot(fig) | |
| with col2: | |
| fig, ax = plt.subplots(figsize=(8, 6)) | |
| ax.barh(['No ASD', 'ASD'], pred_proba, color=['#10b981', '#ef4444']) | |
| ax.set_xlabel('Probability', fontweight='bold') | |
| ax.set_title('Risk Comparison', fontweight='bold', fontsize=12) | |
| for i, v in enumerate(pred_proba): | |
| ax.text(v + 0.02, i, f'{v:.1%}', va='center', fontweight='bold') | |
| st.pyplot(fig) | |
| # SHAP Explanation | |
| st.markdown("---") | |
| st.markdown("### π Feature Contribution Analysis (SHAP)") | |
| st.markdown("*Shows which factors most influenced this prediction*") | |
| try: | |
| shap_vals = explainer.shap_values(input_scaled) | |
| if isinstance(shap_vals, list): | |
| shap_class1 = np.array(shap_vals[1])[0] | |
| else: | |
| shap_class1 = shap_vals[:, :, 1][0] | |
| contributions = pd.DataFrame({ | |
| 'Feature': feature_names, | |
| 'Impact': np.abs(shap_class1) | |
| }).sort_values('Impact', ascending=True).tail(10) | |
| fig, ax = plt.subplots(figsize=(10, 6)) | |
| colors = ['#ef4444' if shap_class1[feature_names.index(f)] > 0 else '#10b981' | |
| for f in contributions['Feature']] | |
| ax.barh(range(len(contributions)), contributions['Impact'], color=colors) | |
| ax.set_yticks(range(len(contributions))) | |
| ax.set_yticklabels(contributions['Feature']) | |
| ax.set_xlabel('Contribution Magnitude', fontweight='bold') | |
| ax.set_title('Top 10 Features Influencing This Prediction', fontweight='bold') | |
| ax.invert_yaxis() | |
| plt.tight_layout() | |
| st.pyplot(fig) | |
| except Exception as e: | |
| st.warning(f"Could not generate SHAP visualization: {str(e)}") | |
| # Recommendations | |
| st.markdown("---") | |
| st.markdown("### π‘ Professional Recommendations") | |
| if recommendation == "low": | |
| st.markdown("<div class='success-box' style='color: #000;'><strong style='color: #000;'>β LOW RISK ASSESSMENT</strong><br><span style='color: #000;'>Based on the screening assessment, the likelihood of autism spectrum disorder appears low. Continue with routine monitoring and healthy practices.</span></div>", unsafe_allow_html=True) | |
| elif recommendation == "medium": | |
| st.markdown("<div class='warning-box' style='color: #000;'><strong style='color: #000;'>β οΈ MEDIUM RISK ASSESSMENT</strong><br><span style='color: #000;'>Some indicators are present. Professional consultation is recommended. Consider scheduling an appointment with a specialist for formal evaluation.</span></div>", unsafe_allow_html=True) | |
| else: # high | |
| st.markdown("<div class='danger-box' style='color: #000;'><strong style='color: #000;'>π΄ HIGH RISK ASSESSMENT</strong><br><span style='color: #000;'>Multiple indicators detected. Professional consultation is highly recommended. Please schedule an appointment with an autism specialist for comprehensive evaluation and diagnosis.</span></div>", unsafe_allow_html=True) | |
| st.success("β Analysis Complete! Review the results above.") | |
| except Exception as e: | |
| st.error(f"β Error during analysis: {str(e)}") | |
| st.info("π‘ Tip: Please check that all fields are filled correctly.") | |
| # For debugging | |
| #st.write(f"Debug Info: {e}") | |
| #st.write(f"Input data: {input_dict}") | |
| # ============================================================================ | |
| # ANALYTICS PAGE | |
| # ============================================================================ | |
| elif page == "π Analytics": | |
| st.markdown("### π Model Analytics & Performance") | |
| col1, col2, col3, col4 = st.columns(4) | |
| with col1: | |
| st.metric("π Training Samples", "704") | |
| with col2: | |
| st.metric("π― Model Accuracy", "92.5%") | |
| with col3: | |
| st.metric("π§ Total Features", "18") | |
| with col4: | |
| st.metric("π Model Type", "Random Forest") | |
| st.markdown("---") | |
| st.markdown("### π Top Contributing Features") | |
| try: | |
| if isinstance(shap_values_data, np.ndarray) and shap_values_data.ndim == 3: | |
| shap_class1 = shap_values_data[:, :, 1] | |
| mean_shap = np.abs(shap_class1).mean(axis=0) | |
| else: | |
| mean_shap = np.abs(shap_values_data[1]).mean(axis=0) | |
| top_features = pd.DataFrame({ | |
| 'Feature': feature_names, | |
| 'Importance': mean_shap | |
| }).sort_values('Importance', ascending=False).head(10) | |
| fig, ax = plt.subplots(figsize=(10, 6)) | |
| ax.barh(range(len(top_features)), top_features['Importance'], color='#667eea') | |
| ax.set_yticks(range(len(top_features))) | |
| ax.set_yticklabels(top_features['Feature']) | |
| ax.set_xlabel('Mean |SHAP Value|', fontweight='bold') | |
| ax.set_title('Top 10 Most Important Features for ASD Prediction', fontweight='bold') | |
| ax.invert_yaxis() | |
| plt.tight_layout() | |
| st.pyplot(fig) | |
| st.markdown("### π Feature Importance Breakdown") | |
| for idx, row in top_features.iterrows(): | |
| st.write(f"**{idx+1}. {row['Feature']}** - Importance: {row['Importance']:.4f}") | |
| except: | |
| st.warning("Feature importance data not available") | |
| # ============================================================================ | |
| # FAQ PAGE | |
| # ============================================================================ | |
| elif page == "β FAQ": | |
| st.markdown("### β Frequently Asked Questions") | |
| with st.expander("β What is this screening tool?"): | |
| st.write(""" | |
| This is an AI-powered autism spectrum screening tool that uses machine learning | |
| (Random Forest) and explainable AI (SHAP) to assess the likelihood of autism | |
| spectrum disorder based on AQ-10 assessment and demographic information. | |
| """) | |
| with st.expander("β Is this a clinical diagnosis?"): | |
| st.write(""" | |
| NO. This tool is for SCREENING purposes only. It is NOT a clinical diagnosis. | |
| A qualified healthcare professional must perform formal evaluation for definitive diagnosis. | |
| """) | |
| with st.expander("β How accurate is this tool?"): | |
| st.write(""" | |
| The model achieves 92.5% accuracy on test data. However, individual predictions | |
| may vary and should always be validated by healthcare professionals. | |
| """) | |
| with st.expander("β What do the SHAP values mean?"): | |
| st.write(""" | |
| SHAP (SHapley Additive exPlanations) values show how much each feature | |
| contributed to the prediction. Longer bars indicate stronger influence on the result. | |
| """) | |
| with st.expander("β Is my data private and secure?"): | |
| st.write(""" | |
| Yes. No data is stored on any server or database. All processing happens | |
| locally on your device. Your information is completely private. | |
| """) | |
| with st.expander("β What should I do with my results?"): | |
| st.write(""" | |
| Use these results as a conversation starter with healthcare providers. | |
| Share your screening results with specialists who can perform proper evaluation | |
| and provide professional recommendations. | |
| """) | |
| with st.expander("β How long does the screening take?"): | |
| st.write(""" | |
| The screening assessment and analysis takes less than 1 minute. | |
| The questionnaire itself takes about 5-10 minutes to complete. | |
| """) | |
| # ============================================================================ | |
| # ABOUT PAGE | |
| # ============================================================================ | |
| elif page == "π About": | |
| col1, col2 = st.columns([2, 1]) | |
| with col1: | |
| st.markdown(""" | |
| ### π§ About Autism Spectrum Disorder | |
| Autism Spectrum Disorder (ASD) is a neurodevelopmental condition that affects | |
| how individuals communicate, behave, and interact socially. It exists on a spectrum, | |
| with individuals showing varying levels of support needs. | |
| **Key characteristics may include:** | |
| - Differences in social communication | |
| - Repetitive behaviors or interests | |
| - Sensory sensitivities | |
| - Unique strengths in specific areas | |
| Early screening and intervention can significantly improve outcomes and quality of life. | |
| ### π€ About This Application | |
| **Technology Stack:** | |
| - **Python 3.14.2**: Programming language | |
| - **Streamlit**: Web application framework | |
| - **Scikit-learn**: Machine learning library | |
| - **SHAP**: Model explainability tool | |
| - **Pandas & NumPy**: Data manipulation | |
| - **Matplotlib & Seaborn**: Visualization | |
| **Model Details:** | |
| - **Algorithm**: Random Forest Classifier | |
| - **Training Data**: 704 patient records | |
| - **Features**: 18 screening and demographic features | |
| - **Accuracy**: 92.5% on test set | |
| - **Explainability**: SHAP-based feature importance | |
| ### π About SHAP | |
| SHAP (SHapley Additive exPlanations) is a game-theoretic approach to explain | |
| machine learning predictions. It provides interpretable explanations by computing | |
| the contribution of each feature to each prediction. | |
| """) | |
| with col2: | |
| st.markdown(""" | |
| ### π Resources | |
| **For More Information:** | |
| - American Psychiatric Association | |
| - National Institute of Mental Health | |
| - Autism Society | |
| - World Health Organization | |
| ### π¨ββοΈ Healthcare Professionals | |
| This tool is designed to support clinical decision-making but should always | |
| be used in conjunction with professional judgment and formal diagnostic criteria. | |
| ### π Support | |
| For questions or technical support, please contact the development team. | |
| --- | |
| **Version:** 1.0 | |
| **Status:** β Production Ready | |
| **Last Updated:** March 2026 | |
| """) | |
| # ============================================================================ | |
| # FOOTER | |
| # ============================================================================ | |
| st.markdown("---") | |
| st.markdown(""" | |
| <div style="text-align: center; padding: 20px; color: #6b7280; font-size: 0.9em; border-top: 1px solid #e5e7eb;"> | |
| <strong>π₯ Autism Spectrum Disorder Screening System</strong><br> | |
| Powered by Explainable AI (SHAP) | Machine Learning | Streamlit<br> | |
| <em>For screening purposes only | Always consult healthcare professionals</em><br> | |
| Β© 2026 All Rights Reserved | Status: β Production Ready | |
| </div> | |
| """, unsafe_allow_html=True) | |