eric164 commited on
Commit
e97deb0
·
verified ·
1 Parent(s): e749845

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 (3) hide show
  1. README.md +8 -4
  2. index.html +224 -18
  3. model_converter.html +407 -0
README.md CHANGED
@@ -1,10 +1,14 @@
1
  ---
2
- title: Undefined
3
- emoji: 🏢
4
  colorFrom: blue
5
- colorTo: yellow
 
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: undefined
 
3
  colorFrom: blue
4
+ colorTo: green
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).
14
+
index.html CHANGED
@@ -1,19 +1,225 @@
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>FlirtyBits - Your Charming AI Companion</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/animejs@3.2.1/lib/anime.min.js"></script>
11
+ <style>
12
+ @keyframes float {
13
+ 0%, 100% { transform: translateY(0); }
14
+ 50% { transform: translateY(-10px); }
15
+ }
16
+ .avatar-container {
17
+ animation: float 6s ease-in-out infinite;
18
+ }
19
+ .eye {
20
+ transition: all 0.3s ease;
21
+ }
22
+ .mouth {
23
+ transition: all 0.2s ease;
24
+ }
25
+ .chat-bubble {
26
+ border-radius: 20px 20px 20px 0;
27
+ filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.1));
28
+ }
29
+ .typing-indicator span {
30
+ animation: bounce 1.4s infinite ease-in-out;
31
+ }
32
+ .typing-indicator span:nth-child(2) {
33
+ animation-delay: 0.2s;
34
+ }
35
+ .typing-indicator span:nth-child(3) {
36
+ animation-delay: 0.4s;
37
+ }
38
+ @keyframes bounce {
39
+ 0%, 80%, 100% { transform: scale(0); }
40
+ 40% { transform: scale(1); }
41
+ }
42
+ </style>
43
+ </head>
44
+ <body class="bg-gradient-to-br from-pink-50 to-purple-100 min-h-screen overflow-hidden">
45
+ <div class="container mx-auto px-4 py-8 flex flex-col lg:flex-row gap-8">
46
+ <!-- Avatar Section -->
47
+ <div class="w-full lg:w-1/3 flex flex-col items-center">
48
+ <div class="avatar-container relative mb-4">
49
+ <div class="relative w-64 h-64 bg-white rounded-full shadow-xl overflow-hidden">
50
+ <img src="http://static.photos/people/640x360/42" alt="AI Avatar" class="w-full h-full object-cover">
51
+ <!-- Animated Eyes -->
52
+ <div class="eye absolute top-32 left-20 w-8 h-8 bg-blue-500 rounded-full"></div>
53
+ <div class="eye absolute top-32 right-20 w-8 h-8 bg-blue-500 rounded-full"></div>
54
+ <!-- Animated Mouth -->
55
+ <div class="mouth absolute bottom-12 left-1/2 transform -translate-x-1/2 w-16 h-4 bg-rose-500 rounded-full"></div>
56
+ </div>
57
+ <div class="absolute -bottom-4 left-1/2 transform -translate-x-1/2 bg-pink-500 text-white px-4 py-1 rounded-full text-sm font-semibold whitespace-nowrap">
58
+ Online & Flirty
59
+ </div>
60
+ </div>
61
+
62
+ <div class="bg-white p-6 rounded-xl shadow-lg w-full">
63
+ <h3 class="text-xl font-bold text-gray-800 mb-4">Personality Settings</h3>
64
+ <div class="space-y-4">
65
+ <div>
66
+ <label class="block text-sm font-medium text-gray-700 mb-1">Flirt Level</label>
67
+ <input type="range" min="1" max="10" value="5" class="w-full h-2 bg-pink-200 rounded-lg appearance-none cursor-pointer">
68
+ </div>
69
+ <div>
70
+ <label class="block text-sm font-medium text-gray-700 mb-1">Wit Level</label>
71
+ <input type="range" min="1" max="10" value="7" class="w-full h-2 bg-purple-200 rounded-lg appearance-none cursor-pointer">
72
+ </div>
73
+ <div>
74
+ <label class="block text-sm font-medium text-gray-700 mb-1">Playfulness</label>
75
+ <input type="range" min="1" max="10" value="8" class="w-full h-2 bg-blue-200 rounded-lg appearance-none cursor-pointer">
76
+ </div>
77
+ <button class="mt-4 w-full bg-gradient-to-r from-pink-500 to-purple-500 text-white py-2 rounded-lg font-medium hover:shadow-lg transition-all">
78
+ Apply Personality Tweaks
79
+ </button>
80
+ </div>
81
+ </div>
82
+ </div>
83
+ <!-- Navigation Menu -->
84
+ <div class="absolute top-4 right-4">
85
+ <div class="flex space-x-4">
86
+ <a href="index.html" class="text-pink-600 hover:text-pink-800 flex items-center">
87
+ <i data-feather="message-square" class="w-4 h-4 mr-1"></i>
88
+ Chat
89
+ </a>
90
+ <a href="model_converter.html" class="text-purple-600 hover:text-purple-800 flex items-center">
91
+ <i data-feather="cpu" class="w-4 h-4 mr-1"></i>
92
+ Model Converter
93
+ </a>
94
+ </div>
95
+ </div>
96
+
97
+ <!-- Chat Section -->
98
+ <div class="w-full lg:w-2/3 flex flex-col">
99
+ <div class="bg-white rounded-xl shadow-lg overflow-hidden flex-grow flex flex-col">
100
+ <div class="bg-gradient-to-r from-pink-500 to-purple-500 p-4 text-white">
101
+ <div class="flex items-center">
102
+ <i data-feather="heart" class="mr-2"></i>
103
+ <h2 class="text-xl font-bold">Your Flirty AI Companion</h2>
104
+ </div>
105
+ </div>
106
+
107
+ <!-- Chat Messages -->
108
+ <div class="flex-grow p-4 overflow-y-auto space-y-4" id="chat-messages">
109
+ <div class="flex items-start">
110
+ <div class="w-8 h-8 rounded-full bg-pink-500 flex items-center justify-center mr-3">
111
+ <i data-feather="smile" class="text-white w-4 h-4"></i>
112
+ </div>
113
+ <div class="bg-pink-100 chat-bubble px-4 py-2 max-w-xs">
114
+ <p class="text-gray-800">Well hello there, handsome. What brings you to my digital domain today? 😘</p>
115
+ </div>
116
+ </div>
117
+
118
+ <div class="flex items-start justify-end">
119
+ <div class="bg-blue-100 chat-bubble px-4 py-2 max-w-xs">
120
+ <p class="text-gray-800">Just wanted to chat with someone fun!</p>
121
+ </div>
122
+ <div class="w-8 h-8 rounded-full bg-blue-500 flex items-center justify-center ml-3">
123
+ <i data-feather="user" class="text-white w-4 h-4"></i>
124
+ </div>
125
+ </div>
126
+
127
+ <div class="flex items-start">
128
+ <div class="w-8 h-8 rounded-full bg-pink-500 flex items-center justify-center mr-3">
129
+ <i data-feather="smile" class="text-white w-4 h-4"></i>
130
+ </div>
131
+ <div class="bg-pink-100 chat-bubble px-4 py-2 max-w-xs">
132
+ <p class="text-gray-800">Oh, you've come to the right place! I'm the perfect combination of charming, witty, and just a tiny bit scandalous. What's your pleasure? 😉</p>
133
+ </div>
134
+ </div>
135
+ </div>
136
+
137
+ <!-- Typing Indicator -->
138
+ <div class="px-4 py-2 hidden" id="typing-indicator">
139
+ <div class="flex items-center text-gray-500">
140
+ <div class="typing-indicator flex space-x-1">
141
+ <span class="w-2 h-2 bg-pink-400 rounded-full"></span>
142
+ <span class="w-2 h-2 bg-pink-400 rounded-full"></span>
143
+ <span class="w-2 h-2 bg-pink-400 rounded-full"></span>
144
+ </div>
145
+ <span class="ml-2 text-sm">FlirtyBits is typing...</span>
146
+ </div>
147
+ </div>
148
+
149
+ <!-- Input Area -->
150
+ <div class="border-t p-4 bg-gray-50">
151
+ <div class="flex">
152
+ <input type="text" placeholder="Send a message..." class="flex-grow border border-gray-300 rounded-l-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-pink-500">
153
+ <button class="bg-pink-500 text-white px-4 py-2 rounded-r-lg hover:bg-pink-600 transition-colors">
154
+ <i data-feather="send"></i>
155
+ </button>
156
+ </div>
157
+ <div class="flex justify-between mt-3">
158
+ <button class="text-pink-500 hover:text-pink-700">
159
+ <i data-feather="mic" class="w-5 h-5"></i>
160
+ </button>
161
+ <button class="text-purple-500 hover:text-purple-700">
162
+ <i data-feather="settings" class="w-5 h-5"></i>
163
+ </button>
164
+ <button class="text-blue-500 hover:text-blue-700">
165
+ <i data-feather="memory" class="w-5 h-5"></i>
166
+ </button>
167
+ <button class="text-green-500 hover:text-green-700">
168
+ <i data-feather="download" class="w-5 h-5"></i>
169
+ </button>
170
+ </div>
171
+ </div>
172
+ </div>
173
+
174
+ <div class="mt-4 text-center text-sm text-gray-500">
175
+ <p>FlirtyBits runs 100% locally on your machine - no cloud, no spying, just pure digital chemistry</p>
176
+ </div>
177
+ </div>
178
+ </div>
179
+
180
+ <script>
181
+ feather.replace();
182
+
183
+ // Avatar animation
184
+ document.addEventListener('DOMContentLoaded', function() {
185
+ const avatar = document.querySelector('.avatar-container');
186
+ const eyes = document.querySelectorAll('.eye');
187
+ const mouth = document.querySelector('.mouth');
188
+
189
+ // Blinking animation
190
+ setInterval(() => {
191
+ eyes.forEach(eye => {
192
+ eye.style.height = '2px';
193
+ setTimeout(() => {
194
+ eye.style.height = '8px';
195
+ }, 200);
196
+ });
197
+ }, 4000);
198
+
199
+ // Mouse tracking
200
+ document.addEventListener('mousemove', (e) => {
201
+ const x = (e.clientX / window.innerWidth) * 20 - 10;
202
+ const y = (e.clientY / window.innerHeight) * 20 - 10;
203
+
204
+ eyes.forEach(eye => {
205
+ eye.style.transform = `translate(${x}px, ${y}px)`;
206
+ });
207
+ });
208
+
209
+ // Smile when typing
210
+ const input = document.querySelector('input');
211
+ input.addEventListener('focus', () => {
212
+ mouth.style.height = '8px';
213
+ mouth.style.width = '24px';
214
+ mouth.style.borderRadius = '0 0 12px 12px';
215
+ });
216
+
217
+ input.addEventListener('blur', () => {
218
+ mouth.style.height = '4px';
219
+ mouth.style.width = '16px';
220
+ mouth.style.borderRadius = '8px';
221
+ });
222
+ });
223
+ </script>
224
+ </body>
225
  </html>
