Add support for NovelAI V4 model and configuration settings (#816)

# PR Checklist
- [ ] Have you checked if it works normally in all models? *Ignore this
if it doesn't use models.*
- [ ] Have you checked if it works normally in all web, local, and node
hosted versions? If it doesn't, have you blocked it in those versions?
- [ ] Have you added type definitions?

# Description
Add and enable temporary settings for NovelAI V4 models.
Character-specific prompt settings have been temporarily forcibly added,
so modifications are needed to allow custom prompt values to be input
later.
NovelAI V4 모델 추가.
캐릭터별 프롬프트는 임시추가 했기때문에 추후 커스텀 설정 할 수 있도록 변경해야함.
This commit is contained in:
kwaroran
2025-04-14 14:05:56 +09:00
committed by GitHub
3 changed files with 237 additions and 149 deletions

View File

@@ -35,7 +35,25 @@
image: '',
InfoExtracted: 0.5,
RefStrength: 0.5,
refimage: ''
refimage: '',
autoSmea:false,
legacy_uc:false,
use_coords:false,
v4_prompt:{
caption:{
base_caption:'',
char_captions:[]
},
use_coords:false,
use_order:true
},
v4_negative_prompt:{
caption:{
base_caption:'',
char_captions:[]
},
legacy_uc:false,
}
}
if (DBState.db.NAIImgConfig.sampler === 'ddim_v3'){
DBState.db.NAIImgConfig.sm = false
@@ -43,7 +61,7 @@
}
});
let submenu = $state(DBState.db.useLegacyGUI ? -1 : 0)
let submenu = $state(DBState.db.useLegacyGUI ? -1 : 0);
// HypaV3
$effect(() => {
@@ -88,6 +106,16 @@
return parseFloat(maxMemoryRatio.toFixed(2));
}
// End HypaV3
let imageModel = '';
// add init NAI V4
// if(DBState.db.NAIImgConfig.autoSmea === undefined) DBState.db.NAIImgConfig.autoSmea = false;
// if(DBState.db.NAIImgConfig.use_coords === undefined) DBState.db.NAIImgConfig.use_coords = false;
// if(DBState.db.NAIImgConfig.v4_prompt.use_coords === undefined) DBState.db.NAIImgConfig.v4_prompt.use_coords = false;
// if(DBState.db.NAIImgConfig.v4_prompt.use_order === undefined) DBState.db.NAIImgConfig.v4_prompt.use_order = false;
// if(DBState.db.NAIImgConfig.v4_negative_prompt.legacy_uc === undefined) DBState.db.NAIImgConfig.v4_negative_prompt.legacy_uc = false;
</script>
<h2 class="mb-2 text-2xl font-bold mt-2">{language.otherBots}</h2>
@@ -168,50 +196,89 @@
<TextInput size="sm" marginBottom bind:value={DBState.db.sdConfig.hr_upscaler}/>
{/if}
{/if}
{#if DBState.db.sdProvider === 'novelai'}
<span class="text-textcolor mt-2">Novel AI {language.providerURL}</span>
<TextInput size="sm" marginBottom placeholder="https://image.novelai.net" bind:value={DBState.db.NAIImgUrl}/>
<span class="text-textcolor">API Key</span>
<TextInput size="sm" marginBottom placeholder="pst-..." bind:value={DBState.db.NAIApiKey}/>
<span class="text-textcolor">Model</span>
<TextInput size="sm" marginBottom placeholder="nai-diffusion-3" bind:value={DBState.db.NAIImgModel}/>
<TextInput size="sm" marginBottom placeholder="nai-diffusion-4-full" bind:value={DBState.db.NAIImgModel}/>
<SelectInput className="mt-2 mb-4" bind:value={imageModel} onchange={(e)=>{
DBState.db.NAIImgModel = imageModel;
}}>
<OptionInput value="" >Choose...</OptionInput>
<OptionInput value="nai-diffusion-4-full" >nai-diffusion-4-full</OptionInput>
<OptionInput value="nai-diffusion-4-curated-preview" >nai-diffusion-4-curated-preview</OptionInput>
<OptionInput value="nai-diffusion-3" >nai-diffusion-3</OptionInput>
<OptionInput value="nai-diffusion-furry-3" >nai-diffusion-furry-3</OptionInput>
<OptionInput value="nai-diffusion-2" >nai-diffusion-2</OptionInput>
</SelectInput>
<span class="text-textcolor">Width</span>
<NumberInput size="sm" marginBottom min={0} max={2048} bind:value={DBState.db.NAIImgConfig.width}/>
<span class="text-textcolor">Height</span>
<NumberInput size="sm" marginBottom min={0} max={2048} bind:value={DBState.db.NAIImgConfig.height}/>
<span class="text-textcolor">Sampler</span>
<SelectInput className="mt-2 mb-4" bind:value={DBState.db.NAIImgConfig.sampler}>
<OptionInput value="k_euler" >Euler</OptionInput>
<OptionInput value="k_euler_ancestral" >Euler Ancestral</OptionInput>
<OptionInput value="k_dpmpp_2s_ancestral" >DPM++ 2S Ancestral</OptionInput>
<OptionInput value="k_dpmpp_2m" >DPM++ 2M</OptionInput>
<OptionInput value="k_dpmpp_sde" >DPM++ SDE</OptionInput>
<OptionInput value="k_dpmpp_2s" >DPM++ 2S</OptionInput>
<OptionInput value="ddim_v3" >DDIM</OptionInput>
</SelectInput>
{#if DBState.db.NAIImgModel === 'nai-diffusion-4-full'
|| DBState.db.NAIImgModel === 'nai-diffusion-4-curated-preview'}
<SelectInput className="mt-2 mb-4" bind:value={DBState.db.NAIImgConfig.sampler}>
<OptionInput value="k_euler_ancestral" >(Recommended)Euler Ancestral</OptionInput>
<OptionInput value="k_dpmpp_2s_ancestral" >(Recommended)DPM++ 2S Ancestral</OptionInput>
<OptionInput value="k_dpmpp_2m_sde" >(Recommended)DPM++ 2M SDE</OptionInput>
<OptionInput value="k_euler" >(Other)Euler</OptionInput>
<OptionInput value="k_dpmpp_2m" >(Other)DPM++ 2M</OptionInput>
<OptionInput value="k_dpmpp_sde" >(Other)DPM++ SDE</OptionInput>
</SelectInput>
{:else}
<SelectInput className="mt-2 mb-4" bind:value={DBState.db.NAIImgConfig.sampler}>
<OptionInput value="k_euler" >Euler</OptionInput>
<OptionInput value="k_euler_ancestral" >Euler Ancestral</OptionInput>
<OptionInput value="k_dpmpp_2s_ancestral" >DPM++ 2S Ancestral</OptionInput>
<OptionInput value="k_dpmpp_2m" >DPM++ 2M</OptionInput>
<OptionInput value="k_dpmpp_sde" >DPM++ SDE</OptionInput>
<OptionInput value="k_dpmpp_2s" >DPM++ 2S</OptionInput>
<OptionInput value="ddim_v3" >DDIM</OptionInput>
</SelectInput>
{/if}
<span class="text-textcolor">steps</span>
<NumberInput size="sm" marginBottom min={0} max={2048} bind:value={DBState.db.NAIImgConfig.steps}/>
<span class="text-textcolor">CFG scale</span>
<NumberInput size="sm" marginBottom min={0} max={2048} bind:value={DBState.db.NAIImgConfig.scale}/>
{#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'
|| DBState.db.NAIImgModel === 'nai-diffusion-4-curated-preview'}
<Check bind:check={DBState.db.NAIImgConfig.sm_dyn} name='Use DYN'/>
{/if}
<Check bind:check={DBState.db.NAII2I} name="Enable I2I"/>
{#if DBState.db.NAIImgModel === 'nai-diffusion-4-full'
|| DBState.db.NAIImgModel === 'nai-diffusion-4-curated-preview'}
<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}
{#if DBState.db.NAII2I}
<span class="text-textcolor mt-4">Strength</span>
<SliderInput min={0} max={0.99} step={0.01} bind:value={DBState.db.NAIImgConfig.strength}/>
<span class="text-textcolor2 mb-6 text-sm">{DBState.db.NAIImgConfig.strength}</span>
<span class="text-textcolor">Noise</span>
<SliderInput min={0} max={0.99} step={0.01} bind:value={DBState.db.NAIImgConfig.noise}/>
<span class="text-textcolor2 mb-6 text-sm">{DBState.db.NAIImgConfig.noise}</span>
<span class="text-textcolor">Base image</span>
<button onclick={async () => {
const img = await selectSingleFile([
@@ -231,12 +298,12 @@
{:else}
{#await getCharImage(DBState.db.NAIImgConfig.image, '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>
{: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}
<Check bind:check={DBState.db.NAIREF} name="Enable Reference" className="mt-4"/>
@@ -273,8 +340,8 @@
{: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>
{: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>

View File

@@ -1,5 +1,5 @@
import { get } from "svelte/store"
import { getDatabase, type character } from "../storage/database.svelte"
import { getDatabase, type character, type NAIImgConfig } from "../storage/database.svelte"
import { requestChatData } from "./request"
import { alertError } from "../alert"
import { fetchNative, globalFetch, readImage } from "../globalApi.svelte"
@@ -125,6 +125,62 @@ export async function generateAIImage(genPrompt:string, currentChar:character, n
let reqlist:any = {}
const commonReq = {
body: {
"input": genPrompt,
"model": db.NAIImgModel,
"parameters": {
"params_version": 3,
"add_original_image": true,
"cfg_rescale": 0,
"controlnet_strength": 1,
"dynamic_thresholding": false,
"n_samples": 1,
"width": db.NAIImgConfig.width,
"height": db.NAIImgConfig.height,
"sampler": db.NAIImgConfig.sampler,
"steps": db.NAIImgConfig.steps,
"scale": db.NAIImgConfig.scale,
"negative_prompt": neg,
"sm": false,
"sm_dyn": false,
"noise": db.NAIImgConfig.noise,
"noise_schedule": "native",
"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,
//add v4
"autoSmea": db.NAIImgConfig.autoSmea,
use_coords: db.NAIImgConfig.use_coords,
legacy_uc: db.NAIImgConfig.legacy_uc,
v4_prompt:{
caption:{
base_caption:genPrompt,
char_captions: []
},
use_coords: db.NAIImgConfig.v4_prompt.use_coords,
use_order: db.NAIImgConfig.v4_prompt.use_order
},
"v4_negative_prompt":{
caption:{
base_caption:neg,
char_captions: []
},
legacy_uc: db.NAIImgConfig.v4_negative_prompt.legacy_uc,
}
}
},
headers:{
"Authorization": "Bearer " + db.NAIApiKey
},
rawResponse: true
}
if(db.NAII2I){
let seed = Math.floor(Math.random() * 10000000000)
@@ -139,9 +195,6 @@ export async function generateAIImage(genPrompt:string, currentChar:character, n
}
let refimgbase64 = undefined
if(db.NAIREF){
if(db.NAIImgConfig.refimage !== ''){
@@ -149,56 +202,20 @@ export async function generateAIImage(genPrompt:string, currentChar:character, n
}
}
reqlist = {
body: {
"action": "img2img",
"input": genPrompt,
"model": db.NAIImgModel,
"parameters": {
"params_version": 1,
"add_original_image": true,
"cfg_rescale": 0,
"controlnet_strength": 1,
"dynamic_thresholding": false,
"extra_noise_seed": seed,
"n_samples": 1,
"width": db.NAIImgConfig.width,
"height": db.NAIImgConfig.height,
"sampler": db.NAIImgConfig.sampler,
"steps": db.NAIImgConfig.steps,
"scale": db.NAIImgConfig.scale,
"seed": seed,
"negative_prompt": neg,
"sm": false,
"sm_dyn": false,
"noise": db.NAIImgConfig.noise,
"noise_schedule": "native",
"strength": db.NAIImgConfig.strength,
"image": base64img,
"ucPreset": 3,
"uncond_scale": 1,
"qualityToggle": false,
"lagacy_v3_extend": false,
"lagacy": false,
"reference_information_extracted": db.NAIImgConfig.InfoExtracted,
"reference_strength": db.NAIImgConfig.RefStrength
}
},
headers:{
"Authorization": "Bearer " + db.NAIApiKey
},
rawResponse: true
}
reqlist = commonReq;
reqlist.body.action = "img2img";
reqlist.body.parameters.image = base64img;
reqlist.body.parameters.extra_noise_seed = seed;
reqlist.body.parameters.seed = seed;
if(refimgbase64 !== undefined){
reqlist.body.parameters.reference_image = refimgbase64
}
console.log({img2img:reqlist});
}else{
if (db.NAIREF) {
let base64img = ''
if(db.NAIImgConfig.image === ''){
const charimg = currentChar.image;
@@ -208,84 +225,15 @@ export async function generateAIImage(genPrompt:string, currentChar:character, n
} else{
base64img = Buffer.from(await readImage(db.NAIImgConfig.refimage)).toString('base64');
}
reqlist = {
body: {
"action": "generate",
"input": genPrompt,
"model": db.NAIImgModel,
"parameters": {
"params_version": 1,
"add_original_image": true,
"cfg_rescale": 0,
"controlnet_strength": 1,
"dynamic_thresholding": false,
"n_samples": 1,
"width": db.NAIImgConfig.width,
"height": db.NAIImgConfig.height,
"sampler": db.NAIImgConfig.sampler,
"steps": db.NAIImgConfig.steps,
"scale": db.NAIImgConfig.scale,
"negative_prompt": neg,
"sm": db.NAIImgConfig.sm,
"sm_dyn": db.NAIImgConfig.sm_dyn,
"noise_schedule": "native",
"ucPreset": 3,
"uncond_scale": 1,
"qualityToggle": false,
"legacy": false,
"lagacy_v3_extend": false,
"reference_image": base64img,
"reference_strength": db.NAIImgConfig.RefStrength,
"reference_information_extracted": db.NAIImgConfig.InfoExtracted
}
},
headers:{
"Authorization": "Bearer " + db.NAIApiKey
},
rawResponse: true
}
reqlist = commonReq;
reqlist.body.action = 'generate';
reqlist.body.parameters.reference_image = base64img;
console.log({generate:reqlist});
} else {
reqlist = {
body: {
"input": genPrompt,
"model": db.NAIImgModel,
"parameters": {
"params_version": 1,
"width": db.NAIImgConfig.width,
"height": db.NAIImgConfig.height,
"scale": db.NAIImgConfig.scale,
"sampler": db.NAIImgConfig.sampler,
"steps": db.NAIImgConfig.steps,
"n_samples": 1,
"ucPreset": 3,
"qualityToggle": false,
"sm": db.NAIImgConfig.sm,
"sm_dyn": db.NAIImgConfig.sm_dyn,
"dynamic_thresholding": false,
"controlnet_strength": 1,
"legacy": false,
"add_original_image": true,
"uncond_scale": 1,
"cfg_rescale": 0,
"noise_schedule": "native",
"legacy_v3_extend": false,
"reference_information_extracted": db.NAIImgConfig.InfoExtracted,
"reference_strength": db.NAIImgConfig.RefStrength,
"negative_prompt": neg,
}
},
headers:{
"Authorization": "Bearer " + db.NAIApiKey
},
rawResponse: true
}
reqlist = commonReq;
reqlist.body.action = 'generate';
console.log({nothing:reqlist});
}
}
try {
const da = await globalFetch(db.NAIImgUrl, reqlist)

View File

@@ -264,9 +264,49 @@ export function setDatabase(data:Database){
image:"",
refimage:"",
InfoExtracted:1,
RefStrength:0.4
RefStrength:0.4,
//add 4
autoSmea:false,
legacy_uc:false,
use_coords:false,
v4_prompt:{
caption:{
base_caption:'',
char_captions:[]
},
use_coords:false,
use_order:true
},
v4_negative_prompt:{
caption:{
base_caption:'',
char_captions:[]
},
legacy_uc:false,
}
}
}
//add NAI v4 (사용중인 사람용 추가 DB Init)
if(checkNullish(data.NAIImgConfig.v4_prompt)){
data.NAIImgConfig.autoSmea = false;
data.NAIImgConfig.use_coords = false;
data.NAIImgConfig.legacy_uc = false;
data.NAIImgConfig.v4_prompt = {
caption:{
base_caption:"",
char_captions:[]
},
use_coords:false,
use_order:true
};
data.NAIImgConfig.v4_negative_prompt = {
caption:{
base_caption:"",
char_captions:[]
},
legacy_uc:false,
};
}
if(checkNullish(data.customTextTheme)){
data.customTextTheme = {
FontColorStandard: "#f8f8f2",
@@ -1363,7 +1403,7 @@ interface sdConfig{
hr_upscaler:string
}
interface NAIImgConfig{
export interface NAIImgConfig{
width:number,
height:number,
sampler:string,
@@ -1377,6 +1417,39 @@ interface NAIImgConfig{
refimage:string,
InfoExtracted:number,
RefStrength:number
//add 4
autoSmea:boolean,
use_coords:boolean,
legacy_uc: boolean,
v4_prompt:NAIImgConfigV4Prompt,
v4_negative_prompt:NAIImgConfigV4NegativePrompt,
}
//add 4
interface NAIImgConfigV4Prompt{
caption: NAIImgConfigV4Caption,
use_coords: boolean,
use_order: boolean
}
//add 4
interface NAIImgConfigV4NegativePrompt{
caption: NAIImgConfigV4Caption,
legacy_uc: boolean
}
//add 4
interface NAIImgConfigV4Caption{
base_caption: string,
char_captions: NAIImgConfigV4CharCaption[]
}
//add 4
interface NAIImgConfigV4CharCaption{
char_caption: string,
centers:
{
x: number,
y: number
}[]
}
interface ComfyConfig{