mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-23 22:22:11 -03:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6d8408e626 | ||
|
|
0906271aa9 | ||
|
|
4c33c9d256 | ||
|
|
fa9c78209f | ||
|
|
6678ec8a60 | ||
|
|
854e467c12 | ||
|
|
e6b94c7b21 | ||
|
|
2c6f9d8602 | ||
|
|
c74033b9c0 | ||
|
|
d2b21d27bb | ||
|
|
215272469f | ||
|
|
f7d05ab0f1 | ||
|
|
6f2ad2be77 |
@@ -34,6 +34,14 @@ Enhance your Civitai browsing experience with our companion browser extension! S
|
|||||||
|
|
||||||
## Release Notes
|
## Release Notes
|
||||||
|
|
||||||
|
### v0.8.26
|
||||||
|
* **Creator Search Option**
|
||||||
|
- Added ability to search models by creator name, making it easier to find models from specific authors.
|
||||||
|
* **Enhanced Node Usability**
|
||||||
|
- Improved user experience for Lora Loader, Lora Stacker, and WanVideo Lora Select nodes by fixing the maximum height of the text input area. Users can now freely and conveniently adjust the LoRA region within these nodes.
|
||||||
|
* **Compatibility Fixes**
|
||||||
|
- Resolved compatibility issues with ComfyUI and certain custom nodes, including ComfyUI-Custom-Scripts, ensuring smoother integration and operation.
|
||||||
|
|
||||||
### v0.8.25
|
### v0.8.25
|
||||||
* **LoRA List Reordering**
|
* **LoRA List Reordering**
|
||||||
- Drag & Drop: Easily rearrange LoRA entries using the drag handle.
|
- Drag & Drop: Easily rearrange LoRA entries using the drag handle.
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import asyncio
|
|
||||||
import re
|
import re
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import folder_paths # type: ignore
|
import folder_paths # type: ignore
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class BaseModelRoutes(ABC):
|
|||||||
prefix: URL prefix (e.g., 'loras', 'checkpoints')
|
prefix: URL prefix (e.g., 'loras', 'checkpoints')
|
||||||
"""
|
"""
|
||||||
# Common model management routes
|
# Common model management routes
|
||||||
app.router.add_get(f'/api/{prefix}', self.get_models)
|
app.router.add_get(f'/api/{prefix}/list', self.get_models)
|
||||||
app.router.add_post(f'/api/{prefix}/delete', self.delete_model)
|
app.router.add_post(f'/api/{prefix}/delete', self.delete_model)
|
||||||
app.router.add_post(f'/api/{prefix}/exclude', self.exclude_model)
|
app.router.add_post(f'/api/{prefix}/exclude', self.exclude_model)
|
||||||
app.router.add_post(f'/api/{prefix}/fetch-civitai', self.fetch_civitai)
|
app.router.add_post(f'/api/{prefix}/fetch-civitai', self.fetch_civitai)
|
||||||
@@ -177,6 +177,7 @@ class BaseModelRoutes(ABC):
|
|||||||
'filename': request.query.get('search_filename', 'true').lower() == 'true',
|
'filename': request.query.get('search_filename', 'true').lower() == 'true',
|
||||||
'modelname': request.query.get('search_modelname', 'true').lower() == 'true',
|
'modelname': request.query.get('search_modelname', 'true').lower() == 'true',
|
||||||
'tags': request.query.get('search_tags', 'false').lower() == 'true',
|
'tags': request.query.get('search_tags', 'false').lower() == 'true',
|
||||||
|
'creator': request.query.get('search_creator', 'false').lower() == 'true',
|
||||||
'recursive': request.query.get('recursive', 'false').lower() == 'true',
|
'recursive': request.query.get('recursive', 'false').lower() == 'true',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import os
|
import os
|
||||||
import subprocess
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
import logging
|
import logging
|
||||||
import toml
|
import toml
|
||||||
@@ -7,7 +6,6 @@ import git
|
|||||||
import zipfile
|
import zipfile
|
||||||
import shutil
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
from datetime import datetime
|
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
from typing import Dict, List
|
from typing import Dict, List
|
||||||
|
|
||||||
|
|||||||
@@ -199,6 +199,22 @@ class BaseModelService(ABC):
|
|||||||
for tag in item['tags']):
|
for tag in item['tags']):
|
||||||
search_results.append(item)
|
search_results.append(item)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# Search by creator
|
||||||
|
civitai = item.get('civitai')
|
||||||
|
creator_username = ''
|
||||||
|
if civitai and isinstance(civitai, dict):
|
||||||
|
creator = civitai.get('creator')
|
||||||
|
if creator and isinstance(creator, dict):
|
||||||
|
creator_username = creator.get('username', '')
|
||||||
|
if search_options.get('creator', False) and creator_username:
|
||||||
|
if fuzzy_search:
|
||||||
|
if fuzzy_match(creator_username, search):
|
||||||
|
search_results.append(item)
|
||||||
|
continue
|
||||||
|
elif search.lower() in creator_username.lower():
|
||||||
|
search_results.append(item)
|
||||||
|
continue
|
||||||
|
|
||||||
return search_results
|
return search_results
|
||||||
|
|
||||||
|
|||||||
@@ -199,8 +199,6 @@ class ModelHashIndex:
|
|||||||
|
|
||||||
def get_hash_by_filename(self, filename: str) -> Optional[str]:
|
def get_hash_by_filename(self, filename: str) -> Optional[str]:
|
||||||
"""Get hash for a filename without extension"""
|
"""Get hash for a filename without extension"""
|
||||||
# Strip extension if present to make the function more flexible
|
|
||||||
filename = os.path.splitext(filename)[0]
|
|
||||||
return self._filename_to_hash.get(filename)
|
return self._filename_to_hash.get(filename)
|
||||||
|
|
||||||
def clear(self) -> None:
|
def clear(self) -> None:
|
||||||
|
|||||||
@@ -50,7 +50,8 @@ VALID_LORA_TYPES = ['lora', 'locon', 'dora']
|
|||||||
|
|
||||||
# Civitai model tags in priority order for subfolder organization
|
# Civitai model tags in priority order for subfolder organization
|
||||||
CIVITAI_MODEL_TAGS = [
|
CIVITAI_MODEL_TAGS = [
|
||||||
'character', 'style', 'concept', 'clothing', 'base model',
|
'character', 'style', 'concept', 'clothing',
|
||||||
|
# 'base model', # exclude 'base model'
|
||||||
'poses', 'background', 'tool', 'vehicle', 'buildings',
|
'poses', 'background', 'tool', 'vehicle', 'buildings',
|
||||||
'objects', 'assets', 'animal', 'action'
|
'objects', 'assets', 'animal', 'action'
|
||||||
]
|
]
|
||||||
@@ -91,7 +91,7 @@ class DownloadManager:
|
|||||||
with open(progress_file, 'r', encoding='utf-8') as f:
|
with open(progress_file, 'r', encoding='utf-8') as f:
|
||||||
saved_progress = json.load(f)
|
saved_progress = json.load(f)
|
||||||
download_progress['processed_models'] = set(saved_progress.get('processed_models', []))
|
download_progress['processed_models'] = set(saved_progress.get('processed_models', []))
|
||||||
logger.info(f"Loaded previous progress, {len(download_progress['processed_models'])} models already processed")
|
logger.debug(f"Loaded previous progress, {len(download_progress['processed_models'])} models already processed")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to load progress file: {e}")
|
logger.error(f"Failed to load progress file: {e}")
|
||||||
download_progress['processed_models'] = set()
|
download_progress['processed_models'] = set()
|
||||||
@@ -230,7 +230,7 @@ class DownloadManager:
|
|||||||
|
|
||||||
# Update total count
|
# Update total count
|
||||||
download_progress['total'] = len(all_models)
|
download_progress['total'] = len(all_models)
|
||||||
logger.info(f"Found {download_progress['total']} models to process")
|
logger.debug(f"Found {download_progress['total']} models to process")
|
||||||
|
|
||||||
# Process each model
|
# Process each model
|
||||||
for i, (scanner_type, model, scanner) in enumerate(all_models):
|
for i, (scanner_type, model, scanner) in enumerate(all_models):
|
||||||
@@ -250,7 +250,7 @@ class DownloadManager:
|
|||||||
# Mark as completed
|
# Mark as completed
|
||||||
download_progress['status'] = 'completed'
|
download_progress['status'] = 'completed'
|
||||||
download_progress['end_time'] = time.time()
|
download_progress['end_time'] = time.time()
|
||||||
logger.info(f"Example images download completed: {download_progress['completed']}/{download_progress['total']} models processed")
|
logger.debug(f"Example images download completed: {download_progress['completed']}/{download_progress['total']} models processed")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
error_msg = f"Error during example images download: {str(e)}"
|
error_msg = f"Error during example images download: {str(e)}"
|
||||||
@@ -307,7 +307,7 @@ class DownloadManager:
|
|||||||
logger.debug(f"Skipping already processed model: {model_name}")
|
logger.debug(f"Skipping already processed model: {model_name}")
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
logger.info(f"Model {model_name} marked as processed but folder empty or missing, reprocessing")
|
logger.debug(f"Model {model_name} marked as processed but folder empty or missing, reprocessing")
|
||||||
|
|
||||||
# Create model directory
|
# Create model directory
|
||||||
model_dir = os.path.join(output_dir, model_hash)
|
model_dir = os.path.join(output_dir, model_hash)
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ def get_lora_info(lora_name):
|
|||||||
# No event loop is running, we can use asyncio.run()
|
# No event loop is running, we can use asyncio.run()
|
||||||
return asyncio.run(_get_lora_info_async())
|
return asyncio.run(_get_lora_info_async())
|
||||||
|
|
||||||
def fuzzy_match(text: str, pattern: str, threshold: float = 0.7) -> bool:
|
def fuzzy_match(text: str, pattern: str, threshold: float = 0.85) -> bool:
|
||||||
"""
|
"""
|
||||||
Check if text matches pattern using fuzzy matching.
|
Check if text matches pattern using fuzzy matching.
|
||||||
Returns True if similarity ratio is above threshold.
|
Returns True if similarity ratio is above threshold.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "comfyui-lora-manager"
|
name = "comfyui-lora-manager"
|
||||||
description = "Revolutionize your workflow with the ultimate LoRA companion for ComfyUI!"
|
description = "Revolutionize your workflow with the ultimate LoRA companion for ComfyUI!"
|
||||||
version = "0.8.25"
|
version = "0.8.26"
|
||||||
license = {file = "LICENSE"}
|
license = {file = "LICENSE"}
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aiohttp",
|
"aiohttp",
|
||||||
|
|||||||
@@ -7,5 +7,4 @@ olefile
|
|||||||
toml
|
toml
|
||||||
numpy
|
numpy
|
||||||
natsort
|
natsort
|
||||||
pyyaml
|
|
||||||
GitPython
|
GitPython
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ export function getApiEndpoints(modelType) {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
// Base CRUD operations
|
// Base CRUD operations
|
||||||
list: `/api/${modelType}`,
|
list: `/api/${modelType}/list`,
|
||||||
delete: `/api/${modelType}/delete`,
|
delete: `/api/${modelType}/delete`,
|
||||||
exclude: `/api/${modelType}/exclude`,
|
exclude: `/api/${modelType}/exclude`,
|
||||||
rename: `/api/${modelType}/rename`,
|
rename: `/api/${modelType}/rename`,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
DOWNLOAD_ENDPOINTS,
|
DOWNLOAD_ENDPOINTS,
|
||||||
WS_ENDPOINTS
|
WS_ENDPOINTS
|
||||||
} from './apiConfig.js';
|
} from './apiConfig.js';
|
||||||
import { createModelApiClient } from './modelApiFactory.js';
|
import { resetAndReload } from './modelApiFactory.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract base class for all model API clients
|
* Abstract base class for all model API clients
|
||||||
@@ -91,10 +91,7 @@ export class BaseModelApiClient {
|
|||||||
pageState.currentPage = 1; // Reset to first page
|
pageState.currentPage = 1; // Reset to first page
|
||||||
}
|
}
|
||||||
|
|
||||||
const startTime = performance.now();
|
|
||||||
const result = await this.fetchModelsPage(pageState.currentPage, pageState.pageSize);
|
const result = await this.fetchModelsPage(pageState.currentPage, pageState.pageSize);
|
||||||
const endTime = performance.now();
|
|
||||||
console.log(`fetchModelsPage耗时: ${(endTime - startTime).toFixed(2)} ms`);
|
|
||||||
|
|
||||||
state.virtualScroller.refreshWithData(
|
state.virtualScroller.refreshWithData(
|
||||||
result.items,
|
result.items,
|
||||||
@@ -105,8 +102,16 @@ export class BaseModelApiClient {
|
|||||||
pageState.hasMore = result.hasMore;
|
pageState.hasMore = result.hasMore;
|
||||||
pageState.currentPage = pageState.currentPage + 1;
|
pageState.currentPage = pageState.currentPage + 1;
|
||||||
|
|
||||||
if (updateFolders && result.folders) {
|
if (updateFolders) {
|
||||||
updateFolderTags(result.folders);
|
const response = await fetch(this.apiConfig.endpoints.folders);
|
||||||
|
if (response.ok) {
|
||||||
|
const data = await response.json();
|
||||||
|
updateFolderTags(data.folders);
|
||||||
|
} else {
|
||||||
|
const errorData = await response.json().catch(() => ({}));
|
||||||
|
const errorMsg = errorData && errorData.error ? errorData.error : response.statusText;
|
||||||
|
console.error(`Error getting folders: ${errorMsg}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -321,6 +326,8 @@ export class BaseModelApiClient {
|
|||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`Failed to refresh ${this.apiConfig.config.displayName}s: ${response.status} ${response.statusText}`);
|
throw new Error(`Failed to refresh ${this.apiConfig.config.displayName}s: ${response.status} ${response.statusText}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resetAndReload(true);
|
||||||
|
|
||||||
showToast(`${fullRebuild ? 'Full rebuild' : 'Refresh'} complete`, 'success');
|
showToast(`${fullRebuild ? 'Full rebuild' : 'Refresh'} complete`, 'success');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -629,6 +636,9 @@ export class BaseModelApiClient {
|
|||||||
if (pageState.searchOptions.tags !== undefined) {
|
if (pageState.searchOptions.tags !== undefined) {
|
||||||
params.append('search_tags', pageState.searchOptions.tags.toString());
|
params.append('search_tags', pageState.searchOptions.tags.toString());
|
||||||
}
|
}
|
||||||
|
if (pageState.searchOptions.creator !== undefined) {
|
||||||
|
params.append('search_creator', pageState.searchOptions.creator.toString());
|
||||||
|
}
|
||||||
params.append('recursive', (pageState.searchOptions?.recursive ?? false).toString());
|
params.append('recursive', (pageState.searchOptions?.recursive ?? false).toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,9 @@ export class HeaderManager {
|
|||||||
this.filterManager = null;
|
this.filterManager = null;
|
||||||
|
|
||||||
// Initialize appropriate managers based on current page
|
// Initialize appropriate managers based on current page
|
||||||
this.initializeManagers();
|
if (this.currentPage !== 'statistics') {
|
||||||
|
this.initializeManagers();
|
||||||
|
}
|
||||||
|
|
||||||
// Set up common header functionality
|
// Set up common header functionality
|
||||||
this.initializeCommonElements();
|
this.initializeCommonElements();
|
||||||
@@ -37,11 +39,8 @@ export class HeaderManager {
|
|||||||
this.searchManager = new SearchManager({ page: this.currentPage });
|
this.searchManager = new SearchManager({ page: this.currentPage });
|
||||||
window.searchManager = this.searchManager;
|
window.searchManager = this.searchManager;
|
||||||
|
|
||||||
// Initialize FilterManager for all page types that have filters
|
this.filterManager = new FilterManager({ page: this.currentPage });
|
||||||
if (document.getElementById('filterButton')) {
|
window.filterManager = this.filterManager;
|
||||||
this.filterManager = new FilterManager({ page: this.currentPage });
|
|
||||||
window.filterManager = this.filterManager;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
initializeCommonElements() {
|
initializeCommonElements() {
|
||||||
|
|||||||
@@ -241,7 +241,7 @@ function showModelModalFromCard(card, modelType) {
|
|||||||
tags: JSON.parse(card.dataset.tags || '[]'),
|
tags: JSON.parse(card.dataset.tags || '[]'),
|
||||||
modelDescription: card.dataset.modelDescription || '',
|
modelDescription: card.dataset.modelDescription || '',
|
||||||
// LoRA specific fields
|
// LoRA specific fields
|
||||||
...(modelType === 'lora' && {
|
...(modelType === MODEL_TYPES.LORA && {
|
||||||
usage_tips: card.dataset.usage_tips,
|
usage_tips: card.dataset.usage_tips,
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -297,7 +297,10 @@ export class DownloadManager {
|
|||||||
// Set default root if available
|
// Set default root if available
|
||||||
const defaultRootKey = `default_${this.apiClient.modelType}_root`;
|
const defaultRootKey = `default_${this.apiClient.modelType}_root`;
|
||||||
const defaultRoot = getStorageItem('settings', {})[defaultRootKey];
|
const defaultRoot = getStorageItem('settings', {})[defaultRootKey];
|
||||||
|
console.log(`Default root for ${this.apiClient.modelType}:`, defaultRoot);
|
||||||
|
console.log('Available roots:', rootsData.roots);
|
||||||
if (defaultRoot && rootsData.roots.includes(defaultRoot)) {
|
if (defaultRoot && rootsData.roots.includes(defaultRoot)) {
|
||||||
|
console.log(`Setting default root: ${defaultRoot}`);
|
||||||
modelRoot.value = defaultRoot;
|
modelRoot.value = defaultRoot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -763,22 +763,7 @@ class ExampleImagesManager {
|
|||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
||||||
if (data.success) {
|
if (!data.success) {
|
||||||
// Only show progress if there are actually items to download
|
|
||||||
if (data.status && data.status.total > 0) {
|
|
||||||
this.isDownloading = true;
|
|
||||||
this.isPaused = false;
|
|
||||||
this.hasShownCompletionToast = false;
|
|
||||||
this.startTime = new Date();
|
|
||||||
this.updateUI(data.status);
|
|
||||||
this.showProgressPanel();
|
|
||||||
this.startProgressUpdates();
|
|
||||||
this.updateDownloadButtonText();
|
|
||||||
console.log(`Auto download started: ${data.status.total} items to process`);
|
|
||||||
} else {
|
|
||||||
console.log('Auto download check completed - no new items to download');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console.warn('Auto download check failed:', data.error);
|
console.warn('Auto download check failed:', data.error);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -318,6 +318,7 @@ export class SearchManager {
|
|||||||
filename: options.filename || false,
|
filename: options.filename || false,
|
||||||
modelname: options.modelname || false,
|
modelname: options.modelname || false,
|
||||||
tags: options.tags || false,
|
tags: options.tags || false,
|
||||||
|
creator: options.creator || false,
|
||||||
recursive: recursive
|
recursive: recursive
|
||||||
};
|
};
|
||||||
} else if (this.currentPage === 'checkpoints') {
|
} else if (this.currentPage === 'checkpoints') {
|
||||||
@@ -325,6 +326,7 @@ export class SearchManager {
|
|||||||
filename: options.filename || false,
|
filename: options.filename || false,
|
||||||
modelname: options.modelname || false,
|
modelname: options.modelname || false,
|
||||||
tags: options.tags || false,
|
tags: options.tags || false,
|
||||||
|
creator: options.creator || false,
|
||||||
recursive: recursive
|
recursive: recursive
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ export const state = {
|
|||||||
filename: true,
|
filename: true,
|
||||||
modelname: true,
|
modelname: true,
|
||||||
tags: false,
|
tags: false,
|
||||||
|
creator: false,
|
||||||
recursive: false
|
recursive: false
|
||||||
},
|
},
|
||||||
filters: {
|
filters: {
|
||||||
@@ -83,6 +84,7 @@ export const state = {
|
|||||||
searchOptions: {
|
searchOptions: {
|
||||||
filename: true,
|
filename: true,
|
||||||
modelname: true,
|
modelname: true,
|
||||||
|
creator: false,
|
||||||
recursive: false
|
recursive: false
|
||||||
},
|
},
|
||||||
filters: {
|
filters: {
|
||||||
@@ -110,6 +112,7 @@ export const state = {
|
|||||||
filename: true,
|
filename: true,
|
||||||
modelname: true,
|
modelname: true,
|
||||||
tags: false,
|
tags: false,
|
||||||
|
creator: false,
|
||||||
recursive: false
|
recursive: false
|
||||||
},
|
},
|
||||||
filters: {
|
filters: {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
{% block init_title %}Initializing Checkpoints Manager{% endblock %}
|
{% block init_title %}Initializing Checkpoints Manager{% endblock %}
|
||||||
{% block init_message %}Scanning and building checkpoints cache. This may take a few moments...{% endblock %}
|
{% block init_message %}Scanning and building checkpoints cache. This may take a few moments...{% endblock %}
|
||||||
{% block init_check_url %}/api/checkpoints?page=1&page_size=1{% endblock %}
|
{% block init_check_url %}/api/checkpoints/list?page=1&page_size=1{% endblock %}
|
||||||
|
|
||||||
{% block additional_components %}
|
{% block additional_components %}
|
||||||
|
|
||||||
|
|||||||
@@ -86,15 +86,18 @@
|
|||||||
<div class="search-option-tag active" data-option="filename">Filename</div>
|
<div class="search-option-tag active" data-option="filename">Filename</div>
|
||||||
<div class="search-option-tag active" data-option="modelname">Checkpoint Name</div>
|
<div class="search-option-tag active" data-option="modelname">Checkpoint Name</div>
|
||||||
<div class="search-option-tag active" data-option="tags">Tags</div>
|
<div class="search-option-tag active" data-option="tags">Tags</div>
|
||||||
|
<div class="search-option-tag" data-option="creator">Creator</div>
|
||||||
{% elif request.path == '/embeddings' %}
|
{% elif request.path == '/embeddings' %}
|
||||||
<div class="search-option-tag active" data-option="filename">Filename</div>
|
<div class="search-option-tag active" data-option="filename">Filename</div>
|
||||||
<div class="search-option-tag active" data-option="modelname">Embedding Name</div>
|
<div class="search-option-tag active" data-option="modelname">Embedding Name</div>
|
||||||
<div class="search-option-tag active" data-option="tags">Tags</div>
|
<div class="search-option-tag active" data-option="tags">Tags</div>
|
||||||
|
<div class="search-option-tag" data-option="creator">Creator</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<!-- Default options for LoRAs page -->
|
<!-- Default options for LoRAs page -->
|
||||||
<div class="search-option-tag active" data-option="filename">Filename</div>
|
<div class="search-option-tag active" data-option="filename">Filename</div>
|
||||||
<div class="search-option-tag active" data-option="modelname">Model Name</div>
|
<div class="search-option-tag active" data-option="modelname">Model Name</div>
|
||||||
<div class="search-option-tag active" data-option="tags">Tags</div>
|
<div class="search-option-tag active" data-option="tags">Tags</div>
|
||||||
|
<div class="search-option-tag" data-option="creator">Creator</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
{% block init_title %}Initializing Embeddings Manager{% endblock %}
|
{% block init_title %}Initializing Embeddings Manager{% endblock %}
|
||||||
{% block init_message %}Scanning and building embeddings cache. This may take a few moments...{% endblock %}
|
{% block init_message %}Scanning and building embeddings cache. This may take a few moments...{% endblock %}
|
||||||
{% block init_check_url %}/api/embeddings?page=1&page_size=1{% endblock %}
|
{% block init_check_url %}/api/embeddings/list?page=1&page_size=1{% endblock %}
|
||||||
|
|
||||||
{% block additional_components %}
|
{% block additional_components %}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
{% block init_title %}Initializing LoRA Manager{% endblock %}
|
{% block init_title %}Initializing LoRA Manager{% endblock %}
|
||||||
{% block init_message %}Scanning and building LoRA cache. This may take a few minutes...{% endblock %}
|
{% block init_message %}Scanning and building LoRA cache. This may take a few minutes...{% endblock %}
|
||||||
{% block init_check_url %}/api/loras?page=1&page_size=1{% endblock %}
|
{% block init_check_url %}/api/loras/list?page=1&page_size=1{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% include 'components/controls.html' %}
|
{% include 'components/controls.html' %}
|
||||||
|
|||||||
@@ -5,9 +5,6 @@ export function addJsonDisplayWidget(node, name, opts) {
|
|||||||
|
|
||||||
// Set initial height
|
// Set initial height
|
||||||
const defaultHeight = 200;
|
const defaultHeight = 200;
|
||||||
container.style.setProperty('--comfy-widget-min-height', `${defaultHeight}px`);
|
|
||||||
container.style.setProperty('--comfy-widget-max-height', `${defaultHeight * 2}px`);
|
|
||||||
container.style.setProperty('--comfy-widget-height', `${defaultHeight}px`);
|
|
||||||
|
|
||||||
Object.assign(container.style, {
|
Object.assign(container.style, {
|
||||||
display: "block",
|
display: "block",
|
||||||
@@ -113,16 +110,6 @@ export function addJsonDisplayWidget(node, name, opts) {
|
|||||||
widgetValue = v;
|
widgetValue = v;
|
||||||
displayJson(widgetValue, widget);
|
displayJson(widgetValue, widget);
|
||||||
},
|
},
|
||||||
getMinHeight: function() {
|
|
||||||
return parseInt(container.style.getPropertyValue('--comfy-widget-min-height')) || defaultHeight;
|
|
||||||
},
|
|
||||||
getMaxHeight: function() {
|
|
||||||
return parseInt(container.style.getPropertyValue('--comfy-widget-max-height')) || defaultHeight * 2;
|
|
||||||
},
|
|
||||||
getHeight: function() {
|
|
||||||
// Return actual container height to reduce the gap
|
|
||||||
return parseInt(container.style.getPropertyValue('--comfy-widget-height')) || defaultHeight;
|
|
||||||
},
|
|
||||||
hideOnZoom: true
|
hideOnZoom: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -156,6 +156,7 @@ app.registerExtension({
|
|||||||
|
|
||||||
// Update input widget callback
|
// Update input widget callback
|
||||||
const inputWidget = this.widgets[0];
|
const inputWidget = this.widgets[0];
|
||||||
|
inputWidget.options.getMaxHeight = () => 100;
|
||||||
this.inputWidget = inputWidget;
|
this.inputWidget = inputWidget;
|
||||||
inputWidget.callback = (value) => {
|
inputWidget.callback = (value) => {
|
||||||
if (isUpdating) return;
|
if (isUpdating) return;
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ app.registerExtension({
|
|||||||
|
|
||||||
// Update input widget callback
|
// Update input widget callback
|
||||||
const inputWidget = this.widgets[0];
|
const inputWidget = this.widgets[0];
|
||||||
|
inputWidget.options.getMaxHeight = () => 100;
|
||||||
this.inputWidget = inputWidget;
|
this.inputWidget = inputWidget;
|
||||||
inputWidget.callback = (value) => {
|
inputWidget.callback = (value) => {
|
||||||
if (isUpdating) return;
|
if (isUpdating) return;
|
||||||
|
|||||||
@@ -19,9 +19,6 @@ export function addLorasWidget(node, name, opts, callback) {
|
|||||||
|
|
||||||
// Set initial height using CSS variables approach
|
// Set initial height using CSS variables approach
|
||||||
const defaultHeight = 200;
|
const defaultHeight = 200;
|
||||||
container.style.setProperty('--comfy-widget-min-height', `${defaultHeight}px`);
|
|
||||||
container.style.setProperty('--comfy-widget-max-height', `${defaultHeight * 2}px`);
|
|
||||||
container.style.setProperty('--comfy-widget-height', `${defaultHeight}px`);
|
|
||||||
|
|
||||||
Object.assign(container.style, {
|
Object.assign(container.style, {
|
||||||
display: "flex",
|
display: "flex",
|
||||||
@@ -712,23 +709,8 @@ export function addLorasWidget(node, name, opts, callback) {
|
|||||||
widgetValue = updatedValue;
|
widgetValue = updatedValue;
|
||||||
renderLoras(widgetValue, widget);
|
renderLoras(widgetValue, widget);
|
||||||
},
|
},
|
||||||
getMinHeight: function() {
|
|
||||||
return parseInt(container.style.getPropertyValue('--comfy-widget-min-height')) || defaultHeight;
|
|
||||||
},
|
|
||||||
getMaxHeight: function() {
|
|
||||||
return parseInt(container.style.getPropertyValue('--comfy-widget-max-height')) || defaultHeight * 2;
|
|
||||||
},
|
|
||||||
getHeight: function() {
|
|
||||||
return parseInt(container.style.getPropertyValue('--comfy-widget-height')) || defaultHeight;
|
|
||||||
},
|
|
||||||
hideOnZoom: true,
|
hideOnZoom: true,
|
||||||
selectOn: ['click', 'focus'],
|
selectOn: ['click', 'focus']
|
||||||
afterResize: function(node) {
|
|
||||||
// Re-render after node resize
|
|
||||||
if (this.value && this.value.length > 0) {
|
|
||||||
renderLoras(this.value, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
widget.value = defaultValue;
|
widget.value = defaultValue;
|
||||||
|
|||||||
@@ -5,9 +5,6 @@ export function addTagsWidget(node, name, opts, callback) {
|
|||||||
|
|
||||||
// Set initial height
|
// Set initial height
|
||||||
const defaultHeight = 150;
|
const defaultHeight = 150;
|
||||||
container.style.setProperty('--comfy-widget-min-height', `${defaultHeight}px`);
|
|
||||||
container.style.setProperty('--comfy-widget-max-height', `${defaultHeight * 2}px`);
|
|
||||||
container.style.setProperty('--comfy-widget-height', `${defaultHeight}px`);
|
|
||||||
|
|
||||||
Object.assign(container.style, {
|
Object.assign(container.style, {
|
||||||
display: "flex",
|
display: "flex",
|
||||||
@@ -199,23 +196,8 @@ export function addTagsWidget(node, name, opts, callback) {
|
|||||||
widgetValue = v;
|
widgetValue = v;
|
||||||
renderTags(widgetValue, widget);
|
renderTags(widgetValue, widget);
|
||||||
},
|
},
|
||||||
getMinHeight: function() {
|
|
||||||
return parseInt(container.style.getPropertyValue('--comfy-widget-min-height')) || defaultHeight;
|
|
||||||
},
|
|
||||||
getMaxHeight: function() {
|
|
||||||
return parseInt(container.style.getPropertyValue('--comfy-widget-max-height')) || defaultHeight * 2;
|
|
||||||
},
|
|
||||||
getHeight: function() {
|
|
||||||
return parseInt(container.style.getPropertyValue('--comfy-widget-height')) || defaultHeight;
|
|
||||||
},
|
|
||||||
hideOnZoom: true,
|
hideOnZoom: true,
|
||||||
selectOn: ['click', 'focus'],
|
selectOn: ['click', 'focus']
|
||||||
afterResize: function(node) {
|
|
||||||
// Re-render tags after node resize
|
|
||||||
if (this.value && this.value.length > 0) {
|
|
||||||
renderTags(this.value, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set initial value
|
// Set initial value
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ app.registerExtension({
|
|||||||
|
|
||||||
// Update input widget callback
|
// Update input widget callback
|
||||||
const inputWidget = this.widgets[1];
|
const inputWidget = this.widgets[1];
|
||||||
|
inputWidget.options.getMaxHeight = () => 100;
|
||||||
this.inputWidget = inputWidget;
|
this.inputWidget = inputWidget;
|
||||||
inputWidget.callback = (value) => {
|
inputWidget.callback = (value) => {
|
||||||
if (isUpdating) return;
|
if (isUpdating) return;
|
||||||
|
|||||||
Reference in New Issue
Block a user