Support numeric values in inputs and enhance image generation configs

Updated `SelectInput` and `OptionInput` to allow `value` as `string | number`. Extended image generation configurations with new features, including `cfg_rescale`, `noise_schedule`, and vibe data handling. Improved the setup for reference images and added support for mnemonist dependency in the package manager.
This commit is contained in:
YH_KIM
2025-05-03 16:38:04 +09:00
parent 21561fe5ff
commit 5b0ca460a5
7 changed files with 284 additions and 72 deletions

15
pnpm-lock.yaml generated
View File

@@ -158,6 +158,9 @@ importers:
ml-distance:
specifier: ^4.0.1
version: 4.0.1
mnemonist:
specifier: ^0.40.3
version: 0.40.3
mobile-drag-drop:
specifier: 3.0.0-rc.0
version: 3.0.0-rc.0
@@ -2756,6 +2759,9 @@ packages:
ml-tree-similarity@1.0.0:
resolution: {integrity: sha512-XJUyYqjSuUQkNQHMscr6tcjldsOoAekxADTplt40QKfwW6nd++1wHWV9AArl0Zvw/TIHgNaZZNvr8QGvE8wLRg==}
mnemonist@0.40.3:
resolution: {integrity: sha512-Vjyr90sJ23CKKH/qPAgUKicw/v6pRoamxIEDFOF8uSgFME7DqPRpHgRTejWVjkdGg5dXj0/NyxZHZ9bcjH+2uQ==}
mobile-drag-drop@3.0.0-rc.0:
resolution: {integrity: sha512-f8wIDTbBYLBW/+5sei1cqUE+StyDpf/LP+FRZELlVX6tmOOmELk84r3wh1z3woxCB9G5octhF06K5COvFjGgqg==}
@@ -2900,6 +2906,9 @@ packages:
object-inspect@1.13.1:
resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==}
obliterator@2.0.5:
resolution: {integrity: sha512-42CPE9AhahZRsMNslczq0ctAEtqk8Eka26QofnqC346BZdHDySk3LWka23LI7ULIw11NmltpiLagIq8gBozxTw==}
ollama@0.5.0:
resolution: {integrity: sha512-CRtRzsho210EGdK52GrUMohA2pU+7NbgEaBG3DcYeRmvQthDO7E2LHOkLlUUeaYUlNmEd8icbjC02ug9meSYnw==}
@@ -6505,6 +6514,10 @@ snapshots:
binary-search: 1.3.6
num-sort: 2.1.0
mnemonist@0.40.3:
dependencies:
obliterator: 2.0.5
mobile-drag-drop@3.0.0-rc.0: {}
modify-values@1.0.1: {}
@@ -6665,6 +6678,8 @@ snapshots:
object-inspect@1.13.1: {}
obliterator@2.0.5: {}
ollama@0.5.0:
dependencies:
whatwg-fetch: 3.6.20

View File

