""" Front-end en Gradio para convertir archivos TDMS (NI LabVIEW) a UFF (Universal File Format, dataset 58). Listo para desplegar en Hugging Face Spaces (SDK: gradio). """ import os import tempfile import gradio as gr import pandas as pd from converter import inspect_tdms, convert_tdms_to_uff try: import spaces _gpu = spaces.GPU except ImportError: def _gpu(fn): return fn # ---------------------------------------------------------------- helpers def _labels_from_summary(summary): return [f'{row["grupo"]}/{row["canal"]}' for row in summary] def cargar_tdms(file): """Al subir un archivo: inspecciona y muestra los canales disponibles.""" if file is None: return ( gr.update(value=None), gr.update(choices=[], value=[]), "Sube un archivo .tdms para comenzar.", ) try: summary = inspect_tdms(file.name) except Exception as e: return ( gr.update(value=None), gr.update(choices=[], value=[]), f"❌ No se pudo leer el TDMS: {e}", ) if not summary: return ( gr.update(value=None), gr.update(choices=[], value=[]), "⚠️ El archivo no contiene canales.", ) df = pd.DataFrame(summary) labels = _labels_from_summary(summary) msg = f"✅ {len(labels)} canal(es) detectado(s). Selecciona cuáles convertir." return gr.update(value=df), gr.update(choices=labels, value=labels), msg @_gpu def convertir(file, seleccion, progress=gr.Progress()): """Convierte los canales seleccionados y devuelve el archivo .uff.""" if file is None: return None, "❌ Primero sube un archivo .tdms." if not seleccion: return None, "❌ Selecciona al menos un canal." base = os.path.splitext(os.path.basename(file.name))[0] out_dir = tempfile.mkdtemp() out_path = os.path.join(out_dir, f"{base}.uff") def cb(frac, msg): progress(frac, desc=msg) try: n, warns = convert_tdms_to_uff( file.name, out_path, selected=list(seleccion), progress_cb=cb ) except Exception as e: return None, f"❌ Error durante la conversión: {e}" msg = f"✅ Conversión completa: {n} canal(es) escritos como dataset 58." if warns: msg += "\n\n⚠️ Avisos:\n" + "\n".join(f"• {w}" for w in warns) return out_path, msg # ---------------------------------------------------------------- interfaz with gr.Blocks(title="TDMS → UFF") as demo: gr.Markdown( """ # Conversor TDMS → UFF Convierte archivos **TDMS** (NI LabVIEW / DIAdem) a **UFF** (Universal File Format, *dataset 58* — series de tiempo), compatible con software de análisis modal y de vibraciones. """ ) with gr.Row(): with gr.Column(scale=1): archivo = gr.File( label="Archivo TDMS", file_types=[".tdms"], type="filepath", ) canales = gr.CheckboxGroup( label="Canales a convertir", choices=[], ) boton = gr.Button("Convertir a UFF", variant="primary") with gr.Column(scale=2): tabla = gr.Dataframe( label="Contenido del TDMS", interactive=False, ) estado = gr.Markdown("Sube un archivo .tdms para comenzar.") salida = gr.File(label="Archivo UFF generado") archivo.change(cargar_tdms, inputs=archivo, outputs=[tabla, canales, estado]) boton.click(convertir, inputs=[archivo, canales], outputs=[salida, estado]) gr.Markdown( """ --- **Notas** - Cada canal se escribe como un *dataset 58* con eje X en segundos (usa `wf_increment` del TDMS; si no existe, asume dt = 1 s). - La unidad del canal (`unit_string`) se conserva en el eje Y. - Salida en UFF ASCII, legible por pyuff, ME'scope, Test.Lab, etc. """ ) if __name__ == "__main__": demo.launch()