Ferrell Synthetic Intelligence commited on
Commit ·
05d169b
1
Parent(s): 2d4ed0b
Add local model pack import manager
Browse files- app.js +21 -1
- index.html +1 -0
app.js
CHANGED
|
@@ -57,11 +57,14 @@ function renderModels() {
|
|
| 57 |
list.innerHTML = '';
|
| 58 |
lanes.innerHTML = '';
|
| 59 |
state.manifest.models.forEach(model => {
|
|
|
|
|
|
|
| 60 |
const roles = model.roles.join(' / ');
|
| 61 |
const item = document.createElement('button');
|
| 62 |
item.className = 'model-item';
|
| 63 |
-
item.innerHTML = `<span class="status ${
|
| 64 |
item.onclick = () => selectModel(model);
|
|
|
|
| 65 |
list.appendChild(item);
|
| 66 |
const lane = document.createElement('button');
|
| 67 |
lane.className = `lane ${model.status}`;
|
|
@@ -71,6 +74,23 @@ function renderModels() {
|
|
| 71 |
});
|
| 72 |
}
|
| 73 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
function selectModel(model) {
|
| 75 |
state.selected = model;
|
| 76 |
$('#selected-model').textContent = model.name;
|
|
|
|
| 57 |
list.innerHTML = '';
|
| 58 |
lanes.innerHTML = '';
|
| 59 |
state.manifest.models.forEach(model => {
|
| 60 |
+
const installed = JSON.parse(localStorage.getItem(`aide.model.${model.id}`) || 'null');
|
| 61 |
+
const visibleStatus = installed ? 'imported' : model.status;
|
| 62 |
const roles = model.roles.join(' / ');
|
| 63 |
const item = document.createElement('button');
|
| 64 |
item.className = 'model-item';
|
| 65 |
+
item.innerHTML = `<span class="status ${visibleStatus}"></span><span>${esc(model.name)}</span><small>${esc(model.format)} | ${esc(visibleStatus)} | ${esc(roles)}</small><strong class="pack-action">${installed ? 'REPLACE' : 'IMPORT'}</strong>`;
|
| 66 |
item.onclick = () => selectModel(model);
|
| 67 |
+
item.querySelector('.pack-action').onclick = event => { event.stopPropagation(); importModel(model); };
|
| 68 |
list.appendChild(item);
|
| 69 |
const lane = document.createElement('button');
|
| 70 |
lane.className = `lane ${model.status}`;
|
|
|
|
| 74 |
});
|
| 75 |
}
|
| 76 |
|
| 77 |
+
async function importModel(model) {
|
| 78 |
+
const input = $('#model-file-input');
|
| 79 |
+
input.value = '';
|
| 80 |
+
input.onchange = async () => {
|
| 81 |
+
const file = input.files?.[0];
|
| 82 |
+
if (!file) return;
|
| 83 |
+
const digest = await crypto.subtle.digest('SHA-256', await file.arrayBuffer());
|
| 84 |
+
const hash = [...new Uint8Array(digest)].map(byte => byte.toString(16).padStart(2, '0')).join('');
|
| 85 |
+
const record = { id: model.id, name: file.name, bytes: file.size, sha256: hash, imported_at: new Date().toISOString(), source_repo: model.source_revision };
|
| 86 |
+
localStorage.setItem(`aide.model.${model.id}`, JSON.stringify(record));
|
| 87 |
+
appendLog('MODEL PACK', `${model.name} imported locally. SHA-256: ${hash}. Runtime attachment is still required before inference.`);
|
| 88 |
+
renderModels();
|
| 89 |
+
selectModel(model);
|
| 90 |
+
};
|
| 91 |
+
input.click();
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
function selectModel(model) {
|
| 95 |
state.selected = model;
|
| 96 |
$('#selected-model').textContent = model.name;
|
index.html
CHANGED
|
@@ -85,5 +85,6 @@
|
|
| 85 |
</aside>
|
| 86 |
</main>
|
| 87 |
<script src="app.js"></script>
|
|
|
|
| 88 |
</body>
|
| 89 |
</html>
|
|
|
|
| 85 |
</aside>
|
| 86 |
</main>
|
| 87 |
<script src="app.js"></script>
|
| 88 |
+
<input id="model-file-input" type="file" accept=".gguf,.safetensors" hidden>
|
| 89 |
</body>
|
| 90 |
</html>
|