import gradio as gr import pandas as pd import matplotlib.pyplot as plt import numpy as np from datetime import datetime import io import base64 from transformers import pipeline from reportlab.lib.pagesizes import letter, A4 from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Image, Table, TableStyle, PageBreak from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.lib.units import inch from reportlab.lib import colors from reportlab.lib.enums import TA_CENTER, TA_JUSTIFY, TA_LEFT import tempfile import os import warnings warnings.filterwarnings("ignore") # Initialize the AI model for text generation try: # Using a smaller, efficient model that works well on HF Spaces generator = pipeline( "text-generation", model="microsoft/DialoGPT-medium", pad_token_id=50256 ) except Exception as e: print(f"Model loading error: {e}") generator = None def calculate_metrics(quiz_scores, assignment_scores, participation_score): """Calculate key performance metrics""" quiz_avg = np.mean(quiz_scores) if quiz_scores else 0 assignment_avg = np.mean(assignment_scores) if assignment_scores else 0 overall_avg = (quiz_avg * 0.4 + assignment_avg * 0.4 + participation_score * 0.2) # Determine grade letter if overall_avg >= 97: grade = "A+" elif overall_avg >= 93: grade = "A" elif overall_avg >= 90: grade = "A-" elif overall_avg >= 87: grade = "B+" elif overall_avg >= 83: grade = "B" elif overall_avg >= 80: grade = "B-" elif overall_avg >= 77: grade = "C+" elif overall_avg >= 73: grade = "C" elif overall_avg >= 70: grade = "C-" elif overall_avg >= 67: grade = "D+" elif overall_avg >= 65: grade = "D" else: grade = "F" return { 'quiz_avg': round(quiz_avg, 1), 'assignment_avg': round(assignment_avg, 1), 'overall_avg': round(overall_avg, 1), 'grade': grade } def analyze_performance(metrics, quiz_scores, assignment_scores): """Analyze performance patterns and generate insights""" strengths = [] improvements = [] # Analyze quiz vs assignment performance if metrics['assignment_avg'] > metrics['quiz_avg'] + 5: improvements.append("Quiz performance under timed conditions") strengths.append("Consistent assignment quality and preparation") elif metrics['quiz_avg'] > metrics['assignment_avg'] + 5: strengths.append("Strong performance under pressure") improvements.append("Assignment completion and thoroughness") # Analyze score consistency if quiz_scores: quiz_std = np.std(quiz_scores) if quiz_std < 5: strengths.append("Consistent quiz performance") elif quiz_std > 15: improvements.append("Score consistency and preparation routine") # Overall performance analysis if metrics['overall_avg'] >= 90: strengths.append("Excellent overall academic performance") elif metrics['overall_avg'] >= 80: strengths.append("Strong understanding of course material") else: improvements.append("Fundamental concept mastery") return strengths[:3], improvements[:3] # Limit to top 3 each def generate_ai_insights(student_name, subject, metrics, strengths, improvements): """Generate AI-powered insights and recommendations""" # Fallback insights if AI model fails fallback_insights = { 'strengths_text': f"{student_name} demonstrates solid academic foundation with a {metrics['grade']} average. Strong areas include consistent study habits and course engagement.", 'recommendations': [ "Continue maintaining current study schedule and habits", "Focus on areas showing lower performance for improvement", "Seek additional help or resources for challenging topics", "Practice active recall and spaced repetition techniques" ] } if not generator: return fallback_insights try: # Create prompts for AI generation strengths_prompt = f"Student {student_name} in {subject} shows strengths in: {', '.join(strengths)}. Explain these strengths briefly:" # Generate insights (simplified for demo) strengths_response = generator( strengths_prompt, max_length=150, num_return_sequences=1, temperature=0.7, pad_token_id=50256 ) recommendations = [ f"Focus on improving {improvements[0] if improvements else 'fundamental concepts'}", f"Build upon strength in {strengths[0] if strengths else 'current performance level'}", "Establish regular study schedule with consistent review sessions", "Seek additional practice in areas showing room for growth" ] return { 'strengths_text': strengths_response[0]['generated_text'][:200] + "...", 'recommendations': recommendations } except Exception as e: print(f"AI generation error: {e}") return fallback_insights def create_performance_chart(metrics, save_path=None): """Create a simple performance visualization""" categories = ['Quiz Average', 'Assignment Average', 'Participation', 'Overall'] scores = [metrics['quiz_avg'], metrics['assignment_avg'], metrics.get('participation', 0), metrics['overall_avg']] fig, ax = plt.subplots(figsize=(10, 6)) bars = ax.bar(categories, scores, color=['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4']) # Add value labels on bars for bar, score in zip(bars, scores): height = bar.get_height() ax.text(bar.get_x() + bar.get_width()/2., height + 1, f'{score:.1f}%', ha='center', va='bottom', fontweight='bold') ax.set_ylim(0, 100) ax.set_ylabel('Score (%)', fontweight='bold') ax.set_title('Performance Overview', fontsize=16, fontweight='bold', pad=20) ax.grid(axis='y', alpha=0.3) # Color code based on performance for i, (bar, score) in enumerate(zip(bars, scores)): if score >= 90: bar.set_color('#2ECC71') # Green elif score >= 80: bar.set_color('#F39C12') # Orange else: bar.set_color('#E74C3C') # Red plt.tight_layout() # Save chart if path provided if save_path: plt.savefig(save_path, dpi=300, bbox_inches='tight') return fig def create_pdf_report(student_name, subject, time_period, metrics, strengths, improvements, insights, participation_score, additional_notes="", chart_path=None): """Generate a comprehensive PDF report""" # Create temporary PDF file temp_pdf = tempfile.NamedTemporaryFile(delete=False, suffix='.pdf') pdf_path = temp_pdf.name temp_pdf.close() # Create PDF document doc = SimpleDocTemplate(pdf_path, pagesize=A4, rightMargin=72, leftMargin=72, topMargin=72, bottomMargin=18) # Get styles styles = getSampleStyleSheet() # Custom styles title_style = ParagraphStyle( 'CustomTitle', parent=styles['Heading1'], fontSize=24, spaceAfter=30, alignment=TA_CENTER, textColor=colors.darkblue ) heading_style = ParagraphStyle( 'CustomHeading', parent=styles['Heading2'], fontSize=16, spaceAfter=12, spaceBefore=20, textColor=colors.darkblue ) subheading_style = ParagraphStyle( 'CustomSubheading', parent=styles['Heading3'], fontSize=14, spaceAfter=8, spaceBefore=12, textColor=colors.darkgreen ) body_style = ParagraphStyle( 'CustomBody', parent=styles['Normal'], fontSize=11, spaceAfter=6, alignment=TA_JUSTIFY ) # Build PDF content story = [] # Title story.append(Paragraph("📊 Student Performance Report", title_style)) story.append(Spacer(1, 12)) # Student Information Table student_data = [ ['Student Name:', student_name], ['Subject/Course:', subject], ['Reporting Period:', time_period], ['Report Generated:', datetime.now().strftime('%B %d, %Y')], ['Generated By:', 'Scoreazy AI Agent'] ] student_table = Table(student_data, colWidths=[2*inch, 4*inch]) student_table.setStyle(TableStyle([ ('BACKGROUND', (0, 0), (0, -1), colors.lightblue), ('TEXTCOLOR', (0, 0), (0, -1), colors.darkblue), ('ALIGN', (0, 0), (-1, -1), 'LEFT'), ('FONTNAME', (0, 0), (0, -1), 'Helvetica-Bold'), ('FONTNAME', (1, 0), (1, -1), 'Helvetica'), ('FONTSIZE', (0, 0), (-1, -1), 12), ('GRID', (0, 0), (-1, -1), 1, colors.black), ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'), ])) story.append(student_table) story.append(Spacer(1, 20)) # Performance Summary story.append(Paragraph("📈 Performance Summary", heading_style)) performance_data = [ ['Metric', 'Score', 'Grade'], ['Overall Performance', f"{metrics['overall_avg']}%", metrics['grade']], ['Quiz Average', f"{metrics['quiz_avg']}%", ''], ['Assignment Average', f"{metrics['assignment_avg']}%", ''], ['Participation Score', f"{participation_score}%", ''] ] performance_table = Table(performance_data, colWidths=[2.5*inch, 1.5*inch, 1*inch]) performance_table.setStyle(TableStyle([ ('BACKGROUND', (0, 0), (-1, 0), colors.darkblue), ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke), ('ALIGN', (0, 0), (-1, -1), 'CENTER'), ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'), ('FONTNAME', (0, 1), (-1, -1), 'Helvetica'), ('FONTSIZE', (0, 0), (-1, -1), 11), ('GRID', (0, 0), (-1, -1), 1, colors.black), ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'), ('BACKGROUND', (0, 1), (-1, -1), colors.beige), ])) story.append(performance_table) story.append(Spacer(1, 20)) # Add chart if available if chart_path and os.path.exists(chart_path): story.append(Paragraph("📊 Performance Visualization", heading_style)) chart_img = Image(chart_path, width=6*inch, height=3.6*inch) story.append(chart_img) story.append(Spacer(1, 20)) # Strengths Section story.append(Paragraph("✅ Identified Strengths", heading_style)) for i, strength in enumerate(strengths, 1): story.append(Paragraph(f"{i}. {strength.title()}", subheading_style)) story.append(Paragraph(f"Student demonstrates consistent performance and understanding in this area, " f"showing mastery of key concepts and skills.", body_style)) story.append(Spacer(1, 8)) # Areas for Improvement story.append(Paragraph("⚠️ Areas for Improvement", heading_style)) for i, improvement in enumerate(improvements, 1): story.append(Paragraph(f"{i}. {improvement.title()}", subheading_style)) story.append(Paragraph(f"This area presents opportunities for growth and enhanced learning outcomes. " f"Focused attention in this area will yield significant improvements.", body_style)) story.append(Spacer(1, 8)) # Recommendations story.append(Paragraph("🎯 Personalized Recommendations", heading_style)) for i, rec in enumerate(insights['recommendations'], 1): story.append(Paragraph(f"{i}. {rec}", body_style)) story.append(Spacer(1, 6)) # Additional Notes if additional_notes: story.append(Spacer(1, 20)) story.append(Paragraph("📝 Additional Notes", heading_style)) story.append(Paragraph(additional_notes, body_style)) # Next Steps story.append(Spacer(1, 20)) story.append(Paragraph("📅 Next Steps", heading_style)) next_steps = [ "Review this report with student and parent/guardian", "Monitor progress on recommended improvement areas over the next 2-3 weeks", "Schedule follow-up assessment to track improvement", "Continue building on identified strengths through advanced challenges", "Implement suggested study strategies and learning techniques" ] for step in next_steps: story.append(Paragraph(f"• {step}", body_style)) story.append(Spacer(1, 4)) # Footer story.append(Spacer(1, 30)) footer_style = ParagraphStyle( 'Footer', parent=styles['Normal'], fontSize=10, alignment=TA_CENTER, textColor=colors.grey ) story.append(Paragraph("Report generated by Scoreazy AI Agent | Educational Technology Solutions", footer_style)) story.append(Paragraph("For questions or support, please contact your instructor", footer_style)) # Build PDF doc.build(story) return pdf_path def generate_report(student_name, subject, quiz_scores_str, assignment_scores_str, participation_score, time_period, additional_notes=""): """Main function to generate the complete student report""" try: # Parse input scores quiz_scores = [float(x.strip()) for x in quiz_scores_str.split(',') if x.strip()] assignment_scores = [float(x.strip()) for x in assignment_scores_str.split(',') if x.strip()] # Validate scores all_scores = quiz_scores + assignment_scores + [participation_score] if any(score < 0 or score > 100 for score in all_scores): return "Error: All scores must be between 0 and 100.", None, None # Calculate metrics metrics = calculate_metrics(quiz_scores, assignment_scores, participation_score) metrics['participation'] = participation_score # Analyze performance strengths, improvements = analyze_performance(metrics, quiz_scores, assignment_scores) # Generate AI insights insights = generate_ai_insights(student_name, subject, metrics, strengths, improvements) # Create temporary file for chart chart_temp = tempfile.NamedTemporaryFile(delete=False, suffix='.png') chart_path = chart_temp.name chart_temp.close() # Create visualization chart = create_performance_chart(metrics, save_path=chart_path) # Generate PDF report pdf_path = create_pdf_report( student_name, subject, time_period, metrics, strengths, improvements, insights, participation_score, additional_notes, chart_path ) # Generate report text for display report = f""" # 📊 Student Performance Report **Student Name:** {student_name} **Subject:** {subject} **Reporting Period:** {time_period} **Generated Date:** {datetime.now().strftime('%B %d, %Y')} --- ## 📈 Performance Summary - **Overall Grade:** {metrics['grade']} ({metrics['overall_avg']}%) - **Quiz Average:** {metrics['quiz_avg']}% - **Assignment Average:** {metrics['assignment_avg']}% - **Participation Score:** {participation_score}% --- ## ✅ Identified Strengths """ for i, strength in enumerate(strengths, 1): report += f"{i}. **{strength.title()}**: Demonstrates consistent performance and understanding in this area.\n" report += "\n## ⚠️ Areas for Improvement\n" for i, improvement in enumerate(improvements, 1): report += f"{i}. **{improvement.title()}**: Focus area for enhanced learning outcomes.\n" report += f""" --- ## 🎯 Recommendations """ for i, rec in enumerate(insights['recommendations'], 1): report += f"{i}. {rec}\n" if additional_notes: report += f""" --- ## 📝 Additional Notes {additional_notes} """ report += """ --- ## 📅 Next Steps - Review this report with student and parent/guardian - Monitor progress on recommended improvement areas - Schedule follow-up assessment in 2-3 weeks - Continue building on identified strengths --- *Report generated by Scoreazy AI Agent | Educational Technology Solutions* """ # Clean up temporary chart file try: os.unlink(chart_path) except: pass return report, chart, pdf_path except ValueError as e: return f"Error parsing scores: {str(e)}. Please ensure scores are numbers separated by commas.", None, None except Exception as e: return f"Error generating report: {str(e)}", None, None # Create Gradio interface def create_interface(): with gr.Blocks(title="📊 Report Generator Bot", theme=gr.themes.Soft()) as app: gr.Markdown(""" # 🤖 Student Report Generator Bot ### Powered by AI | Built for Scoreazy Assignment Generate comprehensive student performance reports with AI-powered insights and recommendations. """) with gr.Row(): with gr.Column(scale=1): gr.Markdown("## 📝 Student Information") student_name = gr.Textbox( label="Student Name", placeholder="Enter student's full name", value="Sarah Johnson" ) subject = gr.Textbox( label="Subject/Course", placeholder="e.g., Mathematics, Science, English", value="Mathematics" ) time_period = gr.Textbox( label="Time Period", placeholder="e.g., Quarter 1, Week 1-4, Month 1", value="Quarter 1" ) with gr.Column(scale=1): gr.Markdown("## 📊 Performance Data") quiz_scores = gr.Textbox( label="Quiz Scores (comma-separated)", placeholder="85, 78, 92, 88", value="85, 78, 92, 88, 90" ) assignment_scores = gr.Textbox( label="Assignment Scores (comma-separated)", placeholder="90, 87, 93, 89", value="90, 87, 93, 89, 91" ) participation_score = gr.Slider( label="Participation Score", minimum=0, maximum=100, value=88, step=1 ) additional_notes = gr.Textbox( label="Additional Notes (Optional)", placeholder="Any specific observations or concerns...", lines=3 ) generate_btn = gr.Button("🚀 Generate Report", variant="primary", size="lg") with gr.Row(): with gr.Column(scale=2): report_output = gr.Markdown(label="Generated Report") with gr.Column(scale=1): chart_output = gr.Plot(label="Performance Chart") # PDF Download Section with gr.Row(): pdf_output = gr.File(label="📄 Download PDF Report", visible=False) download_status = gr.Markdown("", visible=False) # Example button def load_example(): return ( "Alex Rodriguez", "Computer Science", "95, 87, 91, 89, 93", "88, 92, 86, 94, 90", 85, "Semester 1", "Student shows strong technical aptitude but could benefit from more consistent participation in class discussions." ) def generate_and_update(student_name, subject, quiz_scores, assignment_scores, participation_score, time_period, additional_notes): """Generate report and update interface with PDF""" report, chart, pdf_path = generate_report( student_name, subject, quiz_scores, assignment_scores, participation_score, time_period, additional_notes ) if pdf_path and os.path.exists(pdf_path): return ( report, chart, gr.update(value=pdf_path, visible=True), gr.update(value="✅ **PDF Report Generated Successfully!** Click the download button above to save your report.", visible=True) ) else: return ( report, chart, gr.update(visible=False), gr.update(value="❌ Error generating PDF report." if pdf_path is None else "", visible=bool(report)) ) example_btn = gr.Button("📋 Load Example Data", variant="secondary") example_btn.click( fn=load_example, outputs=[student_name, subject, quiz_scores, assignment_scores, participation_score, time_period, additional_notes] ) generate_btn.click( fn=generate_and_update, inputs=[student_name, subject, quiz_scores, assignment_scores, participation_score, time_period, additional_notes], outputs=[report_output, chart_output, pdf_output, download_status] ) gr.Markdown(""" --- ### 💡 How to Use: 1. **Enter student information** and course details 2. **Input performance data** - use comma-separated values for multiple scores 3. **Add participation score** using the slider 4. **Click "Generate Report"** to create AI-powered analysis 5. **Review the comprehensive report** with strengths, improvements, and recommendations 6. **Download PDF version** for offline viewing and sharing ### 🔧 Features: - ✅ Automated performance analysis - ✅ AI-generated insights and recommendations - ✅ Visual performance charts - ✅ Professional report formatting - ✅ **PDF download with embedded charts** - ✅ Customizable input parameters ### 📄 PDF Report Includes: - Complete performance analysis with charts - Professional formatting for printing - All recommendations and insights - Visual performance graphs - Ready for sharing with parents/educators """) return app # Launch the app if __name__ == "__main__": app = create_interface() app.launch(share=True)