866 lines
28 KiB
Plaintext
866 lines
28 KiB
Plaintext
|
|
{
|
|||
|
|
"cells": [
|
|||
|
|
{
|
|||
|
|
"cell_type": "code",
|
|||
|
|
"execution_count": null,
|
|||
|
|
"id": "1f540c43",
|
|||
|
|
"metadata": {},
|
|||
|
|
"outputs": [],
|
|||
|
|
"source": [
|
|||
|
|
"import os\n",
|
|||
|
|
"import tkinter as tk\n",
|
|||
|
|
"from tkinter import filedialog, simpledialog, messagebox\n",
|
|||
|
|
"import re\n",
|
|||
|
|
"from datetime import datetime\n",
|
|||
|
|
"import pandas as pd\n",
|
|||
|
|
"import pdfplumber\n",
|
|||
|
|
"from tkinter import messagebox\n",
|
|||
|
|
"import sys\n"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "code",
|
|||
|
|
"execution_count": 43,
|
|||
|
|
"id": "74f35480",
|
|||
|
|
"metadata": {},
|
|||
|
|
"outputs": [],
|
|||
|
|
"source": [
|
|||
|
|
"START_MARKER = \"Planeamento e execução da formação – Respostas:\"\n",
|
|||
|
|
"END_MARKER = \"Ação dos formadores\"\n",
|
|||
|
|
"OUT_DIR = \"output_tables\"\n",
|
|||
|
|
"os.makedirs(OUT_DIR, exist_ok=True)\n",
|
|||
|
|
"\n",
|
|||
|
|
"root = tk.Tk()\n",
|
|||
|
|
"root.withdraw() \n",
|
|||
|
|
"root.update()\n"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "code",
|
|||
|
|
"execution_count": 44,
|
|||
|
|
"id": "8b51acae",
|
|||
|
|
"metadata": {},
|
|||
|
|
"outputs": [
|
|||
|
|
{
|
|||
|
|
"data": {
|
|||
|
|
"text/plain": [
|
|||
|
|
"'D:\\\\DAQ\\\\Relatorios\\\\2CFPQP-ART\\\\2CFPQP_RAI_Art.pdf'"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"execution_count": 44,
|
|||
|
|
"metadata": {},
|
|||
|
|
"output_type": "execute_result"
|
|||
|
|
}
|
|||
|
|
],
|
|||
|
|
"source": [
|
|||
|
|
"pdf_path = filedialog.askopenfilename(\n",
|
|||
|
|
" title=\"Seleciona o PDF\",\n",
|
|||
|
|
" filetypes=[(\"PDF files\", \"*.pdf\"), (\"All files\", \"*.*\")]\n",
|
|||
|
|
")\n",
|
|||
|
|
"\n",
|
|||
|
|
"if not pdf_path:\n",
|
|||
|
|
" messagebox.showerror(\"Erro\", \"Nenhum PDF selecionado.\")\n",
|
|||
|
|
" raise SystemExit\n",
|
|||
|
|
"\n",
|
|||
|
|
"pdf_path = os.path.abspath(pdf_path)\n",
|
|||
|
|
"pdf_path\n"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "code",
|
|||
|
|
"execution_count": 45,
|
|||
|
|
"id": "e62c1fbb",
|
|||
|
|
"metadata": {},
|
|||
|
|
"outputs": [
|
|||
|
|
{
|
|||
|
|
"data": {
|
|||
|
|
"text/plain": [
|
|||
|
|
"'2CFPQP-Art'"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"execution_count": 45,
|
|||
|
|
"metadata": {},
|
|||
|
|
"output_type": "execute_result"
|
|||
|
|
}
|
|||
|
|
],
|
|||
|
|
"source": [
|
|||
|
|
"course_name = simpledialog.askstring(\n",
|
|||
|
|
" title=\"Nome do Curso\",\n",
|
|||
|
|
" prompt=\"Introduz o nome do curso:\"\n",
|
|||
|
|
")\n",
|
|||
|
|
"\n",
|
|||
|
|
"if not course_name:\n",
|
|||
|
|
" messagebox.showerror(\"Erro\", \"Nome do curso não foi preenchido.\")\n",
|
|||
|
|
" raise SystemExit\n",
|
|||
|
|
"\n",
|
|||
|
|
"course_name\n"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "code",
|
|||
|
|
"execution_count": 46,
|
|||
|
|
"id": "212eb52c",
|
|||
|
|
"metadata": {},
|
|||
|
|
"outputs": [
|
|||
|
|
{
|
|||
|
|
"data": {
|
|||
|
|
"text/plain": [
|
|||
|
|
"'2024'"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"execution_count": 46,
|
|||
|
|
"metadata": {},
|
|||
|
|
"output_type": "execute_result"
|
|||
|
|
}
|
|||
|
|
],
|
|||
|
|
"source": [
|
|||
|
|
"year = simpledialog.askstring(\n",
|
|||
|
|
" title=\"Ano\",\n",
|
|||
|
|
" prompt=\"Introduz o ano (ex: 2024):\"\n",
|
|||
|
|
")\n",
|
|||
|
|
"\n",
|
|||
|
|
"if not year or not year.isdigit():\n",
|
|||
|
|
" messagebox.showerror(\"Erro\", \"Ano inválido.\")\n",
|
|||
|
|
" raise SystemExit\n",
|
|||
|
|
"\n",
|
|||
|
|
"year\n"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "code",
|
|||
|
|
"execution_count": 47,
|
|||
|
|
"id": "5a225637",
|
|||
|
|
"metadata": {},
|
|||
|
|
"outputs": [],
|
|||
|
|
"source": [
|
|||
|
|
"def norm_text(s: str) -> str:\n",
|
|||
|
|
" if not s:\n",
|
|||
|
|
" return \"\"\n",
|
|||
|
|
" s = s.replace(\"–\", \"-\")\n",
|
|||
|
|
" s = re.sub(r\"\\s+\", \" \", s).strip().lower()\n",
|
|||
|
|
" return s\n",
|
|||
|
|
"\n",
|
|||
|
|
"def clean_cell(x) -> str:\n",
|
|||
|
|
" if x is None:\n",
|
|||
|
|
" return \"\"\n",
|
|||
|
|
" x = str(x).replace(\"\\n\", \" \").replace(\"\\r\", \" \").strip()\n",
|
|||
|
|
" x = re.sub(r\"\\s+\", \" \", x)\n",
|
|||
|
|
" return x\n",
|
|||
|
|
"\n",
|
|||
|
|
"def normalize_df(df: pd.DataFrame) -> pd.DataFrame:\n",
|
|||
|
|
" df = df.copy().applymap(clean_cell)\n",
|
|||
|
|
" df = df.loc[~(df.apply(lambda r: all(v == \"\" for v in r), axis=1))].reset_index(drop=True)\n",
|
|||
|
|
" return df\n",
|
|||
|
|
"\n",
|
|||
|
|
"def df_flattext(df: pd.DataFrame) -> str:\n",
|
|||
|
|
" vals = df.astype(str).fillna(\"\").values.flatten().tolist()\n",
|
|||
|
|
" return \" \".join(vals)\n",
|
|||
|
|
"\n",
|
|||
|
|
"def safe_filename(s: str) -> str:\n",
|
|||
|
|
" s = re.sub(r\"[\\\\/:*?\\\"<>|]+\", \"_\", s)\n",
|
|||
|
|
" s = re.sub(r\"\\s+\", \"_\", s.strip())\n",
|
|||
|
|
" return s[:180]\n"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "code",
|
|||
|
|
"execution_count": 48,
|
|||
|
|
"id": "990ce85a",
|
|||
|
|
"metadata": {},
|
|||
|
|
"outputs": [
|
|||
|
|
{
|
|||
|
|
"data": {
|
|||
|
|
"text/plain": [
|
|||
|
|
"(7, 8)"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"execution_count": 48,
|
|||
|
|
"metadata": {},
|
|||
|
|
"output_type": "execute_result"
|
|||
|
|
}
|
|||
|
|
],
|
|||
|
|
"source": [
|
|||
|
|
"start_n = norm_text(START_MARKER)\n",
|
|||
|
|
"end_n = norm_text(END_MARKER)\n",
|
|||
|
|
"with pdfplumber.open(pdf_path) as pdf:\n",
|
|||
|
|
" start_page = None\n",
|
|||
|
|
" end_page = None\n",
|
|||
|
|
" for i, page in enumerate(pdf.pages):\n",
|
|||
|
|
" txt = norm_text(page.extract_text() or \"\")\n",
|
|||
|
|
" if start_n in txt:\n",
|
|||
|
|
" start_page = i\n",
|
|||
|
|
" break\n",
|
|||
|
|
" if start_page is None:\n",
|
|||
|
|
" raise ValueError(f\"Não encontrei o início: {START_MARKER}\")\n",
|
|||
|
|
" for j in range(start_page, len(pdf.pages)):\n",
|
|||
|
|
" txt = norm_text(pdf.pages[j].extract_text() or \"\")\n",
|
|||
|
|
" if end_n in txt:\n",
|
|||
|
|
" end_page = j\n",
|
|||
|
|
" break\n",
|
|||
|
|
" if end_page is None:\n",
|
|||
|
|
" raise ValueError(f\"Encontrei o início, mas não encontrei o fim: {END_MARKER}\")\n",
|
|||
|
|
"(start_page + 1, end_page + 1)\n"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "code",
|
|||
|
|
"execution_count": 49,
|
|||
|
|
"id": "43916fc0",
|
|||
|
|
"metadata": {},
|
|||
|
|
"outputs": [
|
|||
|
|
{
|
|||
|
|
"name": "stderr",
|
|||
|
|
"output_type": "stream",
|
|||
|
|
"text": [
|
|||
|
|
"C:\\Users\\garci\\AppData\\Local\\Temp\\ipykernel_17004\\2567387785.py:16: FutureWarning: DataFrame.applymap has been deprecated. Use DataFrame.map instead.\n",
|
|||
|
|
" df = df.copy().applymap(clean_cell)\n",
|
|||
|
|
"C:\\Users\\garci\\AppData\\Local\\Temp\\ipykernel_17004\\2567387785.py:16: FutureWarning: DataFrame.applymap has been deprecated. Use DataFrame.map instead.\n",
|
|||
|
|
" df = df.copy().applymap(clean_cell)\n",
|
|||
|
|
"C:\\Users\\garci\\AppData\\Local\\Temp\\ipykernel_17004\\2567387785.py:16: FutureWarning: DataFrame.applymap has been deprecated. Use DataFrame.map instead.\n",
|
|||
|
|
" df = df.copy().applymap(clean_cell)\n",
|
|||
|
|
"C:\\Users\\garci\\AppData\\Local\\Temp\\ipykernel_17004\\2567387785.py:16: FutureWarning: DataFrame.applymap has been deprecated. Use DataFrame.map instead.\n",
|
|||
|
|
" df = df.copy().applymap(clean_cell)\n"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"data": {
|
|||
|
|
"text/plain": [
|
|||
|
|
"4"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"execution_count": 49,
|
|||
|
|
"metadata": {},
|
|||
|
|
"output_type": "execute_result"
|
|||
|
|
}
|
|||
|
|
],
|
|||
|
|
"source": [
|
|||
|
|
"candidates = []\n",
|
|||
|
|
"\n",
|
|||
|
|
"with pdfplumber.open(pdf_path) as pdf:\n",
|
|||
|
|
" for pno in range(start_page, end_page + 1):\n",
|
|||
|
|
" page = pdf.pages[pno]\n",
|
|||
|
|
" tables = page.extract_tables() or []\n",
|
|||
|
|
"\n",
|
|||
|
|
" for ti, tbl in enumerate(tables, start=1):\n",
|
|||
|
|
" if not tbl or len(tbl) < 2:\n",
|
|||
|
|
" continue\n",
|
|||
|
|
" header = tbl[0]\n",
|
|||
|
|
" body = tbl[1:]\n",
|
|||
|
|
" df = pd.DataFrame(body, columns=header)\n",
|
|||
|
|
" df = normalize_df(df)\n",
|
|||
|
|
"\n",
|
|||
|
|
" r, c = df.shape\n",
|
|||
|
|
" if r < 2 or c < 2:\n",
|
|||
|
|
" continue\n",
|
|||
|
|
" text_n = norm_text(df_flattext(df))\n",
|
|||
|
|
" score = 0\n",
|
|||
|
|
" if c >= 3: score += 10\n",
|
|||
|
|
" if r >= 4: score += 10\n",
|
|||
|
|
" if pno == start_page: score += 15\n",
|
|||
|
|
" for kw in [\"planeamento\", \"execucao\", \"formacao\", \"respostas\", \"formadores\"]:\n",
|
|||
|
|
" if kw in text_n:\n",
|
|||
|
|
" score += 2\n",
|
|||
|
|
"\n",
|
|||
|
|
" empties = (df == \"\").sum().sum()\n",
|
|||
|
|
" total = r * c\n",
|
|||
|
|
" if total and empties / total > 0.6:\n",
|
|||
|
|
" score -= 10\n",
|
|||
|
|
"\n",
|
|||
|
|
" candidates.append((score, pno, ti, df))\n",
|
|||
|
|
"\n",
|
|||
|
|
"len(candidates)\n"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "code",
|
|||
|
|
"execution_count": 50,
|
|||
|
|
"id": "cd4bd06b",
|
|||
|
|
"metadata": {},
|
|||
|
|
"outputs": [
|
|||
|
|
{
|
|||
|
|
"name": "stdout",
|
|||
|
|
"output_type": "stream",
|
|||
|
|
"text": [
|
|||
|
|
"Bloco: páginas 7 → 8\n",
|
|||
|
|
"Tabela escolhida: p7_t1 (score=35)\n",
|
|||
|
|
"Dimensões: (18, 4)\n"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"data": {
|
|||
|
|
"text/html": [
|
|||
|
|
"<div>\n",
|
|||
|
|
"<style scoped>\n",
|
|||
|
|
" .dataframe tbody tr th:only-of-type {\n",
|
|||
|
|
" vertical-align: middle;\n",
|
|||
|
|
" }\n",
|
|||
|
|
"\n",
|
|||
|
|
" .dataframe tbody tr th {\n",
|
|||
|
|
" vertical-align: top;\n",
|
|||
|
|
" }\n",
|
|||
|
|
"\n",
|
|||
|
|
" .dataframe thead th {\n",
|
|||
|
|
" text-align: right;\n",
|
|||
|
|
" }\n",
|
|||
|
|
"</style>\n",
|
|||
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|||
|
|
" <thead>\n",
|
|||
|
|
" <tr style=\"text-align: right;\">\n",
|
|||
|
|
" <th></th>\n",
|
|||
|
|
" <th>Indicadores</th>\n",
|
|||
|
|
" <th>Avaliação</th>\n",
|
|||
|
|
" <th>None</th>\n",
|
|||
|
|
" <th>Ganhos / Perdas</th>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" </thead>\n",
|
|||
|
|
" <tbody>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>0</th>\n",
|
|||
|
|
" <td>1. Intervenção da Unidade Formadora</td>\n",
|
|||
|
|
" <td>Inicial</td>\n",
|
|||
|
|
" <td>Final</td>\n",
|
|||
|
|
" <td></td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>1</th>\n",
|
|||
|
|
" <td>1.1 Apoio Técnico administrativo</td>\n",
|
|||
|
|
" <td>N/A</td>\n",
|
|||
|
|
" <td>3.91</td>\n",
|
|||
|
|
" <td>N/A</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>2</th>\n",
|
|||
|
|
" <td>1.2 Alojamento</td>\n",
|
|||
|
|
" <td>4.55</td>\n",
|
|||
|
|
" <td>4.45</td>\n",
|
|||
|
|
" <td>-0.1</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>3</th>\n",
|
|||
|
|
" <td>1.3 Alimentação</td>\n",
|
|||
|
|
" <td>4.27</td>\n",
|
|||
|
|
" <td>4.0</td>\n",
|
|||
|
|
" <td>-0.27</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>4</th>\n",
|
|||
|
|
" <td>2. Intervenção da Direção de Curso</td>\n",
|
|||
|
|
" <td>Inicial</td>\n",
|
|||
|
|
" <td>Final</td>\n",
|
|||
|
|
" <td></td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>5</th>\n",
|
|||
|
|
" <td>2.1 Apoio prestado pela Direção de Curso</td>\n",
|
|||
|
|
" <td>N/A</td>\n",
|
|||
|
|
" <td>4.09</td>\n",
|
|||
|
|
" <td>N/A</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>6</th>\n",
|
|||
|
|
" <td>3. Programa de Curso</td>\n",
|
|||
|
|
" <td>Inicial</td>\n",
|
|||
|
|
" <td>Final</td>\n",
|
|||
|
|
" <td></td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>7</th>\n",
|
|||
|
|
" <td>3.1 Grau de dificuldade do curso</td>\n",
|
|||
|
|
" <td>3.55</td>\n",
|
|||
|
|
" <td>3.27</td>\n",
|
|||
|
|
" <td>-0.28</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>8</th>\n",
|
|||
|
|
" <td>3.2 Utilidade do Curso para futuras funções</td>\n",
|
|||
|
|
" <td>4.09</td>\n",
|
|||
|
|
" <td>3.82</td>\n",
|
|||
|
|
" <td>-0.27</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>9</th>\n",
|
|||
|
|
" <td>3.3 Motivação e participação</td>\n",
|
|||
|
|
" <td>4.45</td>\n",
|
|||
|
|
" <td>4.09</td>\n",
|
|||
|
|
" <td>-0.36</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>10</th>\n",
|
|||
|
|
" <td>3.4 Grau de conhecimento adquirido com o curso</td>\n",
|
|||
|
|
" <td>3.73</td>\n",
|
|||
|
|
" <td>4.09</td>\n",
|
|||
|
|
" <td>0.36</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>11</th>\n",
|
|||
|
|
" <td>4. Funcionamento do Curso</td>\n",
|
|||
|
|
" <td></td>\n",
|
|||
|
|
" <td></td>\n",
|
|||
|
|
" <td>Média</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>12</th>\n",
|
|||
|
|
" <td>4.1 Objetivo do curso</td>\n",
|
|||
|
|
" <td></td>\n",
|
|||
|
|
" <td></td>\n",
|
|||
|
|
" <td>3.64</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>13</th>\n",
|
|||
|
|
" <td>4.2 Conteúdo do curso</td>\n",
|
|||
|
|
" <td></td>\n",
|
|||
|
|
" <td></td>\n",
|
|||
|
|
" <td>3.55</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>14</th>\n",
|
|||
|
|
" <td>4.3 Adequação dos trabalhos/exercícios</td>\n",
|
|||
|
|
" <td></td>\n",
|
|||
|
|
" <td></td>\n",
|
|||
|
|
" <td>3.36</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>15</th>\n",
|
|||
|
|
" <td>4.4 Instalações afetas à formação</td>\n",
|
|||
|
|
" <td></td>\n",
|
|||
|
|
" <td></td>\n",
|
|||
|
|
" <td>3.82</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>16</th>\n",
|
|||
|
|
" <td>4.5 Meios audiovisuais e didáticos</td>\n",
|
|||
|
|
" <td></td>\n",
|
|||
|
|
" <td></td>\n",
|
|||
|
|
" <td>4.09</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>17</th>\n",
|
|||
|
|
" <td>4.6 Documentos e bibliografias disponibilizadas</td>\n",
|
|||
|
|
" <td></td>\n",
|
|||
|
|
" <td></td>\n",
|
|||
|
|
" <td>4.09</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" </tbody>\n",
|
|||
|
|
"</table>\n",
|
|||
|
|
"</div>"
|
|||
|
|
],
|
|||
|
|
"text/plain": [
|
|||
|
|
" Indicadores Avaliação None \\\n",
|
|||
|
|
"0 1. Intervenção da Unidade Formadora Inicial Final \n",
|
|||
|
|
"1 1.1 Apoio Técnico administrativo N/A 3.91 \n",
|
|||
|
|
"2 1.2 Alojamento 4.55 4.45 \n",
|
|||
|
|
"3 1.3 Alimentação 4.27 4.0 \n",
|
|||
|
|
"4 2. Intervenção da Direção de Curso Inicial Final \n",
|
|||
|
|
"5 2.1 Apoio prestado pela Direção de Curso N/A 4.09 \n",
|
|||
|
|
"6 3. Programa de Curso Inicial Final \n",
|
|||
|
|
"7 3.1 Grau de dificuldade do curso 3.55 3.27 \n",
|
|||
|
|
"8 3.2 Utilidade do Curso para futuras funções 4.09 3.82 \n",
|
|||
|
|
"9 3.3 Motivação e participação 4.45 4.09 \n",
|
|||
|
|
"10 3.4 Grau de conhecimento adquirido com o curso 3.73 4.09 \n",
|
|||
|
|
"11 4. Funcionamento do Curso \n",
|
|||
|
|
"12 4.1 Objetivo do curso \n",
|
|||
|
|
"13 4.2 Conteúdo do curso \n",
|
|||
|
|
"14 4.3 Adequação dos trabalhos/exercícios \n",
|
|||
|
|
"15 4.4 Instalações afetas à formação \n",
|
|||
|
|
"16 4.5 Meios audiovisuais e didáticos \n",
|
|||
|
|
"17 4.6 Documentos e bibliografias disponibilizadas \n",
|
|||
|
|
"\n",
|
|||
|
|
" Ganhos / Perdas \n",
|
|||
|
|
"0 \n",
|
|||
|
|
"1 N/A \n",
|
|||
|
|
"2 -0.1 \n",
|
|||
|
|
"3 -0.27 \n",
|
|||
|
|
"4 \n",
|
|||
|
|
"5 N/A \n",
|
|||
|
|
"6 \n",
|
|||
|
|
"7 -0.28 \n",
|
|||
|
|
"8 -0.27 \n",
|
|||
|
|
"9 -0.36 \n",
|
|||
|
|
"10 0.36 \n",
|
|||
|
|
"11 Média \n",
|
|||
|
|
"12 3.64 \n",
|
|||
|
|
"13 3.55 \n",
|
|||
|
|
"14 3.36 \n",
|
|||
|
|
"15 3.82 \n",
|
|||
|
|
"16 4.09 \n",
|
|||
|
|
"17 4.09 "
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"execution_count": 50,
|
|||
|
|
"metadata": {},
|
|||
|
|
"output_type": "execute_result"
|
|||
|
|
}
|
|||
|
|
],
|
|||
|
|
"source": [
|
|||
|
|
"if not candidates:\n",
|
|||
|
|
" raise ValueError(\"Encontrei o bloco, mas não encontrei tabelas nas páginas desse intervalo.\")\n",
|
|||
|
|
"\n",
|
|||
|
|
"candidates.sort(key=lambda x: x[0], reverse=True)\n",
|
|||
|
|
"best_score, best_pno, best_ti, best_df = candidates[0]\n",
|
|||
|
|
"\n",
|
|||
|
|
"print(f\"Bloco: páginas {start_page+1} → {end_page+1}\")\n",
|
|||
|
|
"print(f\"Tabela escolhida: p{best_pno+1}_t{best_ti} (score={best_score})\")\n",
|
|||
|
|
"print(\"Dimensões:\", best_df.shape)\n",
|
|||
|
|
"\n",
|
|||
|
|
"best_df.head(30)\n"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "code",
|
|||
|
|
"execution_count": 51,
|
|||
|
|
"id": "884d3881",
|
|||
|
|
"metadata": {},
|
|||
|
|
"outputs": [],
|
|||
|
|
"source": [
|
|||
|
|
"def dot_to_comma(df: pd.DataFrame) -> pd.DataFrame:\n",
|
|||
|
|
" df = df.copy()\n",
|
|||
|
|
"\n",
|
|||
|
|
" def convert(x):\n",
|
|||
|
|
" if isinstance(x, (int, float)):\n",
|
|||
|
|
" return str(x).replace(\".\", \",\")\n",
|
|||
|
|
" if isinstance(x, str):\n",
|
|||
|
|
" # só troca se parecer número (ex: \"3.5\")\n",
|
|||
|
|
" if re.fullmatch(r\"-?\\d+\\.\\d+\", x):\n",
|
|||
|
|
" return x.replace(\".\", \",\")\n",
|
|||
|
|
" return x\n",
|
|||
|
|
"\n",
|
|||
|
|
" return df.applymap(convert)"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "code",
|
|||
|
|
"execution_count": 52,
|
|||
|
|
"id": "f1d5c545",
|
|||
|
|
"metadata": {},
|
|||
|
|
"outputs": [
|
|||
|
|
{
|
|||
|
|
"data": {
|
|||
|
|
"text/html": [
|
|||
|
|
"<div>\n",
|
|||
|
|
"<style scoped>\n",
|
|||
|
|
" .dataframe tbody tr th:only-of-type {\n",
|
|||
|
|
" vertical-align: middle;\n",
|
|||
|
|
" }\n",
|
|||
|
|
"\n",
|
|||
|
|
" .dataframe tbody tr th {\n",
|
|||
|
|
" vertical-align: top;\n",
|
|||
|
|
" }\n",
|
|||
|
|
"\n",
|
|||
|
|
" .dataframe thead th {\n",
|
|||
|
|
" text-align: right;\n",
|
|||
|
|
" }\n",
|
|||
|
|
"</style>\n",
|
|||
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|||
|
|
" <thead>\n",
|
|||
|
|
" <tr style=\"text-align: right;\">\n",
|
|||
|
|
" <th></th>\n",
|
|||
|
|
" <th>0</th>\n",
|
|||
|
|
" <th>1</th>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" </thead>\n",
|
|||
|
|
" <tbody>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>0</th>\n",
|
|||
|
|
" <td>1.1 Apoio Técnico administrativo</td>\n",
|
|||
|
|
" <td>3.91</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>1</th>\n",
|
|||
|
|
" <td>1.2 Alojamento</td>\n",
|
|||
|
|
" <td>4.45</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>2</th>\n",
|
|||
|
|
" <td>1.3 Alimentação</td>\n",
|
|||
|
|
" <td>4.0</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>3</th>\n",
|
|||
|
|
" <td>2.1 Apoio prestado pela Direção de Curso</td>\n",
|
|||
|
|
" <td>4.09</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>4</th>\n",
|
|||
|
|
" <td>3.1 Grau de dificuldade do curso</td>\n",
|
|||
|
|
" <td>3.27</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>5</th>\n",
|
|||
|
|
" <td>3.2 Utilidade do Curso para futuras funções</td>\n",
|
|||
|
|
" <td>3.82</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>6</th>\n",
|
|||
|
|
" <td>3.3 Motivação e participação</td>\n",
|
|||
|
|
" <td>4.09</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>7</th>\n",
|
|||
|
|
" <td>3.4 Grau de conhecimento adquirido com o curso</td>\n",
|
|||
|
|
" <td>4.09</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>8</th>\n",
|
|||
|
|
" <td>4.1 Objetivo do curso</td>\n",
|
|||
|
|
" <td>3.64</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>9</th>\n",
|
|||
|
|
" <td>4.2 Conteúdo do curso</td>\n",
|
|||
|
|
" <td>3.55</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>10</th>\n",
|
|||
|
|
" <td>4.3 Adequação dos trabalhos/exercícios</td>\n",
|
|||
|
|
" <td>3.36</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>11</th>\n",
|
|||
|
|
" <td>4.4 Instalações afetas à formação</td>\n",
|
|||
|
|
" <td>3.82</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>12</th>\n",
|
|||
|
|
" <td>4.5 Meios audiovisuais e didáticos</td>\n",
|
|||
|
|
" <td>4.09</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>13</th>\n",
|
|||
|
|
" <td>4.6 Documentos e bibliografias disponibilizadas</td>\n",
|
|||
|
|
" <td>4.09</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" </tbody>\n",
|
|||
|
|
"</table>\n",
|
|||
|
|
"</div>"
|
|||
|
|
],
|
|||
|
|
"text/plain": [
|
|||
|
|
" 0 1\n",
|
|||
|
|
"0 1.1 Apoio Técnico administrativo 3.91\n",
|
|||
|
|
"1 1.2 Alojamento 4.45\n",
|
|||
|
|
"2 1.3 Alimentação 4.0\n",
|
|||
|
|
"3 2.1 Apoio prestado pela Direção de Curso 4.09\n",
|
|||
|
|
"4 3.1 Grau de dificuldade do curso 3.27\n",
|
|||
|
|
"5 3.2 Utilidade do Curso para futuras funções 3.82\n",
|
|||
|
|
"6 3.3 Motivação e participação 4.09\n",
|
|||
|
|
"7 3.4 Grau de conhecimento adquirido com o curso 4.09\n",
|
|||
|
|
"8 4.1 Objetivo do curso 3.64\n",
|
|||
|
|
"9 4.2 Conteúdo do curso 3.55\n",
|
|||
|
|
"10 4.3 Adequação dos trabalhos/exercícios 3.36\n",
|
|||
|
|
"11 4.4 Instalações afetas à formação 3.82\n",
|
|||
|
|
"12 4.5 Meios audiovisuais e didáticos 4.09\n",
|
|||
|
|
"13 4.6 Documentos e bibliografias disponibilizadas 4.09"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"execution_count": 52,
|
|||
|
|
"metadata": {},
|
|||
|
|
"output_type": "execute_result"
|
|||
|
|
}
|
|||
|
|
],
|
|||
|
|
"source": [
|
|||
|
|
"rows_config = {\n",
|
|||
|
|
" 1: [0, 2],\n",
|
|||
|
|
" 2: [0, 2],\n",
|
|||
|
|
" 3: [0, 2],\n",
|
|||
|
|
" 5: [0, 2],\n",
|
|||
|
|
" 7: [0, 2],\n",
|
|||
|
|
" 8: [0, 2],\n",
|
|||
|
|
" 9: [0, 2],\n",
|
|||
|
|
" 10: [0, 2],\n",
|
|||
|
|
" 12: [0, 3],\n",
|
|||
|
|
" 13: [0, 3],\n",
|
|||
|
|
" 14: [0, 3],\n",
|
|||
|
|
" 15: [0, 3],\n",
|
|||
|
|
" 16: [0, 3],\n",
|
|||
|
|
" 17: [0, 3]\n",
|
|||
|
|
"}\n",
|
|||
|
|
"\n",
|
|||
|
|
"new_rows = []\n",
|
|||
|
|
"\n",
|
|||
|
|
"for row_idx, col_idxs in rows_config.items():\n",
|
|||
|
|
" values = best_df.iloc[row_idx, col_idxs].tolist()\n",
|
|||
|
|
" new_rows.append(values)\n",
|
|||
|
|
"\n",
|
|||
|
|
"new_df = pd.DataFrame(new_rows)\n",
|
|||
|
|
"new_df"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "code",
|
|||
|
|
"execution_count": 53,
|
|||
|
|
"id": "5dfa7c90",
|
|||
|
|
"metadata": {},
|
|||
|
|
"outputs": [
|
|||
|
|
{
|
|||
|
|
"name": "stderr",
|
|||
|
|
"output_type": "stream",
|
|||
|
|
"text": [
|
|||
|
|
"C:\\Users\\garci\\AppData\\Local\\Temp\\ipykernel_17004\\2220260037.py:13: FutureWarning: DataFrame.applymap has been deprecated. Use DataFrame.map instead.\n",
|
|||
|
|
" return df.applymap(convert)\n"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"data": {
|
|||
|
|
"text/html": [
|
|||
|
|
"<div>\n",
|
|||
|
|
"<style scoped>\n",
|
|||
|
|
" .dataframe tbody tr th:only-of-type {\n",
|
|||
|
|
" vertical-align: middle;\n",
|
|||
|
|
" }\n",
|
|||
|
|
"\n",
|
|||
|
|
" .dataframe tbody tr th {\n",
|
|||
|
|
" vertical-align: top;\n",
|
|||
|
|
" }\n",
|
|||
|
|
"\n",
|
|||
|
|
" .dataframe thead th {\n",
|
|||
|
|
" text-align: right;\n",
|
|||
|
|
" }\n",
|
|||
|
|
"</style>\n",
|
|||
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|||
|
|
" <thead>\n",
|
|||
|
|
" <tr style=\"text-align: right;\">\n",
|
|||
|
|
" <th></th>\n",
|
|||
|
|
" <th>1.1 Apoio Técnico administrativo</th>\n",
|
|||
|
|
" <th>1.2 Alojamento</th>\n",
|
|||
|
|
" <th>1.3 Alimentação</th>\n",
|
|||
|
|
" <th>2.1 Apoio prestado pela Direção de Curso</th>\n",
|
|||
|
|
" <th>3.1 Grau de dificuldade do curso</th>\n",
|
|||
|
|
" <th>3.2 Utilidade do Curso para futuras funções</th>\n",
|
|||
|
|
" <th>3.3 Motivação e participação</th>\n",
|
|||
|
|
" <th>3.4 Grau de conhecimento adquirido com o curso</th>\n",
|
|||
|
|
" <th>4.1 Objetivo do curso</th>\n",
|
|||
|
|
" <th>4.2 Conteúdo do curso</th>\n",
|
|||
|
|
" <th>4.3 Adequação dos trabalhos/exercícios</th>\n",
|
|||
|
|
" <th>4.4 Instalações afetas à formação</th>\n",
|
|||
|
|
" <th>4.5 Meios audiovisuais e didáticos</th>\n",
|
|||
|
|
" <th>4.6 Documentos e bibliografias disponibilizadas</th>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" </thead>\n",
|
|||
|
|
" <tbody>\n",
|
|||
|
|
" <tr>\n",
|
|||
|
|
" <th>2024 - 2CFPQP-Art</th>\n",
|
|||
|
|
" <td>3,91</td>\n",
|
|||
|
|
" <td>4,45</td>\n",
|
|||
|
|
" <td>4,0</td>\n",
|
|||
|
|
" <td>4,09</td>\n",
|
|||
|
|
" <td>3,27</td>\n",
|
|||
|
|
" <td>3,82</td>\n",
|
|||
|
|
" <td>4,09</td>\n",
|
|||
|
|
" <td>4,09</td>\n",
|
|||
|
|
" <td>3,64</td>\n",
|
|||
|
|
" <td>3,55</td>\n",
|
|||
|
|
" <td>3,36</td>\n",
|
|||
|
|
" <td>3,82</td>\n",
|
|||
|
|
" <td>4,09</td>\n",
|
|||
|
|
" <td>4,09</td>\n",
|
|||
|
|
" </tr>\n",
|
|||
|
|
" </tbody>\n",
|
|||
|
|
"</table>\n",
|
|||
|
|
"</div>"
|
|||
|
|
],
|
|||
|
|
"text/plain": [
|
|||
|
|
" 1.1 Apoio Técnico administrativo 1.2 Alojamento \\\n",
|
|||
|
|
"2024 - 2CFPQP-Art 3,91 4,45 \n",
|
|||
|
|
"\n",
|
|||
|
|
" 1.3 Alimentação 2.1 Apoio prestado pela Direção de Curso \\\n",
|
|||
|
|
"2024 - 2CFPQP-Art 4,0 4,09 \n",
|
|||
|
|
"\n",
|
|||
|
|
" 3.1 Grau de dificuldade do curso \\\n",
|
|||
|
|
"2024 - 2CFPQP-Art 3,27 \n",
|
|||
|
|
"\n",
|
|||
|
|
" 3.2 Utilidade do Curso para futuras funções \\\n",
|
|||
|
|
"2024 - 2CFPQP-Art 3,82 \n",
|
|||
|
|
"\n",
|
|||
|
|
" 3.3 Motivação e participação \\\n",
|
|||
|
|
"2024 - 2CFPQP-Art 4,09 \n",
|
|||
|
|
"\n",
|
|||
|
|
" 3.4 Grau de conhecimento adquirido com o curso \\\n",
|
|||
|
|
"2024 - 2CFPQP-Art 4,09 \n",
|
|||
|
|
"\n",
|
|||
|
|
" 4.1 Objetivo do curso 4.2 Conteúdo do curso \\\n",
|
|||
|
|
"2024 - 2CFPQP-Art 3,64 3,55 \n",
|
|||
|
|
"\n",
|
|||
|
|
" 4.3 Adequação dos trabalhos/exercícios \\\n",
|
|||
|
|
"2024 - 2CFPQP-Art 3,36 \n",
|
|||
|
|
"\n",
|
|||
|
|
" 4.4 Instalações afetas à formação \\\n",
|
|||
|
|
"2024 - 2CFPQP-Art 3,82 \n",
|
|||
|
|
"\n",
|
|||
|
|
" 4.5 Meios audiovisuais e didáticos \\\n",
|
|||
|
|
"2024 - 2CFPQP-Art 4,09 \n",
|
|||
|
|
"\n",
|
|||
|
|
" 4.6 Documentos e bibliografias disponibilizadas \n",
|
|||
|
|
"2024 - 2CFPQP-Art 4,09 "
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
"execution_count": 53,
|
|||
|
|
"metadata": {},
|
|||
|
|
"output_type": "execute_result"
|
|||
|
|
}
|
|||
|
|
],
|
|||
|
|
"source": [
|
|||
|
|
"data_dict = dict(zip(new_df[0], new_df[1]))\n",
|
|||
|
|
"final_df = pd.DataFrame([data_dict])\n",
|
|||
|
|
"final_df.index = [f\"{year} - {course_name}\"]\n",
|
|||
|
|
"final_df = dot_to_comma(final_df)\n",
|
|||
|
|
"final_df"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "code",
|
|||
|
|
"execution_count": null,
|
|||
|
|
"id": "10337d57",
|
|||
|
|
"metadata": {},
|
|||
|
|
"outputs": [],
|
|||
|
|
"source": [
|
|||
|
|
"def save_row_if_new(final_df: pd.DataFrame, xlsx_path: str, row_name: str, sheet_name: str = \"Resultados\"):\n",
|
|||
|
|
" root = tk.Tk()\n",
|
|||
|
|
" root.withdraw()\n",
|
|||
|
|
" if not os.path.exists(xlsx_path):\n",
|
|||
|
|
" final_df.to_excel(xlsx_path, sheet_name=sheet_name, index=True)\n",
|
|||
|
|
" messagebox.showinfo(\"OK\", f\"Ficheiro criado e linha guardada:\\n{row_name}\\n\\n{xlsx_path}\")\n",
|
|||
|
|
" return False \n",
|
|||
|
|
" try:\n",
|
|||
|
|
" existing = pd.read_excel(xlsx_path, sheet_name=sheet_name, index_col=0)\n",
|
|||
|
|
" except ValueError:\n",
|
|||
|
|
" final_df.to_excel(xlsx_path, sheet_name=sheet_name, index=True)\n",
|
|||
|
|
" messagebox.showinfo(\"OK\", f\"Sheet '{sheet_name}' criada e linha guardada:\\n{row_name}\")\n",
|
|||
|
|
" return False\n",
|
|||
|
|
" if row_name in existing.index.astype(str):\n",
|
|||
|
|
" messagebox.showwarning(\"Já existe\", f\"Já existe uma linha com este nome:\\n{row_name}\\n\\nNada foi gravado.\")\n",
|
|||
|
|
" return True\n",
|
|||
|
|
" updated = pd.concat([existing, final_df], axis=0)\n",
|
|||
|
|
" with pd.ExcelWriter(xlsx_path, engine=\"openpyxl\", mode=\"w\") as writer:\n",
|
|||
|
|
" updated.to_excel(writer, sheet_name=sheet_name, index=True)\n",
|
|||
|
|
" messagebox.showinfo(\"OK\", f\"Linha adicionada com sucesso:\\n{row_name}\\n\\n{xlsx_path}\")\n",
|
|||
|
|
" return False\n",
|
|||
|
|
"row_name = f\"{year} - {course_name}\"\n",
|
|||
|
|
"xlsx_path = \"BDpowerbi.xlsx\"\n",
|
|||
|
|
"_duplicado = save_row_if_new(final_df, xlsx_path, row_name, sheet_name=\"Resultados\")\n",
|
|||
|
|
"\n",
|
|||
|
|
"sys.exit(0)"
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
],
|
|||
|
|
"metadata": {
|
|||
|
|
"kernelspec": {
|
|||
|
|
"display_name": "Python 3",
|
|||
|
|
"language": "python",
|
|||
|
|
"name": "python3"
|
|||
|
|
},
|
|||
|
|
"language_info": {
|
|||
|
|
"codemirror_mode": {
|
|||
|
|
"name": "ipython",
|
|||
|
|
"version": 3
|
|||
|
|
},
|
|||
|
|
"file_extension": ".py",
|
|||
|
|
"mimetype": "text/x-python",
|
|||
|
|
"name": "python",
|
|||
|
|
"nbconvert_exporter": "python",
|
|||
|
|
"pygments_lexer": "ipython3",
|
|||
|
|
"version": "3.14.2"
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
"nbformat": 4,
|
|||
|
|
"nbformat_minor": 5
|
|||
|
|
}
|