histlearn commited on
Commit
120f658
·
verified ·
1 Parent(s): 68ca5e6

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +214 -0
app.py ADDED
@@ -0,0 +1,214 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import camelot
3
+ import pandas as pd
4
+ import matplotlib.pyplot as plt
5
+ import numpy as np
6
+ from fpdf import FPDF
7
+ import tempfile
8
+ import os
9
+
10
+ def converter_nota(valor):
11
+ if pd.isna(valor) or valor == '-' or valor == 'N':
12
+ return 0
13
+ try:
14
+ return float(valor)
15
+ except:
16
+ return 0
17
+
18
+ def plotar_evolucao_bimestres(df_filtrado, temp_dir):
19
+ plt.figure(figsize=(12, 6))
20
+
21
+ disciplinas_basicas = ['LINGUA PORTUGUESA', 'ARTE', 'LINGUA ESTRANGEIRA INGLES',
22
+ 'GEOGRAFIA', 'CIENCIAS', 'HISTORIA', 'MATEMATICA']
23
+
24
+ estilos = {
25
+ 'LINGUA PORTUGUESA': {'cor': '#DC143C', 'marcador': 'p', 'zorder': 1, 'linestyle': '-', 'desloc': 0.1},
26
+ 'ARTE': {'cor': '#4169E1', 'marcador': 'D', 'zorder': 2, 'linestyle': '--', 'desloc': 0.08},
27
+ 'LINGUA ESTRANGEIRA INGLES': {'cor': '#9370DB', 'marcador': 'h', 'zorder': 3, 'linestyle': '-.', 'desloc': 0.06},
28
+ 'GEOGRAFIA': {'cor': '#32CD32', 'marcador': '^', 'zorder': 4, 'linestyle': ':', 'desloc': 0.04},
29
+ 'CIENCIAS': {'cor': '#FF8C00', 'marcador': 's', 'zorder': 5, 'linestyle': '-', 'desloc': 0.02},
30
+ 'HISTORIA': {'cor': '#00CED1', 'marcador': '*', 'zorder': 6, 'linestyle': '--', 'desloc': -0.02},
31
+ 'MATEMATICA': {'cor': '#FF69B4', 'marcador': 'o', 'zorder': 7, 'linestyle': '-.', 'desloc': -0.04}
32
+ }
33
+
34
+ plt.grid(True, linestyle='--', alpha=0.3, zorder=0)
35
+
36
+ colunas_notas = ['Nota B1', 'Nota B2', 'Nota B3', 'Nota B4']
37
+
38
+ for disciplina in disciplinas_basicas:
39
+ dados_disciplina = df_filtrado[df_filtrado['Disciplina'] == disciplina]
40
+ if not dados_disciplina.empty:
41
+ notas = dados_disciplina[colunas_notas].values[0]
42
+ notas_validas = notas > 0
43
+
44
+ if any(notas_validas):
45
+ bimestres = np.arange(1, len(colunas_notas) + 1)[notas_validas]
46
+ notas_filtradas = notas[notas_validas]
47
+
48
+ estilo = estilos[disciplina]
49
+ notas_deslocadas = notas_filtradas + estilo['desloc']
50
+
51
+ plt.plot(bimestres, notas_deslocadas,
52
+ color=estilo['cor'],
53
+ marker=estilo['marcador'],
54
+ markersize=10,
55
+ linewidth=2.5,
56
+ label=disciplina,
57
+ zorder=estilo['zorder'],
58
+ linestyle=estilo['linestyle'],
59
+ alpha=0.8)
60
+
61
+ for x, y in zip(bimestres, notas_filtradas):
62
+ plt.annotate(str(y), (x, y), textcoords="offset points", xytext=(0, 10), ha='center')
63
+
64
+ plt.title('Evolução das Médias por Disciplina ao Longo dos Bimestres')
65
+ plt.xlabel('Bimestres')
66
+ plt.ylabel('Média de Notas')
67
+ plt.xticks([1, 2, 3, 4], ['B1', 'B2', 'B3', 'B4'])
68
+ plt.ylim(0, 10)
69
+ plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
70
+ plt.tight_layout()
71
+
72
+ # Salvar o gráfico
73
+ plot_path = os.path.join(temp_dir, 'evolucao_notas.png')
74
+ plt.savefig(plot_path, bbox_inches='tight', dpi=300)
75
+ plt.close()
76
+ return plot_path
77
+
78
+ def plotar_graficos_destacados(df_boletim_clean, temp_dir):
79
+ disciplinas = df_boletim_clean['Disciplina'].astype(str)
80
+
81
+ medias_frequencia = df_boletim_clean[['Freq B1', 'Freq B2', 'Freq B3', 'Freq B4']].apply(pd.to_numeric, errors='coerce').mean(axis=1)
82
+ medias_notas = df_boletim_clean[['Nota B1', 'Nota B2', 'Nota B3', 'Nota B4']].apply(pd.to_numeric, errors='coerce').mean(axis=1)
83
+
84
+ cores_notas = ['red' if media < 5 else 'blue' for media in medias_notas]
85
+ cores_frequencias = ['red' if media < 75 else 'green' for media in medias_frequencia]
86
+
87
+ frequencia_global_media = medias_frequencia.mean()
88
+
89
+ plt.figure(figsize=(12, 6))
90
+
91
+ plt.subplot(1, 2, 1)
92
+ plt.bar(disciplinas, medias_notas, color=cores_notas)
93
+ plt.title('Média de Notas por Disciplina (Vermelho: < 5)')
94
+ plt.xticks(rotation=90)
95
+ plt.ylim(0, 10)
96
+
97
+ plt.subplot(1, 2, 2)
98
+ plt.bar(disciplinas, medias_frequencia, color=cores_frequencias)
99
+ plt.title('Média de Frequência por Disciplina (Vermelho: < 75%)')
100
+ plt.xticks(rotation=90)
101
+ plt.ylim(0, 100)
102
+
103
+ plt.suptitle(f"Frequência Global Média: {frequencia_global_media:.2f}%")
104
+
105
+ if frequencia_global_media < 75:
106
+ plt.figtext(0.5, 0.01, "Cuidado: Risco de Reprovação por Baixa Frequência", ha="center", fontsize=12, color="red")
107
+
108
+ plt.tight_layout()
109
+
110
+ # Salvar o gráfico
111
+ plot_path = os.path.join(temp_dir, 'medias_frequencias.png')
112
+ plt.savefig(plot_path, bbox_inches='tight', dpi=300)
113
+ plt.close()
114
+ return plot_path
115
+
116
+ def gerar_relatorio_pdf(df, grafico1_path, grafico2_path):
117
+ pdf = FPDF()
118
+ pdf.add_page()
119
+
120
+ # Título
121
+ pdf.set_font('Arial', 'B', 16)
122
+ pdf.cell(0, 10, 'Relatório de Desempenho Escolar', 0, 1, 'C')
123
+ pdf.ln(10)
124
+
125
+ # Adicionar gráficos
126
+ pdf.image(grafico1_path, x=10, w=190)
127
+ pdf.ln(10)
128
+ pdf.image(grafico2_path, x=10, w=190)
129
+ pdf.ln(10)
130
+
131
+ # Adicionar avisos
132
+ pdf.set_font('Arial', 'B', 12)
133
+ pdf.cell(0, 10, 'Avisos Importantes:', 0, 1, 'L')
134
+ pdf.set_font('Arial', '', 10)
135
+
136
+ medias_notas = df[['Nota B1', 'Nota B2', 'Nota B3', 'Nota B4']].apply(pd.to_numeric, errors='coerce').mean(axis=1)
137
+ medias_freq = df[['Freq B1', 'Freq B2', 'Freq B3', 'Freq B4']].apply(pd.to_numeric, errors='coerce').mean(axis=1)
138
+
139
+ for idx, (disciplina, media_nota, media_freq) in enumerate(zip(df['Disciplina'], medias_notas, medias_freq)):
140
+ if media_nota < 5:
141
+ pdf.cell(0, 10, f'- {disciplina}: Média de notas abaixo de 5 ({media_nota:.1f})', 0, 1, 'L')
142
+ if media_freq < 75:
143
+ pdf.cell(0, 10, f'- {disciplina}: Frequência abaixo de 75% ({media_freq:.1f}%)', 0, 1, 'L')
144
+
145
+ # Salvar PDF em um arquivo temporário
146
+ temp_pdf = tempfile.NamedTemporaryFile(delete=False, suffix='.pdf')
147
+ pdf_path = temp_pdf.name
148
+ pdf.output(pdf_path)
149
+ return pdf_path
150
+
151
+ def processar_boletim(pdf_file):
152
+ try:
153
+ # Criar diretório temporário
154
+ temp_dir = tempfile.mkdtemp()
155
+
156
+ # Salvar o arquivo PDF enviado
157
+ temp_pdf = os.path.join(temp_dir, 'boletim.pdf')
158
+ with open(temp_pdf, 'wb') as f:
159
+ f.write(pdf_file)
160
+
161
+ # Extrair tabelas do PDF
162
+ tables = camelot.read_pdf(temp_pdf, pages='all', flavor='lattice')
163
+
164
+ if len(tables) == 0:
165
+ return None, "Nenhuma tabela encontrada no PDF."
166
+
167
+ # Processar primeira tabela
168
+ df = tables[0].df
169
+
170
+ # Renomear colunas
171
+ df.columns = ['Disciplina', 'Nota B1', 'Freq B1', '%Freq B1', 'AC B1',
172
+ 'Nota B2', 'Freq B2', '%Freq B2', 'AC B2',
173
+ 'Nota B3', 'Freq B3', '%Freq B3', 'AC B3',
174
+ 'Nota B4', 'Freq B4', '%Freq B4', 'AC B4',
175
+ 'CF', 'Nota Final', 'Freq Final', 'AC Final']
176
+
177
+ # Converter notas
178
+ colunas_notas = ['Nota B1', 'Nota B2', 'Nota B3', 'Nota B4']
179
+ for col in colunas_notas:
180
+ df[col] = df[col].apply(converter_nota)
181
+
182
+ # Gerar gráficos
183
+ grafico1_path = plotar_evolucao_bimestres(df, temp_dir)
184
+ grafico2_path = plotar_graficos_destacados(df, temp_dir)
185
+
186
+ # Gerar PDF com o relatório
187
+ pdf_path = gerar_relatorio_pdf(df, grafico1_path, grafico2_path)
188
+
189
+ return pdf_path, "Relatório gerado com sucesso!"
190
+
191
+ except Exception as e:
192
+ return None, f"Erro ao processar o boletim: {str(e)}"
193
+ finally:
194
+ # Limpar arquivos temporários
195
+ if 'temp_dir' in locals():
196
+ for file in os.listdir(temp_dir):
197
+ os.remove(os.path.join(temp_dir, file))
198
+ os.rmdir(temp_dir)
199
+
200
+ # Interface Gradio
201
+ iface = gr.Interface(
202
+ fn=processar_boletim,
203
+ inputs=gr.File(label="Upload do Boletim (PDF)"),
204
+ outputs=[
205
+ gr.File(label="Relatório (PDF)"),
206
+ gr.Textbox(label="Status")
207
+ ],
208
+ title="Análise de Boletim Escolar",
209
+ description="Faça upload do boletim em PDF para gerar um relatório com análises e visualizações.",
210
+ allow_flagging="never"
211
+ )
212
+
213
+ if __name__ == "__main__":
214
+ iface.launch(server_name="0.0.0.0")