Spaces:
Running
Running
| /** | |
| * ConversionGuideManager - Manages conversion guides for unsupported model formats | |
| * Displays instructions to convert various ML model formats to ONNX | |
| * Requirements: 7.1-7.4, 8.1-8.4, 9.1-9.4, 10.1-10.4, 11.1-11.4, 12.1-12.4, 13.1-13.4, 14.1-14.6 | |
| */ | |
| class ConversionGuideManager { | |
| constructor() { | |
| this._errorContainer = document.getElementById('errorContainer'); | |
| } | |
| // βββ Declarative Guide Configs ββββββββββββββββββββββββββββββββββββββββββ | |
| static get GUIDE_CONFIGS() { | |
| return [ | |
| { | |
| id: 'keras', | |
| extensions: ['.h5', '.keras'], | |
| icon: 'fas fa-brain', | |
| formatName: 'Keras/TensorFlow', | |
| pipCommand: 'pip install tf2onnx tensorflow', | |
| codeSnippet: `import tf2onnx | |
| import tensorflow as tf | |
| model = tf.keras.models.load_model("model.h5") | |
| # Convert to ONNX | |
| spec = (tf.TensorSpec(model.input_shape, tf.float32, name="input"),) | |
| output_path = "model.onnx" | |
| model_proto, _ = tf2onnx.convert.from_keras( | |
| model, input_signature=spec, output_path=output_path | |
| ) | |
| print(f"Saved ONNX model to {output_path}")`, | |
| messages: { | |
| en: { | |
| title: 'Keras/TensorFlow file (.h5/.keras) is not directly supported', | |
| body: 'is a Keras/TensorFlow format. Please convert to <strong>.onnx</strong> before uploading.', | |
| installNote: 'Install:' | |
| }, | |
| vi: { | |
| title: 'Tα»p Keras/TensorFlow (.h5/.keras) khΓ΄ng Δược hα» trợ trα»±c tiαΊΏp', | |
| body: 'lΓ Δα»nh dαΊ‘ng Keras/TensorFlow. Vui lΓ²ng convert sang <strong>.onnx</strong> trΖ°α»c khi upload.', | |
| installNote: 'CΓ i ΔαΊ·t:' | |
| }, | |
| ja: { | |
| title: 'Keras/TensorFlow γγ‘γ€γ« (.h5/.keras) γ―η΄ζ₯γ΅γγΌγγγγ¦γγΎγγ', | |
| body: 'γ― Keras/TensorFlow ε½’εΌγ§γγγ’γγγγΌγγγεγ« <strong>.onnx</strong> γ«ε€ζγγ¦γγ γγγ', | |
| installNote: 'γ€γ³γΉγγΌγ«:' | |
| } | |
| } | |
| }, | |
| { | |
| id: 'tensorflow-savedmodel', | |
| extensions: ['.pb'], | |
| icon: 'fas fa-project-diagram', | |
| formatName: 'TensorFlow SavedModel', | |
| pipCommand: 'pip install tf2onnx tensorflow', | |
| codeSnippet: `import tf2onnx | |
| import tensorflow as tf | |
| # Load SavedModel | |
| graph_def, inputs, outputs = tf2onnx.tf_loader.from_saved_model( | |
| "saved_model_dir" | |
| ) | |
| # Convert to ONNX | |
| model_proto, _ = tf2onnx.convert.from_graph_def( | |
| graph_def, | |
| input_names=inputs, | |
| output_names=outputs, | |
| output_path="model.onnx" | |
| ) | |
| print("Saved ONNX model to model.onnx")`, | |
| messages: { | |
| en: { | |
| title: 'TensorFlow SavedModel (.pb) is not directly supported', | |
| body: 'is a TensorFlow SavedModel format. Please convert to <strong>.onnx</strong> before uploading.', | |
| installNote: 'Install:' | |
| }, | |
| vi: { | |
| title: 'Tα»p TensorFlow SavedModel (.pb) khΓ΄ng Δược hα» trợ trα»±c tiαΊΏp', | |
| body: 'lΓ Δα»nh dαΊ‘ng TensorFlow SavedModel. Vui lΓ²ng convert sang <strong>.onnx</strong> trΖ°α»c khi upload.', | |
| installNote: 'CΓ i ΔαΊ·t:' | |
| }, | |
| ja: { | |
| title: 'TensorFlow SavedModel (.pb) γ―η΄ζ₯γ΅γγΌγγγγ¦γγΎγγ', | |
| body: 'γ― TensorFlow SavedModel ε½’εΌγ§γγγ’γγγγΌγγγεγ« <strong>.onnx</strong> γ«ε€ζγγ¦γγ γγγ', | |
| installNote: 'γ€γ³γΉγγΌγ«:' | |
| } | |
| } | |
| }, | |
| { | |
| id: 'coreml', | |
| extensions: ['.mlmodel'], | |
| icon: 'fas fa-apple-alt', | |
| formatName: 'CoreML', | |
| pipCommand: 'pip install coremltools onnxmltools', | |
| codeSnippet: `import coremltools | |
| import onnxmltools | |
| # Load CoreML model | |
| coreml_model = coremltools.utils.load_spec("model.mlmodel") | |
| # Convert to ONNX | |
| onnx_model = onnxmltools.convert_coreml(coreml_model) | |
| onnxmltools.utils.save_model(onnx_model, "model.onnx") | |
| print("Saved ONNX model to model.onnx")`, | |
| messages: { | |
| en: { | |
| title: 'CoreML file (.mlmodel) is not directly supported', | |
| body: 'is a CoreML format. Please convert to <strong>.onnx</strong> before uploading.', | |
| installNote: 'Install:' | |
| }, | |
| vi: { | |
| title: 'Tα»p CoreML (.mlmodel) khΓ΄ng Δược hα» trợ trα»±c tiαΊΏp', | |
| body: 'lΓ Δα»nh dαΊ‘ng CoreML. Vui lΓ²ng convert sang <strong>.onnx</strong> trΖ°α»c khi upload.', | |
| installNote: 'CΓ i ΔαΊ·t:' | |
| }, | |
| ja: { | |
| title: 'CoreML γγ‘γ€γ« (.mlmodel) γ―η΄ζ₯γ΅γγΌγγγγ¦γγΎγγ', | |
| body: 'γ― CoreML ε½’εΌγ§γγγ’γγγγΌγγγεγ« <strong>.onnx</strong> γ«ε€ζγγ¦γγ γγγ', | |
| installNote: 'γ€γ³γΉγγΌγ«:' | |
| } | |
| } | |
| }, | |
| { | |
| id: 'caffe', | |
| extensions: ['.caffemodel'], | |
| icon: 'fas fa-coffee', | |
| formatName: 'Caffe', | |
| pipCommand: 'pip install caffe2onnx', | |
| codeSnippet: `from caffe2onnx import convertToOnnx | |
| # Convert Caffe model to ONNX | |
| # Requires both .prototxt and .caffemodel files | |
| graph = convertToOnnx("deploy.prototxt", "model.caffemodel") | |
| graph.save("model.onnx") | |
| print("Saved ONNX model to model.onnx")`, | |
| messages: { | |
| en: { | |
| title: 'Caffe file (.caffemodel) is not directly supported', | |
| body: 'is a Caffe format. Please convert to <strong>.onnx</strong> before uploading.', | |
| installNote: 'Install:' | |
| }, | |
| vi: { | |
| title: 'Tα»p Caffe (.caffemodel) khΓ΄ng Δược hα» trợ trα»±c tiαΊΏp', | |
| body: 'lΓ Δα»nh dαΊ‘ng Caffe. Vui lΓ²ng convert sang <strong>.onnx</strong> trΖ°α»c khi upload.', | |
| installNote: 'CΓ i ΔαΊ·t:' | |
| }, | |
| ja: { | |
| title: 'Caffe γγ‘γ€γ« (.caffemodel) γ―η΄ζ₯γ΅γγΌγγγγ¦γγΎγγ', | |
| body: 'γ― Caffe ε½’εΌγ§γγγ’γγγγΌγγγεγ« <strong>.onnx</strong> γ«ε€ζγγ¦γγ γγγ', | |
| installNote: 'γ€γ³γΉγγΌγ«:' | |
| } | |
| } | |
| }, | |
| { | |
| id: 'darknet', | |
| extensions: ['.weights'], | |
| icon: 'fas fa-moon', | |
| formatName: 'Darknet/YOLO', | |
| pipCommand: 'pip install torch ultralytics', | |
| codeSnippet: `from ultralytics import YOLO | |
| # Load Darknet/YOLO weights via Ultralytics | |
| model = YOLO("yolov8n.pt") # or load custom weights | |
| # Export to ONNX (Darknet -> PyTorch -> ONNX pipeline) | |
| model.export(format="onnx", imgsz=640) | |
| print("Saved ONNX model to yolov8n.onnx")`, | |
| messages: { | |
| en: { | |
| title: 'Darknet/YOLO file (.weights) is not directly supported', | |
| body: 'is a Darknet/YOLO format. Please convert to <strong>.onnx</strong> via PyTorch before uploading.', | |
| installNote: 'Install:' | |
| }, | |
| vi: { | |
| title: 'Tα»p Darknet/YOLO (.weights) khΓ΄ng Δược hα» trợ trα»±c tiαΊΏp', | |
| body: 'lΓ Δα»nh dαΊ‘ng Darknet/YOLO. Vui lΓ²ng convert sang <strong>.onnx</strong> qua PyTorch trΖ°α»c khi upload.', | |
| installNote: 'CΓ i ΔαΊ·t:' | |
| }, | |
| ja: { | |
| title: 'Darknet/YOLO γγ‘γ€γ« (.weights) γ―η΄ζ₯γ΅γγΌγγγγ¦γγΎγγ', | |
| body: 'γ― Darknet/YOLO ε½’εΌγ§γγγ’γγγγΌγγγεγ« PyTorch η΅η±γ§ <strong>.onnx</strong> γ«ε€ζγγ¦γγ γγγ', | |
| installNote: 'γ€γ³γΉγγΌγ«:' | |
| } | |
| } | |
| }, | |
| { | |
| id: 'paddlepaddle', | |
| extensions: ['.pdmodel'], | |
| icon: 'fas fa-ship', | |
| formatName: 'PaddlePaddle', | |
| pipCommand: 'pip install paddle2onnx paddlepaddle', | |
| codeSnippet: `import paddle2onnx | |
| # Convert PaddlePaddle model to ONNX | |
| paddle2onnx.command.program2onnx( | |
| model_dir="paddle_model_dir", | |
| model_filename="model.pdmodel", | |
| params_filename="model.pdiparams", | |
| save_file="model.onnx", | |
| opset_version=13 | |
| ) | |
| print("Saved ONNX model to model.onnx")`, | |
| messages: { | |
| en: { | |
| title: 'PaddlePaddle file (.pdmodel) is not directly supported', | |
| body: 'is a PaddlePaddle format. Please convert to <strong>.onnx</strong> before uploading.', | |
| installNote: 'Install:' | |
| }, | |
| vi: { | |
| title: 'Tα»p PaddlePaddle (.pdmodel) khΓ΄ng Δược hα» trợ trα»±c tiαΊΏp', | |
| body: 'lΓ Δα»nh dαΊ‘ng PaddlePaddle. Vui lΓ²ng convert sang <strong>.onnx</strong> trΖ°α»c khi upload.', | |
| installNote: 'CΓ i ΔαΊ·t:' | |
| }, | |
| ja: { | |
| title: 'PaddlePaddle γγ‘γ€γ« (.pdmodel) γ―η΄ζ₯γ΅γγΌγγγγ¦γγΎγγ', | |
| body: 'γ― PaddlePaddle ε½’εΌγ§γγγ’γγγγΌγγγεγ« <strong>.onnx</strong> γ«ε€ζγγ¦γγ γγγ', | |
| installNote: 'γ€γ³γΉγγΌγ«:' | |
| } | |
| } | |
| }, | |
| { | |
| id: 'mxnet', | |
| extensions: ['.params'], | |
| icon: 'fas fa-cubes', | |
| formatName: 'MXNet', | |
| pipCommand: 'pip install mxnet', | |
| codeSnippet: `import mxnet as mx | |
| from mxnet.contrib import onnx as onnx_mxnet | |
| # Convert MXNet model to ONNX | |
| # Requires both symbol JSON and params files | |
| converted_model = onnx_mxnet.export_model( | |
| sym="model-symbol.json", | |
| params="model-0000.params", | |
| input_shape=[(1, 3, 224, 224)], | |
| input_type="float32", | |
| onnx_file_path="model.onnx" | |
| ) | |
| print("Saved ONNX model to model.onnx")`, | |
| messages: { | |
| en: { | |
| title: 'MXNet file (.params) is not directly supported', | |
| body: 'is an MXNet format. Please convert to <strong>.onnx</strong> before uploading.', | |
| installNote: 'Install:' | |
| }, | |
| vi: { | |
| title: 'Tα»p MXNet (.params) khΓ΄ng Δược hα» trợ trα»±c tiαΊΏp', | |
| body: 'lΓ Δα»nh dαΊ‘ng MXNet. Vui lΓ²ng convert sang <strong>.onnx</strong> trΖ°α»c khi upload.', | |
| installNote: 'CΓ i ΔαΊ·t:' | |
| }, | |
| ja: { | |
| title: 'MXNet γγ‘γ€γ« (.params) γ―η΄ζ₯γ΅γγΌγγγγ¦γγΎγγ', | |
| body: 'γ― MXNet ε½’εΌγ§γγγ’γγγγΌγγγεγ« <strong>.onnx</strong> γ«ε€ζγγ¦γγ γγγ', | |
| installNote: 'γ€γ³γΉγγΌγ«:' | |
| } | |
| } | |
| } | |
| ]; | |
| } | |
| // βββ Public API βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| /** | |
| * Check if a filename has a conversion-guide extension. | |
| * @param {string} fileName | |
| * @returns {boolean} | |
| */ | |
| isConversionFormat(fileName) { | |
| if (!fileName || typeof fileName !== 'string') return false; | |
| const lower = fileName.toLowerCase(); | |
| return ConversionGuideManager.GUIDE_CONFIGS.some(config => | |
| config.extensions.some(ext => lower.endsWith(ext)) | |
| ); | |
| } | |
| /** | |
| * Display the conversion guide for the given file. | |
| * @param {string} fileName | |
| */ | |
| showGuide(fileName) { | |
| if (!this._errorContainer) return; | |
| const lower = (fileName || '').toLowerCase(); | |
| const config = ConversionGuideManager.GUIDE_CONFIGS.find(c => | |
| c.extensions.some(ext => lower.endsWith(ext)) | |
| ); | |
| if (!config) return; | |
| const lang = this._getLanguage(); | |
| const msgs = config.messages[lang] || config.messages['en']; | |
| const escapedName = this._escapeHtml(fileName); | |
| this._errorContainer.innerHTML = ''; | |
| const div = document.createElement('div'); | |
| div.className = 'alert alert-warning alert-dismissible fade show'; | |
| div.setAttribute('role', 'alert'); | |
| div.innerHTML = ` | |
| <div class="d-flex align-items-start"> | |
| <i class="fas fa-exchange-alt me-3 mt-1 fs-4 text-warning"></i> | |
| <div class="flex-grow-1"> | |
| <h6 class="alert-heading mb-2"> | |
| <i class="${config.icon} me-1"></i> | |
| ${msgs.title} | |
| </h6> | |
| <p class="mb-2"> | |
| <strong>"${escapedName}"</strong> ${msgs.body} | |
| </p> | |
| <hr class="my-2"> | |
| <p class="mb-1 fw-bold"><i class="fas fa-code me-1"></i> Convert ${config.formatName} β ONNX:</p> | |
| <pre class="bg-dark text-light p-2 rounded small mb-2" style="white-space:pre-wrap;"><code>${this._escapeHtml(config.codeSnippet)}</code></pre> | |
| <p class="mb-0 text-muted small"> | |
| <i class="fas fa-info-circle me-1"></i> | |
| ${msgs.installNote} <code>${config.pipCommand}</code> | |
| </p> | |
| </div> | |
| </div> | |
| <button type="button" class="btn-close" aria-label="Close" | |
| onclick="this.closest('.alert').remove()"></button> | |
| `; | |
| this._errorContainer.appendChild(div); | |
| } | |
| // βββ Private ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| /** | |
| * Get the current language from localStorage, default to 'en'. | |
| * @returns {string} | |
| */ | |
| _getLanguage() { | |
| try { | |
| const lang = localStorage.getItem('onnx_explorer_help_lang'); | |
| if (lang && ['en', 'vi', 'ja'].includes(lang)) return lang; | |
| } catch (_) { | |
| // localStorage not accessible | |
| } | |
| return 'en'; | |
| } | |
| /** | |
| * Escape HTML using DOM text node method to prevent XSS. | |
| * @param {string} str | |
| * @returns {string} | |
| */ | |
| _escapeHtml(str) { | |
| const div = document.createElement('div'); | |
| div.appendChild(document.createTextNode(str || '')); | |
| return div.innerHTML; | |
| } | |
| } | |
| // Export as global for browser usage | |
| window.ConversionGuideManager = ConversionGuideManager; | |