Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -514,6 +514,7 @@ def plotar_graficos_destacados(disciplinas_dados: List[Dict], temp_dir: str) ->
|
|
514 |
def gerar_relatorio_pdf(df: pd.DataFrame, disciplinas_dados: List[Dict],
|
515 |
grafico_basica: str, grafico_diversificada: str,
|
516 |
grafico_medias: str) -> str:
|
|
|
517 |
pdf = PDFReport()
|
518 |
pdf.set_auto_page_break(auto=True, margin=15)
|
519 |
|
@@ -534,7 +535,7 @@ def gerar_relatorio_pdf(df: pd.DataFrame, disciplinas_dados: List[Dict],
|
|
534 |
# Nome do aluno
|
535 |
if hasattr(df, 'attrs') and 'nome' in df.attrs:
|
536 |
pdf.set_font('Helvetica', 'B', 11)
|
537 |
-
pdf.cell(30, 7, 'Nome:',
|
538 |
pdf.set_font('Helvetica', '', 11)
|
539 |
pdf.cell(0, 7, df.attrs['nome'],
|
540 |
0, new_x=XPos.LMARGIN, new_y=YPos.NEXT)
|
@@ -548,100 +549,50 @@ def gerar_relatorio_pdf(df: pd.DataFrame, disciplinas_dados: List[Dict],
|
|
548 |
0, new_x=XPos.LMARGIN, new_y=YPos.NEXT, align='R')
|
549 |
pdf.ln(15)
|
550 |
|
551 |
-
#
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
560 |
-
|
561 |
-
pdf.set_font('Helvetica', 'B', 14)
|
562 |
-
pdf.cell(0, 10, 'Evolução das Notas - Parte Diversificada',
|
563 |
-
0, new_x=XPos.LMARGIN, new_y=YPos.NEXT, align='L')
|
564 |
-
pdf.line(10, pdf.get_y(), 200, pdf.get_y())
|
565 |
-
pdf.ln(10)
|
566 |
-
pdf.image(grafico_diversificada, x=10, w=190)
|
567 |
|
568 |
-
# Terceira página - Médias e Frequências
|
569 |
pdf.add_page()
|
570 |
-
|
571 |
-
|
572 |
-
|
573 |
-
|
574 |
-
|
575 |
-
|
|
|
|
|
|
|
576 |
|
577 |
-
# Quarta página - Análise Detalhada
|
578 |
pdf.add_page()
|
579 |
-
|
580 |
-
|
581 |
-
|
582 |
-
|
583 |
-
|
584 |
-
|
585 |
-
|
586 |
-
medias_notas = [d['media_notas'] for d in disciplinas_dados]
|
587 |
-
medias_freq = [d['media_freq'] for d in disciplinas_dados]
|
588 |
-
media_global = np.mean(medias_notas)
|
589 |
-
freq_global = np.mean(medias_freq)
|
590 |
-
|
591 |
-
pdf.set_font('Helvetica', 'B', 12)
|
592 |
-
pdf.cell(0, 7, 'Resumo Geral:',
|
593 |
-
0, new_x=XPos.LMARGIN, new_y=YPos.NEXT, align='L')
|
594 |
-
pdf.ln(5)
|
595 |
-
|
596 |
-
pdf.set_font('Helvetica', '', 11)
|
597 |
-
pdf.cell(0, 7, f'Média Global: {media_global:.1f}',
|
598 |
-
0, new_x=XPos.LMARGIN, new_y=YPos.NEXT, align='L')
|
599 |
-
pdf.cell(0, 7, f'Frequência Global: {freq_global:.1f}%',
|
600 |
-
0, new_x=XPos.LMARGIN, new_y=YPos.NEXT, align='L')
|
601 |
-
pdf.ln(10)
|
602 |
-
|
603 |
-
# Pontos de atenção
|
604 |
-
pdf.set_font('Helvetica', 'B', 12)
|
605 |
-
pdf.cell(0, 10, 'Pontos de Atenção:',
|
606 |
-
0, new_x=XPos.LMARGIN, new_y=YPos.NEXT, align='L')
|
607 |
-
pdf.ln(5)
|
608 |
-
|
609 |
-
pdf.set_font('Helvetica', '', 10)
|
610 |
-
disciplinas_risco = []
|
611 |
-
for disc_data in disciplinas_dados:
|
612 |
-
avisos = []
|
613 |
-
if disc_data['media_notas'] < LIMITE_APROVACAO_NOTA:
|
614 |
-
avisos.append(
|
615 |
-
f"Média de notas abaixo de {LIMITE_APROVACAO_NOTA} ({disc_data['media_notas']:.1f})"
|
616 |
-
)
|
617 |
-
if disc_data['media_freq'] < LIMITE_APROVACAO_FREQ:
|
618 |
-
avisos.append(
|
619 |
-
f"Frequência abaixo de {LIMITE_APROVACAO_FREQ}% ({disc_data['media_freq']:.1f}%)"
|
620 |
-
)
|
621 |
-
|
622 |
-
if avisos:
|
623 |
-
disciplinas_risco.append((disc_data['disciplina'], avisos))
|
624 |
-
|
625 |
-
if disciplinas_risco:
|
626 |
-
for disc, avisos in disciplinas_risco:
|
627 |
-
pdf.set_font('Helvetica', 'B', 10)
|
628 |
-
pdf.cell(0, 7, f'- {disc}:',
|
629 |
-
0, new_x=XPos.LMARGIN, new_y=YPos.NEXT, align='L')
|
630 |
-
pdf.set_font('Helvetica', '', 10)
|
631 |
-
for aviso in avisos:
|
632 |
-
pdf.cell(10) # Indentação
|
633 |
-
pdf.cell(0, 7, f'- {aviso}',
|
634 |
-
0, new_x=XPos.LMARGIN, new_y=YPos.NEXT, align='L')
|
635 |
else:
|
636 |
-
|
637 |
-
0, new_x=XPos.LMARGIN, new_y=YPos.NEXT, align='L')
|
638 |
-
|
639 |
-
pdf.header_footer()
|
640 |
|
641 |
-
# Salvar PDF
|
642 |
with temp_file(suffix='.pdf') as temp_pdf:
|
643 |
pdf.output(temp_pdf)
|
644 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
645 |
|
646 |
def processar_boletim(file) -> Tuple[Optional[str], str]:
|
647 |
"""Função principal que processa o boletim e gera o relatório."""
|
|
|
514 |
def gerar_relatorio_pdf(df: pd.DataFrame, disciplinas_dados: List[Dict],
|
515 |
grafico_basica: str, grafico_diversificada: str,
|
516 |
grafico_medias: str) -> str:
|
517 |
+
"""Gera relatório PDF com análise completa."""
|
518 |
pdf = PDFReport()
|
519 |
pdf.set_auto_page_break(auto=True, margin=15)
|
520 |
|
|
|
535 |
# Nome do aluno
|
536 |
if hasattr(df, 'attrs') and 'nome' in df.attrs:
|
537 |
pdf.set_font('Helvetica', 'B', 11)
|
538 |
+
pdf.cell(30, 7, 'Nome:', new_x=XPos.RIGHT, new_y=YPos.TOP)
|
539 |
pdf.set_font('Helvetica', '', 11)
|
540 |
pdf.cell(0, 7, df.attrs['nome'],
|
541 |
0, new_x=XPos.LMARGIN, new_y=YPos.NEXT)
|
|
|
549 |
0, new_x=XPos.LMARGIN, new_y=YPos.NEXT, align='R')
|
550 |
pdf.ln(15)
|
551 |
|
552 |
+
# Inserir gráficos com verificação
|
553 |
+
if os.path.exists(grafico_basica):
|
554 |
+
pdf.set_font('Helvetica', 'B', 14)
|
555 |
+
pdf.cell(0, 10, 'Evolução das Notas - Formação Geral Básica',
|
556 |
+
0, new_x=XPos.LMARGIN, new_y=YPos.NEXT, align='L')
|
557 |
+
pdf.line(10, pdf.get_y(), 200, pdf.get_y())
|
558 |
+
pdf.ln(10)
|
559 |
+
pdf.image(grafico_basica, x=10, w=190)
|
560 |
+
else:
|
561 |
+
logger.error("Gráfico de formação básica não encontrado.")
|
|
|
|
|
|
|
|
|
|
|
|
|
562 |
|
|
|
563 |
pdf.add_page()
|
564 |
+
if os.path.exists(grafico_diversificada):
|
565 |
+
pdf.set_font('Helvetica', 'B', 14)
|
566 |
+
pdf.cell(0, 10, 'Evolução das Notas - Parte Diversificada',
|
567 |
+
0, new_x=XPos.LMARGIN, new_y=YPos.NEXT, align='L')
|
568 |
+
pdf.line(10, pdf.get_y(), 200, pdf.get_y())
|
569 |
+
pdf.ln(10)
|
570 |
+
pdf.image(grafico_diversificada, x=10, w=190)
|
571 |
+
else:
|
572 |
+
logger.error("Gráfico de parte diversificada não encontrado.")
|
573 |
|
|
|
574 |
pdf.add_page()
|
575 |
+
if os.path.exists(grafico_medias):
|
576 |
+
pdf.set_font('Helvetica', 'B', 14)
|
577 |
+
pdf.cell(0, 10, 'Análise de Médias e Frequências',
|
578 |
+
0, new_x=XPos.LMARGIN, new_y=YPos.NEXT, align='L')
|
579 |
+
pdf.line(10, pdf.get_y(), 200, pdf.get_y())
|
580 |
+
pdf.ln(10)
|
581 |
+
pdf.image(grafico_medias, x=10, w=190)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
582 |
else:
|
583 |
+
logger.error("Gráfico de médias e frequências não encontrado.")
|
|
|
|
|
|
|
584 |
|
585 |
+
# Salvar PDF em um arquivo temporário
|
586 |
with temp_file(suffix='.pdf') as temp_pdf:
|
587 |
pdf.output(temp_pdf)
|
588 |
+
|
589 |
+
# Verifique se o arquivo PDF foi realmente salvo
|
590 |
+
if os.path.exists(temp_pdf):
|
591 |
+
logger.info("Relatório PDF gerado com sucesso.")
|
592 |
+
return temp_pdf
|
593 |
+
else:
|
594 |
+
logger.error("Falha ao salvar o relatório PDF.")
|
595 |
+
return None
|
596 |
|
597 |
def processar_boletim(file) -> Tuple[Optional[str], str]:
|
598 |
"""Função principal que processa o boletim e gera o relatório."""
|