/** * 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 .onnx 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 .onnx trước khi upload.', installNote: 'Cài đặt:' }, ja: { title: 'Keras/TensorFlow ファイル (.h5/.keras) は直接サポートされていません', body: 'は Keras/TensorFlow 形式です。アップロードする前に .onnx に変換してください。', 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 .onnx 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 .onnx trước khi upload.', installNote: 'Cài đặt:' }, ja: { title: 'TensorFlow SavedModel (.pb) は直接サポートされていません', body: 'は TensorFlow SavedModel 形式です。アップロードする前に .onnx に変換してください。', 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 .onnx 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 .onnx trước khi upload.', installNote: 'Cài đặt:' }, ja: { title: 'CoreML ファイル (.mlmodel) は直接サポートされていません', body: 'は CoreML 形式です。アップロードする前に .onnx に変換してください。', 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 .onnx 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 .onnx trước khi upload.', installNote: 'Cài đặt:' }, ja: { title: 'Caffe ファイル (.caffemodel) は直接サポートされていません', body: 'は Caffe 形式です。アップロードする前に .onnx に変換してください。', 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 .onnx 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 .onnx qua PyTorch trước khi upload.', installNote: 'Cài đặt:' }, ja: { title: 'Darknet/YOLO ファイル (.weights) は直接サポートされていません', body: 'は Darknet/YOLO 形式です。アップロードする前に PyTorch 経由で .onnx に変換してください。', 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 .onnx 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 .onnx trước khi upload.', installNote: 'Cài đặt:' }, ja: { title: 'PaddlePaddle ファイル (.pdmodel) は直接サポートされていません', body: 'は PaddlePaddle 形式です。アップロードする前に .onnx に変換してください。', 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 .onnx 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 .onnx trước khi upload.', installNote: 'Cài đặt:' }, ja: { title: 'MXNet ファイル (.params) は直接サポートされていません', body: 'は MXNet 形式です。アップロードする前に .onnx に変換してください。', 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 = `
${msgs.title}

"${escapedName}" ${msgs.body}


Convert ${config.formatName} → ONNX:

${this._escapeHtml(config.codeSnippet)}

${msgs.installNote} ${config.pipCommand}

`; 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;