Files
IPSExtractor/gui/view.py
T

272 lines
9.4 KiB
Python

"""Vista principal de la aplicación GUI con `customtkinter`.
Expone métodos para enlazar callbacks, leer entradas y escribir salida en un
área de texto, además de habilitar/deshabilitar controles durante el proceso.
"""
import os
import customtkinter as ctk
from gui.styles import AppStyles
from gui.tabs import SettingsTab, ResultsTab, MainProcessingTab, PreclassificationTab, MetricsTab
class InvoiceAppView(ctk.CTk):
"""Ventana principal con pestañas de Procesar y Configuración."""
def __init__(self):
"""Construye la ventana principal y sus pestañas/controles."""
super().__init__()
self.title("IPSExtractor - Procesador de Documentos")
self.geometry("1100x800")
# Configurar tema
AppStyles.configure_theme()
# Obtener estilos
self.fonts = AppStyles.get_fonts()
self.colors = AppStyles.get_colors()
# Retrocompatibilidad: usar los nombres antiguos
self.font_title = self.fonts["title"]
self.font_section = self.fonts["section"]
self.font_ui = self.fonts["ui"]
self.font_mono = self.fonts["mono"]
# Layout principal
self.grid_columnconfigure(0, weight=1)
self.grid_rowconfigure(0, weight=1)
# TabView principal con estilo
self.tabs = ctk.CTkTabview(self, width=1000, height=700)
self.tabs.grid(row=0, column=0, sticky="nsew", padx=20, pady=20)
self.tab_main = self.tabs.add("Procesar Documentos")
self.tab_preclass = self.tabs.add("Preclasificación")
self.tab_results = self.tabs.add("Resultados")
self.tab_settings = self.tabs.add("Configuración")
self.tab_usage = self.tabs.add("Dashboard & Métricas")
# =========================================================================
# --- TAB: PROCESAR DOCUMENTOS ---
# =========================================================================
self.main_tab = MainProcessingTab(self.tab_main)
# =========================================================================
# --- TAB: RESULTADOS ---
# =========================================================================
self.results_tab = ResultsTab(self.tab_results)
# =========================================================================
# --- TAB: CONFIGURACIÓN ---
# =========================================================================
self.settings_tab = SettingsTab(self.tab_settings)
# =========================================================================
# --- TAB: PRECLASIFICACIÓN ---
# =========================================================================
self.preclass_tab = PreclassificationTab(self.tab_preclass)
# =========================================================================
# --- TAB: DASHBOARD & MÉTRICAS ---
# =========================================================================
self.metrics_tab = MetricsTab(self.tab_usage)
# ---------------------------------------------------------------------------
# MÉTODOS PÚBLICOS (API COMPATIBLE)
# ---------------------------------------------------------------------------
def set_on_select_root(self, callback):
self.main_tab.set_on_select_root(callback)
def set_on_select_preclass_root(self, callback):
self.preclass_tab.set_on_select_root(callback)
def set_on_process(self, callback):
self.main_tab.set_on_process(callback)
def set_on_select_csv(self, callback):
self.main_tab.set_on_select_csv(callback)
def set_on_save_settings(self, callback):
self.settings_tab.set_on_save(callback)
def get_selected_model(self) -> str:
return self.settings_tab.get_selected_model()
def set_selected_model(self, model: str) -> None:
self.settings_tab.set_selected_model(model)
def get_concurrency_limit(self) -> int:
return self.settings_tab.get_concurrency_limit()
def set_concurrency_limit(self, limit: int) -> None:
self.settings_tab.set_concurrency_limit(limit)
def set_on_run_preclassification(self, callback):
self.preclass_tab.set_on_run(callback)
def set_on_export_excel(self, callback):
self.preclass_tab.set_on_export_excel(callback)
def set_on_organize_files(self, callback):
self.preclass_tab.set_on_organize_files(callback)
def enable_preclass_actions(self, enabled: bool):
self.preclass_tab.enable_actions(enabled)
# --- Métodos Resultados ---
def set_on_res_search(self, callback):
self.results_tab.set_on_search(callback)
def set_on_res_export(self, callback):
self.results_tab.set_on_export(callback)
def set_on_res_refresh(self, callback):
self.results_tab.set_on_refresh(callback)
def set_on_res_organize(self, callback):
self.results_tab.set_on_organize(callback)
def set_on_res_select(self, callback):
self.results_tab.set_on_select_result(callback)
def update_res_matches_table(self, rows):
self.results_tab.update_matches_table(rows)
def update_res_runs_combo(self, runs: list):
self.results_tab.update_runs_combo(runs)
def set_res_run(self, run_id: int | str):
self.results_tab.set_run_id(run_id)
def get_res_filters(self):
return self.results_tab.get_filters()
def update_res_table(self, rows):
self.results_tab.update_results_table(rows)
def append_preclass_output(self, text: str) -> None:
self.preclass_tab.append_output(text)
def append_preclass_output_safe(self, text: str) -> None:
self.after(0, lambda: self.preclass_tab.append_output_safe(text))
def get_root_path(self) -> str:
return self.main_tab.get_root_path()
def set_root_path(self, path: str) -> None:
self.main_tab.set_root_path(path)
def set_csv_path(self, path: str) -> None:
self.main_tab.set_csv_path(path)
def set_preclass_root_path(self, path: str) -> None:
self.preclass_tab.set_root_path(path)
def get_selected_result_values(self) -> tuple | None:
return self.results_tab.get_selected_result_values()
def get_process_mode(self) -> str:
"""Devuelve el modo de procesamiento: 'radicados' o 'general'."""
return self.main_tab.get_process_mode()
def get_preclass_root_path(self) -> str:
return self.preclass_tab.get_root_path()
def get_preclass_mode(self) -> str:
"""Devuelve el modo de preclasificación: 'radicados' o 'general'."""
return self.preclass_tab.get_mode()
def get_preclass_range(self) -> tuple[bool, int, int]:
"""Devuelve (habilitado, desde, hasta) para preclasificación."""
return self.preclass_tab.get_range()
def get_preclass_target_info(self) -> dict:
"""Devuelve la configuración del archivo objetivo."""
return self.preclass_tab.get_target_info()
def get_keywords(self) -> str:
return self.main_tab.get_keywords()
def get_fields(self) -> str:
return self.main_tab.get_fields()
def get_csv_path(self) -> str:
return self.main_tab.get_csv_path()
def show_tiff_range_controls(self, show: bool) -> None:
self.main_tab.show_tiff_range_controls(show)
def get_tiff_start_page(self) -> int:
return self.main_tab.get_tiff_start_page()
def get_tiff_end_page(self) -> int:
return self.main_tab.get_tiff_end_page()
def append_output(self, text: str) -> None:
self.main_tab.append_output(text)
def append_output_safe(self, text: str) -> None:
self.after(0, lambda: self.main_tab.append_output_safe(text))
def set_processing(self, processing: bool) -> None:
self.main_tab.enable_controls(not processing)
# --- TAB PRECLASIFICACIÓN ---
try:
# Actualizar controles de la pestaña de preclasificación
self.preclass_tab.enable_controls(not processing)
# Actualizar controles de la pestaña de configuración
self.settings_tab.enable_controls(not processing)
except Exception:
pass
# --- TAB USO ---
def append_usage(self, text: str) -> None:
self.metrics_tab.append_usage(text)
def append_usage_safe(self, text: str) -> None:
self.after(0, lambda: self.metrics_tab.append_usage_safe(text))
def clear_usage(self) -> None:
self.metrics_tab.clear()
def set_usage_totals(self, **kwargs):
self.metrics_tab.set_usage_totals(**kwargs)
def update_kpis(self, overall: dict, extract_phase: dict, normalize_phase: dict) -> None:
self.metrics_tab.update_kpis(overall, extract_phase, normalize_phase)
def update_cost_line(self, doc_index: int, total_cost_usd: float) -> None:
self.metrics_tab.update_cost_line(doc_index, total_cost_usd)
def update_token_bars(self, input_extract: int, cached_extract: int, output_extract: int,
input_norm: int, cached_norm: int, output_norm: int) -> None:
self.metrics_tab.update_token_bars(input_extract, cached_extract, output_extract,
input_norm, cached_norm, output_norm)
def update_comparison_table(self, comparisons: list[dict]) -> None:
self.metrics_tab.update_comparison_table(comparisons)
def append_usage_row(self, phase: str, radicado: str, usage: dict | None, cost: dict | None) -> None:
self.metrics_tab.append_usage_row(phase, radicado, usage, cost)
# --- HELPERS INTERNOS ---
def get_preclass_patterns(self) -> list[dict]:
"""Devuelve la lista de patrones de preclasificación definida en la pestaña."""
return self.preclass_tab.get_patterns()
def get_doc_types(self) -> list[dict]:
return self.main_tab.get_doc_types()
def set_doc_types(self, doc_types: list[dict]) -> None:
self.main_tab.set_doc_types(doc_types)
def validate_doc_types(self) -> tuple[bool, str | None]:
return self.main_tab.validate_doc_types()