feat: enrich model info dialog with location, size, tags, and trained words from metadata
This commit is contained in:
+16
-1
@@ -776,6 +776,7 @@ class ModelResolverExtension:
|
||||
|
||||
# Get the file path to hash
|
||||
file_path = resolved_path if resolved_path else None
|
||||
file_location = ""
|
||||
|
||||
if not file_path and category:
|
||||
# Try to find the file in the model directories using folder_paths
|
||||
@@ -854,16 +855,26 @@ class ModelResolverExtension:
|
||||
|
||||
# Search CivitAI for the model using hash
|
||||
if download_available and file_path and _os.path.exists(file_path):
|
||||
file_location = _os.path.dirname(file_path).replace("\\", "/")
|
||||
if file_location and not file_location.endswith("/"):
|
||||
file_location += "/"
|
||||
try:
|
||||
from .core.sources.civitai import (
|
||||
get_model_info_for_file,
|
||||
)
|
||||
|
||||
result = get_model_info_for_file(file_path)
|
||||
if result and result.get("url"):
|
||||
if result and (
|
||||
result.get("url")
|
||||
or result.get("version_url")
|
||||
or result.get("from_metadata")
|
||||
or result.get("trained_words")
|
||||
):
|
||||
return web.json_response(
|
||||
{
|
||||
"filename": filename,
|
||||
"location": result.get("location")
|
||||
or file_location,
|
||||
"url": result.get("url"),
|
||||
"version_url": result.get("version_url"),
|
||||
"model_id": result.get("model_id"),
|
||||
@@ -874,6 +885,7 @@ class ModelResolverExtension:
|
||||
"version_id": result.get("version_id"),
|
||||
"version_name": result.get("version_name", ""),
|
||||
"sha256": result.get("sha256"),
|
||||
"size": result.get("size"),
|
||||
"base_model": result.get("base_model"),
|
||||
"tags": result.get("tags", []),
|
||||
"trained_words": result.get(
|
||||
@@ -904,8 +916,11 @@ class ModelResolverExtension:
|
||||
return web.json_response(
|
||||
{
|
||||
"url": result["url"],
|
||||
"location": file_location,
|
||||
"model_name": result.get("name", clean_name),
|
||||
"version_id": result.get("version_id"),
|
||||
"size": result.get("size"),
|
||||
"tags": result.get("tags", []),
|
||||
}
|
||||
)
|
||||
except Exception as e:
|
||||
|
||||
+161
-16
@@ -1805,11 +1805,86 @@ def _read_model_metadata(metadata_path: str) -> Optional[Dict[str, Any]]:
|
||||
return None
|
||||
|
||||
|
||||
def _as_metadata_dict(value: Any) -> Dict[str, Any]:
|
||||
return value if isinstance(value, dict) else {}
|
||||
|
||||
|
||||
def _as_metadata_list(value: Any) -> List[Any]:
|
||||
if value is None:
|
||||
return []
|
||||
if isinstance(value, list):
|
||||
return value
|
||||
if isinstance(value, tuple):
|
||||
return list(value)
|
||||
return [value] if value else []
|
||||
|
||||
|
||||
def _first_metadata_value(*values: Any) -> Any:
|
||||
for value in values:
|
||||
if value is None:
|
||||
continue
|
||||
if isinstance(value, str) and not value.strip():
|
||||
continue
|
||||
if isinstance(value, (list, tuple, dict)) and not value:
|
||||
continue
|
||||
return value
|
||||
return None
|
||||
|
||||
|
||||
def _metadata_size_to_bytes(value: Any) -> Optional[int]:
|
||||
if value is None or value == "":
|
||||
return None
|
||||
|
||||
try:
|
||||
size = int(float(value))
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
|
||||
return size if size >= 0 else None
|
||||
|
||||
|
||||
def _format_model_location(file_path: str) -> str:
|
||||
if not file_path:
|
||||
return ""
|
||||
|
||||
location = os.path.dirname(file_path).replace("\\", "/")
|
||||
if location and not location.endswith("/"):
|
||||
location += "/"
|
||||
return location
|
||||
|
||||
|
||||
def _normalize_metadata_trained_words(*values: Any) -> List[str]:
|
||||
words: List[str] = []
|
||||
seen = set()
|
||||
|
||||
for value in values:
|
||||
for item in _as_metadata_list(value):
|
||||
if isinstance(item, dict):
|
||||
item = (
|
||||
item.get("word")
|
||||
or item.get("name")
|
||||
or item.get("text")
|
||||
or item.get("value")
|
||||
)
|
||||
text = str(item or "").strip()
|
||||
if not text:
|
||||
continue
|
||||
key = text.lower()
|
||||
if key in seen:
|
||||
continue
|
||||
seen.add(key)
|
||||
words.append(text)
|
||||
|
||||
return words
|
||||
|
||||
|
||||
def _metadata_to_model_info(metadata: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Convert metadata file format to model info format used by our extension.
|
||||
"""
|
||||
civitai_data = metadata.get("civitai") or {}
|
||||
civitai_data = _as_metadata_dict(metadata.get("civitai"))
|
||||
selected_version = _as_metadata_dict(metadata.get("selected_version"))
|
||||
path_metadata = _as_metadata_dict(metadata.get("path_metadata"))
|
||||
|
||||
# Extract images with metadata
|
||||
images = []
|
||||
@@ -1840,14 +1915,21 @@ def _metadata_to_model_info(metadata: Dict[str, Any]) -> Dict[str, Any]:
|
||||
}
|
||||
)
|
||||
|
||||
# Get trained words from CivitAI data
|
||||
trained_words = civitai_data.get("trainedWords") or []
|
||||
if isinstance(trained_words, str):
|
||||
trained_words = [trained_words] if trained_words else []
|
||||
# Get trained words from common sidecar shapes, including LoRA Manager metadata.
|
||||
trained_words = _normalize_metadata_trained_words(
|
||||
metadata.get("trained_words"),
|
||||
metadata.get("trainedWords"),
|
||||
civitai_data.get("trainedWords"),
|
||||
selected_version.get("trained_words"),
|
||||
selected_version.get("trainedWords"),
|
||||
path_metadata.get("trained_words"),
|
||||
path_metadata.get("trainedWords"),
|
||||
)
|
||||
|
||||
# Get model info
|
||||
model_info = civitai_data.get("model") or {}
|
||||
version_info = civitai_data
|
||||
model_info = _as_metadata_dict(civitai_data.get("model"))
|
||||
file_infos = _as_metadata_list(civitai_data.get("files"))
|
||||
file_info = _as_metadata_dict(file_infos[0]) if file_infos else {}
|
||||
|
||||
# Build model_id from CivitAI data
|
||||
model_id = civitai_data.get("modelId") or civitai_data.get("id")
|
||||
@@ -1855,11 +1937,38 @@ def _metadata_to_model_info(metadata: Dict[str, Any]) -> Dict[str, Any]:
|
||||
return {
|
||||
"source": "metadata",
|
||||
"model_id": model_id,
|
||||
"model_name": metadata.get("model_name") or metadata.get("file_name", ""),
|
||||
"model_name": _first_metadata_value(
|
||||
metadata.get("model_name"),
|
||||
metadata.get("modelName"),
|
||||
model_info.get("name"),
|
||||
metadata.get("file_name"),
|
||||
)
|
||||
or "",
|
||||
"model_type": model_info.get("type", "") or civitai_data.get("type", ""),
|
||||
"version_id": civitai_data.get("id"),
|
||||
"version_name": civitai_data.get("name", ""),
|
||||
"version_name": _first_metadata_value(
|
||||
metadata.get("version_name"),
|
||||
metadata.get("versionName"),
|
||||
selected_version.get("name"),
|
||||
civitai_data.get("name"),
|
||||
)
|
||||
or "",
|
||||
"sha256": metadata.get("sha256", ""),
|
||||
"size": _metadata_size_to_bytes(
|
||||
_first_metadata_value(
|
||||
metadata.get("size"),
|
||||
metadata.get("file_size"),
|
||||
metadata.get("fileSize"),
|
||||
metadata.get("sizeBytes"),
|
||||
path_metadata.get("size"),
|
||||
path_metadata.get("file_size"),
|
||||
path_metadata.get("fileSize"),
|
||||
path_metadata.get("sizeBytes"),
|
||||
(file_info.get("sizeKB") * 1024)
|
||||
if file_info.get("sizeKB") is not None
|
||||
else None,
|
||||
)
|
||||
),
|
||||
"url": f"https://civitai.com/models/{civitai_data.get('modelId')}"
|
||||
if civitai_data.get("modelId")
|
||||
else None,
|
||||
@@ -1867,14 +1976,32 @@ def _metadata_to_model_info(metadata: Dict[str, Any]) -> Dict[str, Any]:
|
||||
if model_id
|
||||
else None,
|
||||
"download_url": civitai_data.get("downloadUrl"),
|
||||
"base_model": (metadata.get("base_model") or civitai_data.get("baseModel", "")),
|
||||
"tags": metadata.get("tags") or [],
|
||||
"base_model": _first_metadata_value(
|
||||
metadata.get("base_model"),
|
||||
metadata.get("baseModel"),
|
||||
selected_version.get("base_model"),
|
||||
selected_version.get("baseModel"),
|
||||
civitai_data.get("baseModel"),
|
||||
)
|
||||
or "",
|
||||
"tags": _as_metadata_list(metadata.get("tags") or model_info.get("tags")),
|
||||
"trained_words": trained_words,
|
||||
"images": images,
|
||||
"clip_skip": civitai_data.get("clipSkip"),
|
||||
"description": metadata.get("model_description", "")
|
||||
or civitai_data.get("description", ""),
|
||||
"model_description": metadata.get("model_description", ""),
|
||||
"description": _first_metadata_value(
|
||||
metadata.get("modelDescription"),
|
||||
metadata.get("model_description"),
|
||||
metadata.get("description"),
|
||||
model_info.get("description"),
|
||||
civitai_data.get("description"),
|
||||
)
|
||||
or "",
|
||||
"model_description": _first_metadata_value(
|
||||
metadata.get("modelDescription"),
|
||||
metadata.get("model_description"),
|
||||
model_info.get("description"),
|
||||
)
|
||||
or "",
|
||||
"from_metadata": True,
|
||||
}
|
||||
|
||||
@@ -1903,7 +2030,15 @@ def get_model_info_for_file(
|
||||
metadata = _read_model_metadata(metadata_path)
|
||||
if metadata:
|
||||
log_info(f"Using metadata file for {file_path}")
|
||||
return _metadata_to_model_info(metadata)
|
||||
result = _metadata_to_model_info(metadata)
|
||||
result["file_path"] = file_path
|
||||
result["location"] = _format_model_location(file_path)
|
||||
if not result.get("size"):
|
||||
try:
|
||||
result["size"] = os.path.getsize(file_path)
|
||||
except Exception:
|
||||
pass
|
||||
return result
|
||||
else:
|
||||
# Debug: list all files in the same directory
|
||||
directory = os.path.dirname(file_path)
|
||||
@@ -1919,4 +2054,14 @@ def get_model_info_for_file(
|
||||
if not file_hash:
|
||||
return None
|
||||
|
||||
return get_model_info_by_hash(file_hash, api_key)
|
||||
result = get_model_info_by_hash(file_hash, api_key)
|
||||
if result:
|
||||
result["file_path"] = file_path
|
||||
result["location"] = _format_model_location(file_path)
|
||||
if not result.get("size"):
|
||||
try:
|
||||
result["size"] = os.path.getsize(file_path)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return result
|
||||
|
||||
@@ -3365,8 +3365,9 @@
|
||||
/* Info Area (type/base model tags) */
|
||||
.mr-info-area {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-bottom: 16px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.mr-info-tag {
|
||||
display: inline-flex;
|
||||
@@ -3386,6 +3387,37 @@
|
||||
.mr-info-tag.-basemodel-sdxl-turbo { background: rgba(33,150,243,0.2); color: #64B5F6; }
|
||||
.mr-info-tag.-basemodel-flux\.1 { background: rgba(255,152,0,0.2); color: #FFB74D; }
|
||||
.mr-info-tag.-basemodel-flux\.1-d { background: rgba(255,152,0,0.2); color: #FFB74D; }
|
||||
.mr-info-tags-row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
margin: 0 0 16px;
|
||||
}
|
||||
.mr-info-tags-label {
|
||||
flex: 0 0 auto;
|
||||
padding-top: 5px;
|
||||
color: var(--mr-text-muted, #888);
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.04em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.mr-info-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
min-width: 0;
|
||||
}
|
||||
.mr-info-model-tag {
|
||||
max-width: 180px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
border: 1px solid rgba(255,255,255,0.08);
|
||||
background: rgba(255,255,255,0.06);
|
||||
color: var(--mr-text-muted, #c8c8c8);
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
/* Info Table */
|
||||
.mr-info-table {
|
||||
@@ -3413,6 +3445,12 @@
|
||||
color: var(--input-text, #e0e0e0);
|
||||
word-break: break-word;
|
||||
}
|
||||
.mr-info-location {
|
||||
font-family: "Cascadia Mono", "Consolas", monospace;
|
||||
font-size: 12px;
|
||||
line-height: 1.45;
|
||||
word-break: break-all;
|
||||
}
|
||||
.mr-info-trained-words-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -300,12 +300,20 @@ export const modelInfoMethods = {
|
||||
<span class="mr-info-tag mr-info-type"></span>
|
||||
<span class="mr-info-tag mr-info-basemodel"></span>
|
||||
</div>
|
||||
<div class="mr-info-tags-row mr-hidden-initial">
|
||||
<span class="mr-info-tags-label">Tags</span>
|
||||
<div class="mr-info-tags"></div>
|
||||
</div>
|
||||
<table class="mr-info-table">
|
||||
<tbody>
|
||||
<tr class="mr-info-file-row">
|
||||
<td><span>File <span class="mr-tooltip-badge" data-tooltip="The model file name found locally or returned by CivitAI.">?</span></span></td>
|
||||
<td><span class="mr-info-file"></span></td>
|
||||
</tr>
|
||||
<tr class="mr-info-location-row mr-hidden-initial">
|
||||
<td><span>Location <span class="mr-tooltip-badge" data-tooltip="Folder where this local model file is stored.">?</span></span></td>
|
||||
<td><span class="mr-info-location"></span></td>
|
||||
</tr>
|
||||
<tr class="mr-info-hash-row">
|
||||
<td><span>Hash (sha256) <span class="mr-tooltip-badge" data-tooltip="Unique fingerprint of the local file. Model Resolver uses it to confirm the exact CivitAI version.">?</span></span></td>
|
||||
<td><span class="mr-info-hash"></span></td>
|
||||
@@ -322,6 +330,10 @@ export const modelInfoMethods = {
|
||||
<td><span>Base Model <span class="mr-tooltip-badge" data-tooltip="Base model this resource was made for, for example SD1.5, SDXL or Flux.">?</span></span></td>
|
||||
<td><span class="mr-info-base-model"></span></td>
|
||||
</tr>
|
||||
<tr class="mr-info-size-row mr-hidden-initial">
|
||||
<td><span>Size <span class="mr-tooltip-badge" data-tooltip="The local model file size, read from metadata or from the file on disk.">?</span></span></td>
|
||||
<td><span class="mr-info-size"></span></td>
|
||||
</tr>
|
||||
<tr class="mr-info-trainedwords-row mr-hidden-initial">
|
||||
<td>
|
||||
<div class="mr-info-trained-words-label">
|
||||
@@ -489,9 +501,162 @@ export const modelInfoMethods = {
|
||||
)];
|
||||
}
|
||||
|
||||
if (words && typeof words === 'object') {
|
||||
return this.normalizeTrainedWords(
|
||||
words.trained_words
|
||||
|| words.trainedWords
|
||||
|| words.words
|
||||
|| words.values
|
||||
|| []
|
||||
);
|
||||
}
|
||||
|
||||
return [];
|
||||
},
|
||||
|
||||
formatInfoDialogLocation(data = {}) {
|
||||
let location = data.location
|
||||
|| data.folder_path
|
||||
|| data.folderPath
|
||||
|| data.download_directory
|
||||
|| data.downloadDirectory
|
||||
|| data.directory
|
||||
|| '';
|
||||
|
||||
if (!location) {
|
||||
const fullPath = data.resolved_path || data.resolvedPath || data.full_path || data.fullPath || data.path || '';
|
||||
const normalizedFullPath = String(fullPath || '').replace(/\\/g, '/');
|
||||
const lastSlash = normalizedFullPath.lastIndexOf('/');
|
||||
if (lastSlash > 0) {
|
||||
location = normalizedFullPath.slice(0, lastSlash + 1);
|
||||
}
|
||||
}
|
||||
|
||||
location = String(location || '').trim().replace(/\\/g, '/');
|
||||
if (location && !location.endsWith('/')) {
|
||||
location += '/';
|
||||
}
|
||||
|
||||
return location;
|
||||
},
|
||||
|
||||
normalizeInfoTags(tags) {
|
||||
if (Array.isArray(tags)) {
|
||||
const seen = new Set();
|
||||
const result = [];
|
||||
for (let tag of tags) {
|
||||
if (tag && typeof tag === 'object') {
|
||||
tag = tag.name || tag.tag || tag.text || tag.value || '';
|
||||
}
|
||||
const text = String(tag || '').trim();
|
||||
if (!text) continue;
|
||||
const key = text.toLowerCase();
|
||||
if (seen.has(key)) continue;
|
||||
seen.add(key);
|
||||
result.push(text);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
if (typeof tags === 'string') {
|
||||
return this.normalizeInfoTags(
|
||||
tags
|
||||
.split(/[\n,|;]/)
|
||||
.map(tag => tag.trim())
|
||||
.filter(Boolean)
|
||||
);
|
||||
}
|
||||
|
||||
if (tags && typeof tags === 'object') {
|
||||
return this.normalizeInfoTags(
|
||||
tags.tags
|
||||
|| tags.model_tags
|
||||
|| tags.modelTags
|
||||
|| tags.values
|
||||
|| []
|
||||
);
|
||||
}
|
||||
|
||||
return [];
|
||||
},
|
||||
|
||||
getInfoDialogTags(data = {}) {
|
||||
const sources = [
|
||||
data.tags,
|
||||
data.model_tags,
|
||||
data.modelTags,
|
||||
data.civitai?.tags,
|
||||
data.civitai?.model?.tags,
|
||||
data.model?.tags,
|
||||
data.metadata?.tags,
|
||||
data.path_metadata?.tags
|
||||
];
|
||||
|
||||
return this.normalizeInfoTags(
|
||||
sources.flatMap(source => this.normalizeInfoTags(source))
|
||||
);
|
||||
},
|
||||
|
||||
formatInfoDialogSize(data = {}) {
|
||||
const rawSize = data.size
|
||||
?? data.file_size
|
||||
?? data.fileSize
|
||||
?? data.size_bytes
|
||||
?? data.sizeBytes
|
||||
?? data.file?.size
|
||||
?? data.file?.sizeBytes
|
||||
?? null;
|
||||
|
||||
if (rawSize === null || rawSize === undefined || rawSize === '') return '';
|
||||
if (rawSize === 0 || rawSize === '0') return '0 B';
|
||||
|
||||
const numericSize = Number(rawSize);
|
||||
if (Number.isFinite(numericSize)) {
|
||||
return typeof this.formatBytes === 'function'
|
||||
? this.formatBytes(numericSize)
|
||||
: `${numericSize} B`;
|
||||
}
|
||||
|
||||
return String(rawSize);
|
||||
},
|
||||
|
||||
getInfoDialogTrainedWords(data = {}) {
|
||||
const sources = [
|
||||
data.trained_words,
|
||||
data.trainedWords,
|
||||
data.civitai?.trainedWords,
|
||||
data.civitai?.trained_words,
|
||||
data.selected_version?.trainedWords,
|
||||
data.selected_version?.trained_words,
|
||||
data.modelVersion?.trainedWords,
|
||||
data.modelVersion?.trained_words,
|
||||
data.model_version?.trainedWords,
|
||||
data.model_version?.trained_words,
|
||||
data.version?.trainedWords,
|
||||
data.version?.trained_words,
|
||||
data.path_metadata?.trainedWords,
|
||||
data.path_metadata?.trained_words,
|
||||
data.metadata?.trainedWords,
|
||||
data.metadata?.trained_words
|
||||
];
|
||||
|
||||
return this.normalizeTrainedWords(
|
||||
sources.flatMap(source => this.normalizeTrainedWords(source))
|
||||
);
|
||||
},
|
||||
|
||||
setInfoTableRowVisible(row, visible) {
|
||||
if (!row) return;
|
||||
row.classList.toggle('mr-hidden-initial', !visible);
|
||||
row.style.display = visible ? '' : 'none';
|
||||
},
|
||||
|
||||
setInfoElementVisible(element, visible) {
|
||||
if (!element) return;
|
||||
element.classList.toggle('mr-hidden-initial', !visible);
|
||||
element.style.display = visible ? '' : 'none';
|
||||
},
|
||||
|
||||
updateSelectedTrainedWordsSummary(dialog) {
|
||||
if (!dialog) return;
|
||||
|
||||
@@ -639,13 +804,19 @@ export const modelInfoMethods = {
|
||||
*/
|
||||
async fetchModelInfoForDialog(loraName, modelData, dialog) {
|
||||
try {
|
||||
const resolvedPath = modelData?.resolved_path
|
||||
|| modelData?.path
|
||||
|| modelData?.full_path
|
||||
|| modelData?.folder_path
|
||||
|| modelData?.download_directory
|
||||
|| '';
|
||||
const response = await api.fetchApi('/model_resolver/civitai-search', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
filename: loraName,
|
||||
category: modelData?.category || '',
|
||||
resolved_path: modelData?.resolved_path || ''
|
||||
resolved_path: resolvedPath
|
||||
})
|
||||
});
|
||||
|
||||
@@ -706,12 +877,39 @@ export const modelInfoMethods = {
|
||||
}
|
||||
}
|
||||
|
||||
// Update top tags
|
||||
const tagsRowEl = dialog.querySelector('.mr-info-tags-row');
|
||||
const tagsEl = dialog.querySelector('.mr-info-tags');
|
||||
if (tagsRowEl && tagsEl) {
|
||||
const tags = this.getInfoDialogTags(data);
|
||||
if (tags.length > 0) {
|
||||
tagsEl.innerHTML = tags.map(tag => `
|
||||
<span class="mr-info-tag mr-info-model-tag" data-tooltip="${this.escapeHtml(tag)}">
|
||||
${this.escapeHtml(tag)}
|
||||
</span>
|
||||
`).join('');
|
||||
this.setInfoElementVisible(tagsRowEl, true);
|
||||
this.bindTooltips(tagsEl);
|
||||
} else {
|
||||
tagsEl.innerHTML = '';
|
||||
this.setInfoElementVisible(tagsRowEl, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Update file
|
||||
const fileEl = dialog.querySelector('.mr-info-file');
|
||||
if (fileEl && data.filename) {
|
||||
fileEl.textContent = data.filename;
|
||||
}
|
||||
|
||||
// Update location
|
||||
const locationEl = dialog.querySelector('.mr-info-location');
|
||||
if (locationEl) {
|
||||
const location = this.formatInfoDialogLocation(data);
|
||||
locationEl.textContent = location;
|
||||
this.setInfoTableRowVisible(locationEl.closest('tr'), Boolean(location));
|
||||
}
|
||||
|
||||
// Update hash
|
||||
const hashEl = dialog.querySelector('.mr-info-hash');
|
||||
if (hashEl) {
|
||||
@@ -752,17 +950,22 @@ export const modelInfoMethods = {
|
||||
const baseModel = data.base_model || data.baseModel || '';
|
||||
baseModelRowEl.textContent = baseModel;
|
||||
const row = baseModelRowEl.closest('tr');
|
||||
if (row && baseModel) {
|
||||
row.style.display = '';
|
||||
} else if (row) {
|
||||
row.style.display = 'none';
|
||||
}
|
||||
this.setInfoTableRowVisible(row, Boolean(baseModel));
|
||||
}
|
||||
|
||||
// Update file size row
|
||||
const sizeEl = dialog.querySelector('.mr-info-size');
|
||||
if (sizeEl) {
|
||||
const sizeLabel = this.formatInfoDialogSize(data);
|
||||
sizeEl.textContent = sizeLabel;
|
||||
this.setInfoTableRowVisible(sizeEl.closest('tr'), Boolean(sizeLabel));
|
||||
}
|
||||
|
||||
// Update trained words
|
||||
const trainedWordsEl = dialog.querySelector('.mr-info-trained-words');
|
||||
if (trainedWordsEl) {
|
||||
const words = this.normalizeTrainedWords(data.trained_words || data.trainedWords || []);
|
||||
const words = this.getInfoDialogTrainedWords(data);
|
||||
const row = trainedWordsEl.closest('tr');
|
||||
if (words.length > 0) {
|
||||
dialog._selectedTrainedWords = new Set();
|
||||
trainedWordsEl.innerHTML = `<div class="mr-info-trained-words-list">${words.map(word => `
|
||||
@@ -776,13 +979,11 @@ export const modelInfoMethods = {
|
||||
${this.escapeHtml(word)}
|
||||
</button>
|
||||
`).join('')}</div>`;
|
||||
const row = trainedWordsEl.closest('tr');
|
||||
if (row) row.style.display = '';
|
||||
this.setInfoTableRowVisible(row, true);
|
||||
this.bindTooltips(trainedWordsEl);
|
||||
this.updateSelectedTrainedWordsSummary(dialog);
|
||||
} else {
|
||||
const row = trainedWordsEl.closest('tr');
|
||||
if (row) row.style.display = 'none';
|
||||
this.setInfoTableRowVisible(row, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -790,13 +991,12 @@ export const modelInfoMethods = {
|
||||
const clipSkipEl = dialog.querySelector('.mr-info-clip-skip');
|
||||
if (clipSkipEl) {
|
||||
const clipSkip = data.clip_skip || data.clipSkip;
|
||||
const row = clipSkipEl.closest('tr');
|
||||
if (clipSkip && clipSkip !== 'None') {
|
||||
clipSkipEl.textContent = clipSkip;
|
||||
const row = clipSkipEl.closest('tr');
|
||||
if (row) row.style.display = '';
|
||||
this.setInfoTableRowVisible(row, true);
|
||||
} else {
|
||||
const row = clipSkipEl.closest('tr');
|
||||
if (row) row.style.display = 'none';
|
||||
this.setInfoTableRowVisible(row, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -823,9 +1023,7 @@ export const modelInfoMethods = {
|
||||
descEl.classList.remove('is-expanded');
|
||||
|
||||
const shouldCollapse = textOnly.length > 520 || finalHtml.length > 900;
|
||||
if (actionsEl) {
|
||||
actionsEl.style.display = shouldCollapse ? '' : 'none';
|
||||
}
|
||||
this.setInfoElementVisible(actionsEl, shouldCollapse);
|
||||
if (toggleBtn) {
|
||||
toggleBtn.textContent = 'Show more';
|
||||
}
|
||||
@@ -834,10 +1032,10 @@ export const modelInfoMethods = {
|
||||
}
|
||||
|
||||
const row = descEl.closest('tr');
|
||||
if (row) row.style.display = '';
|
||||
this.setInfoTableRowVisible(row, true);
|
||||
} else {
|
||||
const row = descEl.closest('tr');
|
||||
if (row) row.style.display = 'none';
|
||||
this.setInfoTableRowVisible(row, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user