import NavExt from './nav-ext';
import * as tf from '@tensorflow/tfjs';
import './tensorflow';
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 = `
选择本地模型
`;
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();
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 = featureExtractor.predict(preprocessedImg);
let activation = features;
return activation;
}
window.prepare_qmyixtxi = prepare_qmyixtxi;