import gradio as gr import camelot import pandas as pd import matplotlib.pyplot as plt import numpy as np from fpdf import FPDF import tempfile import os import matplotlib matplotlib.use('Agg') # Usar backend não-interativo def converter_nota(valor): if pd.isna(valor) or valor == '-' or valor == 'N': return 0 try: return float(valor) except: return 0 def plotar_evolucao_bimestres(df_filtrado, temp_dir): plt.figure(figsize=(12, 6)) disciplinas_basicas = ['LINGUA PORTUGUESA', 'ARTE', 'LINGUA ESTRANGEIRA INGLES', 'GEOGRAFIA', 'CIENCIAS', 'HISTORIA', 'MATEMATICA'] estilos = { 'LINGUA PORTUGUESA': {'cor': '#DC143C', 'marcador': 'p', 'zorder': 1, 'linestyle': '-', 'desloc': 0.1}, 'ARTE': {'cor': '#4169E1', 'marcador': 'D', 'zorder': 2, 'linestyle': '--', 'desloc': 0.08}, 'LINGUA ESTRANGEIRA INGLES': {'cor': '#9370DB', 'marcador': 'h', 'zorder': 3, 'linestyle': '-.', 'desloc': 0.06}, 'GEOGRAFIA': {'cor': '#32CD32', 'marcador': '^', 'zorder': 4, 'linestyle': ':', 'desloc': 0.04}, 'CIENCIAS': {'cor': '#FF8C00', 'marcador': 's', 'zorder': 5, 'linestyle': '-', 'desloc': 0.02}, 'HISTORIA': {'cor': '#00CED1', 'marcador': '*', 'zorder': 6, 'linestyle': '--', 'desloc': -0.02}, 'MATEMATICA': {'cor': '#FF69B4', 'marcador': 'o', 'zorder': 7, 'linestyle': '-.', 'desloc': -0.04} } plt.grid(True, linestyle='--', alpha=0.3, zorder=0) colunas_notas = ['Nota B1', 'Nota B2', 'Nota B3', 'Nota B4'] for disciplina in disciplinas_basicas: dados_disciplina = df_filtrado[df_filtrado['Disciplina'] == disciplina] if not dados_disciplina.empty: notas = dados_disciplina[colunas_notas].values[0] notas_validas = notas > 0 if any(notas_validas): bimestres = np.arange(1, len(colunas_notas) + 1)[notas_validas] notas_filtradas = notas[notas_validas] estilo = estilos[disciplina] notas_deslocadas = notas_filtradas + estilo['desloc'] plt.plot(bimestres, notas_deslocadas, color=estilo['cor'], marker=estilo['marcador'], markersize=10, linewidth=2.5, label=disciplina, zorder=estilo['zorder'], linestyle=estilo['linestyle'], alpha=0.8) for x, y in zip(bimestres, notas_filtradas): plt.annotate(str(y), (x, y), textcoords="offset points", xytext=(0, 10), ha='center') plt.title('Evolução das Médias por Disciplina ao Longo dos Bimestres') plt.xlabel('Bimestres') plt.ylabel('Média de Notas') plt.xticks([1, 2, 3, 4], ['B1', 'B2', 'B3', 'B4']) plt.ylim(0, 10) plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left') plt.tight_layout() plot_path = os.path.join(temp_dir, 'evolucao_notas.png') plt.savefig(plot_path, bbox_inches='tight', dpi=300) plt.close() return plot_path def plotar_graficos_destacados(df_boletim_clean, temp_dir): plt.figure(figsize=(12, 6)) disciplinas = df_boletim_clean['Disciplina'].astype(str) medias_frequencia = df_boletim_clean[['Freq B1', 'Freq B2', 'Freq B3', 'Freq B4']].apply(pd.to_numeric, errors='coerce').mean(axis=1) medias_notas = df_boletim_clean[['Nota B1', 'Nota B2', 'Nota B3', 'Nota B4']].apply(pd.to_numeric, errors='coerce').mean(axis=1) cores_notas = ['red' if media < 5 else 'blue' for media in medias_notas] cores_frequencias = ['red' if media < 75 else 'green' for media in medias_frequencia] frequencia_global_media = medias_frequencia.mean() plt.subplot(1, 2, 1) plt.bar(disciplinas, medias_notas, color=cores_notas) plt.title('Média de Notas por Disciplina (Vermelho: < 5)') plt.xticks(rotation=90) plt.ylim(0, 10) plt.subplot(1, 2, 2) plt.bar(disciplinas, medias_frequencia, color=cores_frequencias) plt.title('Média de Frequência por Disciplina (Vermelho: < 75%)') plt.xticks(rotation=90) plt.ylim(0, 100) plt.suptitle(f"Frequência Global Média: {frequencia_global_media:.2f}%") if frequencia_global_media < 75: plt.figtext(0.5, 0.01, "Cuidado: Risco de Reprovação por Baixa Frequência", ha="center", fontsize=12, color="red") plt.tight_layout() plot_path = os.path.join(temp_dir, 'medias_frequencias.png') plt.savefig(plot_path, bbox_inches='tight', dpi=300) plt.close() return plot_path def gerar_relatorio_pdf(df, grafico1_path, grafico2_path): pdf = FPDF() pdf.add_page() pdf.set_font('Arial', 'B', 16) pdf.cell(0, 10, 'Relatório de Desempenho Escolar', 0, 1, 'C') pdf.ln(10) pdf.image(grafico1_path, x=10, w=190) pdf.ln(10) pdf.image(grafico2_path, x=10, w=190) pdf.ln(10) pdf.set_font('Arial', 'B', 12) pdf.cell(0, 10, 'Avisos Importantes:', 0, 1, 'L') pdf.set_font('Arial', '', 10) medias_notas = df[['Nota B1', 'Nota B2', 'Nota B3', 'Nota B4']].apply(pd.to_numeric, errors='coerce').mean(axis=1) medias_freq = df[['Freq B1', 'Freq B2', 'Freq B3', 'Freq B4']].apply(pd.to_numeric, errors='coerce').mean(axis=1) for idx, (disciplina, media_nota, media_freq) in enumerate(zip(df['Disciplina'], medias_notas, medias_freq)): if media_nota < 5: pdf.cell(0, 10, f'- {disciplina}: Média de notas abaixo de 5 ({media_nota:.1f})', 0, 1, 'L') if media_freq < 75: pdf.cell(0, 10, f'- {disciplina}: Frequência abaixo de 75% ({media_freq:.1f}%)', 0, 1, 'L') temp_pdf = tempfile.NamedTemporaryFile(delete=False, suffix='.pdf') pdf_path = temp_pdf.name pdf.output(pdf_path) return pdf_path def processar_boletim(pdf_file): try: temp_dir = tempfile.mkdtemp() # Ler o arquivo temporário e salvar seu conteúdo temp_pdf = os.path.join(temp_dir, 'boletim.pdf') with open(temp_pdf, 'wb') as f: f.write(pdf_file.read()) # Usar .read() para obter o conteúdo do arquivo tables = camelot.read_pdf(temp_pdf, pages='all', flavor='lattice') if len(tables) == 0: return None, "Nenhuma tabela encontrada no PDF." df = tables[0].df df.columns = ['Disciplina', 'Nota B1', 'Freq B1', '%Freq B1', 'AC B1', 'Nota B2', 'Freq B2', '%Freq B2', 'AC B2', 'Nota B3', 'Freq B3', '%Freq B3', 'AC B3', 'Nota B4', 'Freq B4', '%Freq B4', 'AC B4', 'CF', 'Nota Final', 'Freq Final', 'AC Final'] colunas_notas = ['Nota B1', 'Nota B2', 'Nota B3', 'Nota B4'] for col in colunas_notas: df[col] = df[col].apply(converter_nota) grafico1_path = plotar_evolucao_bimestres(df, temp_dir) grafico2_path = plotar_graficos_destacados(df, temp_dir) pdf_path = gerar_relatorio_pdf(df, grafico1_path, grafico2_path) with open(pdf_path, 'rb') as f: pdf_content = f.read() # Limpar arquivos temporários os.remove(pdf_path) for file in os.listdir(temp_dir): os.remove(os.path.join(temp_dir, file)) os.rmdir(temp_dir) return pdf_content, "Relatório gerado com sucesso!" except Exception as e: if 'temp_dir' in locals(): for file in os.listdir(temp_dir): os.remove(os.path.join(temp_dir, file)) os.rmdir(temp_dir) return None, f"Erro ao processar o boletim: {str(e)}" iface = gr.Interface( fn=processar_boletim, inputs=gr.File(label="Upload do Boletim (PDF)"), outputs=[ gr.File(label="Relatório (PDF)"), gr.Textbox(label="Status") ], title="Análise de Boletim Escolar", description="Faça upload do boletim em PDF para gerar um relatório com análises e visualizações.", allow_flagging="never" ) if __name__ == "__main__": iface.launch(server_name="0.0.0.0")