Spaces:
Sleeping
Sleeping
| from datetime import time | |
| 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="AIzaSyDHqRXzvsVneTaeeszHOoSwBh4atyX7xKc") | |
| 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_', 'Degree_He', | |
| 'Research_C', 'Publications_', '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)}") | |
| # Update column references throughout the code | |
| faculty_df = faculty_df.rename(columns={ | |
| 'Years_of_': 'Years_of_Experience', | |
| 'Degree_He': 'Degree_Held', | |
| 'Research_C': 'Research_Count', | |
| 'Publications_': 'Publications_Count' | |
| }) | |
| # 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(), | |
| "graph": lambda df: px.bar(df, x='index', y='count', title="Count of Faculty by Department", | |
| labels={'index': '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(host='0.0.0.0', port=7860) | |