tarefasCMSP / app.py
histlearn's picture
Update app.py
207cd9d verified
raw
history blame
7.74 kB
import gradio as gr
import pandas as pd
import re
import os
from datetime import timedelta
def parse_duration(duration_str):
try:
h, m, s = map(int, duration_str.split(':'))
return timedelta(hours=h, minutes=m, seconds=s)
except:
return timedelta(0)
def format_timedelta(td):
total_seconds = int(td.total_seconds())
hours, remainder = divmod(total_seconds, 3600)
minutes, seconds = divmod(remainder, 60)
return f"{hours:02}:{minutes:02}:{seconds:02}"
def normalize_html_to_csv(input_html_path, output_csv_path):
html_data = pd.read_html(input_html_path)
data = html_data[0]
data.to_csv(output_csv_path, index=False)
def normalize_multiple_excel_to_csv(input_directory, output_directory):
input_excel_paths = [os.path.join(input_directory, f) for f in os.listdir(input_directory) if f.endswith('.xlsx')]
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')]
for input_excel_path, output_csv_path in zip(input_excel_paths, output_csv_paths):
excel_data = pd.read_excel(input_excel_path)
unnecessary_columns = [col for col in excel_data.columns if 'Unnamed' in col]
if unnecessary_columns:
excel_data = excel_data.drop(columns=unnecessary_columns)
excel_data.to_csv(output_csv_path, index=False)
def extract_aluno_pattern(nome):
if isinstance(nome, str):
match = re.search(r"(\d{8,9}-\w{2})", nome.lower())
return match.group(1) if match else None
return None
def match_alunos(tarefas_csv_path, alunos_csv_path, contador_df):
try:
tarefas_df = pd.read_csv(tarefas_csv_path)
alunos_df = pd.read_csv(alunos_csv_path)
except pd.errors.EmptyDataError:
print(f"Arquivo {tarefas_csv_path} ou {alunos_csv_path} está vazio. Pulando...")
return
tarefas_df.columns = tarefas_df.columns.str.strip()
alunos_df.columns = alunos_df.columns.str.strip()
if 'Aluno' not in tarefas_df.columns or 'Nota' not in tarefas_df.columns or 'Duração' not in tarefas_df.columns:
print(f"Colunas 'Aluno', 'Nota' ou 'Duração' não encontradas no arquivo {tarefas_csv_path}. Pulando este arquivo.")
return
def generate_aluno_pattern(ra, dig_ra):
ra_str = str(ra).zfill(9)
ra_without_first_two_digits = ra_str[2:]
return f"{ra_str[1]}{ra_without_first_two_digits}{dig_ra}-sp".lower()
alunos_df['Aluno_Pattern'] = alunos_df.apply(lambda row: generate_aluno_pattern(row['RA'], row['Dig. RA']), axis=1)
tarefas_df['Aluno_Pattern'] = tarefas_df['Aluno'].apply(extract_aluno_pattern)
tarefas_df['Duração'] = tarefas_df['Duração'].apply(parse_duration)
matched_alunos = alunos_df[alunos_df['Aluno_Pattern'].isin(tarefas_df['Aluno_Pattern'])]
result_df = matched_alunos[['Nome do Aluno']].drop_duplicates()
for aluno in result_df['Nome do Aluno']:
aluno_pattern = alunos_df.loc[alunos_df['Nome do Aluno'] == aluno, 'Aluno_Pattern'].values[0]
aluno_tarefas = tarefas_df[tarefas_df['Aluno_Pattern'] == aluno_pattern]
nota_total = aluno_tarefas['Nota'].sum()
tempo_total = aluno_tarefas['Duração'].sum()
if aluno in contador_df['Nome do Aluno'].values:
contador_df.loc[contador_df['Nome do Aluno'] == aluno, 'Tarefas Completadas'] += len(aluno_tarefas)
contador_df.loc[contador_df['Nome do Aluno'] == aluno, 'Acertos Absolutos'] += nota_total
current_total_tempo = pd.to_timedelta(contador_df.loc[contador_df['Nome do Aluno'] == aluno, 'Total Tempo'].values[0])
contador_df.loc[contador_df['Nome do Aluno'] == aluno, 'Total Tempo'] = str(current_total_tempo + tempo_total)
else:
contador_df = pd.concat([contador_df, pd.DataFrame({'Nome do Aluno': [aluno], 'Tarefas Completadas': [len(aluno_tarefas)], 'Acertos Absolutos': [nota_total], 'Total Tempo': [str(tempo_total)]})], ignore_index=True)
return contador_df
def process_all_tarefas_in_directory(directory, alunos_csv_path, contador_csv_path, relatorio_csv_path):
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']]
try:
contador_df = pd.read_csv(contador_csv_path)
except FileNotFoundError:
contador_df = pd.DataFrame(columns=['Nome do Aluno', 'Tarefas Completadas', 'Acertos Absolutos', 'Total Tempo'])
for i, tarefas_file in enumerate(tarefas_files):
print(f"Processando arquivo {i+1}/{len(tarefas_files)}: {tarefas_file}")
contador_df = match_alunos(tarefas_file, alunos_csv_path, contador_df)
print(f"Arquivo {tarefas_file} processado.")
contador_df.to_csv(contador_csv_path, index=False)
process_relatorios(contador_csv_path, relatorio_csv_path)
def process_relatorios(contador_csv_path, relatorio_csv_path):
contador_df = pd.read_csv(contador_csv_path)
contador_df['Média de Acertos'] = ((contador_df['Acertos Absolutos'] / (contador_df['Tarefas Completadas'] * 2)) * 100).round(2).astype(str) + '%'
contador_df['Total Tempo'] = pd.to_timedelta(contador_df['Total Tempo'])
contador_df['Tempo Médio por Tarefa'] = (contador_df['Total Tempo'] / contador_df['Tarefas Completadas']).apply(format_timedelta)
contador_df['Total Tempo'] = contador_df['Total Tempo'].apply(format_timedelta)
contador_df = contador_df.sort_values(by='Tarefas Completadas', ascending=False)
contador_df.to_csv(relatorio_csv_path, index=False)
return contador_df
def process_inputs(html_file, tarefa_files):
input_directory = "temp_files"
output_directory = "temp_files"
os.makedirs(input_directory, exist_ok=True)
os.makedirs(output_directory, exist_ok=True)
html_path = os.path.join(input_directory, "alunos.htm")
with open(html_path, "wb") as f:
f.write(html_file)
alunos_csv_path = os.path.join(output_directory, "alunos_fim.csv")
normalize_html_to_csv(html_path, alunos_csv_path)
for idx, tarefa_file in enumerate(tarefa_files):
tarefa_path = os.path.join(input_directory, f"tarefa_{idx}.xlsx")
with open(tarefa_path, "wb") as f:
f.write(tarefa_file)
normalize_multiple_excel_to_csv(input_directory, output_directory)
contador_csv_path = os.path.join(output_directory, "contador_tarefas.csv")
relatorio_csv_path = os.path.join(output_directory, "relatorio_final.csv")
process_all_tarefas_in_directory(output_directory, alunos_csv_path, contador_csv_path, relatorio_csv_path)
df = process_relatorios(contador_csv_path, relatorio_csv_path)
html_output_path = os.path.join(output_directory, "relatorio_final.html")
df.to_html(html_output_path, index=False)
return df.to_html(index=False), html_output_path
def download_html_file(file_path):
return file_path
# --- Interface Gradio ---
with gr.Blocks() as interface:
gr.Markdown("# Processamento de Relatórios de Tarefas")
html_file = gr.File(label="Upload HTML File (alunos.htm)", type="binary")
excel_files = gr.Files(label="Upload Excel Files (Relatórios de Tarefas)", type="binary", file_count="multiple")
generate_btn = gr.Button("Generate Report")
output_html = gr.HTML()
download_btn = gr.File(label="Download Report")
def process_and_prepare_download(html_file, tarefa_files):
html_content, file_path = process_inputs(html_file, tarefa_files)
return html_content, file_path
generate_btn.click(fn=process_and_prepare_download, inputs=[html_file, excel_files], outputs=[output_html, download_btn])
interface.launch()