Spaces:
Runtime error
Runtime error
from datetime import time | |
import os | |
from flask import Flask, render_template, request | |
import pandas as pd | |
import plotly.express as px | |
import io | |
import base64 | |
import google.generativeai as genai | |
from collections import defaultdict | |
import numpy as np | |
import google.generativeai as genai | |
app = Flask(__name__) | |
# Configure Gemini API | |
genai.configure(api_key=os.getenv('GEMINI_API_KEY')) | |
model = genai.GenerativeModel("gemini-1.5-flash") | |
WEIGHTS = { | |
'experience': 20, | |
'degree': 20, | |
'research': 20, | |
'publication': 20, | |
'skills': 20 | |
} | |
# Ideal student-to-faculty ratio | |
IDEAL_RATIO = 20 | |
def calculate_grades(row, weights): | |
"""Function to calculate grades.""" | |
experience_grade = normalize(row['Years_of_Experience'], 0, 35) * weights['experience'] | |
degree_grade = (1 if row['Degree_Held'] in ['PhD', 'MPhil'] else 0.75) * weights['degree'] | |
research_grade = normalize(row['Research_Count'], 0, 20) * weights['research'] | |
publication_grade = normalize(row['Publications_Count'], 0, 50) * weights['publication'] | |
skills_grade = normalize(len(str(row['Skills']).split(',')), 0, 10) * weights['skills'] | |
total_grade = (experience_grade + degree_grade + research_grade + publication_grade + skills_grade) / sum(weights.values()) | |
if row['Publications_Count'] > 30: | |
total_grade += 0.05 | |
if row['Years_of_Experience'] < 2: | |
total_grade -= 0.05 | |
return min(1.0, max(0.0, total_grade)) | |
def normalize(value, min_value, max_value): | |
"""Function to normalize values.""" | |
return (value - min_value) / (max_value - min_value) if max_value - min_value != 0 else 0 | |
def generate_with_retry(query, retries=3, delay=2): | |
for attempt in range(retries): | |
try: | |
gemini_response = model.generate_content(query) | |
return gemini_response.text | |
except Exception as e: | |
if "429" in str(e) and attempt < retries - 1: | |
time.sleep(delay * (2 ** attempt)) # Correctly use time.sleep | |
else: | |
raise e | |
def perform_swot_analysis(faculty_df, teaching_responses): | |
"""Enhanced SWOT analysis based on faculty data and teaching responses.""" | |
strengths = [] | |
weaknesses = [] | |
opportunities = [] | |
threats = [] | |
# Analyze faculty data | |
avg_experience = faculty_df['Years_of_Experience'].mean() | |
avg_publications = faculty_df['Publications_Count'].mean() | |
avg_research = faculty_df['Research_Count'].mean() | |
phd_count = len(faculty_df[faculty_df['Degree_Held'] == 'PhD']) | |
phd_percentage = (phd_count / len(faculty_df)) * 100 | |
# Faculty Qualifications Analysis | |
if phd_percentage > 60: | |
strengths.append("High percentage of PhD holders ({}%)".format(round(phd_percentage))) | |
elif phd_percentage < 30: | |
weaknesses.append("Low percentage of PhD holders ({}%)".format(round(phd_percentage))) | |
opportunities.append("Encourage faculty to pursue higher education") | |
if avg_experience > 10: | |
strengths.append("Strong experienced faculty base (avg. {} years)".format(round(avg_experience))) | |
elif avg_experience < 5: | |
weaknesses.append("Relatively inexperienced faculty (avg. {} years)".format(round(avg_experience))) | |
opportunities.append("Implement mentorship programs") | |
# Research Output Analysis | |
if avg_publications > 20: | |
strengths.append("High research output through publications") | |
elif avg_publications < 10: | |
weaknesses.append("Low publication count") | |
opportunities.append("Create research incentives") | |
# Teaching Methodology Analysis | |
if teaching_responses: | |
# Course Design Analysis | |
course_revision = teaching_responses.get('course_revision', '') | |
if course_revision == 'Annually': | |
strengths.append("Regular curriculum updates") | |
elif course_revision == 'Rarely': | |
weaknesses.append("Infrequent curriculum revision") | |
threats.append("Risk of outdated curriculum") | |
# Technology Integration | |
tech_usage = teaching_responses.get('tech_usage', '') | |
if tech_usage == 'Yes': | |
strengths.append("Strong technology integration in teaching") | |
else: | |
weaknesses.append("Limited use of technology in teaching") | |
opportunities.append("Implement modern teaching technologies") | |
# Assessment Methods | |
assessment_methods = teaching_responses.get('assessment_methods', []) | |
if len(assessment_methods) >= 3: | |
strengths.append("Diverse assessment methods") | |
elif len(assessment_methods) < 2: | |
weaknesses.append("Limited assessment variety") | |
opportunities.append("Diversify assessment methods") | |
# Practical Learning | |
practical_percentage = int(teaching_responses.get('practical_percentage', 0)) | |
if practical_percentage > 50: | |
strengths.append("Strong practical learning focus") | |
elif practical_percentage < 30: | |
weaknesses.append("Limited practical exposure") | |
opportunities.append("Increase hands-on learning activities") | |
# Student Engagement | |
student_participation = int(teaching_responses.get('student_participation', 0)) | |
if student_participation > 75: | |
strengths.append("High student engagement") | |
elif student_participation < 50: | |
weaknesses.append("Low student participation") | |
opportunities.append("Implement engagement strategies") | |
# Teaching Methods | |
teaching_methods = teaching_responses.get('teaching_methods', []) | |
if len(teaching_methods) >= 3: | |
strengths.append("Diverse teaching methodologies") | |
elif len(teaching_methods) < 2: | |
weaknesses.append("Limited teaching methods") | |
opportunities.append("Expand teaching methodology") | |
# Professional Development | |
prof_dev = int(teaching_responses.get('professional_development', 0)) | |
if prof_dev > 3: | |
strengths.append("Strong commitment to professional development") | |
elif prof_dev < 2: | |
weaknesses.append("Limited professional development") | |
opportunities.append("Increase faculty development programs") | |
# Industry Relevance | |
curriculum_relevance = int(teaching_responses.get('curriculum_relevance', 0)) | |
if curriculum_relevance >= 8: | |
strengths.append("High industry relevance") | |
elif curriculum_relevance <= 5: | |
weaknesses.append("Low industry alignment") | |
threats.append("Risk of skill-industry mismatch") | |
# Add general threats | |
threats.extend([ | |
"Rapid technological changes in education", | |
"Increasing competition from online education", | |
"Changing student learning preferences" | |
]) | |
# Add general opportunities | |
opportunities.extend([ | |
"Integration of emerging technologies", | |
"Industry collaboration potential", | |
"International academic partnerships" | |
]) | |
return { | |
'strengths': strengths, | |
'weaknesses': weaknesses, | |
'opportunities': opportunities, | |
'threats': threats | |
} | |
def index(): | |
plots = {} | |
graded_csv = None | |
department_tables = {} | |
deficiency_table = None | |
departments = [] | |
swot_results=None | |
teaching_responses=None | |
gemini_insights = {} | |
if request.method == 'POST': | |
if 'faculty_file' not in request.files: | |
return render_template('index.html', error="Error: Faculty file must be uploaded.") | |
faculty_file = request.files['faculty_file'] | |
if faculty_file.filename == '': | |
return render_template('index.html', error="Error: Faculty file must be selected for upload.") | |
try: | |
# Load faculty data | |
faculty_df = pd.read_csv(faculty_file) | |
# Validate columns in faculty data | |
required_faculty_columns = {'Name', 'Department', 'Post', 'Years_of_Experience', 'Degree_Held', | |
'Research_Count', 'Publications_Count', 'Skills'} | |
missing_faculty_columns = required_faculty_columns - set(faculty_df.columns) | |
if missing_faculty_columns: | |
return render_template('index.html', | |
error=f"Error: The faculty CSV is missing the following columns: {', '.join(missing_faculty_columns)}") | |
# Calculate grades | |
faculty_df['Grade'] = faculty_df.apply(lambda row: calculate_grades(row, WEIGHTS), axis=1) | |
# Get student counts from the form | |
student_counts = {department: int(request.form.get(f'students_{department}', 0) or 0) for department in faculty_df['Department'].unique()} | |
# Separate tables for each department | |
for department in faculty_df['Department'].unique(): | |
department_data = faculty_df[faculty_df['Department'] == department] | |
department_tables[department] = { | |
'columns': department_data.columns.tolist(), | |
'rows': department_data.values.tolist() | |
} | |
departments.append(department) | |
graph_data = [ | |
{ | |
"title": "Count of Faculty by Department", | |
"data": faculty_df['Department'].value_counts().reset_index(name='count'), | |
"graph": lambda df: px.bar(df, x='Department', y='count', title="Count of Faculty by Department", | |
labels={'Department': 'Department', 'count': 'Count'}), | |
"query": "Provide insights into the distribution of faculty across departments based on this data." | |
}, | |
{ | |
"title": "Students vs Faculty by Department", | |
"data": pd.DataFrame({ | |
"Department": faculty_df['Department'].unique(), | |
"Number_of_Students": [int(request.form.get(f'students_{dep}', 0)) for dep in | |
faculty_df['Department'].unique()], | |
"Number_of_Faculty": faculty_df['Department'].value_counts().values | |
}), | |
"graph": lambda df: px.bar(df, x='Department', y=['Number_of_Students', 'Number_of_Faculty'], | |
barmode='group', | |
title="Students vs Faculty by Department"), | |
"query": "Analyze the relationship between the number of students and faculty by department based on this data." | |
}, | |
{ | |
"title": "Post vs Skills", | |
"data": faculty_df[['Post', 'Skills']].assign( | |
Skills_Count=lambda x: x['Skills'].apply(lambda y: len(str(y).split(',')))), | |
"graph": lambda df: px.scatter(df, x='Post', y='Skills_Count', title="Post vs Skills"), | |
"query": "Explain the relationship between Post and Skills based on this data." | |
}, | |
{ | |
"title": "Degree vs Publications", | |
"data": faculty_df[['Degree_Held', 'Publications_Count']], | |
"graph": lambda df: px.box(df, x='Degree_Held', y='Publications_Count', | |
title="Degree vs Publications", color='Degree_Held'), | |
"query": "Describe the distribution of publications by degree based on this data." | |
}, | |
{ | |
"title": "Department-wise Faculty Count by Degree", | |
"data": faculty_df.groupby(['Department', 'Degree_Held']).size().reset_index(name='Count'), | |
"graph": lambda df: px.bar(df, x='Department', y='Count', color='Degree_Held', barmode='group', | |
title="Department-wise Faculty Count by Degree"), | |
"query": "What can we infer about the qualifications of faculty across departments from this data?" | |
}, | |
{ | |
"title": "Experience Distribution by Degree", | |
"data": faculty_df[['Degree_Held', 'Years_of_Experience']], | |
"graph": lambda df: px.violin(df, x='Degree_Held', y='Years_of_Experience', | |
title="Experience Distribution by Degree", | |
color='Degree_Held'), | |
"query": "Analyze the distribution of experience across different degree levels using this data." | |
}, | |
{ | |
"title": "Research Count by Department", | |
"data": faculty_df.groupby('Department')['Research_Count'].sum().reset_index(), | |
"graph": lambda df: px.bar(df, x='Department', y='Research_Count', | |
title="Research Count by Department"), | |
"query": "What insights can be drawn about the research output of each department based on this data?" | |
}, | |
{ | |
"title": "Publications Count by Department", | |
"data": faculty_df.groupby('Department')['Publications_Count'].sum().reset_index(), | |
"graph": lambda df: px.bar(df, x='Department', y='Publications_Count', | |
title="Publications Count by Department"), | |
"query": "Describe the publication trends across departments using this data." | |
}, | |
{ | |
"title": "Skills Count by Department", | |
"data": faculty_df.groupby('Department').apply( | |
lambda x: x['Skills'].apply(lambda y: len(str(y).split(','))).sum() | |
).reset_index(name='Skills_Count'), | |
"graph": lambda df: px.bar(df, x='Department', y='Skills_Count', | |
title="Skills Count by Department"), | |
"query": "Explain the distribution of skills among faculty across different departments based on this data." | |
}, | |
{ | |
"title": "Grades Distribution", | |
"data": faculty_df[['Department', 'Grade']], | |
"graph": lambda df: px.box(df, x='Department', y='Grade', title="Grades Distribution by Department", | |
color='Department'), | |
"query": "What insights can we infer from the grades distribution of faculty across departments?" | |
}, | |
{ | |
"title": "Experience vs Publications", | |
"data": faculty_df[['Years_of_Experience', 'Publications_Count']], | |
"graph": lambda df: px.scatter(df, x='Years_of_Experience', y='Publications_Count', | |
title="Experience vs Publications", | |
labels={'Years_of_Experience': 'Years of Experience', | |
'Publications_Count': 'Publications Count'}), | |
"query": "Analyze the relationship between years of experience and the number of publications based on this data." | |
}, | |
{ | |
"title": "Top Departments by Research", | |
"data": faculty_df.groupby('Department')['Research_Count'].sum().reset_index().sort_values( | |
by='Research_Count', ascending=False).head(5), | |
"graph": lambda df: px.bar(df, x='Department', y='Research_Count', | |
title="Top 5 Departments by Research Output"), | |
"query": "Identify the top departments by research output and analyze their characteristics." | |
} | |
] | |
for graph in graph_data: | |
# Generate the graph | |
graph_df = graph["data"] | |
fig = graph["graph"](graph_df) | |
plot_html = fig.to_html(full_html=False) | |
plots[graph["title"]] = plot_html | |
# Prepare the query for Gemini | |
query = ( | |
f"{graph['query']}\n\n" | |
"Data:\n" | |
f"{graph_df.to_csv(index=False)}\n\n" | |
"Provide a concise summary in 100 words, formatted without special characters like '*'. " | |
"Use proper sentences and highlight key points using **bold text**." | |
) | |
# Use retry logic for Gemini API | |
try: | |
gemini_response = generate_with_retry(query) | |
raw_text = gemini_response.replace('*', '').strip() | |
# Truncate if necessary | |
if len(raw_text) > 150: | |
raw_text = raw_text[:147].rsplit(' ', 1)[0] + "..." | |
gemini_insights[graph["title"]] = raw_text | |
except Exception as e: | |
gemini_insights[graph["title"]] = f"Error generating insight: {str(e)}" | |
# Move all faculty_counts calculations inside the try block | |
faculty_counts = faculty_df['Department'].value_counts().reset_index() | |
faculty_counts.columns = ['Department', 'Number_of_Faculty'] | |
# Map number of students | |
faculty_counts['Number_of_Students'] = faculty_counts['Department'].map(student_counts) | |
# Calculate ideal numbers based on S (students), R=9 (1+2+6) | |
faculty_counts['Total_Ideal_Faculty'] = (faculty_counts['Number_of_Students'] / IDEAL_RATIO).apply( | |
lambda x: int(x) if x.is_integer() else int(x) + 1 | |
) | |
# Role-specific ideal faculty counts | |
faculty_counts['Ideal_Principal'] = 1 # Always 1 | |
faculty_counts['Ideal_Professor'] = (faculty_counts['Number_of_Students'] * 1 / (20 * 9)).apply( | |
lambda x: int(x) if x.is_integer() else int(x) + 1 | |
) | |
faculty_counts['Ideal_Associate_Professor'] = (faculty_counts['Number_of_Students'] * 2 / (20 * 9)).apply( | |
lambda x: int(x) if x.is_integer() else int(x) + 1 | |
) | |
faculty_counts['Ideal_Assistant_Professor'] = (faculty_counts['Number_of_Students'] * 6 / (20 * 9)).apply( | |
lambda x: int(x) if x.is_integer() else int(x) + 1 | |
) | |
# Calculate deficiencies for each role | |
faculty_counts['Deficiency_Principal'] = faculty_counts['Ideal_Principal'] - faculty_df[ | |
faculty_df['Post'] == 'Principal'].groupby('Department')['Post'].count().reindex(faculty_counts['Department']).fillna(0).astype(int) | |
faculty_counts['Deficiency_Professor'] = faculty_counts['Ideal_Professor'] - faculty_df[ | |
faculty_df['Post'] == 'Professor'].groupby('Department')['Post'].count().reindex(faculty_counts['Department']).fillna(0).astype(int) | |
faculty_counts['Deficiency_Associate_Professor'] = faculty_counts['Ideal_Associate_Professor'] - faculty_df[ | |
faculty_df['Post'] == 'Associate Professor'].groupby('Department')['Post'].count().reindex(faculty_counts['Department']).fillna(0).astype(int) | |
faculty_counts['Deficiency_Assistant_Professor'] = faculty_counts['Ideal_Assistant_Professor'] - faculty_df[ | |
faculty_df['Post'] == 'Assistant Professor'].groupby('Department')['Post'].count().reindex(faculty_counts['Department']).fillna(0).astype(int) | |
# Overall deficiency | |
faculty_counts['Meets_Ratio'] = (faculty_counts['Deficiency_Principal'] <= 0) & \ | |
(faculty_counts['Deficiency_Professor'] <= 0) & \ | |
(faculty_counts['Deficiency_Associate_Professor'] <= 0) & \ | |
(faculty_counts['Deficiency_Assistant_Professor'] <= 0) | |
faculty_counts['Meets_Ratio'] = faculty_counts['Meets_Ratio'].apply(lambda x: "✔️" if x else "❌") | |
# Prepare the final deficiency table | |
deficiency_table = faculty_counts[[ | |
'Department', 'Number_of_Students', 'Number_of_Faculty', | |
'Ideal_Principal', 'Ideal_Professor', 'Ideal_Associate_Professor', 'Ideal_Assistant_Professor', | |
'Deficiency_Principal', 'Deficiency_Professor', 'Deficiency_Associate_Professor', 'Deficiency_Assistant_Professor', | |
'Meets_Ratio']].to_html(classes="table table-bordered table-hover", index=False, escape=False) | |
# Encode graded CSV | |
csv_output = io.BytesIO() | |
faculty_df.to_csv(csv_output, index=False) | |
csv_output.seek(0) | |
graded_csv = base64.b64encode(csv_output.getvalue()).decode() | |
# Collect teaching evaluation responses | |
teaching_responses = { | |
'course_revision': request.form.get('course_revision', ''), | |
'case_studies': request.form.get('case_studies', ''), | |
'assessment_methods': request.form.getlist('assessment_methods') or [], | |
'practical_percentage': int(request.form.get('practical_percentage', 0) or 0), | |
'curriculum_relevance': int(request.form.get('curriculum_relevance', 0) or 0), | |
'interactive_sessions': request.form.get('interactive_sessions', ''), | |
'student_participation': int(request.form.get('student_participation', 0) or 0), | |
'personalized_feedback': request.form.get('personalized_feedback', ''), | |
'student_interest': request.form.get('student_interest', ''), | |
'tech_usage': request.form.get('tech_usage', ''), | |
'teaching_methods': request.form.getlist('teaching_methods') or [], | |
'critical_thinking': request.form.get('critical_thinking', ''), | |
'student_feedback': request.form.get('student_feedback', ''), | |
'feedback_actions': request.form.get('feedback_actions', ''), | |
'professional_development': int(request.form.get('professional_development', 0) or 0) | |
} | |
# Perform SWOT analysis | |
swot_results = perform_swot_analysis(faculty_df, teaching_responses) | |
except Exception as e: | |
return render_template('index.html', error=f"An unexpected error occurred: {str(e)}") | |
return render_template('index.html', | |
plots=plots, | |
graded_csv=graded_csv, | |
department_tables=department_tables, | |
departments=departments, | |
deficiency_table=deficiency_table, | |
gemini_insights=gemini_insights, | |
swot_results=swot_results, | |
teaching_responses=teaching_responses) | |
if __name__ == '__main__': | |
app.run(debug=True, port=5632) | |