eric164 commited on
Commit
e6d6f43
·
verified ·
1 Parent(s): 0889fd6

Maak een Windows .exe model-converter voor Amuse (Stable Diffusion → Amuse ONNX/Olive)

Doel:
Bouw een volledig lokaal Windows-programma (GUI + CLI) dat Stable Diffusion-modellen (.ckpt, .safetensors, of Hugging Face Diffusers mappen) automatisch converteert naar ONNX en Olive-geoptimaliseerde artifacts die bruikbaar zijn in Amuse 2.2.x / Amuse model manager. Package het eindresultaat als een standalone Windows installer (.exe) met één-klik installatie.

Eisen (functionaliteit):
1. Invoer:
- Ondersteun `.ckpt`, `.safetensors`, en Diffusers folder (config + safetensors/pytorch_model.bin).
- UI: eenvoudige drag-and-drop GUI + CLI (voor geautomatiseerde batchjobs).

2. Detectie & voorbereiding:
- Automatisch detecteer modeltype (SD v1/v2/SDXL/SD3) en benodigde tokenizer/text_encoder.
- Controleer rechten/licentie (toon waarschuwingspopup: "Controleer modellicentie voordat u converteert").

3. Conversie naar ONNX:
- Probeer eerst `optimum[onnx]` export flow (`optimum-cli export onnx`) voor diffusers / transformers pipelines.
- Fallback: genereer een betrouwbare export via `torch.onnx.export` voor benodigde componenten (text_encoder, unet, vae), met duidelijke opsplitsing per pipeline.

4. Optimalisatie:
- Integreer Microsoft **Olive** (of Optimum+ONNXRuntime passes) om ONNX modellen hardware-aware te optimaliseren (DirectML/AMDGPU/ONNXRuntime).
- Laat de gebruiker kiezen: «DirectML (Windows)», «CUDA», «CPU (OpenVINO)». Gebruik DirectML as default target voor Amuse compatibiliteit.

5. Validatie:
- Run een snelle inference smoke-test (bijv. 8 steps, tiny prompt) om te checken dat de geconverteerde pipeline produceert zonder shape/IO fouten.
- Toon vergelijking (kort log) van oorspronkelijke en geconverteerde pipeline outputs (hash/shape).

6. Output:
- Produceer een output-map met: `model.onnx`(s), `metadata.json` (originele modelnaam, HF id, conversie datum, precisie), en eventuele Olive config.
- Optie: exporteer in het exacte bestandspatroon dat Amuse Model Manager verwacht (maak een config/manifest zodat Amuse het direct kan importeren).

7. GUI:
- Windows desktop app (PySide6 of Electron+React). Interface met:
• Input area (select files/folders)
• Target hardware selector
• Advanced opties (precision fp16/int8 quantize, steps, scheduler merge)
• Progress bar + logs + warnings
• Knop: "Maak installer"

8. Packaging (.exe):
- Gebruik **PyInstaller** (of Nuitka) om de Python app tot één .exe te bouwen.
- Voor installer: genereer een Inno Setup script (.iss) dat de .exe, output map en shortcuts installeert.
- Voeg een duidelijke README en LICENSE/WAARSCHUWING (model licentie compliance) toe in installer.

9. Dependencies & Requirements:
- Python 3.11+
- pip packages: `diffusers`, `transformers`, `accelerate`, `optimum[onnx]`, `onnx`, `onnxruntime-directml`, `olive-ai` (olive), `safetensors`, `torch` (only if needed), `protobuf`, `pyinstaller`, `PySide6` (of Electron toolchain).
- Duidelijke requirements.txt en build scripts (`build_windows.bat`).

10. Foutafhandeling:
- Bij bekende onnx-export incompatibilities (bv SD3 pipeline issues) detecteer hierover en geef stap-voor-stap fallback instructies of bied een "manual export tool" knop die een gedetailleerde log en sample script schrijft.

