Skip to content

Commit

Permalink
bug fix
Browse files Browse the repository at this point in the history
  • Loading branch information
jammyfu committed Jan 23, 2025
1 parent a701a19 commit 38aa1f1
Show file tree
Hide file tree
Showing 2 changed files with 328 additions and 7 deletions.
333 changes: 327 additions & 6 deletions docs/fix/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ const translations = {
noFilesSelected: "No files selected",
removeFile: "Remove",
zipOption: "Download as ZIP",
processingFiles: "Processing {0}/{1} files...",
processingFiles: "Processing files: {0}/{1}",
successMultipleFiles: "Successfully processed {0} files",
clearButton: "Clear All"
clearButton: "Clear All",
successSingleFile: "Successfully processed 1 file",
errorProcessing: "Error occurred while processing files"
},
zh: {
title: "ComfyUI 工作流修复工具",
Expand All @@ -52,9 +54,11 @@ const translations = {
noFilesSelected: "未选择文件",
removeFile: "移除",
zipOption: "以ZIP格式下载",
processingFiles: "正在处理 {0}/{1} 个文件...",
successMultipleFiles: "成功处理 {0} 个文件",
clearButton: "清除全部"
processingFiles: "正在处理文件:{0}/{1}",
successMultipleFiles: "成功处理{0}个文件",
clearButton: "清除全部",
successSingleFile: "成功处理1个文件",
errorProcessing: "处理文件时发生错误"
}
};

Expand All @@ -70,6 +74,13 @@ document.addEventListener('DOMContentLoaded', () => {
setupEventListeners();
updateHeaderImage();
initializePathOptions();

// 初始化按钮文本
const t = translations[currentLanguage];
const fixButton = document.getElementById('fixButton');
if (fixButton) {
fixButton.textContent = t.fixButton;
}
});

// 添加路径选项初始化函数
Expand Down Expand Up @@ -161,7 +172,13 @@ function updateLanguage() {
// 更新所有文本内容
document.getElementById('title').textContent = t.title;
document.getElementById('dragText').textContent = t.dragText;
document.getElementById('fixButton').textContent = t.fixButton;

// 确保更新 Fix & Download 按钮文本
const fixButton = document.getElementById('fixButton');
if (fixButton) {
fixButton.textContent = t.fixButton;
}

document.getElementById('langBtn').textContent = t.switchLang;
document.getElementById('clearButton').textContent = t.clearButton;
document.getElementById('zipLabel').textContent = t.zipOption;
Expand Down Expand Up @@ -244,6 +261,10 @@ function updateFileList() {
clearButton.disabled = true;
document.getElementById('fixButton').disabled = true;
filesContainer.classList.add('no-scroll');

// 清除错误和成功消息
document.getElementById('error').textContent = '';
document.getElementById('success').textContent = '';
return;
}

Expand Down Expand Up @@ -274,8 +295,24 @@ function clearFiles() {
selectedFiles = [];
updateFileList();
document.getElementById('fileInput').value = '';

// 清除错误和成功消息
document.getElementById('error').textContent = '';
document.getElementById('success').textContent = '';

// 禁用相关按钮
document.getElementById('clearButton').disabled = true;
document.getElementById('fixButton').disabled = true;

// 重置文件拖放区域的状态
const dropZone = document.getElementById('dropZone');
dropZone.classList.remove('dragover');

// 更新文件列表显示
const t = translations[currentLanguage];
const filesContainer = document.getElementById('selectedFiles');
filesContainer.innerHTML = `<div class="file-item"><span class="file-name">${t.noFilesSelected}</span></div>`;
filesContainer.classList.add('no-scroll');
}

// UI更新函数
Expand All @@ -289,4 +326,288 @@ function updateUI() {
const fixType = document.getElementById('fixType').value;
updateDescription();
document.getElementById('pathOptions').classList.toggle('show', fixType === 'path');
}

// 添加下载功能
async function fixAndDownload() {
const t = translations[currentLanguage];
const fixType = document.getElementById('fixType').value;
const useZip = document.getElementById('zipDownload').checked;
const error = document.getElementById('error');
const success = document.getElementById('success');

error.textContent = '';
success.textContent = '';

if (selectedFiles.length === 0) {
error.textContent = t.errorSelectFile;
return;
}

try {
if (useZip) {
// ZIP下载逻辑保持不变
const zip = new JSZip();

for (let i = 0; i < selectedFiles.length; i++) {
const file = selectedFiles[i];
const content = await file.text();
const fixedContent = fixWorkflowContent(content, fixType);
const fileName = file.name.replace('.json', '_fixed.json');
zip.file(fileName, fixedContent);
}

const blob = await zip.generateAsync({type: 'blob'});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'fixed_workflows.zip';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);

success.textContent = t.successMultipleFiles.replace('{0}', selectedFiles.length);
} else {
// 修改后的单文件处理逻辑
let processedCount = 0;
const totalFiles = selectedFiles.length;
const fixedFiles = [];

// 首先处理所有文件
for (const file of selectedFiles) {
try {
const content = await file.text();
const fixedContent = fixWorkflowContent(content, fixType);
const fileName = file.name.replace('.json', '_fixed.json');
fixedFiles.push({
name: fileName,
content: fixedContent
});
processedCount++;
success.textContent = t.processingFiles
.replace('{0}', processedCount)
.replace('{1}', totalFiles);
} catch (err) {
console.error(`Error processing ${file.name}:`, err);
}
}

// 然后逐个下载处理好的文件
for (let i = 0; i < fixedFiles.length; i++) {
const file = fixedFiles[i];
const blob = new Blob([file.content], { type: 'application/json' });
const url = URL.createObjectURL(blob);

await new Promise(resolve => {
setTimeout(() => {
const a = document.createElement('a');
a.href = url;
a.download = file.name;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
resolve();
}, i * 800); // 增加间隔时间到800ms,确保文件能够正确下载
});
}

// 更新最终状态
if (processedCount > 0) {
success.textContent = processedCount === 1
? t.successSingleFile
: t.successMultipleFiles.replace('{0}', processedCount);
}
}
} catch (err) {
error.textContent = t.errorProcessing;
console.error(err);
}
}