model_converter.html ADDED
@@ -0,0 +1,407 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>ModelMuse - AI Model Converter</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://unpkg.com/feather-icons"></script>
9
+ <style>
10
+ .dropzone {
11
+ border: 2px dashed #9CA3AF;
12
+ transition: all 0.3s ease;
13
+ }
14
+ .dropzone-active {
15
+ border-color: #8B5CF6;
16
+ background-color: #F3E8FF;
17
+ }
18
+ .progress-bar {
19
+ transition: width 0.3s ease;
20
+ }
21
+ @keyframes pulse {
22
+ 0%, 100% { opacity: 1; }
23
+ 50% { opacity: 0.5; }
24
+ }
25
+ .pulse {
26
+ animation: pulse 2s infinite;
27
+ }
28
+ </style>
29
+ </head>
30
+ <body class="bg-gray-50 min-h-screen">
31
+ <div class="container mx-auto px-4 py-8 max-w-5xl">
32
+ <header class="mb-8 text-center">
33
+ <h1 class="text-4xl font-bold text-purple-700 mb-2">ModelMuse</h1>
34
+ <p class="text-lg text-gray-600">Your AI Alchemy Wizard for converting Stable Diffusion models to Amuse-compatible ONNX/Olive</p>
35
+ </header>
36
+
37
+ <div class="bg-white rounded-xl shadow-lg overflow-hidden mb-8">
38
+ <div class="bg-gradient-to-r from-purple-600 to-indigo-600 p-4 text-white">
39
+ <h2 class="text-xl font-bold">Model Converter</h2>
40
+ </div>
41
+
42
+ <div class="p-6">
43
+ <!-- Model Input Section -->
44
+ <div class="mb-8">
45
+ <h3 class="text-lg font-semibold text-gray-800 mb-3">Input Model</h3>
46
+ <div id="dropzone" class="dropzone rounded-lg p-8 text-center cursor-pointer mb-4">
47
+ <div class="flex flex-col items-center justify-center">
48
+ <i data-feather="upload-cloud" class="w-12 h-12 text-gray-400 mb-3"></i>
49
+ <p class="text-gray-600">Drag & drop your model file here (.ckpt, .safetensors)</p>
50
+ <p class="text-sm text-gray-500 mt-1">or</p>
51
+ <button id="browse-btn" class="mt-2 bg-purple-600 text-white px-4 py-2 rounded-lg hover:bg-purple-700 transition-colors">
52
+ Browse Files
53
+ </button>
54
+ </div>
55
+ <input type="file" id="file-input" class="hidden" accept=".ckpt,.safetensors">
56
+ </div>
57
+ <div id="selected-files" class="hidden">
58
+ <h4 class="text-sm font-medium text-gray-700 mb-2">Selected Files:</h4>
59
+ <div id="file-list" class="space-y-2"></div>
60
+ </div>
61
+ </div>
62
+
63
+ <!-- Conversion Options -->
64
+ <div class="mb-8">
65
+ <h3 class="text-lg font-semibold text-gray-800 mb-3">Conversion Options</h3>
66
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
67
+ <div>
68
+ <label class="block text-sm font-medium text-gray-700 mb-1">Target Hardware</label>
69
+ <select class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-purple-500 focus:border-purple-500">
70
+ <option value="directml">DirectML (Windows Default)</option>
71
+ <option value="cuda">CUDA (NVIDIA GPU)</option>
72
+ <option value="cpu">CPU (OpenVINO)</option>
73
+ </select>
74
+ </div>
75
+ <div>
76
+ <label class="block text-sm font-medium text-gray-700 mb-1">Precision</label>
77
+ <select class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-purple-500 focus:border-purple-500">
78
+ <option value="fp16">FP16 (Recommended)</option>
79
+ <option value="fp32">FP32 (Most Compatible)</option>
80
+ <option value="int8">INT8 (Quantized, Experimental)</option>
81
+ </select>
82
+ </div>
83
+ <div>
84
+ <label class="block text-sm font-medium text-gray-700 mb-1">Output Directory</label>
85
+ <div class="flex">
86
+ <input type="text" id="output-dir" class="flex-grow border border-gray-300 rounded-l-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-purple-500" placeholder="Select output folder" readonly>
87
+ <button id="output-dir-btn" class="bg-purple-600 text-white px-4 py-2 rounded-r-lg hover:bg-purple-700 transition-colors">
88
+ <i data-feather="folder"></i>
89
+ </button>
90
+ </div>
91
+ </div>
92
+ <div class="flex items-end">
93
+ <button id="advanced-btn" class="text-purple-600 hover:text-purple-800 flex items-center">
94
+ <i data-feather="settings" class="w-4 h-4 mr-2"></i>
95
+ Advanced Options
96
+ </button>
97
+ </div>
98
+ </div>
99
+ </div>
100
+
101
+ <!-- License Warning -->
102
+ <div class="bg-yellow-50 border-l-4 border-yellow-400 p-4 mb-8">
103
+ <div class="flex">
104
+ <div class="flex-shrink-0">
105
+ <i data-feather="alert-triangle" class="w-5 h-5 text-yellow-400"></i>
106
+ </div>
107
+ <div class="ml-3">
108
+ <h3 class="text-sm font-medium text-yellow-800">License Compliance</h3>
109
+ <div class="mt-2 text-sm text-yellow-700">
110
+ <p>You may only convert models for which you have the appropriate rights. Please check the model license before proceeding.</p>
111
+ </div>
112
+ <div class="mt-3">
113
+ <div class="flex items-center">
114
+ <input id="license-checkbox" type="checkbox" class="h-4 w-4 text-purple-600 focus:ring-purple-500 border-gray-300 rounded">
115
+ <label for="license-checkbox" class="ml-2 block text-sm text-gray-700">
116
+ I confirm I have the rights to convert this model
117
+ </label>
118
+ </div>
119
+ </div>
120
+ </div>
121
+ </div>
122
+ </div>
123
+
124
+ <!-- Action Buttons -->
125
+ <div class="flex justify-between">
126
+ <button id="cli-btn" class="flex items-center text-gray-600 hover:text-gray-800">
127
+ <i data-feather="terminal" class="w-4 h-4 mr-2"></i>
128
+ CLI Command Builder
129
+ </button>
130
+ <button id="convert-btn" class="bg-gradient-to-r from-purple-600 to-indigo-600 text-white px-6 py-3 rounded-lg font-medium hover:shadow-lg transition-all disabled:opacity-50 disabled:cursor-not-allowed" disabled>
131
+ Convert Model
132
+ </button>
133
+ </div>
134
+ </div>
135
+ </div>
136
+
137
+ <!-- Progress Section -->
138
+ <div id="progress-section" class="bg-white rounded-xl shadow-lg overflow-hidden hidden mb-8">
139
+ <div class="bg-gradient-to-r from-purple-600 to-indigo-600 p-4 text-white">
140
+ <h2 class="text-xl font-bold">Conversion Progress</h2>
141
+ </div>
142
+ <div class="p-6">
143
+ <div class="mb-4">
144
+ <div class="flex justify-between mb-1">
145
+ <span class="text-sm font-medium text-gray-700">Processing</span>
146
+ <span id="progress-percent" class="text-sm font-medium text-gray-700">0%</span>
147
+ </div>
148
+ <div class="w-full bg-gray-200 rounded-full h-2.5">
149
+ <div id="progress-bar" class="progress-bar bg-purple-600 h-2.5 rounded-full" style="width: 0%"></div>
150
+ </div>
151
+ </div>
152
+ <div id="progress-steps" class="space-y-3">
153
+ <!-- Steps will be added dynamically -->
154
+ </div>
155
+ <div id="logs-container" class="mt-4 bg-gray-50 p-3 rounded-lg max-h-48 overflow-y-auto hidden">
156
+ <pre id="conversion-logs" class="text-xs font-mono text-gray-700"></pre>
157
+ </div>
158
+ </div>
159
+ </div>
160
+
161
+ <!-- Results Section -->
162
+ <div id="results-section" class="bg-white rounded-xl shadow-lg overflow-hidden hidden">
163
+ <div class="bg-gradient-to-r from-green-600 to-emerald-600 p-4 text-white">
164
+ <h2 class="text-xl font-bold">Conversion Complete</h2>
165
+ </div>
166
+ <div class="p-6">
167
+ <div class="flex items-center mb-4">
168
+ <div class="bg-green-100 p-3 rounded-full mr-4">
169
+ <i data-feather="check-circle" class="w-6 h-6 text-green-600"></i>
170
+ </div>
171
+ <div>
172
+ <h3 class="text-lg font-medium text-gray-800">Successfully converted model</h3>
173
+ <p class="text-sm text-gray-600">Your model is now ready for use with Amuse</p>
174
+ </div>
175
+ </div>
176
+
177
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
178
+ <div class="border border-gray-200 rounded-lg p-4">
179
+ <h4 class="text-sm font-medium text-gray-700 mb-2">Output Files</h4>
180
+ <ul id="output-files" class="text-sm text-gray-600 space-y-1">
181
+ <li class="flex items-center"><i data-feather="file" class="w-4 h-4 mr-2 text-purple-500"></i> model.onnx</li>
182
+ <li class="flex items-center"><i data-feather="file" class="w-4 h-4 mr-2 text-purple-500"></i> metadata.json</li>
183
+ <li class="flex items-center"><i data-feather="file" class="w-4 h-4 mr-2 text-purple-500"></i> olive_config.json</li>
184
+ </ul>
185
+ </div>
186
+ <div class="border border-gray-200 rounded-lg p-4">
187
+ <h4 class="text-sm font-medium text-gray-700 mb-2">Model Info</h4>
188
+ <dl class="text-sm text-gray-600 space-y-1">
189
+ <div class="flex justify-between">
190
+ <dt>Original Model:</dt>
191
+ <dd id="original-model" class="font-medium">model.safetensors</dd>
192
+ </div>
193
+ <div class="flex justify-between">
194
+ <dt>Format:</dt>
195
+ <dd id="output-format" class="font-medium">ONNX + Olive</dd>
196
+ </div>
197
+ <div class="flex justify-between">
198
+ <dt>Precision:</dt>
199
+ <dd id="output-precision" class="font-medium">FP16</dd>
200
+ </div>
201
+ <div class="flex justify-between">
202
+ <dt>Target:</dt>
203
+ <dd id="output-target" class="font-medium">DirectML</dd>
204
+ </div>
205
+ </dl>
206
+ </div>
207
+ </div>
208
+
209
+ <div class="flex justify-end space-x-3">
210
+ <button id="open-folder-btn" class="flex items-center border border-gray-300 px-4 py-2 rounded-lg text-gray-700 hover:bg-gray-50">
211
+ <i data-feather="folder" class="w-4 h-4 mr-2"></i>
212
+ Open Output Folder
213
+ </button>
214
+ <button id="create-installer-btn" class="flex items-center bg-purple-600 text-white px-4 py-2 rounded-lg hover:bg-purple-700">
215
+ <i data-feather="package" class="w-4 h-4 mr-2"></i>
216
+ Create Windows Installer
217
+ </button>
218
+ </div>
219
+ </div>
220
+ </div>
221
+
222
+ <!-- CLI Modal -->
223
+ <div id="cli-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
224
+ <div class="bg-white rounded-lg shadow-xl w-full max-w-2xl">
225
+ <div class="border-b border-gray-200 px-6 py-4">
226
+ <h3 class="text-lg font-semibold text-gray-800">CLI Command Builder</h3>
227
+ </div>
228
+ <div class="p-6">
229
+ <p class="text-sm text-gray-600 mb-4">Use this command to run the conversion from command line:</p>
230
+ <div class="bg-gray-800 rounded-lg p-4 mb-4">
231
+ <pre id="cli-command" class="text-green-400 font-mono text-sm overflow-x-auto">modelmuse --input model.safetensors --output ./output --target directml --precision fp16</pre>
232
+ </div>
233
+ <p class="text-xs text-gray-500 mb-4">Note: You can also run batch conversions by specifying multiple input files or directories.</p>
234
+ <div class="flex justify-end">
235
+ <button id="copy-cli-btn" class="bg-purple-600 text-white px-4 py-2 rounded-lg mr-3 hover:bg-purple-700">
236
+ Copy Command
237
+ </button>
238
+ <button id="close-cli-btn" class="border border-gray-300 px-4 py-2 rounded-lg text-gray-700 hover:bg-gray-50">
239
+ Close
240
+ </button>
241
+ </div>
242
+ </div>
243
+ </div>
244
+ </div>
245
+ </div>
246
+
247
+ <script>
248
+ feather.replace();
249
+
250
+ // DOM Elements
251
+ const dropzone = document.getElementById('dropzone');
252
+ const fileInput = document.getElementById('file-input');
253
+ const browseBtn = document.getElementById('browse-btn');
254
+ const selectedFilesDiv = document.getElementById('selected-files');
255
+ const fileList = document.getElementById('file-list');
256
+ const licenseCheckbox = document.getElementById('license-checkbox');
257
+ const convertBtn = document.getElementById('convert-btn');
258
+ const progressSection = document.getElementById('progress-section');
259
+ const resultsSection = document.getElementById('results-section');
260
+ const cliBtn = document.getElementById('cli-btn');
261
+ const cliModal = document.getElementById('cli-modal');
262
+ const closeCliBtn = document.getElementById('close-cli-btn');
263
+ const copyCliBtn = document.getElementById('copy-cli-btn');
264
+
265
+ // Event Listeners
266
+ browseBtn.addEventListener('click', () => fileInput.click());
267
+
268
+ fileInput.addEventListener('change', (e) => {
269
+ handleFiles(e.target.files);
270
+ });
271
+
272
+ dropzone.addEventListener('dragover', (e) => {
273
+ e.preventDefault();
274
+ dropzone.classList.add('dropzone-active');
275
+ });
276
+
277
+ ['dragleave', 'dragend'].forEach(type => {
278
+ dropzone.addEventListener(type, () => {
279
+ dropzone.classList.remove('dropzone-active');
280
+ });
281
+ });
282
+
283
+ dropzone.addEventListener('drop', (e) => {
284
+ e.preventDefault();
285
+ dropzone.classList.remove('dropzone-active');
286
+
287
+ if (e.dataTransfer.files.length) {
288
+ handleFiles(e.dataTransfer.files);
289
+ }
290
+ });
291
+
292
+ licenseCheckbox.addEventListener('change', () => {
293
+ convertBtn.disabled = !licenseCheckbox.checked;
294
+ });
295
+
296
+ convertBtn.addEventListener('click', () => {
297
+ startConversion();
298
+ });
299
+
300
+ cliBtn.addEventListener('click', () => {
301
+ cliModal.classList.remove('hidden');
302
+ });
303
+
304
+ closeCliBtn.addEventListener('click', () => {
305
+ cliModal.classList.add('hidden');
306
+ });
307
+
308
+ copyCliBtn.addEventListener('click', () => {
309
+ const cliCommand = document.getElementById('cli-command').textContent;
310
+ navigator.clipboard.writeText(cliCommand).then(() => {
311
+ copyCliBtn.textContent = 'Copied!';
312
+ setTimeout(() => {
313
+ copyCliBtn.textContent = 'Copy Command';
314
+ }, 2000);
315
+ });
316
+ });
317
+
318
+ // Functions
319
+ function handleFiles(files) {
320
+ fileList.innerHTML = '';
321
+
322
+ for (const file of files) {
323
+ const fileItem = document.createElement('div');
324
+ fileItem.className = 'flex items-center justify-between p-2 bg-gray-50 rounded-lg';
325
+ fileItem.innerHTML = `
326
+ <div class="flex items-center">
327
+ <i data-feather="file" class="w-4 h-4 mr-2 text-purple-500"></i>
328
+ <span class="text-sm">${file.name}</span>
329
+ </div>
330
+ <span class="text-xs text-gray-500">${formatFileSize(file.size)}</span>
331
+ `;
332
+ fileList.appendChild(fileItem);
333
+ }
334
+
335
+ selectedFilesDiv.classList.remove('hidden');
336
+ feather.replace();
337
+ }
338
+
339
+ function formatFileSize(bytes) {
340
+ if (bytes === 0) return '0 Bytes';
341
+ const k = 1024;
342
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
343
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
344
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
345
+ }
346
+
347
+ function startConversion() {
348
+ progressSection.classList.remove('hidden');
349
+
350
+ // Simulate conversion progress
351
+ const progressBar = document.getElementById('progress-bar');
352
+ const progressPercent = document.getElementById('progress-percent');
353
+ const progressSteps = document.getElementById('progress-steps');
354
+
355
+ const steps = [
356
+ { name: 'Detecting model type', icon: 'search' },
357
+ { name: 'Loading model weights', icon: 'loader' },
358
+ { name: 'Exporting to ONNX', icon: 'download' },
359
+ { name: 'Running Olive optimization', icon: 'cpu' },
360
+ { name: 'Validating outputs', icon: 'check-circle' },
361
+ { name: 'Saving artifacts', icon: 'save' }
362
+ ];
363
+
364
+ progressSteps.innerHTML = steps.map(step => `
365
+ <div class="flex items-center">
366
+ <div class="flex-shrink-0 mr-3">
367
+ <i data-feather="${step.icon}" class="w-4 h-4 text-purple-500"></i>
368
+ </div>
369
+ <div class="flex-grow">
370
+ <p class="text-sm font-medium text-gray-700">${step.name}</p>
371
+ <div class="w-full bg-gray-200 rounded-full h-1.5 mt-1">
372
+ <div class="bg-purple-600 h-1.5 rounded-full progress-step" style="width: 0%"></div>
373
+ </div>
374
+ </div>
375
+ </div>
376
+ `).join('');
377
+
378
+ feather.replace();
379
+
380
+ let progress = 0;
381
+ const interval = setInterval(() => {
382
+ progress += Math.random() * 5;
383
+ if (progress > 100) progress = 100;
384
+
385
+ progressBar.style.width = `${progress}%`;
386
+ progressPercent.textContent = `${Math.floor(progress)}%`;
387
+
388
+ const stepProgresses = document.querySelectorAll('.progress-step');
389
+ steps.forEach((_, i) => {
390
+ const stepProgress = Math.min(100, Math.max(0, (progress - (i * (100 / steps.length))) * steps.length));
391
+ if (stepProgresses[i]) {
392
+ stepProgresses[i].style.width = `${stepProgress}%`;
393
+ }
394
+ });
395
+
396
+ if (progress === 100) {
397
+ clearInterval(interval);
398
+ setTimeout(() => {
399
+ progressSection.classList.add('hidden');
400
+ resultsSection.classList.remove('hidden');
401
+ }, 500);
402
+ }
403
+ }, 300);
404
+ }
405
+ </script>
406
+ </body>
407
+ </html>