Spaces:
Running on Zero
Running on Zero
| """ | |
| 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 | |
| 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() | |