model-explorer / js /ui /conversionGuideManager.js
mr4's picture
Upload 71 files
9bd422a verified
/**
* 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;