histlearn commited on
Commit
7cbb42c
·
verified ·
1 Parent(s): 383662c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +62 -32
app.py CHANGED
@@ -117,28 +117,47 @@ class StudentAnalyzer:
117
  self.tarefas_df['Aluno_Pattern'] = self.tarefas_df['Aluno'].apply(extract_pattern)
118
  return self.calculate_metrics()
119
 
120
- def calculate_metrics(self) -> pd.DataFrame:
121
- """Calcula métricas de desempenho dos alunos."""
122
- metrics_df = pd.DataFrame()
123
-
124
- for _, aluno in self.alunos_df.iterrows():
125
- aluno_pattern = aluno['Aluno_Pattern']
126
- aluno_tarefas = self.tarefas_df[self.tarefas_df['Aluno_Pattern'] == aluno_pattern]
 
 
 
 
 
 
 
 
127
 
128
- if not aluno_tarefas.empty:
129
- duracao_total = aluno_tarefas['Duração'].sum()
130
- acertos_total = aluno_tarefas['Nota'].sum()
131
 
132
- metrics = {
133
- 'Nome do Aluno': aluno['Nome do Aluno'],
134
- 'Tarefas Completadas': len(aluno_tarefas),
135
- 'Acertos Absolutos': acertos_total,
136
- 'Total Tempo': str(duracao_total),
137
- 'Tempo Médio por Tarefa': str(duracao_total / len(aluno_tarefas))
138
- }
139
- metrics_df = pd.concat([metrics_df, pd.DataFrame([metrics])], ignore_index=True)
140
-
141
- return metrics_df.sort_values('Acertos Absolutos', ascending=False)
 
 
 
 
 
 
 
 
 
 
 
142
 
143
  class ReportGenerator:
144
  """Classe responsável pela geração de relatórios e visualizações."""
@@ -381,21 +400,26 @@ class ReportGenerator:
381
  raise
382
 
383
  def generate_table_section(self, pdf: FPDF, nivel: str, alunos_nivel: pd.DataFrame):
384
- """Gera uma seção de tabela com formatação melhorada."""
385
  try:
 
386
  pdf.set_font('Arial', 'B', 14)
387
  pdf.set_fill_color(240, 240, 240)
388
 
389
- # Adicionar cabeçalho com estatísticas do nível
 
 
390
  media_acertos = alunos_nivel['Acertos Absolutos'].mean()
391
  media_tarefas = alunos_nivel['Tarefas Completadas'].mean()
392
- taxa_media = media_acertos / media_tarefas if media_tarefas > 0 else 0
 
393
 
 
394
  pdf.cell(0, 10, f'Detalhamento - Nível {nivel}', 0, 1, 'L', True)
395
  pdf.set_font('Arial', '', 10)
396
- pdf.cell(0, 6, f'Média de Acertos: {media_acertos:.1f} | ' +
397
- f'Média de Tarefas: {media_tarefas:.1f} | ' +
398
- f'Taxa Média de Aproveitamento: {taxa_media:.1%}', 0, 1)
399
  pdf.ln(2)
400
 
401
  # Configuração da tabela
@@ -407,28 +431,34 @@ class ReportGenerator:
407
  ('Tempo Total', 35)
408
  ]
409
 
410
- # Cabeçalho
411
  pdf.set_font('Arial', 'B', 10)
412
  pdf.set_fill_color(230, 230, 230)
413
  for titulo, largura in colunas:
414
  pdf.cell(largura, 8, titulo, 1, 0, 'C', True)
415
  pdf.ln()
416
 
417
- # Dados com cores alternadas
418
  pdf.set_font('Arial', '', 10)
419
  for i, (_, row) in enumerate(alunos_nivel.iterrows()):
420
- # Cor de fundo alternada mais suave
421
  fill_color = (248, 248, 248) if i % 2 == 0 else (255, 255, 255)
422
  pdf.set_fill_color(*fill_color)
423
 
 
 
 
 
 
 
424
  tempo = pd.to_timedelta(row['Total Tempo'])
425
  tempo_str = f"{int(tempo.total_seconds() // 60)}min {int(tempo.total_seconds() % 60)}s"
426
- taxa_aproveitamento = row['Acertos Absolutos'] / row['Tarefas Completadas']
427
 
 
428
  pdf.cell(70, 7, str(row['Nome do Aluno'])[:35], 1, 0, 'L', True)
429
  pdf.cell(20, 7, f"{row['Acertos Absolutos']:.0f}", 1, 0, 'R', True)
430
- pdf.cell(20, 7, str(row['Tarefas Completadas']), 1, 0, 'R', True)
431
- pdf.cell(20, 7, f"{taxa_aproveitamento:.1%}", 1, 0, 'R', True)
432
  pdf.cell(35, 7, tempo_str, 1, 0, 'R', True)
433
  pdf.ln()
434
 
 
117
  self.tarefas_df['Aluno_Pattern'] = self.tarefas_df['Aluno'].apply(extract_pattern)
118
  return self.calculate_metrics()
119
 
120
+ def calculate_metrics(self) -> pd.DataFrame:
121
+ """Calcula métricas de desempenho dos alunos, eliminando duplicatas e normalizando valores."""
122
+ try:
123
+ metrics_df = pd.DataFrame()
124
+
125
+ # Agrupar por aluno para eliminar duplicatas
126
+ grouped_tasks = self.tarefas_df.groupby(['Aluno_Pattern']).agg({
127
+ 'Aluno': 'first', # Mantém o primeiro nome encontrado
128
+ 'Duração': 'sum', # Soma total do tempo
129
+ 'Nota': 'sum', # Soma total dos acertos
130
+ }).reset_index()
131
+
132
+ # Contar número de tarefas por aluno
133
+ task_counts = self.tarefas_df.groupby('Aluno_Pattern').size().reset_index(name='total_tarefas')
134
+ grouped_tasks = grouped_tasks.merge(task_counts, on='Aluno_Pattern', how='left')
135
 