11. Security & Legal:
- Toon verplicht waarschuwing: "Je mag alleen modellen converteren waarvoor je de rechten hebt." Stop de conversie niet automatisch, maar log toestemming/acknowledgement.

Deliverables:
- Volledige broncode, `requirements.txt`, en build scripts.
- Een werkende Windows installer `.exe` die de converter installeert.
- README met gebruiksvoorbeeld, troubleshooting en build instructies.
- Voorbeeld-run (sample model small) die aantoonbaar ONNX output produceert en een korte smoke test doorloopt.

Extra opmerkingen voor de generator:
- Gebruik waar mogelijk bestaande, onderhouden libraries (Optimum, Olive) in plaats van bespoke export logic.
- Zorg dat de GUI en CLI dezelfde core conversie-engine gebruiken (DRY).
- Voeg uitgebreide logs en een "Export troubleshooting bundle" knop toe (verzamelt logs + sample inputs) om bug-reports makkelijk te maken.
- Als SD3 automatisch niet exporteerbaar is, genereer een duidelijke melding en produceer een `manual_export_instructions.txt` met de benodigde aangepaste pipeline code en welke Optimum/ORT pipeline ontbreekt.

Einde prompt.

Files changed (2) hide show
  1. README.md +8 -5
  2. index.html +397 -18
README.md CHANGED
@@ -1,10 +1,13 @@
1
  ---
2
- title: Amuse Model Alchemist
3
- emoji:
4
- colorFrom: gray
5
- colorTo: gray
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
1
  ---
2
+ title: Amuse Model Alchemist 🧪
3
+ colorFrom: blue
4
+ colorTo: pink
5
+ emoji: 🐳
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite-v3
10
  ---
11
 
