| import gradio as gr |
| import pandas as pd |
| from datetime import datetime |
| import os |
|
|
| |
| COLUMNS = ['timestamp', 'judge_name', 'team_name', 'go_live', 'usefulness', 'taste', 'problem_statement'] |
|
|
| if not os.path.exists('scores.csv'): |
| |
| df = pd.DataFrame(columns=COLUMNS) |
| |
| df.to_csv('scores.csv', index=False, mode='w') |
| elif os.path.getsize('scores.csv') == 0: |
| |
| pd.DataFrame(columns=COLUMNS).to_csv('scores.csv', index=False, mode='w') |
|
|
| def calculate_final_score(go_live, usefulness, taste, problem_statement): |
| |
| final_score = ( |
| (go_live * 0.30) + |
| (usefulness * 0.30) + |
| (taste * 0.20) + |
| (problem_statement * 0.20) |
| ) * 20 |
| return round(final_score, 2) |
|
|
| def submit_score(judge_name, team_name, go_live, usefulness, taste, problem_statement): |
| if not judge_name.strip(): |
| return "Please enter your name!", judge_name |
| if not team_name: |
| return "Please select a team!", judge_name |
| |
| try: |
| |
| try: |
| scores_df = pd.read_csv('scores.csv') |
| except pd.errors.EmptyDataError: |
| scores_df = pd.DataFrame(columns=COLUMNS) |
| |
| |
| scores = [go_live, usefulness, taste, problem_statement] |
| if any(score < 0 or score > 5 for score in scores): |
| return "All scores must be between 0 and 5!", judge_name |
| |
| |
| if len(scores_df) > 0: |
| duplicate = scores_df[ |
| (scores_df['judge_name'].str.lower() == judge_name.strip().lower()) & |
| (scores_df['team_name'] == team_name) |
| ] |
| if not duplicate.empty: |
| |
| scores_df = scores_df[ |
| ~((scores_df['judge_name'].str.lower() == judge_name.strip().lower()) & |
| (scores_df['team_name'] == team_name)) |
| ] |
| |
| |
| new_score = { |
| 'timestamp': datetime.now().strftime("%Y-%m-%d %H:%M:%S"), |
| 'judge_name': judge_name.strip(), |
| 'team_name': team_name.strip(), |
| 'go_live': go_live, |
| 'usefulness': usefulness, |
| 'taste': taste, |
| 'problem_statement': problem_statement |
| } |
| |
| scores_df = pd.concat([scores_df, pd.DataFrame([new_score])], ignore_index=True) |
| scores_df.to_csv('scores.csv', index=False) |
| |
| return f"✅ Score submitted successfully for team {team_name}!", judge_name |
| |
| except Exception as e: |
| return f"Error submitting score: {str(e)}", judge_name |
|
|
| def generate_report(): |
| try: |
| scores_df = pd.read_csv('scores.csv') |
| if len(scores_df) == 0: |
| return "No scores submitted yet!" |
| |
| |
| team_stats = scores_df.groupby('team_name').agg({ |
| 'judge_name': 'count', |
| 'go_live': 'mean', |
| 'usefulness': 'mean', |
| 'taste': 'mean', |
| 'problem_statement': 'mean' |
| }).round(2) |
| |
| team_stats.rename(columns={'judge_name': 'num_judges'}, inplace=True) |
| |
| |
| team_stats['final_score'] = team_stats.apply( |
| lambda x: calculate_final_score(x['go_live'], x['usefulness'], x['taste'], x['problem_statement']), |
| axis=1 |
| ) |
| |
| |
| team_stats = team_stats.sort_values('final_score', ascending=False) |
| |
| |
| report = "🏆 HACKATHON FINAL RANKINGS 🏆\n" |
| report += "=" * 40 + "\n\n" |
| |
| for idx, (team, stats) in enumerate(team_stats.iterrows(), 1): |
| medal = "🥇" if idx == 1 else "🥈" if idx == 2 else "🥉" if idx == 3 else " " |
| |
| report += f"{medal} Rank #{idx}: {team}\n" |
| report += "─" * 40 + "\n" |
| report += f"📊 FINAL SCORE: {stats['final_score']:.1f}/100" |
| report += f" (Scored by {int(stats['num_judges'])} judge{'s' if stats['num_judges'] > 1 else ''})\n\n" |
| |
| |
| report += "Detailed Scores:\n" |
| |
| |
| bar_length = int(stats['go_live'] * 4) |
| report += f"Go Live (30%): {stats['go_live']}/5 {'█' * bar_length}{'░' * (20-bar_length)}\n" |
| |
| |
| bar_length = int(stats['usefulness'] * 4) |
| report += f"Usefulness (30%): {stats['usefulness']}/5 {'█' * bar_length}{'░' * (20-bar_length)}\n" |
| |
| |
| bar_length = int(stats['taste'] * 4) |
| report += f"Taste (20%): {stats['taste']}/5 {'█' * bar_length}{'░' * (20-bar_length)}\n" |
| |
| |
| bar_length = int(stats['problem_statement'] * 4) |
| report += f"Problem Stmt (20%): {stats['problem_statement']}/5 {'█' * bar_length}{'░' * (20-bar_length)}\n" |
| |
| report += "\n" + "=" * 40 + "\n\n" |
| |
| |
| report += f"Total Teams Evaluated: {len(team_stats)}\n" |
| report += f"Total Scores Submitted: {len(scores_df)}\n" |
| report += f"Number of Judges: {scores_df['judge_name'].nunique()}\n" |
| report += f"Average Score: {team_stats['final_score'].mean():.1f}/100\n" |
| report += f"Highest Score: {team_stats['final_score'].max():.1f}/100\n" |
| |
| |
| unscored_teams = set(TEAM_NAMES) - set(team_stats.index) |
| if unscored_teams: |
| report += "\nTeams Not Yet Scored:\n" |
| for team in sorted(unscored_teams): |
| report += f"• {team}\n" |
| |
| return report |
| |
| except Exception as e: |
| return f"Error generating report: {str(e)}" |
|
|
| |
| TEAM_NAMES = [ |
| "tehlaninayan7", |
| "kya@karu.mai", |
| "Sugarplum", |
| "Bob the Builders AI", |
| "permissionless", |
| "LLM Ninjas", |
| "MailMatch", |
| "Ironold", |
| "ChaiBiscuit", |
| "Dostwriter", |
| "Neural Babel", |
| "Fluid", |
| "Team 1", |
| "fiction AI", |
| "SOLOYOLO" |
| ] |
|
|
| |
| with gr.Blocks(title="Hackathon Judge", theme=gr.themes.Soft()) as app: |
| gr.Markdown( |
| """ |
| # 🏆 Hackathon Judging System |
| ### Welcome to the hackathon judging portal! |
| Please enter your details and scores below. |
| """ |
| ) |
| |
| with gr.Group(visible=True): |
| with gr.Row(): |
| with gr.Column(scale=1): |
| judge_name = gr.Textbox( |
| label="Judge Name", |
| placeholder="Enter your name", |
| elem_classes="input-field" |
| ) |
| with gr.Column(scale=1): |
| team_name = gr.Dropdown( |
| label="Team Name", |
| choices=TEAM_NAMES, |
| elem_classes="input-field" |
| ) |
| |
| gr.Markdown( |
| """ |
| ### Scoring Criteria |
| Please rate each criterion on a scale of 0-5 |
| """ |
| ) |
| |
| with gr.Group(visible=True): |
| with gr.Row(): |
| with gr.Column(): |
| go_live = gr.Slider( |
| minimum=0, |
| maximum=5, |
| step=1, |
| label="Go Live Score (30%)", |
| info="Rate the project's completion and deployment readiness", |
| value=0 |
| ) |
| usefulness = gr.Slider( |
| minimum=0, |
| maximum=5, |
| step=1, |
| label="Usefulness Score (30%)", |
| info="Rate how useful and practical the solution is", |
| value=0 |
| ) |
| with gr.Column(): |
| taste = gr.Slider( |
| minimum=0, |
| maximum=5, |
| step=1, |
| label="Taste Score (20%)", |
| info="Rate the vibe and overall presentation", |
| value=0 |
| ) |
| problem_statement = gr.Slider( |
| minimum=0, |
| maximum=5, |
| step=1, |
| label="Problem Statement Score (20%)", |
| info="Rate how well impactful the problem statement is", |
| value=0 |
| ) |
| |
| with gr.Row(): |
| submit_btn = gr.Button("Submit Scores", variant="primary", scale=2) |
| report_btn = gr.Button("Generate Report", variant="secondary", scale=1) |
| |
| submit_output = gr.Textbox(label="Submission Status", show_label=False) |
| |
| gr.Markdown("### 📊 Final Rankings") |
| report_output = gr.Textbox( |
| label="Final Report", |
| show_label=False, |
| lines=10, |
| container=True |
| ) |
| |
| |
| submit_btn.click( |
| submit_score, |
| inputs=[judge_name, team_name, go_live, usefulness, taste, problem_statement], |
| outputs=[submit_output, judge_name] |
| ) |
| |
| report_btn.click( |
| generate_report, |
| inputs=[], |
| outputs=report_output |
| ) |
| |
| |
| gr.Markdown( |
| """ |
| <style> |
| .gradio-container { |
| font-family: 'Inter', sans-serif; |
| background: linear-gradient(to bottom right, #1a0000, #400000); |
| color: #ffe2e2; |
| } |
| |
| .input-field { |
| border-radius: 8px; |
| background-color: rgba(255, 255, 255, 0.05) !important; |
| border: 1px solid rgba(255, 0, 0, 0.1) !important; |
| color: #fff !important; |
| } |
| |
| .gr-group { |
| border-radius: 16px; |
| background-color: rgba(255, 0, 0, 0.05); |
| border: 1px solid rgba(255, 0, 0, 0.1); |
| padding: 24px; |
| margin: 15px 0; |
| backdrop-filter: blur(10px); |
| box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); |
| } |
| |
| .gr-button { |
| border-radius: 8px; |
| margin: 10px 0; |
| transition: transform 0.2s, box-shadow 0.2s; |
| } |
| |
| .gr-button:hover { |
| transform: translateY(-2px); |
| box-shadow: 0 4px 12px rgba(255, 0, 0, 0.2); |
| } |
| |
| .gr-button.primary { |
| background: linear-gradient(135deg, #ff0000, #cc0000); |
| border: none; |
| } |
| |
| .gr-button.secondary { |
| background: rgba(255, 0, 0, 0.1); |
| border: 1px solid rgba(255, 0, 0, 0.2); |
| } |
| |
| .gr-form { |
| gap: 20px; |
| } |
| |
| /* Slider styling */ |
| .gr-slider { |
| background-color: rgba(255, 0, 0, 0.1); |
| } |
| |
| .gr-slider .handle { |
| background: #ff0000; |
| box-shadow: 0 0 10px rgba(255, 0, 0, 0.5); |
| } |
| |
| .gr-slider .track { |
| background: linear-gradient(90deg, #ff0000, #cc0000); |
| } |
| |
| /* Text elements */ |
| h1, h2, h3 { |
| color: #fff !important; |
| text-shadow: 0 2px 4px rgba(255, 0, 0, 0.2); |
| } |
| |
| .gr-markdown { |
| color: #ffe2e2 !important; |
| } |
| |
| /* Report output styling */ |
| .gr-textbox { |
| background-color: rgba(255, 0, 0, 0.05) !important; |
| border: 1px solid rgba(255, 0, 0, 0.1) !important; |
| color: #fff !important; |
| font-family: 'Courier New', monospace; |
| } |
| |
| /* Labels */ |
| label { |
| color: #ffe2e2 !important; |
| } |
| |
| /* Info text */ |
| .info { |
| color: #ffb3b3 !important; |
| } |
| |
| /* Dropdown styling */ |
| .gr-dropdown { |
| background-color: rgba(255, 0, 0, 0.05) !important; |
| border: 1px solid rgba(255, 0, 0, 0.1) !important; |
| color: #fff !important; |
| border-radius: 8px; |
| } |
| |
| .gr-dropdown:focus { |
| border-color: rgba(255, 0, 0, 0.3) !important; |
| } |
| |
| .gr-dropdown option { |
| background-color: #1a0000; |
| color: #fff; |
| } |
| </style> |
| """ |
| ) |
|
|
| if __name__ == "__main__": |
| app.launch(share=True) |