import NavExt from './nav-ext'; import * as tf from '@tensorflow/tfjs'; import './tensorflow'; import './sound.js'; import * as Blockly from 'blockly/core'; NavExt.init(); window.tf = tf; // let featureExtractor; // featureExtractor = await tf.loadGraphModel("../common/media/tfmodel/model.json"); // window.featureExtractor = featureExtractor; function closeModal() { document.getElementById('modalOverlay').style.display = 'none'; } // 从IndexedDB删除单个模型 async function deleteModel(modelName) { try { await tf.io.removeModel(`indexeddb://${modelName}`); // 从UI移除 const modelItem = document.querySelector(`.model-item[data-model-name="${modelName}"]`); if (modelItem) modelItem.remove(); } catch (error) { console.error('删除模型失败:', error); alert('删除模型失败: ' + error.message); } } // 显示单个模型项 function displayModelItem(modelName) { const modelsList = document.getElementById('imported-models'); if ([...modelsList.children].some(item => item.dataset.modelName === modelName)) { return; } const modelItem = document.createElement('div'); modelItem.className = 'model-item'; modelItem.dataset.modelName = modelName; modelItem.innerHTML = `
${modelName}
`; // 绑定删除事件 modelItem.querySelector('.delete-model').addEventListener('click', () => { deleteModel(modelName); }); modelsList.appendChild(modelItem); } // 清空所有模型 async function clearAllModels() { try { const modelInfos = await tf.io.listModels(); const deletePromises = Object.keys(modelInfos) .map(path => path.replace('indexeddb://', '')) .map(modelName => tf.io.removeModel(`indexeddb://${modelName}`)); await Promise.all(deletePromises); document.getElementById('imported-models').innerHTML = ''; } catch (error) { console.error('清空模型失败:', error); alert('清空模型失败: ' + error.message); } } // 加载并显示所有模型 async function loadAndDisplayAllModels() { try { const modelInfos = await tf.io.listModels(); document.getElementById('imported-models').innerHTML = ''; for (const [path] of Object.entries(modelInfos)) { const modelName = path.replace('indexeddb://', ''); displayModelItem(modelName); } } catch (error) { console.error('加载模型列表失败:', error); } } async function createModal() { const overlay = document.createElement('div'); overlay.id = 'modalOverlay'; Object.assign(overlay.style, { display: 'none', position: 'fixed', top: '0', left: '0', width: '100%', height: '100%', backgroundColor: 'rgba(0,0,0,0.5)', zIndex: '20011216', pointerEvents: 'auto' }); const content = document.createElement('div'); Object.assign(content.style, { backgroundColor: 'white', width: '60%', maxHeight: '80%', margin: '12vh auto', padding: '20px 30px', borderRadius: '12px' }); content.innerHTML = `

选择本地模型

导入模型名称:
❌ 模型结构描述文件(model.json)
未选择
❌ 权重文件(model.weights.bin)
0 个已选择

已导入模型

加载中...
`; overlay.appendChild(content); document.body.appendChild(overlay); content.querySelector('.close-btn').addEventListener('click', closeModal); overlay.addEventListener('click', (e) => { if (e.target === overlay) closeModal(); }); // 获取DOM元素 const modelUpload = document.getElementById('model-upload'); const modelHandle = document.getElementById('model-handle'); const outputDiv = document.getElementById('output'); let jsonFile = null; let weightFiles = []; modelUpload.addEventListener('change', async (event) => { const files = event.target.files; // 获取状态元素 const jsonStatus = document.getElementById('json-status'); const weightsStatus = document.getElementById('weights-status'); // 重置状态显示(保持完整文件名描述) jsonStatus.querySelector('span').textContent = '❌ 模型结构描述文件(model.json)'; jsonStatus.querySelector('div').textContent = '未选择'; weightsStatus.querySelector('span').textContent = '❌ 权重文件(model.weights.bin)'; weightsStatus.querySelector('div').textContent = '0 个已选择'; // 分离 JSON 和权重文件 weightFiles = []; for (let i = 0; i < files.length; i++) { if (files[i].name.endsWith('.json')) { jsonFile = files[i]; } else { weightFiles.push(files[i]); } } if (!jsonFile) { alert('未找到 model.json 文件'); return; } outputDiv.innerHTML = '正在处理上传的模型文件...'; if (jsonFile) { jsonStatus.querySelector('span').textContent = '✅ 模型结构描述文件(model.json)'; jsonStatus.querySelector('div').textContent = '已选择'; const modelName = jsonFile.name.replace('.json', ''); document.getElementById('model-name').value = modelName; } if (weightFiles.length > 0) { weightsStatus.querySelector('span').textContent = '✅ 权重文件(model.weights.bin)'; weightsStatus.querySelector('div').textContent = `${weightFiles.length} 个已选择`; } }); modelHandle.addEventListener('click', async () => { try { const modelNameInput = document.getElementById('model-name'); const modelName = modelNameInput.value || 'mixly-model'; const model = await tf.loadLayersModel( tf.io.browserFiles([jsonFile, ...weightFiles]) ); await model.save(`indexeddb://${modelName}`); loadAndDisplayAllModels(); outputDiv.innerHTML = `模型已成功保存为 ${modelName}!`; } catch (error) { outputDiv.innerHTML = `保存模型出错: ${error.message}`; console.error(error); } }) content.querySelector('#refresh-models').addEventListener('click', loadAndDisplayAllModels); content.querySelector('#clear-models').addEventListener('click', async () => { if (confirm('确定要删除所有模型吗?此操作不可恢复!')) { await clearAllModels(); } }); } createModal(); // 使用立即执行的异步函数,避免 top-level await 导致模块异步加载 (async () => { await loadAndDisplayAllModels(); })(); function openModal() { loadAndDisplayAllModels(); document.getElementById('modalOverlay').style.display = 'block'; } const workspace = Blockly.getMainWorkspace(); workspace.registerButtonCallback('handleModels', function () { openModal(); }); async function prepare_qmyixtxi(imgTensor) { let net = null; if (window.featureExtractor) { net = window.featureExtractor; } else { net = await tf.loadGraphModel("../common/media/tfmodel/model.json"); window.featureExtractor = net; } const preprocessedImg = imgTensor .resizeBilinear([224, 224]) .toFloat() .div(tf.scalar(127.5)) .sub(tf.scalar(1)) .expandDims(0); const features = window.featureExtractor.predict(preprocessedImg); let activation = features; return activation; } window.prepare_qmyixtxi = prepare_qmyixtxi;