mirror of
https://github.com/vladmandic/automatic
synced 2026-09-19 01:04:32 +02:00
new models tab including civitai downloader
Signed-off-by: Vladimir Mandic <mandic00@live.com>
This commit is contained in:
+11
-5
@@ -1,6 +1,6 @@
|
||||
# Change Log for SD.Next
|
||||
|
||||
## Update for 2025-08-02
|
||||
## Update for 2025-08-04
|
||||
|
||||
- **Models**
|
||||
- [FLUX.1-Krea-Dev](https://www.krea.ai/blog/flux-krea-open-source-release)
|
||||
@@ -14,15 +14,21 @@
|
||||
- new embedded docs/wiki search!
|
||||
**Docs** search: fully-local and works in real-time on all document pages
|
||||
**Wiki** search: uses github api to search online wiki pages
|
||||
- quicksettings reset button to restore all quicksettings to default values
|
||||
because things do sometimes get wrong...
|
||||
- updated real-time hints, thanks @CalamitousFelicitousness
|
||||
- updated *models -> current* tab
|
||||
- rewritten **CivitAI downloader**
|
||||
in *models -> civitai*
|
||||
- updated *models -> current* tab
|
||||
- updated *models -> list models* tab
|
||||
- updated *models -> metadata* tab
|
||||
- more css optimizations and styling
|
||||
- quicksettings reset button to restore all quicksettings to default values
|
||||
because things do sometimes get wrong...
|
||||
- redesign *settings -> user interface*
|
||||
- gallery bypass browser cache for thumbnails
|
||||
- gallery safer delete operation
|
||||
- more css optimizations and styling
|
||||
- *hint*: card layout
|
||||
card layout is used by networks, gallery, civitai search, etc.
|
||||
you can change card size in *settings -> user interface*
|
||||
- **Offloading**
|
||||
- changed **default** values for offloading based on detected gpu memory
|
||||
see [offloading docs](https://vladmandic.github.io/sdnext-docs/Offload/) for details
|
||||
|
||||
Submodule extensions-builtin/sdnext-modernui updated: 5403536134...89c232814a
+97
-232
@@ -1,31 +1,76 @@
|
||||
// hack to get pythons str.format in js
|
||||
String.prototype.format = function (arguments) { // eslint-disable-line no-extend-native, func-names
|
||||
String.prototype.format = function (args) { // eslint-disable-line no-extend-native, func-names
|
||||
let thisString = '';
|
||||
for (let charPos = 0; charPos < this.length; charPos++) thisString += this[charPos];
|
||||
for (const key in arguments) { // eslint-disable-line guard-for-in
|
||||
error(key, arguments[key]);
|
||||
for (const key in args) { // eslint-disable-line guard-for-in
|
||||
const stringKey = `{${key}}`;
|
||||
thisString = thisString.replace(new RegExp(stringKey, 'g'), arguments[key]);
|
||||
thisString = thisString.replace(new RegExp(stringKey, 'g'), args[key]);
|
||||
}
|
||||
return thisString;
|
||||
};
|
||||
|
||||
let selectedURL = '';
|
||||
let selectedName = '';
|
||||
let selectedType = '';
|
||||
|
||||
function clearModelDetails() {
|
||||
const el = gradioApp().getElementById('model-details') || gradioApp().getElementById('civitai_models_output') || gradioApp().getElementById('models_outcome');
|
||||
if (!el) return;
|
||||
el.innerHTML = '';
|
||||
}
|
||||
|
||||
const modelDetailsHTML = `
|
||||
<div id="model-details" class="model-details">
|
||||
<h3>{name}</h3>
|
||||
<p>Type: {type}</p>
|
||||
<p>Tags: {tags}</p>
|
||||
<p>NSFW: {nsfw}/{level}</p>
|
||||
<p>Availability: {availability}</p>
|
||||
<p>Downloads: {downloads}</p>
|
||||
<p>Author: {creator}</p>
|
||||
<div>{versions}</div>
|
||||
<div>
|
||||
<img src="{image}" alt="model image" class="preview" style="display: none">
|
||||
<button style="float: right" class="lg secondary gradio-button tool extra-details-close" id="model_details_close" data-hint="Close" onclick="clearModelDetails()"> ✕</button>
|
||||
<table id="model-details-table" class="model-details simple-table">
|
||||
<tr><td>Name</td><td>{name}</td></tr>
|
||||
<tr><td>Type</td><td>{type}</td></tr>
|
||||
<tr><td>Tags</td><td><div>{tags}</div></td></tr>
|
||||
<tr><td>NSFW</td><td>{nsfw} | {level}</td></tr>
|
||||
<tr><td>Availability</td><td>{availability}</td></tr>
|
||||
<tr><td>Downloads</td><td>{downloads}</td></tr>
|
||||
<tr><td>Author</td><td>{creator}</td></tr>
|
||||
<tr><td>Description</td><td><div>{desc}</div></td></tr>
|
||||
</table>
|
||||
<br>
|
||||
<table id="model-versions-table" class="model-versions simple-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th> </th>
|
||||
<th>Version</th>
|
||||
<th>Type</th>
|
||||
<th>Base</th>
|
||||
<th>File</th>
|
||||
<th>Updated</th>
|
||||
<th>Size</th>
|
||||
<th>Availability</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{versions}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const modelVersionsHTML = `
|
||||
<tr>
|
||||
<td>{url}</td>
|
||||
<td>{name}</td>
|
||||
<td>{type}</td>
|
||||
<td>{base}</td>
|
||||
<td>{file}</td>
|
||||
<td>{mtime}</td>
|
||||
<td>{size}</td>
|
||||
<td>{availability}</td>
|
||||
<td><div>{desc}</div></td>
|
||||
</tr>
|
||||
`;
|
||||
|
||||
async function modelCardClick(id) {
|
||||
log('modelCardClick id', id);
|
||||
const el = gradioApp().getElementById('model-details');
|
||||
const el = gradioApp().getElementById('model-details') || gradioApp().getElementById('civitai_models_output') || gradioApp().getElementById('models_outcome');
|
||||
if (!el) return;
|
||||
const res = await fetch(`${window.api}/civitai?model_id=${encodeURI(id)}`);
|
||||
if (!res || res.status !== 200) {
|
||||
@@ -36,229 +81,49 @@ async function modelCardClick(id) {
|
||||
log('modelCardClick data', data);
|
||||
if (!data || data.length === 0) return;
|
||||
data = data[0]; // assuming the first item is the one we want
|
||||
const obj = {
|
||||
name: data.name || 'unknown',
|
||||
|
||||
const versionsHTML = data.versions.map((v) => modelVersionsHTML.format({
|
||||
url: `<div class="link" onclick="startCivitDownload('${v.files[0]?.url}', '${v.files[0]?.name}', '${data.type}')"> \udb80\uddda </div>`,
|
||||
name: v.name || 'unknown',
|
||||
type: v.files[0]?.type || 'unknown',
|
||||
base: v.base || 'unknown',
|
||||
mtime: (new Date(v.mtime)).toLocaleDateString(),
|
||||
availability: v.availability || 'unknown',
|
||||
size: v.files[0]?.size ? `${(v.files[0].size / 1024 / 1024).toFixed(2)} MB` : 'unknown',
|
||||
file: `<a href=${v.files[0]?.url} target="_blank" rel="noopener noreferrer">${v.files[0]?.name || 'unknown'}</a>`,
|
||||
desc: v.desc || 'no description available',
|
||||
})).join('');
|
||||
const url = `<a href="${data.url}" target="_blank" rel="noopener noreferrer">${data.name || 'unknown'}</a>`;
|
||||
const creator = `<a href="https://civitai.com/user/${data.creator}" target="_blank" rel="noopener noreferrer">${data.creator || 'unknown'}</a>`;
|
||||
const images = data.versions.map((v) => v.images).flat().map((i) => i.url); // TODO image gallery
|
||||
const modelHTML = modelDetailsHTML.format({
|
||||
name: url,
|
||||
type: data.type || 'unknown',
|
||||
tags: data.tags?.join(', ') || '',
|
||||
nsfw: data.nsfw ? 'yes' : 'no',
|
||||
level: data.level?.toString() || '',
|
||||
availability: data.availability || 'unknown',
|
||||
downloads: data.downloads?.toString() || '',
|
||||
creator: data.creator || 'unknown',
|
||||
versions: JSON.stringify(data.versions) || '[]',
|
||||
};
|
||||
log(obj);
|
||||
el.innerHTML = modelDetailsHTML.format({
|
||||
name: data.name || 'unknown',
|
||||
type: data.type || 'unknown',
|
||||
tags: data.tags?.join(', ') || '',
|
||||
nsfw: data.nsfw ? 'yes' : 'no',
|
||||
level: data.level?.toString() || '',
|
||||
availability: data.availability || 'unknown',
|
||||
downloads: data.downloads?.toString() || '',
|
||||
creator: data.creator || 'unknown',
|
||||
versions: JSON.stringify(data.versions) || '[]',
|
||||
creator,
|
||||
desc: data.desc || 'no description available',
|
||||
image: images.length > 0 ? images[0] : './sd_extra_networks/thumb?filename=html/card-no-preview.png',
|
||||
versions: versionsHTML || '',
|
||||
});
|
||||
el.innerHTML = modelHTML;
|
||||
}
|
||||
|
||||
const example = {
|
||||
id: 1157409,
|
||||
url: 'https://civitai.com/models/1157409',
|
||||
type: 'Checkpoint',
|
||||
name: 'Tempest-by-Vlad',
|
||||
html: '',
|
||||
desc: 'Base versionFlexible SDXL model with custom encoder and finetuned for larger landscape resolutions with high details and high contrast.Recommended to use medium-low...',
|
||||
tags: [
|
||||
'base model',
|
||||
],
|
||||
nsfw: false,
|
||||
level: 15,
|
||||
availability: 'Public',
|
||||
downloads: 407,
|
||||
creator: 'vmandic',
|
||||
versions: [
|
||||
{
|
||||
id: 1301775,
|
||||
name: 'Base v0.1',
|
||||
base: 'SDXL 1.0',
|
||||
mtime: '2025-01-19T02:53:53.903Z',
|
||||
downloads: 346,
|
||||
availability: 'Public',
|
||||
html: '',
|
||||
desc: 'Initial release',
|
||||
files: [
|
||||
{
|
||||
id: 1206102,
|
||||
size: 6938089790,
|
||||
name: 'tempestByVlad_baseV01.safetensors',
|
||||
type: 'Model',
|
||||
hashes: [
|
||||
'79CB1E32',
|
||||
'8BFAD17222',
|
||||
'8BFAD1722243955B3F94103C69079C280D348B14729251E86824972C1063B616',
|
||||
'43E5E3BB',
|
||||
'DE83D56256411853AB6595CC3D8E865D5310D4A58D49A839DDC104C7F3429D4A',
|
||||
'4E933E1EBE61',
|
||||
],
|
||||
url: 'https://civitai.com/api/download/models/1301775',
|
||||
dct: {},
|
||||
},
|
||||
],
|
||||
images: [
|
||||
{
|
||||
id: 52503951,
|
||||
url: 'https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/18c749f2-42ec-4024-9d20-0b1202b6bacc/width=1024/52503951.jpeg',
|
||||
width: 1024,
|
||||
height: 1024,
|
||||
type: 'image',
|
||||
dct: {},
|
||||
},
|
||||
{
|
||||
id: 52508539,
|
||||
url: 'https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/634d0ea8-ecdb-4ca6-a4ff-145319bc3fd3/width=1024/52508539.jpeg',
|
||||
width: 1024,
|
||||
height: 1024,
|
||||
type: 'image',
|
||||
dct: {},
|
||||
},
|
||||
{
|
||||
id: 52508563,
|
||||
url: 'https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/be529820-a89e-458f-8a3d-86cb43b154ac/width=1024/52508563.jpeg',
|
||||
width: 1024,
|
||||
height: 1024,
|
||||
type: 'image',
|
||||
dct: {},
|
||||
},
|
||||
{
|
||||
id: 52508588,
|
||||
url: 'https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/b2eb456a-a664-4de8-8c3e-6ecd1c4acb38/width=1024/52508588.jpeg',
|
||||
width: 1024,
|
||||
height: 1024,
|
||||
type: 'image',
|
||||
dct: {},
|
||||
},
|
||||
{
|
||||
id: 52508654,
|
||||
url: 'https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/f7b09e3f-4a48-459b-9b32-fa207904f74c/width=1024/52508654.jpeg',
|
||||
width: 1024,
|
||||
height: 1024,
|
||||
type: 'image',
|
||||
dct: {},
|
||||
},
|
||||
{
|
||||
id: 52508659,
|
||||
url: 'https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/fff89f18-628a-43b3-b9f5-44951dc078f7/width=1024/52508659.jpeg',
|
||||
width: 1024,
|
||||
height: 1024,
|
||||
type: 'image',
|
||||
dct: {},
|
||||
},
|
||||
{
|
||||
id: 52508671,
|
||||
url: 'https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/fdd3f774-ce2e-4ea7-82a0-bdb523fb86f6/width=1024/52508671.jpeg',
|
||||
width: 1024,
|
||||
height: 1024,
|
||||
type: 'image',
|
||||
dct: {},
|
||||
},
|
||||
{
|
||||
id: 52512251,
|
||||
url: 'https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/f26971c8-1123-45e3-a85b-2b97c6334b85/width=1024/52512251.jpeg',
|
||||
width: 1024,
|
||||
height: 1024,
|
||||
type: 'image',
|
||||
dct: {},
|
||||
},
|
||||
],
|
||||
dct: {},
|
||||
},
|
||||
{
|
||||
id: 1343512,
|
||||
name: 'Hyper v0.1',
|
||||
base: 'SDXL 1.0',
|
||||
mtime: '2025-01-28T22:54:12.734Z',
|
||||
downloads: 61,
|
||||
availability: 'Public',
|
||||
html: '',
|
||||
desc: 'Time-distilled version',
|
||||
files: [
|
||||
{
|
||||
id: 1246991,
|
||||
size: 6938085702,
|
||||
name: 'tempestByVlad_hyperV01.safetensors',
|
||||
type: 'Model',
|
||||
hashes: [
|
||||
'15943FD9',
|
||||
'4104FC6601',
|
||||
'4104FC6601F71C4C7A770AD422483FD700C8ECF72D06FCD8C4E8CD4B2D1C7DBB',
|
||||
'9F87BCEA',
|
||||
'CB52894625E9C13331285E4435799D707C4EAEF464974159C8B4B217EA32298E',
|
||||
'A0EE15E503DD',
|
||||
],
|
||||
url: 'https://civitai.com/api/download/models/1343512',
|
||||
dct: {},
|
||||
},
|
||||
],
|
||||
images: [
|
||||
{
|
||||
id: 54462987,
|
||||
url: 'https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/1dd020c8-8a9a-4eb3-afec-fe83613217c5/width=1024/54462987.jpeg',
|
||||
width: 1024,
|
||||
height: 768,
|
||||
type: 'image',
|
||||
dct: {},
|
||||
},
|
||||
{
|
||||
id: 54462992,
|
||||
url: 'https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/89edf233-939f-4b2e-97c8-175498704362/width=1536/54462992.jpeg',
|
||||
width: 1536,
|
||||
height: 640,
|
||||
type: 'image',
|
||||
dct: {},
|
||||
},
|
||||
{
|
||||
id: 54463002,
|
||||
url: 'https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/87aea8fb-7687-48d0-98e6-27555b2ff87f/width=768/54463002.jpeg',
|
||||
width: 768,
|
||||
height: 1024,
|
||||
type: 'image',
|
||||
dct: {},
|
||||
},
|
||||
{
|
||||
id: 54463010,
|
||||
url: 'https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/f1ee57cc-8920-4b8d-853a-ad1cfc7d9a5a/width=1024/54463010.jpeg',
|
||||
width: 1024,
|
||||
height: 1024,
|
||||
type: 'image',
|
||||
dct: {},
|
||||
},
|
||||
{
|
||||
id: 54463011,
|
||||
url: 'https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/dda6411b-fd36-484f-a9f0-0db847463128/width=1024/54463011.jpeg',
|
||||
width: 1024,
|
||||
height: 1024,
|
||||
type: 'image',
|
||||
dct: {},
|
||||
},
|
||||
{
|
||||
id: 54463016,
|
||||
url: 'https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/5f266a8c-f215-4e0f-8a64-aacc97f81d70/width=1024/54463016.jpeg',
|
||||
width: 1024,
|
||||
height: 1024,
|
||||
type: 'image',
|
||||
dct: {},
|
||||
},
|
||||
{
|
||||
id: 54463019,
|
||||
url: 'https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/0ad04bdc-41bd-433c-9c25-f5365fbe082c/width=1024/54463019.jpeg',
|
||||
width: 1024,
|
||||
height: 1024,
|
||||
type: 'image',
|
||||
dct: {},
|
||||
},
|
||||
],
|
||||
dct: {},
|
||||
},
|
||||
],
|
||||
dct: {},
|
||||
};
|
||||
function startCivitDownload(url, name, type) {
|
||||
log('startCivitDownload', { url, name, type });
|
||||
selectedURL = url;
|
||||
selectedName = name;
|
||||
selectedType = type;
|
||||
const civitDownloadBtn = gradioApp().getElementById('civitai_download_btn');
|
||||
if (civitDownloadBtn) civitDownloadBtn.click();
|
||||
}
|
||||
|
||||
function downloadCivitModel(modelUrl, modelName, modelType, modelPath, civitToken, innerHTML) {
|
||||
log('downloadCivitModel', { modelUrl, modelName, modelType, modelPath, civitToken });
|
||||
const el = gradioApp().getElementById('civitai_models_output') || gradioApp().getElementById('models_outcome');
|
||||
const currentHTML = el?.innerHTML || '';
|
||||
return [selectedURL, selectedName, selectedType, modelPath, civitToken, currentHTML];
|
||||
}
|
||||
|
||||
@@ -110,8 +110,8 @@ function readCardDescription(page, item) {
|
||||
function getCardsForActivePage() {
|
||||
const pagename = getENActivePage();
|
||||
if (!pagename) return [];
|
||||
const allCards = Array.from(gradioApp().querySelectorAll('.extra-network-cards > .card'));
|
||||
const cards = allCards.filter((el) => el.dataset.page.toLowerCase().includes(pagename.toLowerCase()));
|
||||
let allCards = Array.from(gradioApp().querySelectorAll('.extra-network-cards > .card'));
|
||||
allCards = allCards.filter((el) => el.dataset.page?.toLowerCase().includes(pagename.toLowerCase()));
|
||||
// log('getCardsForActivePage', pagename, cards.length);
|
||||
return allCards;
|
||||
}
|
||||
|
||||
+56
-13
@@ -66,6 +66,10 @@ button {
|
||||
min-width: unset !important;
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin: 0.2em 0em 0.2em 0em;
|
||||
}
|
||||
|
||||
input[type='color'] {
|
||||
height: 32px;
|
||||
width: 64px;
|
||||
@@ -122,6 +126,17 @@ input::-webkit-outer-spin-button, input::-webkit-inner-spin-button {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.link {
|
||||
background-color: var(--background-fill-primary);
|
||||
cursor: pointer;
|
||||
border-radius: var(--input-radius);
|
||||
width: 2em;
|
||||
}
|
||||
|
||||
.link:hover {
|
||||
background-color: var(--button-primary-background-fill);
|
||||
}
|
||||
|
||||
.gradio-dropdown, .block.gradio-slider, .block.gradio-checkbox, .block.gradio-textbox, .block.gradio-radio, .block.gradio-checkboxgroup, .block.gradio-number, .block.gradio-colorpicker {
|
||||
border-width: 0 !important;
|
||||
box-shadow: none !important;
|
||||
@@ -1226,11 +1241,13 @@ table.settings-value-table td {
|
||||
}
|
||||
|
||||
.extra-network-cards .card {
|
||||
height: fit-content;
|
||||
margin: 0 0 0.5em 0.5em;
|
||||
position: relative;
|
||||
scroll-margin-top: 0;
|
||||
scroll-snap-align: start;
|
||||
margin: 0 0 0.5em 0.5em;
|
||||
position: relative;
|
||||
scroll-margin-top: 0;
|
||||
scroll-snap-align: start;
|
||||
height: var(--card-size);
|
||||
width: var(--card-size);
|
||||
contain: strict;
|
||||
}
|
||||
|
||||
.extra-network-cards .card .overlay {
|
||||
@@ -1923,10 +1940,6 @@ div:has(>#tab-gallery-folders) {
|
||||
padding: 0.2em;
|
||||
}
|
||||
|
||||
.docs-results {
|
||||
background-color: var(--sd-group-background-color);
|
||||
}
|
||||
|
||||
.docs-card {
|
||||
margin: 1em 0;
|
||||
background-color: var(--background-fill-primary);
|
||||
@@ -1972,6 +1985,13 @@ div:has(>#tab-gallery-folders) {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.model-config {
|
||||
font-size: 0.8em !important;
|
||||
opacity: 0.8;
|
||||
max-height: 6em;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.simple-table tr {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
@@ -1980,13 +2000,36 @@ div:has(>#tab-gallery-folders) {
|
||||
padding: 0.2em !important;
|
||||
}
|
||||
|
||||
.model-config {
|
||||
font-size: 0.8em !important;
|
||||
opacity: 0.8;
|
||||
max-height: 6em;
|
||||
.simple-table tr {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
.simple-table thead tr {
|
||||
background-color: var(--button-primary-border-color) !important;
|
||||
}
|
||||
|
||||
.simple-table tr:nth-child(odd) {
|
||||
background-color: var(--neutral-900);
|
||||
}
|
||||
|
||||
.simple-table td {
|
||||
padding: 0.2em !important;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.simple-table td div {
|
||||
padding: 0.2em !important;
|
||||
white-space: pre-wrap;
|
||||
max-height: 7em;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.simple-table td:nth-child(1) {
|
||||
color: var(--button-primary-border-color);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@keyframes move {
|
||||
from {
|
||||
background-position-x: 0, -40px;
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
import os
|
||||
import json
|
||||
import rich.progress as p
|
||||
from PIL import Image
|
||||
from modules import shared, errors, paths
|
||||
|
||||
|
||||
pbar = None
|
||||
|
||||
|
||||
def save_video_frame(filepath: str):
|
||||
from modules import video
|
||||
try:
|
||||
frames, fps, duration, w, h, codec, frame = video.get_video_params(filepath, capture=True)
|
||||
except Exception as e:
|
||||
shared.log.error(f'Video: file={filepath} {e}')
|
||||
return None
|
||||
if frame is not None:
|
||||
basename = os.path.splitext(filepath)
|
||||
thumb = f'{basename[0]}.thumb.jpg'
|
||||
shared.log.debug(f'Video: file={filepath} frames={frames} fps={fps} size={w}x{h} codec={codec} duration={duration} thumb={thumb}')
|
||||
frame.save(thumb)
|
||||
else:
|
||||
shared.log.error(f'Video: file={filepath} no frames found')
|
||||
return frame
|
||||
|
||||
|
||||
def download_civit_meta(model_path: str, model_id):
|
||||
fn = os.path.splitext(model_path)[0] + '.json'
|
||||
url = f'https://civitai.com/api/v1/models/{model_id}'
|
||||
r = shared.req(url)
|
||||
if r.status_code == 200:
|
||||
try:
|
||||
data = r.json()
|
||||
shared.writefile(data, filename=fn, mode='w', silent=True)
|
||||
shared.log.info(f'CivitAI download: id={model_id} url={url} file="{fn}"')
|
||||
return r.status_code, len(data), '' # code/size/note
|
||||
except Exception as e:
|
||||
errors.display(e, 'civitai meta')
|
||||
shared.log.error(f'CivitAI meta: id={model_id} url={url} file="{fn}" {e}')
|
||||
return r.status_code, '', str(e)
|
||||
return r.status_code, '', ''
|
||||
|
||||
|
||||
def download_civit_preview(model_path: str, preview_url: str):
|
||||
global pbar # pylint: disable=global-statement
|
||||
if model_path is None:
|
||||
pbar = None
|
||||
return 500, '', ''
|
||||
ext = os.path.splitext(preview_url)[1]
|
||||
preview_file = os.path.splitext(model_path)[0] + ext
|
||||
is_video = preview_file.lower().endswith('.mp4')
|
||||
is_json = preview_file.lower().endswith('.json')
|
||||
if is_json:
|
||||
shared.log.warning(f'CivitAI download: url="{preview_url}" skip json')
|
||||
return 500, '', 'exepected preview image got json'
|
||||
if os.path.exists(preview_file):
|
||||
return 304, '', 'already exists'
|
||||
# res = f'CivitAI download: url={preview_url} file="{preview_file}"'
|
||||
r = shared.req(preview_url, stream=True)
|
||||
total_size = int(r.headers.get('content-length', 0))
|
||||
block_size = 16384 # 16KB blocks
|
||||
written = 0
|
||||
img = None
|
||||
shared.state.begin('CivitAI')
|
||||
if pbar is None:
|
||||
pbar = p.Progress(p.TextColumn('[cyan]Download'), p.DownloadColumn(), p.BarColumn(), p.TaskProgressColumn(), p.TimeRemainingColumn(), p.TimeElapsedColumn(), p.TransferSpeedColumn(), p.TextColumn('[yellow]{task.description}'), console=shared.console)
|
||||
try:
|
||||
with open(preview_file, 'wb') as f:
|
||||
with pbar:
|
||||
task = pbar.add_task(description=preview_file, total=total_size)
|
||||
for data in r.iter_content(block_size):
|
||||
written = written + len(data)
|
||||
f.write(data)
|
||||
pbar.update(task, advance=block_size)
|
||||
if written < 1024: # min threshold
|
||||
os.remove(preview_file)
|
||||
return 400, '', 'removed invalid download'
|
||||
if is_video:
|
||||
img = save_video_frame(preview_file)
|
||||
else:
|
||||
img = Image.open(preview_file)
|
||||
except Exception as e:
|
||||
shared.log.error(f'CivitAI download error: url={preview_url} file="{preview_file}" written={written} {e}')
|
||||
return 500, '', str(e)
|
||||
shared.state.end()
|
||||
if img is None:
|
||||
return 500, '', 'image is none'
|
||||
shared.log.info(f'CivitAI download: url={preview_url} file="{preview_file}" size={total_size} image={img.size}')
|
||||
img.close()
|
||||
return 200, str(total_size), '' # code/size/note
|
||||
|
||||
|
||||
def download_civit_model_thread(model_name: str, model_url: str, model_path: str = "", model_type: str = "Model", token: str = None):
|
||||
import hashlib
|
||||
sha256 = hashlib.sha256()
|
||||
sha256.update(model_url.encode('utf-8'))
|
||||
temp_file = sha256.hexdigest()[:8] + '.tmp'
|
||||
|
||||
headers = {}
|
||||
starting_pos = 0
|
||||
if os.path.isfile(temp_file):
|
||||
starting_pos = os.path.getsize(temp_file)
|
||||
headers['Range'] = f'bytes={starting_pos}-'
|
||||
if token is None or len(token) == 0:
|
||||
token = shared.opts.civitai_token
|
||||
if token is not None and len(token) > 0:
|
||||
headers['Authorization'] = f'Bearer {token}'
|
||||
|
||||
r = shared.req(model_url, headers=headers, stream=True)
|
||||
total_size = int(r.headers.get('content-length', 0))
|
||||
if model_name is None or len(model_name) == 0:
|
||||
cn = r.headers.get('content-disposition', '')
|
||||
model_name = cn.split('filename=')[-1].strip('"')
|
||||
|
||||
model_path = model_path.strip()
|
||||
if len(model_path) > 0:
|
||||
if os.path.isabs(model_path):
|
||||
pass
|
||||
else:
|
||||
model_path = os.path.join(paths.models_path, model_path)
|
||||
elif model_type.lower() == 'lora':
|
||||
model_path = shared.opts.lora_dir
|
||||
elif model_type.lower() == 'embedding':
|
||||
model_path = shared.opts.embeddings_dir
|
||||
elif model_type.lower() == 'vae':
|
||||
model_path = shared.opts.vae_dir
|
||||
else:
|
||||
model_path = shared.opts.ckpt_dir
|
||||
model_file = os.path.join(model_path, model_name)
|
||||
temp_file = os.path.join(model_path, temp_file)
|
||||
|
||||
res = f'Model download: name="{model_name}" url="{model_url}" path="{model_path}" temp="{temp_file}"'
|
||||
if os.path.isfile(model_file):
|
||||
res += ' already exists'
|
||||
shared.log.warning(res)
|
||||
return res
|
||||
|
||||
res += f' size={round((starting_pos + total_size)/1024/1024, 2)}Mb'
|
||||
shared.log.info(res)
|
||||
shared.state.begin('CivitAI')
|
||||
block_size = 16384 # 16KB blocks
|
||||
written = starting_pos
|
||||
global pbar # pylint: disable=global-statement
|
||||
if pbar is None:
|
||||
pbar = p.Progress(p.TextColumn('[cyan]{task.description}'), p.DownloadColumn(), p.BarColumn(), p.TaskProgressColumn(), p.TimeRemainingColumn(), p.TimeElapsedColumn(), p.TransferSpeedColumn(), p.TextColumn('[cyan]{task.fields[name]}'), console=shared.console)
|
||||
with pbar:
|
||||
task = pbar.add_task(description="Download starting", total=starting_pos+total_size, name=model_name)
|
||||
try:
|
||||
with open(temp_file, 'ab') as f:
|
||||
for data in r.iter_content(block_size):
|
||||
if written == 0:
|
||||
try: # check if response is JSON message instead of bytes
|
||||
shared.log.error(f'Model download: response={json.loads(data.decode("utf-8"))}')
|
||||
raise ValueError('response: type=json expected=bytes')
|
||||
except Exception: # this is good
|
||||
pass
|
||||
written = written + len(data)
|
||||
f.write(data)
|
||||
pbar.update(task, description="Download", completed=written)
|
||||
if written < 1024: # min threshold
|
||||
os.remove(temp_file)
|
||||
raise ValueError(f'removed invalid download: bytes={written}')
|
||||
except Exception as e:
|
||||
shared.log.error(f'{res} {e}')
|
||||
finally:
|
||||
pbar.stop_task(task)
|
||||
pbar.remove_task(task)
|
||||
if starting_pos+total_size != written:
|
||||
shared.log.warning(f'{res} written={round(written/1024/1024)}Mb incomplete download')
|
||||
elif os.path.exists(temp_file):
|
||||
shared.log.debug(f'Model download complete: temp="{temp_file}" path="{model_file}"')
|
||||
os.rename(temp_file, model_file)
|
||||
shared.state.end()
|
||||
if os.path.exists(model_file):
|
||||
return model_file
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def download_civit_model(model_url: str, model_name: str = '', model_path: str = '', model_type: str = '', token: str = None):
|
||||
import threading
|
||||
if model_url is None or len(model_url) == 0:
|
||||
err = 'Model download: no url provided'
|
||||
shared.log.error(err)
|
||||
return err
|
||||
thread = threading.Thread(target=download_civit_model_thread, args=(model_name, model_url, model_path, model_type, token))
|
||||
thread.start()
|
||||
thread.join()
|
||||
from modules.sd_models import list_models # pylint: disable=W0621
|
||||
list_models()
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
import json
|
||||
import gradio as gr
|
||||
from modules.shared import log, opts, req, readfile, max_workers
|
||||
|
||||
@@ -58,7 +57,8 @@ def civit_update_metadata():
|
||||
return html.format(tbody=tbody)
|
||||
|
||||
log.debug('CivitAI update metadata: models')
|
||||
from modules import ui_extra_networks, modelloader
|
||||
from modules import ui_extra_networks
|
||||
from modules.civitai.download_civitai import download_civit_meta
|
||||
pages = ui_extra_networks.get_pages('Model')
|
||||
if len(pages) == 0:
|
||||
return 'CivitAI update metadata: no models found'
|
||||
@@ -75,7 +75,7 @@ def civit_update_metadata():
|
||||
if r.status_code == 200:
|
||||
d = r.json()
|
||||
model.id = d['modelId']
|
||||
modelloader.download_civit_meta(model.fn, model.id)
|
||||
download_civit_meta(model.fn, model.id)
|
||||
fn = os.path.splitext(item['filename'])[0] + '.json'
|
||||
model.meta = readfile(fn, silent=True)
|
||||
model.name = model.meta.get('name', model.name)
|
||||
@@ -158,64 +158,8 @@ def civit_search_model(name, tag, model_type):
|
||||
return res, gr.update(visible=len(data1) > 0, value=data1 if len(data1) > 0 else []), gr.update(visible=False, value=None), gr.update(visible=False, value=None)
|
||||
|
||||
|
||||
def civit_select1(evt: gr.SelectData, in_data):
|
||||
model_id = in_data[evt.index[0]][0]
|
||||
data2 = []
|
||||
preview_img = None
|
||||
for model in data:
|
||||
if model['id'] == model_id:
|
||||
for d in model['modelVersions']:
|
||||
try:
|
||||
if d.get('images') is not None and len(d['images']) > 0 and len(d['images'][0]['url']) > 0:
|
||||
preview_img = d['images'][0]['url']
|
||||
data2.append([d.get('id', None), d.get('modelId', None) or model_id, d.get('name', None), d.get('baseModel', None), d.get('createdAt', None) or d.get('publishedAt', None)])
|
||||
except Exception as e:
|
||||
log.error(f'CivitAI select: model="{in_data[evt.index[0]]}" {e}')
|
||||
log.error(f'CivitAI version data={type(d)}: {d}')
|
||||
log.debug(f'CivitAI select: model="{in_data[evt.index[0]]}" versions={len(data2)}')
|
||||
return data2, None, preview_img
|
||||
|
||||
|
||||
def civit_select2(evt: gr.SelectData, in_data):
|
||||
variant_id = in_data[evt.index[0]][0]
|
||||
model_id = in_data[evt.index[0]][1]
|
||||
data3 = []
|
||||
for model in data:
|
||||
if model['id'] == model_id:
|
||||
for variant in model['modelVersions']:
|
||||
if variant['id'] == variant_id:
|
||||
for f in variant['files']:
|
||||
try:
|
||||
if os.path.splitext(f['name'])[1].lower() in ['.safetensors', '.ckpt', '.pt', '.pth', '.bin']:
|
||||
data3.append([f['name'], round(f['sizeKB']), json.dumps(f['metadata']), f['downloadUrl']])
|
||||
except Exception:
|
||||
pass
|
||||
log.debug(f'CivitAI select: model="{in_data[evt.index[0]]}" files={len(data3)}')
|
||||
return data3
|
||||
|
||||
|
||||
def civit_select3(evt: gr.SelectData, in_data):
|
||||
log.debug(f'CivitAI select: variant={in_data[evt.index[0]]}')
|
||||
return in_data[evt.index[0]][3], in_data[evt.index[0]][0], gr.update(interactive=True)
|
||||
|
||||
|
||||
def civit_download_model(model_url: str, model_name: str, model_path: str, model_type: str, token: str = None):
|
||||
if model_url is None or len(model_url) == 0:
|
||||
return 'No model selected'
|
||||
try:
|
||||
from modules.modelloader import download_civit_model
|
||||
res = download_civit_model(model_url, model_name, model_path, model_type, token=token)
|
||||
except Exception as e:
|
||||
res = f"CivitAI model downloaded error: model={model_url} {e}"
|
||||
log.error(res)
|
||||
return res
|
||||
from modules.sd_models import list_models # pylint: disable=W0621
|
||||
list_models()
|
||||
return res
|
||||
|
||||
|
||||
def atomic_civit_search_metadata(item, results):
|
||||
from modules.modelloader import download_civit_preview, download_civit_meta
|
||||
from modules.civitai.download_civitai import download_civit_preview, download_civit_meta
|
||||
if item is None:
|
||||
return
|
||||
try:
|
||||
@@ -344,9 +288,3 @@ def civit_search_metadata(title: str = None):
|
||||
t1 = time.time()
|
||||
log.debug(f'CivitAI search metadata: scanned={scanned} skipped={skipped} time={t1-t0:.2f}')
|
||||
return create_search_metadata_table(results)
|
||||
|
||||
|
||||
def civitai_update_token(token):
|
||||
log.debug('CivitAI update token')
|
||||
opts.civitai_token = token
|
||||
opts.save()
|
||||
|
||||
+1
-182
@@ -1,14 +1,11 @@
|
||||
import io
|
||||
import os
|
||||
import time
|
||||
import json
|
||||
import shutil
|
||||
import importlib
|
||||
import contextlib
|
||||
from typing import Dict
|
||||
from urllib.parse import urlparse
|
||||
from PIL import Image
|
||||
import rich.progress as p
|
||||
import huggingface_hub as hf
|
||||
from installer import install, log
|
||||
from modules import shared, errors, files_cache
|
||||
@@ -48,185 +45,6 @@ def hf_login(token=None):
|
||||
return True
|
||||
|
||||
|
||||
def save_video_frame(filepath: str):
|
||||
from modules import video
|
||||
try:
|
||||
frames, fps, duration, w, h, codec, frame = video.get_video_params(filepath, capture=True)
|
||||
except Exception as e:
|
||||
shared.log.error(f'Video: file={filepath} {e}')
|
||||
return None
|
||||
if frame is not None:
|
||||
basename = os.path.splitext(filepath)
|
||||
thumb = f'{basename[0]}.thumb.jpg'
|
||||
shared.log.debug(f'Video: file={filepath} frames={frames} fps={fps} size={w}x{h} codec={codec} duration={duration} thumb={thumb}')
|
||||
frame.save(thumb)
|
||||
else:
|
||||
shared.log.error(f'Video: file={filepath} no frames found')
|
||||
return frame
|
||||
|
||||
|
||||
def download_civit_meta(model_path: str, model_id):
|
||||
fn = os.path.splitext(model_path)[0] + '.json'
|
||||
url = f'https://civitai.com/api/v1/models/{model_id}'
|
||||
r = shared.req(url)
|
||||
if r.status_code == 200:
|
||||
try:
|
||||
data = r.json()
|
||||
shared.writefile(data, filename=fn, mode='w', silent=True)
|
||||
shared.log.info(f'CivitAI download: id={model_id} url={url} file="{fn}"')
|
||||
return r.status_code, len(data), '' # code/size/note
|
||||
except Exception as e:
|
||||
errors.display(e, 'civitai meta')
|
||||
shared.log.error(f'CivitAI meta: id={model_id} url={url} file="{fn}" {e}')
|
||||
return r.status_code, '', str(e)
|
||||
return r.status_code, '', ''
|
||||
|
||||
|
||||
def download_civit_preview(model_path: str, preview_url: str):
|
||||
global pbar # pylint: disable=global-statement
|
||||
if model_path is None:
|
||||
pbar = None
|
||||
return 500, '', ''
|
||||
ext = os.path.splitext(preview_url)[1]
|
||||
preview_file = os.path.splitext(model_path)[0] + ext
|
||||
is_video = preview_file.lower().endswith('.mp4')
|
||||
is_json = preview_file.lower().endswith('.json')
|
||||
if is_json:
|
||||
shared.log.warning(f'CivitAI download: url="{preview_url}" skip json')
|
||||
return 500, '', 'exepected preview image got json'
|
||||
if os.path.exists(preview_file):
|
||||
return 304, '', 'already exists'
|
||||
# res = f'CivitAI download: url={preview_url} file="{preview_file}"'
|
||||
r = shared.req(preview_url, stream=True)
|
||||
total_size = int(r.headers.get('content-length', 0))
|
||||
block_size = 16384 # 16KB blocks
|
||||
written = 0
|
||||
img = None
|
||||
shared.state.begin('CivitAI')
|
||||
if pbar is None:
|
||||
pbar = p.Progress(p.TextColumn('[cyan]Download'), p.DownloadColumn(), p.BarColumn(), p.TaskProgressColumn(), p.TimeRemainingColumn(), p.TimeElapsedColumn(), p.TransferSpeedColumn(), p.TextColumn('[yellow]{task.description}'), console=shared.console)
|
||||
try:
|
||||
with open(preview_file, 'wb') as f:
|
||||
with pbar:
|
||||
task = pbar.add_task(description=preview_file, total=total_size)
|
||||
for data in r.iter_content(block_size):
|
||||
written = written + len(data)
|
||||
f.write(data)
|
||||
pbar.update(task, advance=block_size)
|
||||
if written < 1024: # min threshold
|
||||
os.remove(preview_file)
|
||||
return 400, '', 'removed invalid download'
|
||||
if is_video:
|
||||
img = save_video_frame(preview_file)
|
||||
else:
|
||||
img = Image.open(preview_file)
|
||||
except Exception as e:
|
||||
shared.log.error(f'CivitAI download error: url={preview_url} file="{preview_file}" written={written} {e}')
|
||||
return 500, '', str(e)
|
||||
shared.state.end()
|
||||
if img is None:
|
||||
return 500, '', 'image is none'
|
||||
shared.log.info(f'CivitAI download: url={preview_url} file="{preview_file}" size={total_size} image={img.size}')
|
||||
img.close()
|
||||
return 200, str(total_size), '' # code/size/note
|
||||
|
||||
|
||||
download_pbar = None
|
||||
|
||||
def download_civit_model_thread(model_name: str, model_url: str, model_path: str = "", model_type: str = "Model", token: str = None):
|
||||
import hashlib
|
||||
sha256 = hashlib.sha256()
|
||||
sha256.update(model_url.encode('utf-8'))
|
||||
temp_file = sha256.hexdigest()[:8] + '.tmp'
|
||||
|
||||
headers = {}
|
||||
starting_pos = 0
|
||||
if os.path.isfile(temp_file):
|
||||
starting_pos = os.path.getsize(temp_file)
|
||||
headers['Range'] = f'bytes={starting_pos}-'
|
||||
if token is None:
|
||||
token = shared.opts.civitai_token
|
||||
if token is not None and len(token) > 0:
|
||||
headers['Authorization'] = f'Bearer {token}'
|
||||
|
||||
r = shared.req(model_url, headers=headers, stream=True)
|
||||
total_size = int(r.headers.get('content-length', 0))
|
||||
if model_name is None or len(model_name) == 0:
|
||||
cn = r.headers.get('content-disposition', '')
|
||||
model_name = cn.split('filename=')[-1].strip('"')
|
||||
|
||||
if model_type == 'LoRA':
|
||||
model_file = os.path.join(shared.opts.lora_dir, model_path, model_name)
|
||||
temp_file = os.path.join(shared.opts.lora_dir, model_path, temp_file)
|
||||
elif model_type == 'Embedding':
|
||||
model_file = os.path.join(shared.opts.embeddings_dir, model_path, model_name)
|
||||
temp_file = os.path.join(shared.opts.embeddings_dir, model_path, temp_file)
|
||||
elif model_type == 'VAE':
|
||||
model_file = os.path.join(shared.opts.vae_dir, model_path, model_name)
|
||||
temp_file = os.path.join(shared.opts.vae_dir, model_path, temp_file)
|
||||
else:
|
||||
model_file = os.path.join(shared.opts.ckpt_dir, model_path, model_name)
|
||||
temp_file = os.path.join(shared.opts.ckpt_dir, model_path, temp_file)
|
||||
|
||||
res = f'Model download: name="{model_name}" url="{model_url}" path="{model_path}" temp="{temp_file}"'
|
||||
if os.path.isfile(model_file):
|
||||
res += ' already exists'
|
||||
shared.log.warning(res)
|
||||
return res
|
||||
|
||||
res += f' size={round((starting_pos + total_size)/1024/1024, 2)}Mb'
|
||||
shared.log.info(res)
|
||||
shared.state.begin('CivitAI')
|
||||
block_size = 16384 # 16KB blocks
|
||||
written = starting_pos
|
||||
global download_pbar # pylint: disable=global-statement
|
||||
if download_pbar is None:
|
||||
download_pbar = p.Progress(p.TextColumn('[cyan]{task.description}'), p.DownloadColumn(), p.BarColumn(), p.TaskProgressColumn(), p.TimeRemainingColumn(), p.TimeElapsedColumn(), p.TransferSpeedColumn(), p.TextColumn('[cyan]{task.fields[name]}'), console=shared.console)
|
||||
with download_pbar:
|
||||
task = download_pbar.add_task(description="Download starting", total=starting_pos+total_size, name=model_name)
|
||||
try:
|
||||
with open(temp_file, 'ab') as f:
|
||||
for data in r.iter_content(block_size):
|
||||
if written == 0:
|
||||
try: # check if response is JSON message instead of bytes
|
||||
shared.log.error(f'Model download: response={json.loads(data.decode("utf-8"))}')
|
||||
raise ValueError('response: type=json expected=bytes')
|
||||
except Exception: # this is good
|
||||
pass
|
||||
written = written + len(data)
|
||||
f.write(data)
|
||||
download_pbar.update(task, description="Download", completed=written)
|
||||
if written < 1024: # min threshold
|
||||
os.remove(temp_file)
|
||||
raise ValueError(f'removed invalid download: bytes={written}')
|
||||
except Exception as e:
|
||||
shared.log.error(f'{res} {e}')
|
||||
finally:
|
||||
download_pbar.stop_task(task)
|
||||
download_pbar.remove_task(task)
|
||||
if starting_pos+total_size != written:
|
||||
shared.log.warning(f'{res} written={round(written/1024/1024)}Mb incomplete download')
|
||||
elif os.path.exists(temp_file):
|
||||
shared.log.debug(f'Model download complete: temp="{temp_file}" path="{model_file}"')
|
||||
os.rename(temp_file, model_file)
|
||||
shared.state.end()
|
||||
if os.path.exists(model_file):
|
||||
return model_file
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def download_civit_model(model_url: str, model_name: str, model_path: str, model_type: str, token: str = None):
|
||||
import threading
|
||||
if model_name is None or len(model_name) == 0:
|
||||
err = 'Model download: no target model name provided'
|
||||
shared.log.error(err)
|
||||
return err
|
||||
thread = threading.Thread(target=download_civit_model_thread, args=(model_name, model_url, model_path, model_type, token))
|
||||
thread.start()
|
||||
return f'Model download: name={model_name} url={model_url} path={model_path}'
|
||||
|
||||
|
||||
def download_diffusers_model(hub_id: str, cache_dir: str = None, download_config: Dict[str, str] = None, token = None, variant = None, revision = None, mirror = None, custom_pipeline = None):
|
||||
if hub_id is None or len(hub_id) == 0:
|
||||
return None
|
||||
@@ -430,6 +248,7 @@ def load_civitai(model: str, url: str):
|
||||
return name # already downloaded
|
||||
else:
|
||||
shared.log.debug(f'Reference download start: model="{name}"')
|
||||
from modules.civitai.download_civitai import download_civit_model_thread
|
||||
download_civit_model_thread(model_name=model, model_url=url, model_path='', model_type='safetensors', token=shared.opts.civitai_token)
|
||||
shared.log.debug(f'Reference download complete: model="{name}"')
|
||||
sd_models.list_models()
|
||||
|
||||
@@ -244,7 +244,8 @@ def get_closet_checkpoint_match(s: str) -> CheckpointInfo:
|
||||
|
||||
# civitai search
|
||||
if shared.opts.sd_checkpoint_autodownload and s.startswith("https://civitai.com/api/download/models"):
|
||||
fn = modelloader.download_civit_model_thread(model_name=None, model_url=s, model_path='', model_type='Model', token=None)
|
||||
from modules.civitai.download_civitai import download_civit_model_thread
|
||||
fn = download_civit_model_thread(model_name=None, model_url=s, model_path='', model_type='Model', token=None)
|
||||
if fn is not None:
|
||||
checkpoint_info = CheckpointInfo(fn)
|
||||
return checkpoint_info
|
||||
|
||||
+25
-11
@@ -514,26 +514,43 @@ options_templates.update(options_section(('image-metadata', "Image Metadata"), {
|
||||
}))
|
||||
|
||||
options_templates.update(options_section(('ui', "User Interface"), {
|
||||
"themes_sep_ui": OptionInfo("<h2>Theme options</h2>", "", gr.HTML),
|
||||
"theme_type": OptionInfo("Standard", "Theme type", gr.Radio, {"choices": ["Modern", "Standard", "None"]}),
|
||||
"theme_style": OptionInfo("Auto", "Theme mode", gr.Radio, {"choices": ["Auto", "Dark", "Light"]}),
|
||||
"gradio_theme": OptionInfo("black-teal", "UI theme", gr.Dropdown, lambda: {"choices": theme.list_themes()}, refresh=theme.refresh_themes),
|
||||
"ui_locale": OptionInfo("Auto", "UI locale", gr.Dropdown, lambda: {"choices": theme.list_locales()}),
|
||||
"subpath": OptionInfo("", "Mount URL subpath"),
|
||||
|
||||
"quicksetting_sep_images": OptionInfo("<h2>Quicksettings</h2>", "", gr.HTML),
|
||||
"quicksettings_list": OptionInfo(["sd_model_checkpoint"], "Quicksettings list", gr.Dropdown, lambda: {"multiselect":True, "choices": opts.list()}),
|
||||
|
||||
"server_sep_ui": OptionInfo("<h2>Startup & Server Options</h2>", "", gr.HTML),
|
||||
"autolaunch": OptionInfo(False, "Autolaunch browser upon startup"),
|
||||
"motd": OptionInfo(False, "Show MOTD"),
|
||||
"subpath": OptionInfo("", "Mount URL subpath"),
|
||||
"ui_request_timeout": OptionInfo(30000, "UI request timeout", gr.Slider, {"minimum": 1000, "maximum": 120000, "step": 10}),
|
||||
|
||||
"cards_sep_ui": OptionInfo("<h2>Card options</h2>", "", gr.HTML),
|
||||
"extra_networks_card_size": OptionInfo(140, "UI card size (px)", gr.Slider, {"minimum": 20, "maximum": 2000, "step": 1}),
|
||||
"extra_networks_card_cover": OptionInfo("sidebar", "UI position", gr.Radio, {"choices": ["cover", "inline", "sidebar"]}),
|
||||
"extra_networks_card_square": OptionInfo(True, "UI disable variable aspect ratio"),
|
||||
|
||||
"other_sep_ui": OptionInfo("<h2>Other...</h2>", "", gr.HTML),
|
||||
"ui_locale": OptionInfo("Auto", "UI locale", gr.Dropdown, lambda: {"choices": theme.list_locales()}),
|
||||
"font_size": OptionInfo(14, "Font size", gr.Slider, {"minimum": 8, "maximum": 32, "step": 1}),
|
||||
"aspect_ratios": OptionInfo("1:1, 4:3, 3:2, 16:9, 16:10, 21:9, 2:3, 3:4, 9:16, 10:16, 9:21", "Allowed aspect ratios"),
|
||||
"logmonitor_show": OptionInfo(True, "Show log view"),
|
||||
"logmonitor_refresh_period": OptionInfo(5000, "Log view update period", gr.Slider, {"minimum": 0, "maximum": 30000, "step": 25}),
|
||||
"ui_request_timeout": OptionInfo(30000, "UI request timeout", gr.Slider, {"minimum": 1000, "maximum": 120000, "step": 10}),
|
||||
"motd": OptionInfo(False, "Show MOTD"),
|
||||
"compact_view": OptionInfo(False, "Compact view"),
|
||||
"ui_columns": OptionInfo(4, "Gallery view columns", gr.Slider, {"minimum": 1, "maximum": 8, "step": 1}),
|
||||
|
||||
"images_sep_log": OptionInfo("<h2>Log Display</h2>", "", gr.HTML),
|
||||
"logmonitor_show": OptionInfo(True, "Show log view"),
|
||||
"logmonitor_refresh_period": OptionInfo(5000, "Log view update period", gr.Slider, {"minimum": 0, "maximum": 30000, "step": 25}),
|
||||
|
||||
"images_sep_ui": OptionInfo("<h2>Outputs & Images</h2>", "", gr.HTML),
|
||||
"return_grid": OptionInfo(True, "Show grid in results"),
|
||||
"return_mask": OptionInfo(False, "Inpainting include greyscale mask in results"),
|
||||
"return_mask_composite": OptionInfo(False, "Inpainting include masked composite in results"),
|
||||
"send_seed": OptionInfo(True, "Send seed when sending prompt or image to other interface", gr.Checkbox, {"visible": False}),
|
||||
"send_size": OptionInfo(False, "Send size when sending prompt or image to another interface", gr.Checkbox, {"visible": False}),
|
||||
"quicksettings_list": OptionInfo(["sd_model_checkpoint"], "Quicksettings list", gr.Dropdown, lambda: {"multiselect":True, "choices": opts.list()}),
|
||||
|
||||
}))
|
||||
|
||||
options_templates.update(options_section(('live-preview', "Live Previews"), {
|
||||
@@ -642,11 +659,8 @@ options_templates.update(options_section(('extra_networks', "Networks"), {
|
||||
"extra_networks": OptionInfo(["All"], "Available networks", gr.Dropdown, lambda: {"multiselect":True, "choices": ['All'] + [en.title for en in extra_networks]}),
|
||||
"extra_networks_sort": OptionInfo("Default", "Sort order", gr.Dropdown, {"choices": ['Default', 'Name [A-Z]', 'Name [Z-A]', 'Date [Newest]', 'Date [Oldest]', 'Size [Largest]', 'Size [Smallest]']}),
|
||||
"extra_networks_view": OptionInfo("gallery", "UI view", gr.Radio, {"choices": ["gallery", "list"]}),
|
||||
"extra_networks_card_cover": OptionInfo("sidebar", "UI position", gr.Radio, {"choices": ["cover", "inline", "sidebar"]}),
|
||||
"extra_networks_height": OptionInfo(0, "UI height (%)", gr.Slider, {"minimum": 0, "maximum": 100, "step": 1}), # set in ui_javascript
|
||||
"extra_networks_sidebar_width": OptionInfo(35, "UI sidebar width (%)", gr.Slider, {"minimum": 10, "maximum": 80, "step": 1}),
|
||||
"extra_networks_card_size": OptionInfo(140, "UI card size (px)", gr.Slider, {"minimum": 20, "maximum": 2000, "step": 1}),
|
||||
"extra_networks_card_square": OptionInfo(True, "UI disable variable aspect ratio"),
|
||||
"extra_networks_height": OptionInfo(0, "UI height (%)", gr.Slider, {"minimum": 0, "maximum": 100, "step": 1}), # set in ui_javascript
|
||||
"extra_networks_fetch": OptionInfo(True, "UI fetch network info on mouse-over"),
|
||||
"extra_network_skip_indexing": OptionInfo(False, "Build info on first access", gr.Checkbox),
|
||||
|
||||
|
||||
+25
-64
@@ -475,13 +475,28 @@ def create_ui():
|
||||
html = create_model_cards(results)
|
||||
return html
|
||||
|
||||
def civitai_update_token(token):
|
||||
log.debug('CivitAI update token')
|
||||
opts.civitai_token = token
|
||||
opts.save()
|
||||
|
||||
def civitai_download(model_url, model_name, model_type, model_path, civit_token, model_output):
|
||||
from modules.civitai.download_civitai import download_civit_model
|
||||
msg = f"<h4>Initiating download</h4><div>{model_name} | {model_type} | <a href='{model_url}'>{model_url}</a></div><br>"
|
||||
yield msg + model_output
|
||||
download_civit_model(model_url, model_name, model_path, model_type, civit_token)
|
||||
yield model_output
|
||||
|
||||
with gr.Row():
|
||||
gr.HTML('<h2>Search & Download</h2>')
|
||||
with gr.Row(elem_id='civitai_search_row'):
|
||||
civit_search_text = gr.Textbox(label='', placeholder='keyword', elem_id="civit_search_text")
|
||||
civit_search_tag = gr.Textbox(label='', placeholder='tag', elem_id="civit_search_text")
|
||||
civit_search_text_btn = ToolButton(value=ui_symbols.search, interactive=True)
|
||||
with gr.Accordion(label='Search options', open=False, elem_id="civitai_search_options"):
|
||||
with gr.Accordion(label='Advanced', open=False, elem_id="civitai_search_options"):
|
||||
civit_download_btn = gr.Button(value="Download model", variant='primary', elem_id="civitai_download_btn", visible=False)
|
||||
with gr.Row():
|
||||
civit_token = gr.Textbox(opts.civitai_token, label='CivitAI token', placeholder='optional access token for private or gated models')
|
||||
with gr.Row():
|
||||
civit_nsfw = gr.Checkbox(label='NSFW allowed', value=True)
|
||||
with gr.Row():
|
||||
@@ -489,71 +504,17 @@ def create_ui():
|
||||
with gr.Row():
|
||||
civit_base = gr.Textbox(label='Base model', placeholder='SDXL, ...')
|
||||
with gr.Row():
|
||||
civit_token = gr.Textbox(opts.civitai_token, label='CivitAI token', placeholder='optional access token for private or gated models')
|
||||
civit_folder = gr.Textbox(label='Download folder', placeholder='optional folder for downloads')
|
||||
with gr.Row():
|
||||
civitai_models_output = gr.HTML('', elem_id="civitai_models_output")
|
||||
# sort, period, limit
|
||||
_dummy = gr.Label(visible=False) # dummy component to get argspec later
|
||||
civit_inputs = [civit_search_text, civit_search_tag, civit_nsfw, civit_type, civit_base, civit_token]
|
||||
civit_search_text_btn.click(fn=civitai_search, inputs=civit_inputs, outputs=[models_outcome])
|
||||
civit_search_text.submit(fn=civitai_search, inputs=civit_inputs, outputs=[models_outcome])
|
||||
civit_search_tag.submit(fn=civitai_search, inputs=civit_inputs, outputs=[models_outcome])
|
||||
|
||||
"""
|
||||
from modules.civitai.legacy_civitai import civitai_update_token, civit_search_model, civit_search_metadata, civit_select1, civit_select2, civit_select3, civit_download_model
|
||||
|
||||
with gr.Row():
|
||||
gr.HTML('<h2>Search for models</h2>')
|
||||
with gr.Row():
|
||||
with gr.Column(scale=1):
|
||||
civit_model_type = gr.Dropdown(label='CivitAI model type', choices=['Model', 'LoRA', 'Embedding', 'VAE', 'Other'], value='Model')
|
||||
with gr.Column(scale=15):
|
||||
with gr.Row():
|
||||
civit_search_text = gr.Textbox('', label='Search models', placeholder='keyword')
|
||||
civit_search_tag = gr.Textbox('', label='', placeholder='tags')
|
||||
civit_search_btn = ToolButton(value=ui_symbols.search, interactive=True)
|
||||
with gr.Row():
|
||||
civit_search_res = gr.HTML('')
|
||||
with gr.Row():
|
||||
gr.HTML('<h2> CivitAI download model<br></h2>')
|
||||
with gr.Row():
|
||||
civit_download_model_btn = gr.Button(value="Download", variant='primary')
|
||||
gr.HTML('<span style="line-height: 2em">Select a model, model version and and model variant from the search results to download or enter model URL manually</span><br>')
|
||||
with gr.Row():
|
||||
civit_token = gr.Textbox(opts.civitai_token, label='CivitAI token', placeholder='optional access token for private or gated models')
|
||||
civit_token.change(fn=civitai_update_token, inputs=[civit_token], outputs=[])
|
||||
with gr.Row():
|
||||
civit_name = gr.Textbox('', label='Model name', placeholder='select model from search results', visible=True)
|
||||
civit_selected = gr.Textbox('', label='Model URL', placeholder='select model from search results', visible=True)
|
||||
civit_path = gr.Textbox('', label='Download path', placeholder='optional subfolder path where to save model', visible=True)
|
||||
with gr.Row():
|
||||
gr.HTML('<h2>Search results</h2>')
|
||||
with gr.Row():
|
||||
civit_headers1 = ['ID', 'Name', 'Tags', 'Downloads', 'Rating']
|
||||
civit_types1 = ['number', 'str', 'str', 'number', 'number']
|
||||
civit_results1 = gr.DataFrame(value=None, label=None, show_label=False, interactive=False, wrap=True, headers=civit_headers1, datatype=civit_types1, type='array', visible=False)
|
||||
with gr.Row():
|
||||
with gr.Column():
|
||||
civit_headers2 = ['ID', 'ModelID', 'Name', 'Base', 'Created', 'Preview']
|
||||
civit_types2 = ['number', 'number', 'str', 'str', 'date', 'str']
|
||||
civit_results2 = gr.DataFrame(value=None, label='Model versions', show_label=True, interactive=False, wrap=True, headers=civit_headers2, datatype=civit_types2, type='array', visible=False)
|
||||
with gr.Column():
|
||||
civit_headers3 = ['Name', 'Size', 'Metadata', 'URL']
|
||||
civit_types3 = ['str', 'number', 'str', 'str']
|
||||
civit_results3 = gr.DataFrame(value=None, label='Model variants', show_label=True, interactive=False, wrap=True, headers=civit_headers3, datatype=civit_types3, type='array', visible=False)
|
||||
|
||||
def is_visible(component):
|
||||
visible = len(component) > 0 if component is not None else False
|
||||
return gr.update(visible=visible)
|
||||
|
||||
civit_search_text.submit(fn=civit_search_model, inputs=[civit_search_text, civit_search_tag, civit_model_type], outputs=[civit_search_res, civit_results1, civit_results2, civit_results3])
|
||||
civit_search_tag.submit(fn=civit_search_model, inputs=[civit_search_text, civit_search_tag, civit_model_type], outputs=[civit_search_res, civit_results1, civit_results2, civit_results3])
|
||||
civit_search_btn.click(fn=civit_search_model, inputs=[civit_search_text, civit_search_tag, civit_model_type], outputs=[civit_search_res, civit_results1, civit_results2, civit_results3])
|
||||
civit_results1.select(fn=civit_select1, inputs=[civit_results1], outputs=[civit_results2, civit_results3, models_image])
|
||||
civit_results2.select(fn=civit_select2, inputs=[civit_results2], outputs=[civit_results3])
|
||||
civit_results3.select(fn=civit_select3, inputs=[civit_results3], outputs=[civit_selected, civit_name, civit_search_btn])
|
||||
civit_results1.change(fn=is_visible, inputs=[civit_results1], outputs=[civit_results1])
|
||||
civit_results2.change(fn=is_visible, inputs=[civit_results2], outputs=[civit_results2])
|
||||
civit_results3.change(fn=is_visible, inputs=[civit_results3], outputs=[civit_results3])
|
||||
civit_download_model_btn.click(fn=civit_download_model, inputs=[civit_selected, civit_name, civit_path, civit_model_type, civit_token], outputs=[models_outcome])
|
||||
"""
|
||||
civit_search_text_btn.click(fn=civitai_search, inputs=civit_inputs, outputs=[civitai_models_output])
|
||||
civit_search_text.submit(fn=civitai_search, inputs=civit_inputs, outputs=[civitai_models_output])
|
||||
civit_search_tag.submit(fn=civitai_search, inputs=civit_inputs, outputs=[civitai_models_output])
|
||||
civit_token.change(fn=civitai_update_token, inputs=[civit_token], outputs=[])
|
||||
civit_download_btn.click(fn=civitai_download, _js="downloadCivitModel", inputs=[_dummy, _dummy, _dummy, civit_folder, civit_token, civitai_models_output], outputs=[civitai_models_output])
|
||||
|
||||
with gr.Tab(label="Huggingface", elem_id="models_huggingface_tab"):
|
||||
from modules.models_hf import hf_search, hf_select, hf_download_model, hf_update_token
|
||||
|
||||
Reference in New Issue
Block a user