EduTechTeam's picture
Update app.py
3ddbbfc verified
import pandas as pd
import numpy as np
import gradio as gr
import os
def process_admissions(file_path, capacity=120):
"""
Loads, filters, and processes student admission data based on defined rules.
Args:
file_path (str): The path to the CSV file containing the student data.
capacity (int): The maximum number of students to admit.
Returns:
tuple: A tuple containing:
- pd.DataFrame: A DataFrame containing all students with admission status ('正取' or '備取'),
or an empty DataFrame if an error occurred or no valid data.
- str: The file path to the saved CSV, or None if an error occurred or no valid data.
"""
try:
df = pd.read_csv(file_path)
print("DataFrame loaded successfully.")
if df is not None:
# Filter out rows where any column contains '未填報-未填寫'
df_filtered = df[~(df == '未填報-未填寫').any(axis=1)].copy()
print(f"DataFrame after filtering: {len(df_filtered)} rows remaining.")
if df_filtered.empty:
print("No valid entries found after filtering.")
return pd.DataFrame(), None
# Shuffle the filtered DataFrame to ensure random selection within priority groups
#df_shuffled = df_filtered.sample(frac=1, random_state=42).reset_index(drop=True)
df_shuffled = df_filtered.sample(frac=1).reset_index(drop=True)
admitted_students_list = []
remaining_df = df_shuffled.copy()
# Prioritize one person per institution, up to capacity
first_admissions_indices = remaining_df.groupby('機關名稱').head(1).index
num_first_admissions = min(len(first_admissions_indices), capacity)
admitted_students_list.append(remaining_df.loc[first_admissions_indices[:num_first_admissions]])
remaining_df = remaining_df.drop(first_admissions_indices[:num_first_admissions])
# Prioritize a second person per institution if capacity permits
current_admitted_count = sum(len(df) for df in admitted_students_list)
if current_admitted_count < capacity:
second_admissions_indices = remaining_df.groupby('機關名稱').head(1).index
additional_capacity = capacity - current_admitted_count
num_second_admissions = min(len(second_admissions_indices), additional_capacity)
admitted_students_list.append(remaining_df.loc[second_admissions_indices[:num_second_admissions]])
remaining_df = remaining_df.drop(second_admissions_indices[:num_second_admissions])
# Allow more if capacity permits, up to the total capacity
current_admitted_count = sum(len(df) for df in admitted_students_list)
if current_admitted_count < capacity:
additional_capacity = capacity - current_admitted_count
additional_admissions_indices = remaining_df.head(additional_capacity).index
admitted_students_list.append(remaining_df.loc[additional_admissions_indices])
remaining_df = remaining_df.drop(additional_admissions_indices)
# Combine all selected students and drop duplicates
admitted_df = pd.concat(admitted_students_list).drop_duplicates().reset_index(drop=True)
# Assign '正取' status and order
if not admitted_df.empty:
admitted_df['錄取順序'] = [f'正取{i+1}' for i in range(len(admitted_df))]
# Assign '備取' status to the remaining students
if not remaining_df.empty:
remaining_df['錄取順序'] = [f'備取{i+1}' for i in range(len(remaining_df))]
else:
remaining_df['錄取順序'] = [] # Ensure column exists even if empty
# Combine admitted and remaining students
final_df = pd.concat([admitted_df, remaining_df]).reset_index(drop=True)
print("Final Student List with Admission Status:")
print(final_df.head()) # 用 print 輸出前幾列
print("\nFinal Student List Info:")
print(final_df.info()) # 仍然可以看 info,用 print 包住就好
# Save the processed DataFrame to a temporary CSV file
output_csv_path = "admitted_students_processed.csv"
final_df.to_csv(output_csv_path, index=False, encoding='utf-8-sig')
print(f"Processed data saved to {output_csv_path}")
return final_df, output_csv_path
else:
print("DataFrame not loaded. Cannot perform processing.")
return pd.DataFrame(), None
except FileNotFoundError:
print(f"Error: '{file_path}' not found. Please ensure the file is in the correct directory.")
return pd.DataFrame(), None
except Exception as e:
print(f"An error occurred during processing: {e}")
return pd.DataFrame(), None
# Assuming process_admissions is defined and available in the environment
# It should return a tuple: (DataFrame, file_path)
def process_admissions_and_return_df_and_file(file_path, capacity):
"""
Processes student admission data and returns the DataFrame and the path to the saved CSV.
Args:
file_path (str): The path to the uploaded CSV file.
capacity (int): The maximum number of students to admit.
Returns:
tuple: A tuple containing:
- pd.DataFrame: The processed DataFrame (including 正取 and 備取).
- str: The file path to the saved CSV, or None if processing failed.
"""
final_df, output_csv_path = process_admissions(file_path, capacity) # Call process_admissions which returns final_df and path
return final_df, output_csv_path # Return final_df and path
if 'process_admissions' in locals():
# Define the Gradio interface
interface = gr.Interface(
fn=process_admissions_and_return_df_and_file,
inputs=[
gr.File(label="Upload CSV File"),
gr.Number(label="Admission Capacity", value=120, precision=0) # Add number input for capacity
],
outputs=[
gr.Dataframe(label="Admitted Students List"), # Changed label to reflect it includes all students
gr.File(label="Download Admitted Students CSV")
],
title="Student Admission Processing",
description="Upload a CSV file to process student admissions based on institutional priority and capacity, and get a list with admission order and a downloadable CSV."
)
print("Gradio interface designed with capacity input.")
else:
print("The 'process_admissions' function is not defined. Please ensure the data processing logic is defined in a previous step.")
if 'interface' in locals():
print("Launching Gradio interface...")
interface.launch(debug=True, share=False)
else:
print("Gradio interface not found. Please ensure the previous steps were executed successfully.")