@@ -3,6 +3,7 @@
import { language } from "src/lang";
import Help from "src/lib/Others/Help.svelte";
import { selectSingleFile } from "src/ts/util";
import { alertError } from "src/ts/alert";
import { DBState } from 'src/ts/stores.svelte';
import { isTauri, saveAsset } from "src/ts/globalApi.svelte";
@@ -39,6 +40,7 @@
autoSmea:false,
legacy_uc:false,
use_coords:false,
cfg_rescale:0,
v4_prompt:{
caption:{
base_caption:'',
@@ -53,7 +55,12 @@
char_captions:[]
},
legacy_uc:false,
}
},
reference_image_multiple: [],
reference_strength_multiple: [0.7],
vibe_data: undefined,
vibe_model_selection: undefined,
noise_schedule: 'karras'
}
if (DBState.db.NAIImgConfig.sampler === 'ddim_v3'){
DBState.db.NAIImgConfig.sm = false
@@ -250,6 +257,13 @@
<span class="text-textcolor">CFG scale</span>
<NumberInput size="sm" marginBottom min={0} max={2048} bind:value={DBState.db.NAIImgConfig.scale}/>
<span class="text-textcolor">Noise Schedule</span>
<SelectInput className="mt-2 mb-4" bind:value={DBState.db.NAIImgConfig.noise_schedule}>
<OptionInput value="karras">karras</OptionInput>
<OptionInput value="exponential">exponential</OptionInput>
<OptionInput value="polyexponential">polyexponential</OptionInput>
</SelectInput>
{#if !DBState.db.NAII2I || DBState.db.NAIImgConfig.sampler !== 'ddim_v3'}
<Check bind:check={DBState.db.NAIImgConfig.sm} name="Use SMEA"/>
{:else if DBState.db.NAIImgModel === 'nai-diffusion-4-full'
@@ -260,13 +274,17 @@
{#if DBState.db.NAIImgModel === 'nai-diffusion-4-full'
|| DBState.db.NAIImgModel === 'nai-diffusion-4-curated-preview'}
<span class="text-textcolor">Prompt Guidance Rescale</span>
<SliderInput marginBottom min={0} max={1} step={0.02} fixed={2} bind:value={DBState.db.NAIImgConfig.cfg_rescale} />
<Check bind:check={DBState.db.NAIImgConfig.autoSmea} name='Auto Smea'/>
<Check bind:check={DBState.db.NAIImgConfig.use_coords} name='Use coords'/>
<Check bind:check={DBState.db.NAIImgConfig.legacy_uc} name='Use legacy uc'/>
<Check bind:check={DBState.db.NAIImgConfig.v4_prompt.use_coords} name='Use v4 prompt coords'/>
<Check bind:check={DBState.db.NAIImgConfig.v4_prompt.use_order} name='Use v4 prompt order'/>
<Check bind:check={DBState.db.NAIImgConfig.v4_negative_prompt.legacy_uc} name='Use v4 negative prompt legacy uc'/>
{/if}
@@ -308,43 +326,138 @@
<Check bind:check={DBState.db.NAIREF} name="Enable Reference" className="mt-4"/>
{#if DBState.db.NAIREF}
<!--{#if DBState.db.NAIREF}-->
<!-- <span class="text-textcolor mt-4">Information Extracted</span>-->
<!-- <SliderInput min={0} max={1} step={0.01} bind:value={DBState.db.NAIImgConfig.InfoExtracted}/>-->
<!-- <span class="text-textcolor2 mb-6 text-sm">{DBState.db.NAIImgConfig.InfoExtracted}</span>-->
<!-- <span class="text-textcolor">Reference Strength</span>-->
<!-- <SliderInput min={0} max={1} step={0.01} bind:value={DBState.db.NAIImgConfig.RefStrength}/>-->
<!-- <span class="text-textcolor2 mb-6 text-sm">{DBState.db.NAIImgConfig.RefStrength}</span>-->
<!-- <span class="text-textcolor">Reference image</span>-->
<!-- <button onclick={async () => {-->
<!-- const img = await selectSingleFile([-->
<!-- 'jpg',-->
<!-- 'jpeg',-->
<!-- 'png',-->
<!-- 'webp'-->
<!-- ])-->
<!-- if(!img){-->
<!-- return null-->
<!-- }-->
<!-- const saveId = await saveAsset(img.data)-->
<!-- DBState.db.NAIImgConfig.refimage = saveId-->
<!-- }}>-->
<!-- {#if DBState.db.NAIImgConfig.refimage === ''}-->
<!-- <div class="rounded-md h-20 w-20 shadow-lg bg-textcolor2 cursor-pointer hover:text-green-500"></div>-->
<!-- {:else}-->
<!-- {#await getCharImage(DBState.db.NAIImgConfig.refimage, 'css')}-->
<!-- <div class="rounded-md h-20 w-20 shadow-lg bg-textcolor2 cursor-pointer hover:text-green-500"></div>-->
<!-- {:then im}-->
<!-- <div class="rounded-md h-20 w-20 shadow-lg bg-textcolor2 cursor-pointer hover:text-green-500" style={im}></div>-->
<!-- {/await}-->
<!-- {/if}-->
<!-- </button>-->
<!--{/if}-->
<span class="text-textcolor mt-4">Information Extracted</span>
<SliderInput min={0} max={1} step={0.01} bind:value={DBState.db.NAIImgConfig.InfoExtracted}/>
<span class="text-textcolor2 mb-6 text-sm">{DBState.db.NAIImgConfig.InfoExtracted}</span>
<span class="text-textcolor">Reference Strength</span>
<SliderInput min={0} max={1} step={0.01} bind:value={DBState.db.NAIImgConfig.RefStrength}/>
<span class="text-textcolor2 mb-6 text-sm">{DBState.db.NAIImgConfig.RefStrength}</span>
<span class="text-textcolor">Reference image</span>
<span class="text-textcolor mt-4">Vibe</span>
<button onclick={async () => {
const img = await selectSingleFile([
'jpg',
'jpeg',
'png',
'webp'
])
if(!img){
const file = await selectSingleFile(['naiv4vibe'])
if(!file){
return null
}
const saveId = await saveAsset(img.data)
DBState.db.NAIImgConfig.refimage = saveId
try {
const vibeData = JSON.parse(new TextDecoder().decode(file.data))
if (vibeData.version !== 1 || vibeData.identifier !== "novelai-vibe-transfer") {
alertError("Invalid vibe file. Version must be 1.")
return
}
// Store the vibe data
DBState.db.NAIImgConfig.vibe_data = vibeData
// Set the thumbnail as preview image for display
if (vibeData.thumbnail) {
// Clear the array and add the thumbnail
DBState.db.NAIImgConfig.reference_image_multiple = [];
// Set default model selection based on current model
if (DBState.db.NAIImgModel.includes('nai-diffusion-4-full')) {
DBState.db.NAIImgConfig.vibe_model_selection = 'v4full';
} else if (DBState.db.NAIImgModel.includes('nai-diffusion-4-curated')) {
DBState.db.NAIImgConfig.vibe_model_selection = 'v4curated';
}
// Set InfoExtracted to the first value for the selected model
const selectedModel = DBState.db.NAIImgConfig.vibe_model_selection;
if (selectedModel && vibeData.encodings[selectedModel]) {
const encodings = vibeData.encodings[selectedModel];
const firstKey = Object.keys(encodings)[0];
if (firstKey) {
DBState.db.NAIImgConfig.InfoExtracted = Number(encodings[firstKey].params.information_extracted);
}
}
}
// Initialize reference_strength_multiple if not set
if (!DBState.db.NAIImgConfig.reference_strength_multiple || !Array.isArray(DBState.db.NAIImgConfig.reference_strength_multiple)) {
DBState.db.NAIImgConfig.reference_strength_multiple = [0.7];
}
} catch (error) {
alertError("Error parsing vibe file: " + error)
}
}}>
{#if DBState.db.NAIImgConfig.refimage === ''}
<div class="rounded-md h-20 w-20 shadow-lg bg-textcolor2 cursor-pointer hover:text-green-500"></div>
{:else}
{#await getCharImage(DBState.db.NAIImgConfig.refimage, 'css')}
<div class="rounded-md h-20 w-20 shadow-lg bg-textcolor2 cursor-pointer hover:text-green-500"></div>
{:then im}
<div class="rounded-md h-20 w-20 shadow-lg bg-textcolor2 cursor-pointer hover:text-green-500" style={im}></div>
{/await}
{/if}
<div class="rounded-md h-20 w-20 shadow-lg bg-textcolor2 cursor-pointer hover:text-green-500 flex items-center justify-center">
<span class="text-sm">Upload Vibe</span>
</div>
</button>
{#if DBState.db.NAIImgConfig.vibe_data}
<div class="mt-2 relative">
<img src={DBState.db.NAIImgConfig.vibe_data.thumbnail} alt="Vibe Preview" class="rounded-md h-60 shadow-lg" />
<button
onclick={() => {
DBState.db.NAIImgConfig.vibe_data = undefined;
DBState.db.NAIImgConfig.vibe_model_selection = undefined;
}}
class="absolute top-2 right-2 bg-red-500 hover:bg-red-700 text-white font-bold py-1 px-2 rounded"
>
Delete
</button>
</div>
<span class="text-textcolor mt-4">Vibe Model</span>
<SelectInput className="mt-2 mb-4" bind:value={DBState.db.NAIImgConfig.vibe_model_selection} onchange={(e) => {
// When vibe model changes, set InfoExtracted to the first value
if (DBState.db.NAIImgConfig.vibe_data?.encodings &&
DBState.db.NAIImgConfig.vibe_model_selection &&
DBState.db.NAIImgConfig.vibe_data.encodings[DBState.db.NAIImgConfig.vibe_model_selection]) {
const encodings = DBState.db.NAIImgConfig.vibe_data.encodings[DBState.db.NAIImgConfig.vibe_model_selection];
const firstKey = Object.keys(encodings)[0];
if (firstKey) {
DBState.db.NAIImgConfig.InfoExtracted = Number(encodings[firstKey].params.information_extracted);
}
}
}}>
{#if DBState.db.NAIImgConfig.vibe_data.encodings?.v4full}
<OptionInput value="v4full">nai-diffusion-4-full</OptionInput>
{/if}
{#if DBState.db.NAIImgConfig.vibe_data.encodings?.v4curated}
<OptionInput value="v4curated">nai-diffusion-4-curated</OptionInput>
{/if}
</SelectInput>
<span class="text-textcolor mt-4">Information Extracted</span>
<SelectInput className="mt-2 mb-4" bind:value={DBState.db.NAIImgConfig.InfoExtracted}>
{#if DBState.db.NAIImgConfig.vibe_model_selection && DBState.db.NAIImgConfig.vibe_data.encodings[DBState.db.NAIImgConfig.vibe_model_selection]}
{#each Object.entries(DBState.db.NAIImgConfig.vibe_data.encodings[DBState.db.NAIImgConfig.vibe_model_selection]) as [key, value]}
<OptionInput value={value.params.information_extracted}>{value.params.information_extracted}</OptionInput>
{/each}
{/if}
</SelectInput>
<span class="text-textcolor mt-4">Reference Strength Multiple</span>
<SliderInput marginBottom min={0} max={1} step={0.1} fixed={2} bind:value={DBState.db.NAIImgConfig.reference_strength_multiple[0]} />
{/if}
{/if}

View File

@@ -1,7 +1,7 @@
<option value={value} selected={selected} class="bg-darkbg appearance-none">{@render children?.()}</option>
<script lang="ts">
interface Props {
value: string;
value: string | number;
selected?: boolean;
children?: import('svelte').Snippet;
}

View File

@@ -17,7 +17,7 @@
</select>
<script lang="ts">
interface Props {
value: string;
value: string | number;
className?: string;
size?: 'sm'|'md'|'lg'|'xl';
children?: import('svelte').Snippet;

View File

@@ -1,10 +1,10 @@
export function declareTest() {
if(import.meta.env.DEV){
globalThis.test = async () => {
const d = await import("./test.js")
return d.test()
}
}
// if(import.meta.env.DEV){
// globalThis.test = async () => {
// const d = await import("./test.js")
// return d.test()
// }
// }
}

View File

@@ -132,7 +132,7 @@ export async function generateAIImage(genPrompt:string, currentChar:character, n
"parameters": {
"params_version": 3,
"add_original_image": true,
"cfg_rescale": 0,
"cfg_rescale": db.NAIImgConfig.cfg_rescale,
"controlnet_strength": 1,
"dynamic_thresholding": false,
"n_samples": 1,
@@ -145,20 +145,22 @@ export async function generateAIImage(genPrompt:string, currentChar:character, n
"sm": false,
"sm_dyn": false,
"noise": db.NAIImgConfig.noise,
"noise_schedule": "native",
"noise_schedule": "karras",
"normalize_reference_strength_multiple":false,
"strength": db.NAIImgConfig.strength,
"ucPreset": 3,
"uncond_scale": 1,
"qualityToggle": false,
"lagacy_v3_extend": false,
"lagacy": false,
"reference_information_extracted": db.NAIImgConfig.InfoExtracted,
"reference_strength": db.NAIImgConfig.RefStrength,
"legacy_v3_extend": false,
"legacy": false,
// "reference_information_extracted": db.NAIImgConfig.InfoExtracted,
// Only set reference_strength if we're not using reference_strength_multiple
"reference_strength": db.NAIImgConfig.reference_strength_multiple !== undefined ? undefined : db.NAIImgConfig.RefStrength,
//add v4
"autoSmea": db.NAIImgConfig.autoSmea,
use_coords: db.NAIImgConfig.use_coords,
legacy_uc: db.NAIImgConfig.legacy_uc,
v4_prompt:{
"use_coords": db.NAIImgConfig.use_coords,
"legacy_uc": db.NAIImgConfig.legacy_uc,
"v4_prompt":{
caption:{
base_caption:genPrompt,
char_captions: []
@@ -172,7 +174,9 @@ export async function generateAIImage(genPrompt:string, currentChar:character, n
char_captions: []
},
legacy_uc: db.NAIImgConfig.v4_negative_prompt.legacy_uc,
}
},
"reference_image_multiple" : [],
"reference_strength_multiple" : [],
}
},
headers:{
@@ -181,6 +185,44 @@ export async function generateAIImage(genPrompt:string, currentChar:character, n
rawResponse: true
}
// Add vibe reference_image_multiple if exists
if(db.NAIImgConfig.vibe_data) {
const vibeData = db.NAIImgConfig.vibe_data;
// Determine which model to use based on vibe_model_selection or fallback to current model
const modelKey = db.NAIImgConfig.vibe_model_selection ||
(db.NAIImgModel.includes('nai-diffusion-4-full') ? 'v4full' :
db.NAIImgModel.includes('nai-diffusion-4-curated') ? 'v4curated' : null);
if(modelKey && vibeData.encodings && vibeData.encodings[modelKey]) {
// Initialize arrays if they don't exist
if(!commonReq.body.parameters.reference_image_multiple) {
commonReq.body.parameters.reference_image_multiple = [];
}
if(!commonReq.body.parameters.reference_strength_multiple) {
commonReq.body.parameters.reference_strength_multiple = [];
}
// Use selected encoding or first available
let encodingKey = db.NAIImgConfig.vibe_model_selection ?
Object.keys(vibeData.encodings[modelKey]).find(key =>
vibeData.encodings[modelKey][key].params.information_extracted ===
(db.NAIImgConfig.InfoExtracted || 1)) :
Object.keys(vibeData.encodings[modelKey])[0];
if(encodingKey) {
const encoding = vibeData.encodings[modelKey][encodingKey].encoding;
// Add encoding to the array
commonReq.body.parameters.reference_image_multiple.push(encoding);
// Add reference_strength_multiple if it exists
const strength = db.NAIImgConfig.reference_strength_multiple &&
db.NAIImgConfig.reference_strength_multiple.length > 0 ?
db.NAIImgConfig.reference_strength_multiple[0] : 0.5;
commonReq.body.parameters.reference_strength_multiple.push(strength);
}
}
}
if(db.NAII2I){
let seed = Math.floor(Math.random() * 10000000000)
@@ -211,6 +253,8 @@ export async function generateAIImage(genPrompt:string, currentChar:character, n
if(refimgbase64 !== undefined){
reqlist.body.parameters.reference_image = refimgbase64
}
console.log({img2img:reqlist});
}else{
@@ -228,10 +272,12 @@ export async function generateAIImage(genPrompt:string, currentChar:character, n
reqlist = commonReq;
reqlist.body.action = 'generate';
reqlist.body.parameters.reference_image = base64img;
console.log({generate:reqlist});
} else {
reqlist = commonReq;
reqlist.body.action = 'generate';
console.log({nothing:reqlist});
}
}

View File

@@ -269,6 +269,7 @@ export function setDatabase(data:Database){
autoSmea:false,
legacy_uc:false,
use_coords:false,
cfg_rescale:0,
v4_prompt:{
caption:{
base_caption:'',
@@ -307,6 +308,9 @@ export function setDatabase(data:Database){
legacy_uc:false,
};
}
if(checkNullish(data.NAIImgConfig.cfg_rescale)){
data.NAIImgConfig.cfg_rescale = 0;
}
if(checkNullish(data.customTextTheme)){
data.customTextTheme = {
FontColorStandard: "#f8f8f2",
@@ -1418,12 +1422,17 @@ export interface NAIImgConfig{
InfoExtracted:number,
RefStrength:number
//add 4
cfg_rescale:number,
autoSmea:boolean,
use_coords:boolean,
legacy_uc: boolean,
v4_prompt:NAIImgConfigV4Prompt,
v4_negative_prompt:NAIImgConfigV4NegativePrompt,
//add vibe
reference_image_multiple?:string[],
reference_strength_multiple?:number[],
vibe_data?:NAIVibeData,
vibe_model_selection?:string
}
//add 4
@@ -1452,6 +1461,35 @@ interface NAIImgConfigV4CharCaption{
}[]
}
// NAI Vibe Data interfaces
interface NAIVibeData {
identifier: string;
version: number;
type: string;
image: string;
id: string;
encodings: {
[key: string]: {
[key: string]: NAIVibeEncoding;
}
};
name: string;
thumbnail: string;
createdAt: number;
importInfo: {
model: string;
information_extracted: number;
strength: number;
};
}
interface NAIVibeEncoding {
encoding: string;
params: {
information_extracted: number;
};
}
interface ComfyConfig{
workflow:string,
posNodeID: string,