Dannyar608 commited on
Commit
018fcd1
Β·
verified Β·
1 Parent(s): 39b1c57

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +211 -12
app.py CHANGED
@@ -24,6 +24,7 @@ from functools import lru_cache
24
  import hashlib
25
  from concurrent.futures import ThreadPoolExecutor
26
  from pydantic import BaseModel
 
27
 
28
  # ========== CONFIGURATION ==========
29
  PROFILES_DIR = "student_profiles"
@@ -440,8 +441,171 @@ class TranscriptParser:
440
 
441
  raise ValueError("Could not identify course information in transcript")
442
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
443
  def parse_transcript(file_obj, progress=gr.Progress()) -> Tuple[str, Optional[Dict]]:
444
- """Process transcript file and return simple confirmation"""
445
  try:
446
  if not file_obj:
447
  raise gr.Error("Please upload a transcript file first (PDF or image)")
@@ -477,11 +641,35 @@ def parse_transcript(file_obj, progress=gr.Progress()) -> Tuple[str, Optional[Di
477
  except Exception as e:
478
  raise ValueError(f"Couldn't parse transcript content. Error: {str(e)}")
479
 
480
- confirmation = "Transcript processed successfully."
481
- if 'gpa' in parsed_data.get('student_info', {}):
482
- confirmation += f"\nGPA detected: {parsed_data['student_info']['gpa']}"
 
 
 
 
483
 
484
- return confirmation, parsed_data
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
485
 
486
  except Exception as e:
487
  error_msg = f"Error processing transcript: {str(e)}"
@@ -938,10 +1126,13 @@ def create_interface():
938
  with gr.Column(scale=2):
939
  transcript_output = gr.Textbox(
940
  label="Analysis Results",
941
- lines=5,
942
  interactive=False,
943
  elem_classes="transcript-results"
944
  )
 
 
 
945
  transcript_data = gr.State()
946
 
947
  file_input.change(
@@ -954,14 +1145,22 @@ def create_interface():
954
  outputs=[file_error, transcript_output]
955
  )
956
 
 
 
 
 
 
 
 
 
 
 
 
 
957
  upload_btn.click(
958
- fn=parse_transcript,
959
  inputs=[file_input, tab_completed],
960
- outputs=[transcript_output, transcript_data]
961
- ).then(
962
- fn=lambda: {0: True},
963
- inputs=None,
964
- outputs=tab_completed
965
  ).then(
966
  fn=lambda: gr.update(elem_classes="completed-tab"),
967
  outputs=step1
 
24
  import hashlib
25
  from concurrent.futures import ThreadPoolExecutor
26
  from pydantic import BaseModel
27
+ import plotly.express as px
28
 
29
  # ========== CONFIGURATION ==========
30
  PROFILES_DIR = "student_profiles"
 
441
 
442
  raise ValueError("Could not identify course information in transcript")
443
 
444
+ # ========== ENHANCED ANALYSIS FUNCTIONS ==========
445
+ def analyze_gpa(parsed_data: Dict) -> str:
446
+ try:
447
+ gpa = float(parsed_data['student_info']['weighted_gpa'])
448
+ if gpa >= 4.5:
449
+ return "🌟 Excellent GPA! You're in the top tier of students."
450
+ elif gpa >= 3.5:
451
+ return "πŸ‘ Good GPA! You're performing above average."
452
+ elif gpa >= 2.5:
453
+ return "ℹ️ Average GPA. Consider focusing on improvement in weaker areas."
454
+ else:
455
+ return "⚠️ Below average GPA. Please consult with your academic advisor."
456
+ except (TypeError, ValueError, KeyError, AttributeError):
457
+ return "❌ Could not analyze GPA."
458
+
459
+ def analyze_graduation_status(parsed_data: Dict) -> str:
460
+ try:
461
+ total_required = sum(
462
+ float(req['required'])
463
+ for req in parsed_data['requirements'].values()
464
+ if req.get('required') and str(req['required']).replace('.', '').isdigit()
465
+ )
466
+
467
+ total_completed = sum(
468
+ float(req['completed'])
469
+ for req in parsed_data['requirements'].values()
470
+ if req.get('completed') and str(req['completed']).replace('.', '').isdigit()
471
+ )
472
+
473
+ completion_percentage = (total_completed / total_required) * 100 if total_required > 0 else 0
474
+
475
+ if completion_percentage >= 100:
476
+ return "πŸŽ‰ You've met all graduation requirements!"
477
+ elif completion_percentage >= 80:
478
+ return f"βœ… You've completed {completion_percentage:.1f}% of requirements. Almost there!"
479
+ elif completion_percentage >= 50:
480
+ return f"πŸ”„ You've completed {completion_percentage:.1f}% of requirements. Keep working!"
481
+ else:
482
+ return f"⚠️ You've only completed {completion_percentage:.1f}% of requirements. Please meet with your counselor."
483
+ except (ZeroDivisionError, TypeError, KeyError, AttributeError):
484
+ return "❌ Could not analyze graduation status."
485
+
486
+ def generate_advice(parsed_data: Dict) -> str:
487
+ advice = []
488
+
489
+ # GPA advice
490
+ try:
491
+ gpa = float(parsed_data['student_info']['weighted_gpa'])
492
+ if gpa < 3.0:
493
+ advice.append("πŸ“š Your GPA could improve. Consider:\n- Seeking tutoring for challenging subjects\n- Meeting with teachers during office hours\n- Developing better study habits")
494
+ except (TypeError, ValueError, KeyError, AttributeError):
495
+ pass
496
+
497
+ # Community service advice
498
+ try:
499
+ service_hours = int(parsed_data['student_info']['community_service_hours'])
500
+ if service_hours < 100:
501
+ advice.append("🀝 Consider more community service:\n- Many colleges value 100+ hours\n- Look for opportunities that align with your interests")
502
+ except (TypeError, ValueError, KeyError, AttributeError):
503
+ pass
504
+
505
+ # Missing requirements advice
506
+ try:
507
+ missing_reqs = [
508
+ req for code, req in parsed_data['requirements'].items()
509
+ if float(req['percent_complete']) < 100 and not code.startswith("Z-Assessment")
510
+ ]
511
+
512
+ if missing_reqs:
513
+ req_list = "\n- ".join([f"{code}: {req['description']}" for code, req in missing_reqs])
514
+ advice.append(f"πŸŽ“ Focus on completing these requirements:\n- {req_list}")
515
+ except (TypeError, ValueError, KeyError, AttributeError):
516
+ pass
517
+
518
+ # Course rigor advice
519
+ try:
520
+ ap_count = sum(1 for course in parsed_data['course_history'] if "Advanced Placement" in course['description'])
521
+ if ap_count < 3:
522
+ advice.append("🧠 Consider taking more challenging courses:\n- AP/IB courses can strengthen college applications\n- Shows academic rigor to admissions officers")
523
+ except (TypeError, KeyError, AttributeError):
524
+ pass
525
+
526
+ return "\n\n".join(advice) if advice else "🎯 You're on track! Keep up the good work."
527
+
528
+ def generate_college_recommendations(parsed_data: Dict) -> str:
529
+ try:
530
+ gpa = float(parsed_data['student_info']['weighted_gpa'])
531
+ ap_count = sum(1 for course in parsed_data['course_history'] if "Advanced Placement" in course['description'])
532
+ service_hours = int(parsed_data['student_info']['community_service_hours']) if parsed_data['student_info'].get('community_service_hours') else 0
533
+
534
+ recommendations = []
535
+
536
+ if gpa >= 4.0 and ap_count >= 5:
537
+ recommendations.append("πŸ›οΈ Reach Schools: Ivy League, Stanford, MIT, etc.")
538
+ if gpa >= 3.7:
539
+ recommendations.append("πŸŽ“ Competitive Schools: Top public universities, selective private colleges")
540
+ if gpa >= 3.0:
541
+ recommendations.append("πŸ“š Good Match Schools: State flagship universities, many private colleges")
542
+ if gpa >= 2.0:
543
+ recommendations.append("🏫 Safety Schools: Community colleges, open admission universities")
544
+
545
+ # Add scholarship opportunities
546
+ if gpa >= 3.5:
547
+ recommendations.append("\nπŸ’° Scholarship Opportunities:\n- Bright Futures (Florida)\n- National Merit Scholarship\n- College-specific merit scholarships")
548
+ elif gpa >= 3.0:
549
+ recommendations.append("\nπŸ’° Scholarship Opportunities:\n- Local community scholarships\n- Special interest scholarships\n- First-generation student programs")
550
+
551
+ # Add extracurricular advice
552
+ if service_hours < 50:
553
+ recommendations.append("\n🎭 Extracurricular Advice:\n- Colleges value depth over breadth in activities\n- Consider leadership roles in 1-2 organizations")
554
+
555
+ if not recommendations:
556
+ return "❌ Not enough data to generate college recommendations"
557
+
558
+ return "Based on your academic profile:\n\n" + "\n\n".join(recommendations)
559
+ except:
560
+ return "❌ Could not generate college recommendations"
561
+
562
+ def create_gpa_visualization(parsed_data: Dict):
563
+ try:
564
+ gpa_data = {
565
+ "Type": ["Weighted GPA", "Unweighted GPA"],
566
+ "Value": [
567
+ float(parsed_data['student_info']['weighted_gpa']),
568
+ float(parsed_data['student_info']['unweighted_gpa'])
569
+ ]
570
+ }
571
+ df = pd.DataFrame(gpa_data)
572
+ fig = px.bar(df, x="Type", y="Value", title="GPA Comparison",
573
+ color="Type", text="Value",
574
+ color_discrete_sequence=["#4C78A8", "#F58518"])
575
+ fig.update_traces(texttemplate='%{text:.2f}', textposition='outside')
576
+ fig.update_layout(yaxis_range=[0,5], uniformtext_minsize=8, uniformtext_mode='hide')
577
+ return fig
578
+ except:
579
+ return None
580
+
581
+ def create_requirements_visualization(parsed_data: Dict):
582
+ try:
583
+ req_data = []
584
+ for code, req in parsed_data['requirements'].items():
585
+ if req.get('percent_complete'):
586
+ completion = float(req['percent_complete'])
587
+ req_data.append({
588
+ "Requirement": code,
589
+ "Completion (%)": completion,
590
+ "Status": "Complete" if completion >= 100 else "Incomplete"
591
+ })
592
+
593
+ if not req_data:
594
+ return None
595
+
596
+ df = pd.DataFrame(req_data)
597
+ fig = px.bar(df, x="Requirement", y="Completion (%)",
598
+ title="Graduation Requirements Completion",
599
+ color="Status",
600
+ color_discrete_map={"Complete": "#2CA02C", "Incomplete": "#D62728"},
601
+ hover_data=["Requirement"])
602
+ fig.update_layout(xaxis={'categoryorder':'total descending'})
603
+ return fig
604
+ except:
605
+ return None
606
+
607
  def parse_transcript(file_obj, progress=gr.Progress()) -> Tuple[str, Optional[Dict]]:
608
+ """Process transcript file and return analysis results"""
609
  try:
610
  if not file_obj:
611
  raise gr.Error("Please upload a transcript file first (PDF or image)")
 
641
  except Exception as e:
642
  raise ValueError(f"Couldn't parse transcript content. Error: {str(e)}")
643
 
644
+ # Perform enhanced analyses
645
+ gpa_analysis = analyze_gpa(parsed_data)
646
+ grad_status = analyze_graduation_status(parsed_data)
647
+ advice = generate_advice(parsed_data)
648
+ college_recs = generate_college_recommendations(parsed_data)
649
+ gpa_viz = create_gpa_visualization(parsed_data)
650
+ req_viz = create_requirements_visualization(parsed_data)
651
 
652
+ # Format results for display
653
+ results = [
654
+ f"πŸ“Š GPA Analysis: {gpa_analysis}",
655
+ f"πŸŽ“ Graduation Status: {grad_status}",
656
+ f"πŸ’‘ Recommendations:\n{advice}",
657
+ f"🏫 College Recommendations:\n{college_recs}"
658
+ ]
659
+
660
+ # Store all analysis results in the parsed_data
661
+ parsed_data['analysis'] = {
662
+ 'gpa_analysis': gpa_analysis,
663
+ 'grad_status': grad_status,
664
+ 'advice': advice,
665
+ 'college_recs': college_recs,
666
+ 'visualizations': {
667
+ 'gpa_viz': gpa_viz,
668
+ 'req_viz': req_viz
669
+ }
670
+ }
671
+
672
+ return "\n\n".join(results), parsed_data
673
 
674
  except Exception as e:
675
  error_msg = f"Error processing transcript: {str(e)}"
 
1126
  with gr.Column(scale=2):
1127
  transcript_output = gr.Textbox(
1128
  label="Analysis Results",
1129
+ lines=10,
1130
  interactive=False,
1131
  elem_classes="transcript-results"
1132
  )
1133
+ with gr.Row():
1134
+ gpa_viz = gr.Plot(label="GPA Visualization", visible=False)
1135
+ req_viz = gr.Plot(label="Requirements Visualization", visible=False)
1136
  transcript_data = gr.State()
1137
 
1138
  file_input.change(
 
1145
  outputs=[file_error, transcript_output]
1146
  )
1147
 
1148
+ def process_and_visualize(file_obj, tab_status):
1149
+ results, data = parse_transcript(file_obj)
1150
+
1151
+ # Update visualizations
1152
+ gpa_viz_update = gr.update(visible=data.get('analysis', {}).get('visualizations', {}).get('gpa_viz') is not None)
1153
+ req_viz_update = gr.update(visible=data.get('analysis', {}).get('visualizations', {}).get('req_viz') is not None)
1154
+
1155
+ # Update tab completion status
1156
+ tab_status[0] = True
1157
+
1158
+ return results, data, gpa_viz_update, req_viz_update, tab_status
1159
+
1160
  upload_btn.click(
1161
+ fn=process_and_visualize,
1162
  inputs=[file_input, tab_completed],
1163
+ outputs=[transcript_output, transcript_data, gpa_viz, req_viz, tab_completed]
 
 
 
 
1164
  ).then(
1165
  fn=lambda: gr.update(elem_classes="completed-tab"),
1166
  outputs=step1