136
+ for _, aluno in self.alunos_df.iterrows():
137
+ aluno_pattern = aluno['Aluno_Pattern']
138
+ aluno_data = grouped_tasks[grouped_tasks['Aluno_Pattern'] == aluno_pattern]
139
 
140
+ if not aluno_data.empty:
141
+ # Calcular métricas por aluno
142
+ total_tarefas = aluno_data['total_tarefas'].iloc[0]
143
+ total_acertos = aluno_data['Nota'].iloc[0]
144
+ duracao_total = aluno_data['Duração'].iloc[0]
145
+
146
+ metrics = {
147
+ 'Nome do Aluno': aluno['Nome do Aluno'],
148
+ 'Tarefas Completadas': total_tarefas,
149
+ 'Acertos Absolutos': total_acertos,
150
+ 'Total Tempo': str(duracao_total),
151
+ 'Tempo Médio por Tarefa': str(duracao_total / total_tarefas if total_tarefas > 0 else timedelta(0))
152
+ }
153
+ metrics_df = pd.concat([metrics_df, pd.DataFrame([metrics])], ignore_index=True)
154
+
155
+ # Ordenar por acertos e resetar índice
156
+ return metrics_df.sort_values('Acertos Absolutos', ascending=False).reset_index(drop=True)
157
+
158
+ except Exception as e:
159
+ logging.error(f"Erro ao calcular métricas: {str(e)}")
160
+ raise
161
 
162
  class ReportGenerator:
163
  """Classe responsável pela geração de relatórios e visualizações."""
 
400
  raise
401
 
402
  def generate_table_section(self, pdf: FPDF, nivel: str, alunos_nivel: pd.DataFrame):
403
+ """Gera uma seção de tabela com formatação melhorada e cálculos corrigidos."""
404
  try:
405
+ # Configuração inicial
406
  pdf.set_font('Arial', 'B', 14)
407
  pdf.set_fill_color(240, 240, 240)
408
 
409
+ # Calcular estatísticas do nível
410
+ total_questoes_por_tarefa = 10 # Número máximo de questões por tarefa
411
+
412
  media_acertos = alunos_nivel['Acertos Absolutos'].mean()
413
  media_tarefas = alunos_nivel['Tarefas Completadas'].mean()
414
+ pontos_possiveis = media_tarefas * total_questoes_por_tarefa
415
+ taxa_media = (media_acertos / pontos_possiveis * 100) if pontos_possiveis > 0 else 0
416
 
417
+ # Cabeçalho da seção
418
  pdf.cell(0, 10, f'Detalhamento - Nível {nivel}', 0, 1, 'L', True)
419
  pdf.set_font('Arial', '', 10)
420
+ pdf.cell(0, 6, (f'Média de Acertos: {media_acertos:.1f} | '
421
+ f'Média de Tarefas: {media_tarefas:.1f} | '
422
+ f'Taxa Média de Aproveitamento: {min(taxa_media, 100):.1f}%'), 0, 1)
423
  pdf.ln(2)
424
 
425
  # Configuração da tabela
 
431
  ('Tempo Total', 35)
432
  ]
433
 
434
+ # Cabeçalho da tabela
435
  pdf.set_font('Arial', 'B', 10)
436
  pdf.set_fill_color(230, 230, 230)
437
  for titulo, largura in colunas:
438
  pdf.cell(largura, 8, titulo, 1, 0, 'C', True)
439
  pdf.ln()
440
 
441
+ # Dados dos alunos
442
  pdf.set_font('Arial', '', 10)
443
  for i, (_, row) in enumerate(alunos_nivel.iterrows()):
444
+ # Alternar cores das linhas
445
  fill_color = (248, 248, 248) if i % 2 == 0 else (255, 255, 255)
446
  pdf.set_fill_color(*fill_color)
447
 
448
+ # Calcular taxa de aproveitamento normalizada
449
+ pontos_possiveis = row['Tarefas Completadas'] * total_questoes_por_tarefa
450
+ taxa_aproveitamento = (row['Acertos Absolutos'] / pontos_possiveis * 100) if pontos_possiveis > 0 else 0
451
+ taxa_aproveitamento = min(taxa_aproveitamento, 100) # Limitar a 100%
452
+
453
+ # Formatar tempo
454
  tempo = pd.to_timedelta(row['Total Tempo'])
455
  tempo_str = f"{int(tempo.total_seconds() // 60)}min {int(tempo.total_seconds() % 60)}s"
 
456
 
457
+ # Adicionar linha na tabela
458
  pdf.cell(70, 7, str(row['Nome do Aluno'])[:35], 1, 0, 'L', True)
459
  pdf.cell(20, 7, f"{row['Acertos Absolutos']:.0f}", 1, 0, 'R', True)
460
+ pdf.cell(20, 7, f"{row['Tarefas Completadas']:.0f}", 1, 0, 'R', True)
461
+ pdf.cell(20, 7, f"{taxa_aproveitamento:.1f}%", 1, 0, 'R', True)
462
  pdf.cell(35, 7, tempo_str, 1, 0, 'R', True)
463
  pdf.ln()
464