12
+ # Welcome to your new DeepSite project!
13
+ This project was created with [DeepSite](https://deepsite.hf.co).
index.html CHANGED
@@ -1,19 +1,398 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  </html>
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Amuse Model Alchemist</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://unpkg.com/feather-icons"></script>
9
+ <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
10
+ <script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.waves.min.js"></script>
11
+ <style>
12
+ .dropzone {
13
+ border: 2px dashed #4b5563;
14
+ transition: all 0.3s ease;
15
+ }
16
+ .dropzone.active {
17
+ border-color: #3b82f6;
18
+ background-color: rgba(59, 130, 246, 0.05);
19
+ }
20
+ .progress-bar {
21
+ transition: width 0.3s ease;
22
+ }
23
+ </style>
24
+ </head>
25
+ <body class="bg-gray-900 text-gray-100 min-h-screen">
26
+ <div id="vanta-bg" class="fixed inset-0 -z-10"></div>
27
+ <div class="container mx-auto px-4 py-12">
28
+ <!-- Header -->
29
+ <header class="text-center mb-12">
30
+ <div class="inline-block bg-gradient-to-r from-blue-500 to-purple-600 p-2 rounded-lg mb-4">
31
+ <i data-feather="cpu" class="w-12 h-12 text-white"></i>
32
+ </div>
33
+ <h1 class="text-4xl font-bold mb-2 bg-clip-text text-transparent bg-gradient-to-r from-blue-400 to-purple-500">
34
+ Amuse Model Alchemist
35
+ </h1>
36
+ <p class="text-xl text-gray-300 max-w-2xl mx-auto">
37
+ Transform your Stable Diffusion models into ONNX/Olive artifacts with alchemical precision
38
+ </p>
39
+ </header>
40
+
41
+ <!-- Main Card -->
42
+ <div class="bg-gray-800/80 backdrop-blur-lg rounded-xl shadow-2xl overflow-hidden max-w-4xl mx-auto">
43
+ <!-- Tabs -->
44
+ <div class="flex border-b border-gray-700">
45
+ <button class="tab-btn active px-6 py-4 font-medium text-blue-400 border-b-2 border-blue-400">
46
+ <i data-feather="upload" class="mr-2"></i> Convert Model
47
+ </button>
48
+ <button class="tab-btn px-6 py-4 font-medium text-gray-400 hover:text-white">
49
+ <i data-feather="terminal" class="mr-2"></i> CLI Mode
50
+ </button>
51
+ <button class="tab-btn px-6 py-4 font-medium text-gray-400 hover:text-white">
52
+ <i data-feather="settings" class="mr-2"></i> Settings
53
+ </button>
54
+ </div>
55
+
56
+ <!-- Content -->
57
+ <div class="p-8">
58
+ <!-- Drop Zone -->
59
+ <div id="dropzone" class="dropzone rounded-lg p-12 text-center mb-8 cursor-pointer">
60
+ <div class="flex flex-col items-center justify-center space-y-4">
61
+ <i data-feather="upload-cloud" class="w-12 h-12 text-gray-400"></i>
62
+ <h3 class="text-xl font-semibold">Drag & Drop Model Files Here</h3>
63
+ <p class="text-gray-400">or click to browse (.ckpt, .safetensors, or Diffusers folder)</p>
64
+ <input type="file" id="fileInput" class="hidden" webkitdirectory mozdirectory msdirectory odirectory directory multiple>
65
+ <button id="browseBtn" class="mt-4 px-6 py-2 bg-blue-600 hover:bg-blue-700 rounded-lg font-medium">
66
+ Select Files
67
+ </button>
68
+ </div>
69
+ </div>
70
+
71
+ <!-- Selected Files -->
72
+ <div id="selectedFiles" class="hidden mb-8">
73
+ <h3 class="text-lg font-semibold mb-3 flex items-center">
74
+ <i data-feather="file" class="mr-2"></i> Selected Files
75
+ </h3>
76
+ <div class="bg-gray-700/50 rounded-lg p-4 max-h-48 overflow-y-auto">
77
+ <div id="fileList" class="space-y-2"></div>
78
+ </div>
79
+ </div>
80
+
81
+ <!-- Conversion Options -->
82
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">
83
+ <div>
84
+ <label class="block text-sm font-medium mb-2">Target Hardware</label>
85
+ <select class="w-full bg-gray-700 border border-gray-600 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
86
+ <option value="directml">DirectML (Windows Default)</option>
87
+ <option value="cuda">NVIDIA CUDA</option>
88
+ <option value="cpu">CPU (OpenVINO)</option>
89
+ </select>
90
+ </div>
91
+ <div>
92
+ <label class="block text-sm font-medium mb-2">Precision</label>
93
+ <select class="w-full bg-gray-700 border border-gray-600 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
94
+ <option value="fp16">FP16 (Recommended)</option>
95
+ <option value="int8">INT8 (Quantized)</option>
96
+ <option value="fp32">FP32 (Full Precision)</option>
97
+ </select>
98
+ </div>
99
+ </div>
100
+
101
+ <!-- Advanced Options -->
102
+ <div class="mb-6">
103
+ <button id="advancedToggle" class="flex items-center text-blue-400 hover:text-blue-300">
104
+ <i data-feather="chevron-down" class="mr-2 w-4 h-4"></i> Advanced Options
105
+ </button>
106
+ <div id="advancedOptions" class="hidden mt-4 space-y-4">
107
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
108
+ <div>
109
+ <label class="block text-sm font-medium mb-2">Model Type</label>
110
+ <select class="w-full bg-gray-700 border border-gray-600 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
111
+ <option value="auto">Auto-detect</option>
112
+ <option value="sd1">SD v1.x</option>
113
+ <option value="sd2">SD v2.x</option>
114
+ <option value="sdxl">SDXL</option>
115
+ <option value="sd3">SD3</option>
116
+ </select>
117
+ </div>
118
+ <div>
119
+ <label class="block text-sm font-medium mb-2">Output Format</label>
120
+ <select class="w-full bg-gray-700 border border-gray-600 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
121
+ <option value="olive">Olive Optimized</option>
122
+ <option value="onnx">Raw ONNX</option>
123
+ <option value="amuse">Amuse Ready</option>
124
+ </select>
125
+ </div>
126
+ </div>
127
+ <div>
128
+ <label class="flex items-center">
129
+ <input type="checkbox" class="rounded bg-gray-700 border-gray-600 text-blue-500 focus:ring-blue-500 mr-2">
130
+ <span>Run Smoke Test After Conversion</span>
131
+ </label>
132
+ </div>
133
+ <div>
134
+ <label class="flex items-center">
135
+ <input type="checkbox" class="rounded bg-gray-700 border-gray-600 text-blue-500 focus:ring-blue-500 mr-2">
136
+ <span>Generate Amuse Import Package</span>
137
+ </label>
138
+ </div>
139
+ </div>
140
+ </div>
141
+
142
+ <!-- Legal Warning -->
143
+ <div class="bg-yellow-900/30 border border-yellow-800 rounded-lg p-4 mb-8">
144
+ <div class="flex items-start">
145
+ <i data-feather="alert-triangle" class="text-yellow-400 mr-3 mt-1"></i>
146
+ <div>
147
+ <h4 class="font-medium text-yellow-300 mb-1">Legal Notice</h4>
148
+ <p class="text-sm text-yellow-200">
149
+ You must have the necessary rights to convert any model. By proceeding, you acknowledge that you have verified the model's license terms.
150
+ </p>
151
+ </div>
152
+ </div>
153
+ </div>
154
+
155
+ <!-- Action Buttons -->
156
+ <div class="flex flex-col sm:flex-row justify-end space-y-3 sm:space-y-0 sm:space-x-4">
157
+ <button class="px-6 py-2.5 bg-gray-700 hover:bg-gray-600 rounded-lg font-medium flex items-center justify-center">
158
+ <i data-feather="save" class="mr-2"></i> Save Settings
159
+ </button>
160
+ <button id="convertBtn" class="px-6 py-2.5 bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700 rounded-lg font-medium flex items-center justify-center">
161
+ <i data-feather="zap" class="mr-2"></i> Convert Model
162
+ </button>
163
+ </div>
164
+ </div>
165
+ </div>
166
+
167
+ <!-- Progress Modal -->
168
+ <div id="progressModal" class="hidden fixed inset-0 bg-black/70 z-50 flex items-center justify-center p-4">
169
+ <div class="bg-gray-800 rounded-xl shadow-2xl w-full max-w-2xl">
170
+ <div class="p-6 border-b border-gray-700">
171
+ <h3 class="text-xl font-semibold flex items-center">
172
+ <i data-feather="rotate-cw" class="mr-2 animate-spin"></i> Converting Model
173
+ </h3>
174
+ </div>
175
+ <div class="p-6">
176
+ <div class="mb-4">
177
+ <div class="flex justify-between text-sm mb-1">
178
+ <span>Progress</span>
179
+ <span id="progressPercent">0%</span>
180
+ </div>
181
+ <div class="w-full bg-gray-700 rounded-full h-2.5">
182
+ <div id="progressBar" class="progress-bar bg-blue-600 h-2.5 rounded-full" style="width: 0%"></div>
183
+ </div>
184
+ </div>
185
+ <div class="bg-gray-700/50 rounded-lg p-4 h-48 overflow-y-auto">
186
+ <div id="progressLog" class="font-mono text-sm text-gray-300 space-y-1">
187
+ <div>> Initializing model conversion...</div>
188
+ </div>
189
+ </div>
190
+ </div>
191
+ <div class="p-4 border-t border-gray-700 flex justify-end">
192
+ <button id="cancelBtn" class="px-4 py-2 bg-gray-700 hover:bg-gray-600 rounded-lg mr-3">
193
+ Cancel
194
+ </button>
195
+ <button id="hideModalBtn" class="px-4 py-2 bg-blue-600 hover:bg-blue-700 rounded-lg disabled:opacity-50" disabled>
196
+ Hide
197
+ </button>
198
+ </div>
199
+ </div>
200
+ </div>
201
+ </div>
202
+
203
+ <script>
204
+ // Initialize Vanta.js background
205
+ VANTA.WAVES({
206
+ el: "#vanta-bg",
207
+ mouseControls: true,
208
+ touchControls: true,
209
+ gyroControls: false,
210
+ minHeight: 200.00,
211
+ minWidth: 200.00,
212
+ scale: 1.00,
213
+ scaleMobile: 1.00,
214
+ color: 0x1e293b,
215
+ shininess: 50.00,
216
+ waveHeight: 15.00,
217
+ waveSpeed: 0.75,
218
+ zoom: 0.85
219
+ });
220
+
221
+ // Initialize Feather Icons
222
+ document.addEventListener('DOMContentLoaded', function() {
223
+ feather.replace();
224
+
225
+ // Tab switching
226
+ const tabBtns = document.querySelectorAll('.tab-btn');
227
+ tabBtns.forEach(btn => {
228
+ btn.addEventListener('click', () => {
229
+ tabBtns.forEach(b => b.classList.remove('active', 'text-blue-400', 'border-blue-400'));
230
+ tabBtns.forEach(b => b.classList.add('text-gray-400'));
231
+ btn.classList.add('active', 'text-blue-400', 'border-blue-400');
232
+ btn.classList.remove('text-gray-400');
233
+ });
234
+ });
235
+
236
+ // Advanced options toggle
237
+ const advancedToggle = document.getElementById('advancedToggle');
238
+ const advancedOptions = document.getElementById('advancedOptions');
239
+ advancedToggle.addEventListener('click', () => {
240
+ const icon = advancedToggle.querySelector('i');
241
+ if (advancedOptions.classList.contains('hidden')) {
242
+ advancedOptions.classList.remove('hidden');
243
+ icon.setAttribute('data-feather', 'chevron-up');
244
+ } else {
245
+ advancedOptions.classList.add('hidden');
246
+ icon.setAttribute('data-feather', 'chevron-down');
247
+ }
248
+ feather.replace();
249
+ });
250
+
251
+ // File dropzone functionality
252
+ const dropzone = document.getElementById('dropzone');
253
+ const fileInput = document.getElementById('fileInput');
254
+ const browseBtn = document.getElementById('browseBtn');
255
+ const selectedFiles = document.getElementById('selectedFiles');
256
+ const fileList = document.getElementById('fileList');
257
+
258
+ // Handle drag and drop
259
+ ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
260
+ dropzone.addEventListener(eventName, preventDefaults, false);
261
+ });
262
+
263
+ function preventDefaults(e) {
264
+ e.preventDefault();
265
+ e.stopPropagation();
266
+ }
267
+
268
+ ['dragenter', 'dragover'].forEach(eventName => {
269
+ dropzone.addEventListener(eventName, highlight, false);
270
+ });
271
+
272
+ ['dragleave', 'drop'].forEach(eventName => {
273
+ dropzone.addEventListener(eventName, unhighlight, false);
274
+ });
275
+
276
+ function highlight() {
277
+ dropzone.classList.add('active');
278
+ }
279
+
280
+ function unhighlight() {
281
+ dropzone.classList.remove('active');
282
+ }
283
+
284
+ dropzone.addEventListener('drop', handleDrop, false);
285
+ browseBtn.addEventListener('click', () => fileInput.click());
286
+
287
+ fileInput.addEventListener('change', function() {
288
+ handleFiles(this.files);
289
+ });
290
+
291
+ function handleDrop(e) {
292
+ const dt = e.dataTransfer;
293
+ const files = dt.files;
294
+ handleFiles(files);
295
+ }
296
+
297
+ function handleFiles(files) {
298
+ if (files.length > 0) {
299
+ selectedFiles.classList.remove('hidden');
300
+ fileList.innerHTML = '';
301
+
302
+ for (let i = 0; i < Math.min(files.length, 5); i++) {
303
+ const file = files[i];
304
+ const fileItem = document.createElement('div');
305
+ fileItem.className = 'flex items-center text-sm';
306
+ fileItem.innerHTML = `
307
+ <i data-feather="file" class="mr-2 text-gray-400"></i>
308
+ <span class="truncate flex-1">${file.name}</span>
309
+ <span class="text-gray-400 ml-2">${formatFileSize(file.size)}</span>
310
+ `;
311
+ fileList.appendChild(fileItem);
312
+ }
313
+
314
+ if (files.length > 5) {
315
+ const moreFiles = document.createElement('div');
316
+ moreFiles.className = 'text-sm text-gray-400';
317
+ moreFiles.textContent = `+ ${files.length - 5} more files`;
318
+ fileList.appendChild(moreFiles);
319
+ }
320
+
321
+ feather.replace();
322
+ }
323
+ }
324
+
325
+ function formatFileSize(bytes) {
326
+ if (bytes === 0) return '0 Bytes';
327
+ const k = 1024;
328
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
329
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
330
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
331
+ }
332
+
333
+ // Conversion simulation
334
+ const convertBtn = document.getElementById('convertBtn');
335
+ const progressModal = document.getElementById('progressModal');
336
+ const progressBar = document.getElementById('progressBar');
337
+ const progressPercent = document.getElementById('progressPercent');
338
+ const progressLog = document.getElementById('progressLog');
339
+ const cancelBtn = document.getElementById('cancelBtn');
340
+ const hideModalBtn = document.getElementById('hideModalBtn');
341
+
342
+ convertBtn.addEventListener('click', () => {
343
+ progressModal.classList.remove('hidden');
344
+ simulateConversion();
345
+ });
346
+
347
+ cancelBtn.addEventListener('click', () => {
348
+ progressModal.classList.add('hidden');
349
+ resetProgress();
350
+ });
351
+
352
+ hideModalBtn.addEventListener('click', () => {
353
+ progressModal.classList.add('hidden');
354
+ });
355
+
356
+ function resetProgress() {
357
+ progressBar.style.width = '0%';
358
+ progressPercent.textContent = '0%';
359
+ progressLog.innerHTML = '<div>> Initializing model conversion...</div>';
360
+ hideModalBtn.disabled = true;
361
+ }
362
+
363
+ function simulateConversion() {
364
+ let progress = 0;
365
+ const steps = [
366
+ {percent: 10, message: "> Detecting model type and components..."},
367
+ {percent: 25, message: "> Preparing model for ONNX export..."},
368
+ {percent: 40, message: "> Exporting text encoder to ONNX format..."},
369
+ {percent: 55, message: "> Exporting UNet to ONNX format..."},
370
+ {percent: 70, message: "> Exporting VAE to ONNX format..."},
371
+ {percent: 85, message: "> Running Olive optimization passes..."},
372
+ {percent: 95, message: "> Performing smoke test validation..."},
373
+ {percent: 100, message: "> Conversion complete! Output saved to models/exported_model"}
374
+ ];
375
+
376
+ const interval = setInterval(() => {
377
+ if (progress >= steps.length) {
378
+ clearInterval(interval);
379
+ hideModalBtn.disabled = false;
380
+ return;
381
+ }
382
+
383
+ const step = steps[progress];
384
+ progressBar.style.width = `${step.percent}%`;
385
+ progressPercent.textContent = `${step.percent}%`;
386
+
387
+ const logEntry = document.createElement('div');
388
+ logEntry.textContent = step.message;
389
+ progressLog.appendChild(logEntry);
390
+ progressLog.scrollTop = progressLog.scrollHeight;
391
+
392
+ progress++;
393
+ }, 1500);
394
+ }
395
+ });
396
+ </script>
397
+ </body>
398
  </html>