// 定义需要进行路径转换的节点类型
const PATH_CONVERSION_NODES = new Set([
"CheckpointLoaderSimple",
"LoraLoader",
"ControlNetLoader",
"UNETLoader",
"VAELoader",
"CLIPLoader",
"DiffControlNetLoader",
"ModelLoader",
"LoadDiffusionModel",
"CheckpointLoader",
"DiffusersLoader",
"LoraLoaderModelOnly",
"VAEDecode",
"VAEEncode",
"CLIPVisionLoader",
"StyleModelLoader",
"UpscaleModelLoader",
"Load LoRA",
"Lora List",
"LoRA Stacker",
"GridLoras",
"CheckpointLoader|pysssss",
"LoraLoader|pysssss",
"LoraSave",
"DualCLIPLoader",
"DualUNETLoader",
"DualVAELoader",
"DualCLIPVisionLoader",
"DualStyleModelLoader",
"DualUpscaleModelLoader"
]);

function fixWorkflowContent(content, fixType) {
const workflow = JSON.parse(content);

if (fixType === 'namespace') {
// 遍历所有节点
for (const nodeId in workflow.nodes) {
const node = workflow.nodes[nodeId];
if (node && node.type) {
// 只修改 nodeMapping 中定义的节点
if (nodeMapping[node.type]) {
node.type = nodeMapping[node.type];
}
}
}
} else if (fixType === 'path') {
// 获取选中的路径类型
const pathType = document.querySelector('input[name="pathType"]:checked').value;
let conversionDirection = pathType;

// 处理自动检测
if (pathType === 'auto') {
const currentFormat = detectPathFormat(workflow);
conversionDirection = currentFormat === 'unix' ? 'toWindows' : 'toUnix';
}

// 遍历所有节点
for (const nodeId in workflow.nodes) {
const node = workflow.nodes[nodeId];
const nodeType = node.type || node.class_type;

// 如果是需要处理的节点类型
if (PATH_CONVERSION_NODES.has(nodeType) && node.widgets_values) {
node.widgets_values = node.widgets_values.map(value => {
if (typeof value === 'string' && !value.includes('base64')) {
// 转换路径分隔符
if (conversionDirection === 'toUnix') {
return value.replace(/\\/g, '/');
} else if (conversionDirection === 'toWindows') {
return value.replace(/\//g, '\\');
}
} else if (typeof value === 'object' && value?.content) {
// 处理特殊格式
if (!value.content.includes('base64')) {
const newContent = conversionDirection === 'toUnix'
? value.content.replace(/\\/g, '/')
: value.content.replace(/\//g, '\\');
return { ...value, content: newContent };
}
}
return value;
});
}
}
}

return JSON.stringify(workflow, null, 2);
}

// 检测路径格式
function detectPathFormat(workflow) {
let unixCount = 0;
let windowsCount = 0;

for (const nodeId in workflow.nodes) {
const node = workflow.nodes[nodeId];
const nodeType = node.type || node.class_type;

if (PATH_CONVERSION_NODES.has(nodeType) && node.widgets_values) {
node.widgets_values.forEach(value => {
if (typeof value === 'string' && !value.includes('base64')) {
const unixSlashes = (value.match(/\//g) || []).length;
const windowsSlashes = (value.match(/\\/g) || []).length;

if (unixSlashes > windowsSlashes) {
unixCount++;
} else if (windowsSlashes > unixSlashes) {
windowsCount++;
}
} else if (typeof value === 'object' && value?.content) {
if (!value.content.includes('base64')) {
const unixSlashes = (value.content.match(/\//g) || []).length;
const windowsSlashes = (value.content.match(/\\/g) || []).length;

if (unixSlashes > windowsSlashes) {
unixCount++;
} else if (windowsSlashes > unixSlashes) {
windowsCount++;
}
}
}
});
}
}

return unixCount > windowsCount ? 'unix' : 'windows';
}

// 更新 nodeMapping 对象
const nodeMapping = {
"MaskPreview": "PaintingCoder::MaskPreview",
"ImageSizeCreator": "PaintingCoder::ImageSizeCreator",
"ImageToBase64": "PaintingCoder::ImageToBase64",
"ImageLatentCreator": "PaintingCoder::ImageLatentCreator",
"DynamicImageCombiner": "PaintingCoder::DynamicImageCombiner",
"DynamicMaskCombiner": "PaintingCoder::DynamicMaskCombiner",
"ImageResolutionAdjuster": "PaintingCoder::ImageResolutionAdjuster",
"TextCombiner": "PaintingCoder::TextCombiner",
"ShowTextPlus": "PaintingCoder::ShowTextPlus",
"SimpleTextInput": "PaintingCoder::SimpleTextInput",
"MultilineTextInput": "PaintingCoder::MultilineTextInput",
"RemoveEmptyLinesAndLeadingSpaces": "PaintingCoder::RemoveEmptyLinesAndLeadingSpaces",
"ImageSwitch": "PaintingCoder::ImageSwitch",
"TextSwitch": "PaintingCoder::TextSwitch",
"MaskSwitch": "PaintingCoder::MaskSwitch",
"LatentSwitch": "PaintingCoder::LatentSwitch",
"WebImageLoader": "PaintingCoder::WebImageLoader",
"MaskPreview+": "PaintingCoder::MaskPreview"
};

function isPaintingCoderNode(type) {
// PaintingCoder 节点的类名前缀列表
const paintingCoderPrefixes = [
'Prompt',
'ControlNet',
'Model',
'VAE',
'CLIP',
'Lora',
'Checkpoint',
'UNET',
'Save',
'Preview',
'KSampler',
'EmptyLatent',
'Conditioning',
'Latent',
'Image',
'Text',
'Mask',
'Dynamic',
'Simple',
'Show',
'Web'
];

// 检查类名是否以任一前缀开头
return paintingCoderPrefixes.some(prefix =>
type.startsWith(prefix) ||
type.startsWith('PaintingCoder::' + prefix)
);
}
2 changes: 1 addition & 1 deletion docs/fix/workflow_fixer.html
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
<a href="https://github.com/jammyfu/ComfyUI_PaintingCoderUtils" target="_blank" title="Visit PaintingCoder on GitHub">
<img src="../images/workflow_fix_top_banner01.jpg" alt="Painting Coder Logo">
</a>
<span class="version-tag">Version 0.2.2</span>
<span class="version-tag">Version 0.2.3</span>
<div class="header-controls">
<button class="header-btn theme-btn" onclick="toggleTheme()" title="Toggle theme">
<!-- 月亮图标 -->
Expand Down

0 comments on commit 38aa1f1

Please sign in to comment.