Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6331b25241 | ||
|
|
c8689d56e4 |
@@ -1,5 +1,12 @@
|
||||
# 📈 Anomalous Model Browser Changelog
|
||||
|
||||
## v1.57.3 Beta (Hotfix: Offline Scan, Prompt Workshop) — 2026-09-29
|
||||
|
||||
### 🔌 Offline scan and small fixes (离线扫描与小修复)
|
||||
- **Offline scan stays offline (离线扫描不再联网)**: "Offline fast read" no longer sends the greyed-out rename and overwrite options, and an offline scan never fetches Civitai model pages or preview images, even for models whose `.info` came from Civitai. Scan requests without options are refused instead of starting an online scan.
|
||||
- Clicking the drop zone at the end of the Prompt Workshop's assembly track focuses the card search again instead of failing silently.
|
||||
- Malformed requests to translation, deletion, scanning and image-material routes get a clear 400 instead of a server error.
|
||||
|
||||
## v1.57.2 Beta (Hotfix: Canvas Performance, Saving Workflows) — 2026-09-27
|
||||
|
||||
### 💾 Saving workflows and Prompt Notes (保存工作流与提示词笔记)
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
[](https://github.com/ltdrdata/ComfyUI-Manager)
|
||||
[](LICENSE)
|
||||
[](CHANGELOG.md)
|
||||
[](CHANGELOG.md)
|
||||
[](https://www.bilibili.com/video/BV1a1bv68EuA/)
|
||||
[](https://youtu.be/hAvsj7uiaCw)
|
||||
|
||||
|
||||
@@ -83,6 +83,11 @@ async def api_get_gallery_images(request):
|
||||
async def api_delete_gallery_image(request):
|
||||
try:
|
||||
data = await request.json()
|
||||
except ValueError:
|
||||
data = None
|
||||
if not isinstance(data, dict):
|
||||
return web.json_response({"status": "error", "message": "Invalid request body"}, status=400)
|
||||
try:
|
||||
filename = data.get("filename")
|
||||
subfolder = data.get("subfolder", "")
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@ def _material_assets_dir(materials_dir, filename, create=False):
|
||||
|
||||
def _inspect_source_image(source_image):
|
||||
source = _normalise_source_image(source_image)
|
||||
if source is None:
|
||||
raise ValueError("Missing source image")
|
||||
if not source["filename"].lower().endswith(".png"):
|
||||
raise ValueError("Only PNG output images can contain reusable workflow metadata")
|
||||
source_path = _output_source_path(source)
|
||||
|
||||
@@ -75,6 +75,11 @@ def _reset_model_cover(base_path):
|
||||
async def api_delete_model(request):
|
||||
try:
|
||||
data = await request.json()
|
||||
except ValueError:
|
||||
data = None
|
||||
if not isinstance(data, dict):
|
||||
return web.json_response({"status": "error", "message": "Invalid request body"}, status=400)
|
||||
try:
|
||||
folder_type = data.get('type', 'checkpoints')
|
||||
subfolder = data.get('subfolder', '/')
|
||||
filename = data.get('filename', '')
|
||||
|
||||
+8
-4
@@ -274,8 +274,10 @@ async def api_scan_folder(request):
|
||||
|
||||
try:
|
||||
data = await request.json()
|
||||
except Exception:
|
||||
data = {}
|
||||
except ValueError:
|
||||
data = None
|
||||
if not isinstance(data, dict):
|
||||
return web.json_response({"status": "error", "message": "Invalid request body"}, status=400)
|
||||
|
||||
offline_only = data.get("offline_only", False)
|
||||
skip_rename = data.get("skip_rename", False)
|
||||
@@ -361,8 +363,10 @@ async def api_scan_all(request):
|
||||
|
||||
try:
|
||||
data = await request.json()
|
||||
except Exception:
|
||||
data = {}
|
||||
except ValueError:
|
||||
data = None
|
||||
if not isinstance(data, dict):
|
||||
return web.json_response({"status": "error", "message": "Invalid request body"}, status=400)
|
||||
|
||||
offline_only = data.get("offline_only", False)
|
||||
use_local_metadata = data.get("use_local_metadata", True)
|
||||
|
||||
@@ -73,7 +73,12 @@ def _translate_with_mymemory(text, tl):
|
||||
async def api_translate(request):
|
||||
try:
|
||||
data = await request.json()
|
||||
text = str(data.get("text", "")).strip()
|
||||
except ValueError:
|
||||
data = None
|
||||
if not isinstance(data, dict):
|
||||
return web.json_response({"status": "error", "message": "Invalid request body"}, status=400)
|
||||
text = str(data.get("text", "")).strip()
|
||||
try:
|
||||
tl = str(data.get("target_lang", "zh-CN")).strip()
|
||||
if not text:
|
||||
return web.json_response({"translated": "", "status": "success"})
|
||||
|
||||
+4
-1
@@ -230,6 +230,9 @@ def main():
|
||||
parser.add_argument("--folder-type", default="", help="由 ComfyUI 传入的模型目录类型,用于执行安全策略")
|
||||
parser.add_argument("--progress-file", default="", help=argparse.SUPPRESS)
|
||||
args = parser.parse_args()
|
||||
if args.offline_only:
|
||||
# Offline means no network at all: previews and model pages come from Civitai.
|
||||
args.skip_media = True
|
||||
|
||||
target_folder = args.folder
|
||||
if not os.path.isdir(target_folder):
|
||||
@@ -396,7 +399,7 @@ def main():
|
||||
|
||||
# --- 额外获取模型主页的说明文字 ---
|
||||
model_id = civitai_data.get("modelId")
|
||||
if model_id and model_id != -1:
|
||||
if model_id and model_id != -1 and not args.offline_only:
|
||||
try:
|
||||
headers = {
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ try {
|
||||
} catch (_) {}
|
||||
|
||||
import { app } from "../../scripts/app.js";
|
||||
import { createBrowserEntry } from "./modules/browser_entry.js?v=20260927-hotfix-1";
|
||||
import { createBrowserEntry } from "./modules/browser_entry.js?v=20260929-hotfix-1";
|
||||
import { createInterfaceSettings, getCurrentLanguage, setAbyssalScarletTheme, t } from "./modules/interface_settings.js";
|
||||
|
||||
export { setAbyssalScarletTheme };
|
||||
|
||||
@@ -218,11 +218,7 @@ export const i18n = {
|
||||
recipeScopePill_partial: "局部子图",
|
||||
recipeViewGrid: "网格视图",
|
||||
recipeViewList: "列表视图",
|
||||
recipeDragHint: "按住拖拽至画布打开新工作流",
|
||||
recipeDragTargetCanvas: "释放以在画布打开新工作流",
|
||||
recipeStatusReady: "模型全部就绪",
|
||||
recipeStatusUnverified: "模型待校验",
|
||||
recipeStatusMissing: "模型缺失",
|
||||
recipeReadinessHint: "检测工作流所需模型在本地环境中的就绪状态,点击卡片进入详情可进行智能比对与替换",
|
||||
promptEnablePart: "启用这个片段",
|
||||
promptUnnamedPart: "未命名片段",
|
||||
@@ -262,21 +258,9 @@ export const i18n = {
|
||||
notebookCompanionModels: "配套模型",
|
||||
notebookMore: "更多",
|
||||
notebookDoneEditing: "📑 查看双语分词",
|
||||
editRaw: "✏️ 编辑原始文本",
|
||||
saveNotebook: "保存笔记",
|
||||
deleteNotebook: "删除笔记",
|
||||
delSure: "确认删除?",
|
||||
sendToCanvas: "发送到画布",
|
||||
createNotebook: "新建笔记",
|
||||
newNotebookName: "新笔记名称...",
|
||||
recipeSearchAndReplace: "词条替换与目标语言",
|
||||
findPlaceholder: "查找...",
|
||||
replacePlaceholder: "替换为...",
|
||||
replaceAll: "全部替换",
|
||||
recipeDiffNone: "未选择",
|
||||
loras: "LoRA 模型",
|
||||
baseModel: "底模",
|
||||
mainModel: "主模型",
|
||||
nbNavHeading: "快速直达",
|
||||
nbNotesHeading: "我的笔记",
|
||||
nbNavModels: "配套模型",
|
||||
@@ -1529,11 +1513,7 @@ export const i18n = {
|
||||
recipeScopePill_partial: "Sub-graph",
|
||||
recipeViewGrid: "Grid View",
|
||||
recipeViewList: "List View",
|
||||
recipeDragHint: "Hold & drag onto canvas to load workflow",
|
||||
recipeDragTargetCanvas: "Drop to load workflow in canvas",
|
||||
recipeStatusReady: "All Models Ready",
|
||||
recipeStatusUnverified: "Models to Verify",
|
||||
recipeStatusMissing: "Models Missing",
|
||||
recipeReadinessHint: "Detects readiness of required models in local environment; click card details for smart matching and replacement",
|
||||
promptEnablePart: "Enable this fragment",
|
||||
promptUnnamedPart: "Untitled fragment",
|
||||
@@ -1573,21 +1553,9 @@ export const i18n = {
|
||||
notebookCompanionModels: "Companion models",
|
||||
notebookMore: "More",
|
||||
notebookDoneEditing: "📑 View Bilingual Tags",
|
||||
editRaw: "✏️ Edit Raw Prompt",
|
||||
saveNotebook: "Save Note",
|
||||
deleteNotebook: "Delete Note",
|
||||
delSure: "Confirm Delete?",
|
||||
sendToCanvas: "Send to Canvas",
|
||||
createNotebook: "New Note",
|
||||
newNotebookName: "New note name...",
|
||||
recipeSearchAndReplace: "Find, Replace & Language",
|
||||
findPlaceholder: "Find...",
|
||||
replacePlaceholder: "Replace with...",
|
||||
replaceAll: "Replace All",
|
||||
recipeDiffNone: "None",
|
||||
loras: "LoRA Models",
|
||||
baseModel: "Base Model",
|
||||
mainModel: "Main Model",
|
||||
nbNavHeading: "Quick Jump",
|
||||
nbNotesHeading: "My Notes",
|
||||
nbNavModels: "Companion Models",
|
||||
|
||||
@@ -1,19 +1,11 @@
|
||||
import { applyNodeMaterialValues } from './node_material_actions.js';
|
||||
import { applyMaterialToSelectedNode } from './ui_material_application.js';
|
||||
import { app } from "../../../scripts/app.js";
|
||||
import { translate } from './locales.js';
|
||||
import { escapeHtml } from './safe_dom.js';
|
||||
import {
|
||||
analyzeModelChainInsertion,
|
||||
getModelChainInsertionCapabilities,
|
||||
spliceModelChainNode,
|
||||
} from './graph_splice.js';
|
||||
import {
|
||||
collectMainModelContextRequests,
|
||||
formatModelTypeLabel,
|
||||
getBaseModelFamily,
|
||||
inferPickerModelType,
|
||||
} from './model_picker.js';
|
||||
import { inferPickerModelType } from './model_picker.js';
|
||||
import { requiresHashForModelRecovery } from './model_policies.js';
|
||||
import { findModelComboWidget, getNativeWidgetValues } from './ui_node_model_picker.js';
|
||||
import { renderParameterPresets } from './ui_node_presets.js';
|
||||
|
||||
@@ -789,5 +789,6 @@ export function createPromptSourceDeck(workbenchGrid, drawer, scope, addSourceCa
|
||||
refresh: renderSourceCardsList,
|
||||
sync: syncMaterialsIntoSourceDeck,
|
||||
hidePreview: (force = false) => hideCardPreviewPopover(force),
|
||||
focusSearch: () => leftSearch.focus(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -704,7 +704,7 @@ export function createPromptWorkbench(owner, container, scope, options) {
|
||||
`;
|
||||
setupDropzoneListeners(snapDock);
|
||||
snapDock.onclick = () => {
|
||||
leftSearch?.focus?.();
|
||||
sourceDeck.focusSearch();
|
||||
showWorkbenchToast(window.anomalous_browser_lang === 'zh' ? '点击左侧词卡即可直接加入此处' : 'Click any card on left to add here');
|
||||
};
|
||||
}
|
||||
|
||||
@@ -533,12 +533,14 @@ export function openScanWizard({ isGlobal = false, targetFiles = null } = {}) {
|
||||
// Execute Scan Logic
|
||||
const doScan = async () => {
|
||||
try {
|
||||
// Offline greys out renaming and overwriting, so none of them may be sent.
|
||||
const offline = scanMode === 'offline';
|
||||
const reqBody = {
|
||||
offline_only: scanMode === 'offline',
|
||||
skip_rename: !enableRename,
|
||||
virtual_rename: enableRename ? enableVirtualRename : false,
|
||||
physical_rename: enableRename ? enablePhysicalRename : false,
|
||||
force_overwrite: enableForceOverwrite
|
||||
offline_only: offline,
|
||||
skip_rename: offline || !enableRename,
|
||||
virtual_rename: !offline && enableRename && enableVirtualRename,
|
||||
physical_rename: !offline && enableRename && enablePhysicalRename,
|
||||
force_overwrite: !offline && enableForceOverwrite
|
||||
};
|
||||
|
||||
if (targetMode === 'custom') {
|
||||
|
||||
Reference in New Issue
Block a user