histlearn commited on
Commit
3c8020f
·
verified ·
1 Parent(s): 9ad46f1

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +175 -0
  2. requirements.txt +5 -0
app.py ADDED
@@ -0,0 +1,175 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import pandas as pd
3
+ import re
4
+ import os
5
+ from datetime import timedelta
6
+
7
+ # --- Funções auxiliares ---
8
+
9
+ def parse_duration(duration_str):
10
+ try:
11
+ h, m, s = map(int, duration_str.split(':'))
12
+ return timedelta(hours=h, minutes=m, seconds=s)
13
+ except:
14
+ return timedelta(0)
15
+
16
+ def format_timedelta(td):
17
+ total_seconds = int(td.total_seconds())
18
+ hours, remainder = divmod(total_seconds, 3600)
19
+ minutes, seconds = divmod(remainder, 60)
20
+ return f"{hours:02}:{minutes:02}:{seconds:02}"
21
+
22
+ def normalize_html_to_csv(input_html_path, output_csv_path):
23
+ html_data = pd.read_html(input_html_path)
24
+ data = html_data[0]
25
+ data.to_csv(output_csv_path, index=False)
26
+
27
+ def normalize_multiple_excel_to_csv(input_directory, output_directory):
28
+ input_excel_paths = [os.path.join(input_directory, f) for f in os.listdir(input_directory) if f.endswith('.xlsx')]
29
+ output_csv_paths = [os.path.join(output_directory, os.path.splitext(f)[0] + '.csv') for f in os.listdir(input_directory) if f.endswith('.xlsx')]
30
+
31
+ for input_excel_path, output_csv_path in zip(input_excel_paths, output_csv_paths):
32
+ excel_data = pd.read_excel(input_excel_path)
33
+ unnecessary_columns = [col for col in excel_data.columns if 'Unnamed' in col]
34
+ if unnecessary_columns:
35
+ excel_data = excel_data.drop(columns=unnecessary_columns)
36
+ excel_data.to_csv(output_csv_path, index=False)
37
+
38
+ def extract_aluno_pattern(nome):
39
+ if isinstance(nome, str):
40
+ match = re.search(r"(\d{8,9}-\w{2})", nome.lower())
41
+ return match.group(1) if match else None
42
+ return None
43
+
44
+ def match_alunos(tarefas_csv_path, alunos_csv_path, contador_csv_path):
45
+ try:
46
+ tarefas_df = pd.read_csv(tarefas_csv_path)
47
+ alunos_df = pd.read_csv(alunos_csv_path)
48
+ except pd.errors.EmptyDataError:
49
+ print(f"Arquivo {tarefas_csv_path} ou {alunos_csv_path} está vazio. Pulando...")
50
+ return
51
+
52
+ tarefas_df.columns = tarefas_df.columns.str.strip()
53
+ alunos_df.columns = alunos_df.columns.str.strip()
54
+
55
+ if 'Aluno' not in tarefas_df.columns or 'Nota' not in tarefas_df.columns or 'Duração' not in tarefas_df.columns:
56
+ print(f"Colunas 'Aluno', 'Nota' ou 'Duração' não encontradas no arquivo {tarefas_csv_path}. Pulando este arquivo.")
57
+ return
58
+
59
+ try:
60
+ contador_df = pd.read_csv(contador_csv_path)
61
+ except FileNotFoundError:
62
+ contador_df = pd.DataFrame(columns=['Nome do Aluno', 'Tarefas Completadas', 'Acertos Absolutos', 'Total Tempo'])
63
+
64
+ if 'Tarefas Completadas' not in contador_df.columns:
65
+ contador_df['Tarefas Completadas'] = 0
66
+ if 'Acertos Absolutos' not in contador_df.columns:
67
+ contador_df['Acertos Absolutos'] = 0
68
+ if 'Total Tempo' not in contador_df.columns:
69
+ contador_df['Total Tempo'] = '00:00:00'
70
+
71
+ def generate_aluno_pattern(ra, dig_ra):
72
+ ra_str = str(ra).zfill(9)
73
+ ra_without_first_two_digits = ra_str[2:]
74
+ return f"{ra_str[1]}{ra_without_first_two_digits}{dig_ra}-sp".lower()
75
+
76
+ alunos_df['Aluno_Pattern'] = alunos_df.apply(lambda row: generate_aluno_pattern(row['RA'], row['Dig. RA']), axis=1)
77
+
78
+ tarefas_df['Aluno_Pattern'] = tarefas_df['Aluno'].apply(extract_aluno_pattern)
79
+ tarefas_df['Duração'] = tarefas_df['Duração'].apply(parse_duration)
80
+
81
+ matched_alunos = alunos_df[alunos_df['Aluno_Pattern'].isin(tarefas_df['Aluno_Pattern'])]
82
+
83
+ # Incluir todos os alunos, mesmo os que não têm tarefas correspondentes
84
+ todos_alunos = pd.DataFrame({'Nome do Aluno': alunos_df['Nome do Aluno'], 'Aluno_Pattern': alunos_df['Aluno_Pattern']})
85
+ todos_alunos = todos_alunos.drop_duplicates()
86
+
87
+ for aluno in todos_alunos['Nome do Aluno']:
88
+ aluno_pattern = todos_alunos.loc[todos_alunos['Nome do Aluno'] == aluno, 'Aluno_Pattern'].values[0]
89
+ aluno_tarefas = tarefas_df[tarefas_df['Aluno_Pattern'] == aluno_pattern]
90
+ nota_total = aluno_tarefas['Nota'].sum() if not aluno_tarefas.empty else 0
91
+ tempo_total = aluno_tarefas['Duração'].sum() if not aluno_tarefas.empty else timedelta(0)
92
+
93
+ if aluno in contador_df['Nome do Aluno'].values:
94
+ contador_df.loc[contador_df['Nome do Aluno'] == aluno, 'Tarefas Completadas'] += aluno_tarefas.shape[0]
95
+ contador_df.loc[contador_df['Nome do Aluno'] == aluno, 'Acertos Absolutos'] += nota_total
96
+ current_total_tempo = pd.to_timedelta(contador_df.loc[contador_df['Nome do Aluno'] == aluno, 'Total Tempo'].values[0])
97
+ contador_df.loc[contador_df['Nome do Aluno'] == aluno, 'Total Tempo'] = str(current_total_tempo + tempo_total)
98
+ else:
99
+ contador_df = pd.concat([contador_df, pd.DataFrame({'Nome do Aluno': [aluno], 'Tarefas Completadas': [aluno_tarefas.shape[0]], 'Acertos Absolutos': [nota_total], 'Total Tempo': [str(tempo_total)]})], ignore_index=True)
100
+
101
+ contador_df.to_csv(contador_csv_path, index=False)
102
+
103
+ return todos_alunos
104
+
105
+ def process_all_tarefas_in_directory(directory, alunos_csv_path, contador_csv_path, relatorio_csv_path):
106
+ tarefas_files = [os.path.join(directory, f) for f in os.listdir(directory) if f.endswith('.csv') and f not in ['alunos_fim.csv', 'contador_tarefas.csv']]
107
+
108
+ for i, tarefas_file in enumerate(tarefas_files):
109
+ print(f"Processando arquivo {i+1}/{len(tarefas_files)}: {tarefas_file}")
110
+ match_alunos(tarefas_file, alunos_csv_path, contador_csv_path)
111
+ print(f"Arquivo {tarefas_file} processado.")
112
+
113
+ process_relatorios(contador_csv_path, relatorio_csv_path)
114
+
115
+ def process_relatorios(contador_csv_path, relatorio_csv_path):
116
+ contador_df = pd.read_csv(contador_csv_path)
117
+ contador_df['Média de Acertos'] = ((contador_df['Acertos Absolutos'] / (contador_df['Tarefas Completadas'] * 2)) * 100).round(2).astype(str) + '%'
118
+ contador_df['Total Tempo'] = pd.to_timedelta(contador_df['Total Tempo'])
119
+
120
+ # Evitar divisão por zero para calcular 'Tempo Médio por Tarefa'
121
+ contador_df['Tempo Médio por Tarefa'] = contador_df.apply(
122
+ lambda row: format_timedelta(row['Total Tempo'] / row['Tarefas Completadas']) if row['Tarefas Completadas'] > 0 else '00:00:00', axis=1
123
+ )
124
+ contador_df['Total Tempo'] = contador_df['Total Tempo'].apply(format_timedelta)
125
+ contador_df = contador_df.sort_values(by='Tarefas Completadas', ascending=False)
126
+ contador_df.to_csv(relatorio_csv_path, index=False)
127
+ return contador_df
128
+
129
+ def process_inputs(html_file, tarefa_files):
130
+ input_directory = "temp_files"
131
+ output_directory = "temp_files"
132
+ os.makedirs(input_directory, exist_ok=True)
133
+ os.makedirs(output_directory, exist_ok=True)
134
+
135
+ html_path = os.path.join(input_directory, "alunos.htm")
136
+ with open(html_path, "wb") as f:
137
+ f.write(html_file)
138
+ alunos_csv_path = os.path.join(output_directory, "alunos_fim.csv")
139
+ normalize_html_to_csv(html_path, alunos_csv_path)
140
+
141
+ for idx, tarefa_file in enumerate(tarefa_files):
142
+ tarefa_path = os.path.join(input_directory, f"tarefa_{idx}.xlsx")
143
+ with open(tarefa_path, "wb") as f:
144
+ f.write(tarefa_file)
145
+ normalize_multiple_excel_to_csv(input_directory, output_directory)
146
+
147
+ contador_csv_path = os.path.join(output_directory, "contador_tarefas.csv")
148
+ relatorio_csv_path = os.path.join(output_directory, "relatorio_final.csv")
149
+ process_all_tarefas_in_directory(output_directory, alunos_csv_path, contador_csv_path, relatorio_csv_path)
150
+
151
+ df = process_relatorios(contador_csv_path, relatorio_csv_path)
152
+ html_output_path = os.path.join(output_directory, "relatorio_final.html")
153
+ df.to_html(html_output_path, index=False)
154
+ return df.to_html(index=False), html_output_path
155
+
156
+ def download_html_file(file_path):
157
+ return file_path
158
+
159
+ # --- Interface Gradio ---
160
+
161
+ with gr.Blocks() as interface:
162
+ gr.Markdown("# Processamento de Relatórios de Tarefas")
163
+ html_file = gr.File(label="Upload HTML File (alunos.htm)", type="binary")
164
+ excel_files = gr.Files(label="Upload Excel Files (Relatórios de Tarefas)", type="binary", file_count="multiple")
165
+ generate_btn = gr.Button("Generate Report")
166
+ output_html = gr.HTML()
167
+ download_btn = gr.File(label="Download Report")
168
+
169
+ def process_and_prepare_download(html_file, tarefa_files):
170
+ html_content, file_path = process_inputs(html_file, tarefa_files)
171
+ return html_content, file_path
172
+
173
+ generate_btn.click(fn=process_and_prepare_download, inputs=[html_file, excel_files], outputs=[output_html, download_btn])
174
+
175
+ interface.launch()
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ pandas
2
+ gradio
3
+ openpyxl
4
+ html5lib
5
+ lxml