CoolFace
Apppublic

Sentiment-Analysis/PWU-MSIT

sourceHugging Faceapache-2.0updated 1y agoView on Hugging Face
0likes
app.py692 linesDownload Raw Back to root
1import gradio as gr2import pandas as pd3import matplotlib.pyplot as plt4import numpy as np5import csv6import os7from datetime import datetime8import torch9from transformers import BertTokenizer, BertForSequenceClassification10import traceback11 12# Define CSV file path13CSV_FILE = "pwu_survey_data.csv"  # Added CSV_FILE definition14 15# Initialize data storage16if not os.path.exists(CSV_FILE):17    with open(CSV_FILE, "w", newline='', encoding='utf-8') as f:18        writer = csv.writer(f)19        headers = [20            "Timestamp", "Program", "Age", "Gender", "Enrolment", "Units",21            "Overall Satisfaction", "Teaching Faculty", "Course Availability", 22            "Academic Advising", "Access to Faculty", "Fellow Students", 23            "Academic Reputation", "Value for Price",24            "Educational Comment", "Educational Sentiment", "Educational Confidence",25            "Classrooms", "Lab Facilities", "Mini Library", "Career Counseling", 26            "OJT Placement", "Conference Room", "Faculty Room", "Head Office",27            "Facilities Comment", "Facilities Sentiment", "Facilities Confidence",28            "Clubs", "Diversity", "Dept Safety", "Activities", 29            "Student Safety", "Social Life",30            "Campus Comment", "Campus Sentiment", "Campus Confidence"31        ]32        writer.writerow(headers)33 34# Load BERT model and tokenizer35try:36    print("Loading BERT model...")37    model_name = "nlptown/bert-base-multilingual-uncased-sentiment"38    tokenizer = BertTokenizer.from_pretrained(model_name)39    model = BertForSequenceClassification.from_pretrained(model_name)40    model.eval()41    print("BERT model loaded successfully!")42except Exception as e:43    print(f"Error loading BERT model: {e}")44    # Fallback to simple sentiment analysis if BERT fails45    model = None46    tokenizer = None47 48def bert_sentiment(text):49    """Analyze sentiment using BERT model with confidence scores"""50    if not text.strip():51        return "", 0.052    53    if model is None or tokenizer is None:54        return "⚠️ Model Error", 0.055    56    try:57        inputs = tokenizer(58            text, 59            return_tensors="pt", 60            truncation=True, 61            max_length=51262        )63        64        with torch.no_grad():65            outputs = model(**inputs)66        67        logits = outputs.logits68        probabilities = torch.softmax(logits, dim=1).numpy()[0]69        rating = np.argmax(probabilities) + 1  # Ratings 1-570        71        # Map ratings to sentiment labels72        if rating >= 4:73            sentiment = "😊 Positive"74        elif rating <= 2:75            sentiment = "😠 Negative"76        else:77            sentiment = "😐 Neutral"78        79        confidence = probabilities[np.argmax(probabilities)]80        return sentiment, round(float(confidence), 3)81    except Exception as e:82        print(f"Sentiment analysis error: {e}")83        return "⚠️ Analysis Error", 0.084 85# Save response to CSV86def save_to_csv(data):87    try:88        with open(CSV_FILE, "a", newline='', encoding='utf-8') as f:89            writer = csv.writer(f)90            writer.writerow(data)91        print(f"Data saved to {os.path.abspath(CSV_FILE)}")92        return True93    except Exception as e:94        print(f"CSV save error: {e}")95        return False96 97# Generate visualizations98def generate_visualizations():99    try:100        # Check if CSV exists and has data101        if not os.path.exists(CSV_FILE) or os.path.getsize(CSV_FILE) < 100:102            return None, None, None, None103        104        df = pd.read_csv(CSV_FILE)105        106        if len(df) < 1:107            return None, None, None, None108        109        # Create visualization placeholders for when data is insufficient110        overall_plot = None111        category_plot = None112        sentiment_plot = None113        heatmap_plot = None114        115        # Overall satisfaction distribution - FIXED116        if 'Overall Satisfaction' in df.columns:117            plt.figure(figsize=(10, 5))118            119            # Define the correct order of satisfaction levels120            satisfaction_order = ['Very satisfied', 'Satisfied', 'Neutral', 'Dissatisfied', 'Very dissatisfied']121            122            # Count occurrences of each satisfaction level123            satisfaction_counts = df['Overall Satisfaction'].value_counts()124            125            # Reindex to include all satisfaction levels, even if count is zero126            satisfaction_counts = satisfaction_counts.reindex(satisfaction_order, fill_value=0)127            128            # Create bar plot129            colors = ['#4CAF50', '#8BC34A', '#FFC107', '#FF9800', '#F44336']130            satisfaction_counts.plot(kind='bar', color=colors)131            132            plt.title("Overall Satisfaction Distribution")133            plt.ylabel("Number of Students")134            plt.xlabel("Satisfaction Level")135            plt.xticks(rotation=45)136            plt.tight_layout()137            overall_plot = plt.gcf()138            plt.close()139        140        # Convert ratings to numerical values for other visualizations141        rating_map = {'Poor':1, 'Fair':2, 'Good':3, 'Very Good':4, 'Excellent':5}142        rating_cols = [143            'Teaching Faculty', 'Course Availability', 'Academic Advising', 144            'Access to Faculty', 'Fellow Students', 'Academic Reputation', 'Value for Price',145            'Classrooms', 'Lab Facilities', 'Mini Library', 'Career Counseling', 146            'OJT Placement', 'Conference Room', 'Faculty Room', 'Head Office',147            'Clubs', 'Diversity', 'Dept Safety', 'Activities', 'Student Safety', 'Social Life'148        ]149        150        for col in rating_cols:151            if col in df.columns:152                df[col] = df[col].map(rating_map)153        154        # Average ratings by category155        categories = {156            "Educational Experience": [157                'Teaching Faculty', 'Course Availability', 'Academic Advising', 158                'Access to Faculty', 'Fellow Students', 'Academic Reputation', 'Value for Price'159            ],160            "Facilities & Services": [161                'Classrooms', 'Lab Facilities', 'Mini Library', 'Career Counseling', 162                'OJT Placement', 'Conference Room', 'Faculty Room', 'Head Office'163            ],164            "Campus Life": [165                'Clubs', 'Diversity', 'Dept Safety', 'Activities', 166                'Student Safety', 'Social Life'167            ]168        }169        170        avg_ratings = {}171        for category, cols in categories.items():172            available_cols = [col for col in cols if col in df.columns]173            if available_cols:174                # Calculate average only if we have at least 1 valid value175                if len(df[available_cols].dropna()) > 0:176                    avg_ratings[category] = df[available_cols].mean().mean()177        178        if avg_ratings:179            plt.figure(figsize=(10, 5))180            pd.Series(avg_ratings).plot(kind='bar', color=['#2196F3', '#3F51B5', '#9C27B0'])181            plt.title("Average Ratings by Category")182            plt.ylabel("Average Rating (1-5)")183            plt.ylim(0, 5)184            plt.xticks(rotation=0)185            plt.tight_layout()186            category_plot = plt.gcf()187            plt.close()188        189        # Sentiment distribution190        sentiment_cols = ['Educational Sentiment', 'Facilities Sentiment', 'Campus Sentiment']191        available_sentiment_cols = [col for col in sentiment_cols if col in df.columns]192        193        if available_sentiment_cols:194            sentiment_counts = pd.concat([df[col].value_counts() for col in available_sentiment_cols], axis=1)195            sentiment_counts.columns = ['Educational', 'Facilities', 'Campus']196            sentiment_counts = sentiment_counts.fillna(0)197            198            if not sentiment_counts.empty:199                plt.figure(figsize=(10, 5))200                sentiment_counts.plot(kind='bar', color=['#4CAF50', '#2196F3', '#FF9800'])201                plt.title("Sentiment Distribution by Category")202                plt.ylabel("Number of Comments")203                plt.xticks(rotation=0)204                plt.legend(title="Category")205                plt.tight_layout()206                sentiment_plot = plt.gcf()207                plt.close()208        209        # Detailed ratings heatmap210        detailed_ratings = []211        for category, cols in categories.items():212            available_cols = [col for col in cols if col in df.columns]213            if available_cols:214                # Calculate average only if we have data215                if len(df[available_cols].dropna()) > 0:216                    category_avg = df[available_cols].mean()217                    for col in available_cols:218                        detailed_ratings.append({219                            'Category': category,220                            'Aspect': col,221                            'Rating': category_avg[col]222                        })223        224        if detailed_ratings:225            detailed_df = pd.DataFrame(detailed_ratings)226            pivot_df = detailed_df.pivot(index='Category', columns='Aspect', values='Rating')227            228            plt.figure(figsize=(12, 8))229            plt.imshow(pivot_df, cmap='RdYlGn', vmin=1, vmax=5)230            plt.colorbar(label='Rating (1-5)')231            plt.title("Detailed Aspect Ratings")232            plt.xticks(range(len(pivot_df.columns)), pivot_df.columns, rotation=45, ha='right')233            plt.yticks(range(len(pivot_df.index)), pivot_df.index)234            235            # Add text annotations236            for i in range(len(pivot_df.index)):237                for j in range(len(pivot_df.columns)):238                    plt.text(j, i, f"{pivot_df.iloc[i, j]:.1f}", 239                             ha="center", va="center", color="black", fontsize=9)240            241            plt.tight_layout()242            heatmap_plot = plt.gcf()243            plt.close()244        245        return overall_plot, category_plot, sentiment_plot, heatmap_plot246    247    except Exception as e:248        print(f"Visualization error: {e}")249        return None, None, None, None250 251# Create placeholder visualizations for when data is insufficient252def create_empty_plot(message):253    plt.figure(figsize=(10, 5))254    plt.text(0.5, 0.5, message, 255             ha='center', va='center', 256             fontsize=14, color='gray')257    plt.axis('off')258    plt.tight_layout()259    fig = plt.gcf()260    plt.close()261    return fig262 263# Reset all form fields264def reset_form():265    return [266        None,  # program267        20,    # age268        None,  # gender269        None,  # enrolment270        15,    # units271        None,  # overall_satisfaction272        None,  # teaching_faculty273        None,  # course_avail274        None,  # academic_advising275        None,  # access_faculty276        None,  # fellow_students277        None,  # academic_reputation278        None,  # value_price279        "",    # edu_comment280        None,  # classrooms281        None,  # lab_facilities282        None,  # mini_library283        None,  # career_counseling284        None,  # ojt_placement285        None,  # conference_room286        None,  # faculty_room287        None,  # head_office288        "",    # facility_comment289        None,  # clubs290        None,  # diversity291        None,  # dept_safety292        None,  # activities293        None,  # student_safety294        None,  # social_life295        "",    # campus_comment296    ]297 298# Function to handle CSV download299def get_csv_file():300    if os.path.exists(CSV_FILE):301        return os.path.abspath(CSV_FILE)302    else:303        raise gr.Error("CSV file does not exist yet. Submit at least one survey to create it.")304 305# Main survey function with error handling306def submit_survey(307    program, age, gender, enrolment, units,308    overall_satisfaction,309    teaching_faculty, course_avail, academic_advising, 310    access_faculty, fellow_students, academic_reputation, value_price,311    edu_comment,312    classrooms, lab_facilities, mini_library, career_counseling,313    ojt_placement, conference_room, faculty_room, head_office,314    facility_comment,315    clubs, diversity, dept_safety, activities, student_safety, social_life,316    campus_comment317):318    try:319        # Sentiment analysis with BERT320        edu_sentiment, edu_conf = bert_sentiment(edu_comment)321        facility_sentiment, facility_conf = bert_sentiment(facility_comment)322        campus_sentiment, campus_conf = bert_sentiment(campus_comment)323        324        # Prepare data for CSV325        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")326        data = [327            timestamp, 328            program or "", 329            age or 0, 330            gender or "", 331            enrolment or "", 332            units or 0,333            overall_satisfaction or "",334            teaching_faculty or "", 335            course_avail or "", 336            academic_advising or "", 337            access_faculty or "", 338            fellow_students or "", 339            academic_reputation or "", 340            value_price or "",341            edu_comment or "", 342            edu_sentiment or "", 343            edu_conf or 0,344            classrooms or "", 345            lab_facilities or "", 346            mini_library or "", 347            career_counseling or "",348            ojt_placement or "", 349            conference_room or "", 350            faculty_room or "", 351            head_office or "",352            facility_comment or "", 353            facility_sentiment or "", 354            facility_conf or 0,355            clubs or "", 356            diversity or "", 357            dept_safety or "", 358            activities or "", 359            student_safety or "", 360            social_life or "",361            campus_comment or "", 362            campus_sentiment or "", 363            campus_conf or 0364        ]365        366        # Save to CSV367        save_success = save_to_csv(data)368        369        # Generate visualizations370        overall_plot, category_plot, sentiment_plot, heatmap_plot = generate_visualizations()371        372        # Create sentiment display373        sentiment_html = f"""374        <div style="background-color:maroon; padding:20px; border-radius:10px; margin-bottom:20px; border:1px solid #dee2e6;">375            <h3 style="color:#343a40;">📝 Sentiment Analysis</h3>376            <div style="display:flex; justify-content:space-between; margin-top:15px; gap:15px;">377                <div style="text-align:center; background-color:blue; padding:15px; border-radius:8px; width:100%; border:1px solid #cfe2ff;">378                    <h4 style="color:#0d6efd;">Educational Experience</h4>379                    <div style="font-size:36px;">{edu_sentiment.split()[0] if edu_sentiment and ' ' in edu_sentiment else ""}</div>380                    <p><b>{edu_sentiment}</b><br>(Confidence: {edu_conf*100:.1f}%)</p>381                </div>382                <div style="text-align:center; background-color:blue; padding:15px; border-radius:8px; width:100%; border:1px solid #cfe2ff;">383                    <h4 style="color:#0d6efd;">Facilities & Services</h4>384                    <div style="font-size:36px;">{facility_sentiment.split()[0] if facility_sentiment and ' ' in facility_sentiment else ""}</div>385                    <p><b>{facility_sentiment}</b><br>(Confidence: {facility_conf*100:.1f}%)</p>386                </div>387                <div style="text-align:center; background-color:blue; padding:15px; border-radius:8px; width:100%; border:1px solid #cfe2ff;">388                    <h4 style="color:#0d6efd;">Campus Life</h4>389                    <div style="font-size:36px;">{campus_sentiment.split()[0] if campus_sentiment and ' ' in campus_sentiment else ""}</div>390                    <p><b>{campus_sentiment}</b><br>(Confidence: {campus_conf*100:.1f}%)</p>391                </div>392            </div>393        </div>394        """395        396        if save_success:397            status = "<div style='color:green; padding:10px; background-color:#e6ffe6; border-radius:5px;'>✅ Survey submitted successfully!</div>"398        else:399            status = "<div style='color:red; padding:10px; background-color:#ffebee; border-radius:5px;'>❌ Error saving data! Check console for details.</div>"400        401        # Create placeholder plots if needed402        if overall_plot is None:403            overall_plot = create_empty_plot("Not enough data yet\nfor overall satisfaction")404        if category_plot is None:405            category_plot = create_empty_plot("Not enough data yet\nfor category ratings")406        if sentiment_plot is None:407            sentiment_plot = create_empty_plot("Not enough data yet\nfor sentiment analysis")408        if heatmap_plot is None:409            heatmap_plot = create_empty_plot("Not enough data yet\nfor detailed ratings")410        411        return sentiment_html, overall_plot, category_plot, sentiment_plot, heatmap_plot, status412    413    except Exception as e:414        error_trace = traceback.format_exc()415        print(f"Submission error: {error_trace}")416        error_html = f"""417        <div style="background-color:#ffebee; padding:20px; border-radius:10px; margin-bottom:20px;">418            <h3>⚠️ Submission Error</h3>419            <p>An error occurred while processing your submission:</p>420            <pre>{str(e)}</pre>421            <p>Please try again or contact support.</p>422        </div>423        """424        status = f"<div style='color:red; padding:10px; background-color:#ffebee; border-radius:5px;'>❌ Error: {str(e)}</div>"425        426        # Create placeholder plots for error case427        empty_plot = create_empty_plot("Data not available due to error")428        return error_html, empty_plot, empty_plot, empty_plot, empty_plot, status429 430# Create Gradio interface with Tabs431with gr.Blocks(title="PWU-Student Satisfaction Survey", theme=gr.themes.Soft()) as demo:432    gr.Markdown("# 🎓 PWU-Student Satisfaction Survey")433    gr.Markdown("Share your experiences to help us improve our programs and facilities!")434    gr.Markdown("Complete the survey by clicking the tabs")435    436    with gr.Tab("Student Profile"):437        gr.Markdown("## Part I: Student Profile")438        with gr.Group():439            program = gr.Radio(440                label="Program", 441                choices=["", "BSFT", "MSFS", "MFSM"],442                value="",443                interactive=True444            )445            age = gr.Number(label="Age (in years)", minimum=16, maximum=60, value=20)446            gender = gr.Radio(447                label="Gender", 448                choices=["", "Male", "Female", "Other/Prefer not to say"],449                value=""450            )451            enrolment = gr.Radio(452                label="Enrolment status", 453                choices=["", "Freshman", "New Student/Transferee", "Old student", "Returnee"],454                value=""455            )456            units = gr.Slider(457                label="Current load (no. of units)", 458                minimum=1, maximum=24, step=1, value=15459            )460    461    with gr.Tab("Educational Experiences"):462        gr.Markdown("## Part II: Educational Experiences")463        overall_satisfaction = gr.Radio(464            label="1. Overall, how satisfied are you with your educational experience at our school?",465            choices=["", "Very satisfied", "Satisfied", "Neutral", "Dissatisfied", "Very dissatisfied"],466            value="",467            interactive=True468        )469        470        gr.Markdown("2. How would you rate the following aspects of your educational experience?")471        with gr.Row():472            teaching_faculty = gr.Radio(473                label="Quality of teaching faculty",474                choices=["", "Poor", "Fair", "Good", "Very Good", "Excellent"],475                value=""476            )477            course_avail = gr.Radio(478                label="Course availability",479                choices=["", "Poor", "Fair", "Good", "Very Good", "Excellent"],480                value=""481            )482        with gr.Row():483            academic_advising = gr.Radio(484                label="Academic advising",485                choices=["", "Poor", "Fair", "Good", "Very Good", "Excellent"],486                value=""487            )488            access_faculty = gr.Radio(489                label="Access to teaching faculty",490                choices=["", "Poor", "Fair", "Good", "Very Good", "Excellent"],491                value=""492            )493        with gr.Row():494            fellow_students = gr.Radio(495                label="Fellow students' academic ability",496                choices=["", "Poor", "Fair", "Good", "Very Good", "Excellent"],497                value=""498            )499            academic_reputation = gr.Radio(500                label="Academic reputation of the school",501                choices=["", "Poor", "Fair", "Good", "Very Good", "Excellent"],502                value=""503            )504        value_price = gr.Radio(505            label="Value of the education for the price",506            choices=["", "Poor", "Fair", "Good", "Very Good", "Excellent"],507            value=""508        )509        510        edu_comment = gr.Textbox(511            label="3. Is there anything else you'd like to share about your educational experience?",512            placeholder="Share your thoughts here...",513            lines=3514        )515    516    with gr.Tab("Facilities & Services"):517        gr.Markdown("## Support Services & Facilities")518        gr.Markdown("4. How would you rate the following services/facilities at the school?")519        with gr.Row():520            classrooms = gr.Radio(521                label="Classrooms",522                choices=["", "Poor", "Fair", "Good", "Very Good", "Excellent"],523                value=""524            )525            lab_facilities = gr.Radio(526                label="Food & Research Laboratory Facilities",527                choices=["", "Poor", "Fair", "Good", "Very Good", "Excellent"],528                value=""529            )530        with gr.Row():531            mini_library = gr.Radio(532                label="Mini Library",533                choices=["", "Poor", "Fair", "Good", "Very Good", "Excellent"],534                value=""535            )536            career_counseling = gr.Radio(537                label="Career Counseling",538                choices=["", "Poor", "Fair", "Good", "Very Good", "Excellent"],539                value=""540            )541        with gr.Row():542            ojt_placement = gr.Radio(543                label="OJT/Practicum placement",544                choices=["", "Poor", "Fair", "Good", "Very Good", "Excellent"],545                value=""546            )547            conference_room = gr.Radio(548                label="Department's Conference Room",549                choices=["", "Poor", "Fair", "Good", "Very Good", "Excellent"],550                value=""551            )552        with gr.Row():553            faculty_room = gr.Radio(554                label="Faculty room",555                choices=["", "Poor", "Fair", "Good", "Very Good", "Excellent"],556                value=""557            )558            head_office = gr.Radio(559                label="Head's Office",560                choices=["", "Poor", "Fair", "Good", "Very Good", "Excellent"],561                value=""562            )563        564        facility_comment = gr.Textbox(565            label="5. Is there anything else you'd like to share about our support services and facilities?",566            placeholder="Share your thoughts here...",567            lines=3568        )569    570    with gr.Tab("Campus Life"):571        gr.Markdown("## Campus Life")572        gr.Markdown("6. How would you rate the following aspects of your student life at the school?")573        with gr.Row():574            clubs = gr.Radio(575                label="Clubs and student organizations",576                choices=["", "Poor", "Fair", "Good", "Very Good", "Excellent"],577                value=""578            )579            diversity = gr.Radio(580                label="Student diversity",581                choices=["", "Poor", "Fair", "Good", "Very Good", "Excellent"],582                value=""583            )584        with gr.Row():585            dept_safety = gr.Radio(586                label="Department's safety",587                choices=["", "Poor", "Fair", "Good", "Very Good", "Excellent"],588                value=""589            )590            activities = gr.Radio(591                label="Co- & Extracurricular activities",592                choices=["", "Poor", "Fair", "Good", "Very Good", "Excellent"],593                value=""594            )595        with gr.Row():596            student_safety = gr.Radio(597                label="Student safety",598                choices=["", "Poor", "Fair", "Good", "Very Good", "Excellent"],599                value=""600            )601            social_life = gr.Radio(602                label="Social life",603                choices=["", "Poor", "Fair", "Good", "Very Good", "Excellent"],604                value=""605            )606        607        campus_comment = gr.Textbox(608            label="7. Is there anything else you'd like to share about your campus life?",609            placeholder="Share your thoughts here...",610            lines=3611        )612    613    with gr.Tab("Results & Analytics"):614        gr.Markdown("## Survey Results & Analytics")615        gr.Markdown("Submit your survey to see real-time analysis and visualizations")616        617        with gr.Row():618            submit_btn = gr.Button("Submit Survey", variant="primary")619            reset_btn = gr.Button("Clear Form", variant="secondary")620            download_btn = gr.Button("Click to activate CSV report below ", variant="secondary")621        622        # Output components623        sentiment_output = gr.HTML(label="Sentiment Analysis")624        625        with gr.Row():626            with gr.Column():627                gr.Markdown("### Satisfaction Distribution")628                plot1 = gr.Plot(label="Overall Satisfaction")629            with gr.Column():630                gr.Markdown("### Category Ratings")631                plot2 = gr.Plot(label="Category Ratings")632        633        with gr.Row():634            with gr.Column():635                gr.Markdown("### Sentiment Analysis")636                plot3 = gr.Plot(label="Sentiment Distribution")637            with gr.Column():638                gr.Markdown("### Detailed Ratings")639                plot4 = gr.Plot(label="Aspect Ratings Heatmap")640        641        file_download = gr.File(label="CSV Report", visible=True)642        643        # Status message644        status = gr.HTML()645    646    # Input components list647    input_components = [648        program, age, gender, enrolment, units,649        overall_satisfaction,650        teaching_faculty, course_avail, academic_advising, 651        access_faculty, fellow_students, academic_reputation, value_price,652        edu_comment,653        classrooms, lab_facilities, mini_library, career_counseling,654        ojt_placement, conference_room, faculty_room, head_office,655        facility_comment,656        clubs, diversity, dept_safety, activities, student_safety, social_life,657        campus_comment658    ]659    660    # Submit action661    submit_btn.click(662        fn=submit_survey,663        inputs=input_components,664        outputs=[sentiment_output, plot1, plot2, plot3, plot4, status]665    )666    667    # Reset action668    reset_btn.click(669        fn=reset_form,670        inputs=[],671        outputs=input_components672    )673    674    # Download action - fixed675    download_btn.click(676        fn=get_csv_file,677        inputs=[],678        outputs=file_download679    )680    681    # Footer682    gr.HTML(f"""683    <div style="text-align: center; padding: 20px; margin-top: 20px; background-color: maroon; border-radius: 8px; border:1px solid #dee2e6;">684        <p style="margin-bottom:10px; color:#6c757d; ">CSV saved to: <code>{os.path.abspath(CSV_FILE)}</code></p>685        <p style="color:#6c757d;">Thank you for helping us improve our programs and services</p>686    </div>687    """)688 689# Launch the application690if __name__ == "__main__":691    print("Starting Gradio server...")692    demo.launch()