Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 18 additions & 18 deletions src/novelai_python/sdk/ai/_enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,7 @@ def get_modifiers(model: Model) -> Modifier:
]:
return Modifier(
qualityTags="",
suffix=", location, very aesthetic, masterpiece, no text"
suffix=", very aesthetic, masterpiece, no text"
)
if model in [
Model.NAI_DIFFUSION_4_5_CURATED,
Expand Down Expand Up @@ -661,12 +661,12 @@ def get_uc_preset(model: ModelTypeAlias) -> List[UcPrompt]:
UcPrompt(
category="heavy",
name="lowQualityPlusBadAnatomy",
text="lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry"
text="nsfw, lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry"
),
UcPrompt(
category="light",
name="lowQuality",
text="lowres, text, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry"
text="nsfw, lowres, text, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry"
),
UcPrompt(
category="none",
Expand All @@ -682,12 +682,12 @@ def get_uc_preset(model: ModelTypeAlias) -> List[UcPrompt]:
UcPrompt(
category="light",
name="lowQuality",
text="worst quality, low quality, what has science done, what, nightmare fuel, eldritch horror, where is your god now, why"
text="nsfw, worst quality, low quality, what has science done, what, nightmare fuel, eldritch horror, where is your god now, why"
),
UcPrompt(
category="heavy",
name="badAnatomy",
text="{worst quality}, low quality, distracting watermark, [nightmare fuel], {{unfinished}}, deformed, outline, pattern, simple background"
text="nsfw, {worst quality}, low quality, distracting watermark, [nightmare fuel], {{unfinished}}, deformed, outline, pattern, simple background"
),
UcPrompt(
category="none",
Expand All @@ -702,12 +702,12 @@ def get_uc_preset(model: ModelTypeAlias) -> List[UcPrompt]:
UcPrompt(
category="heavy",
name="heavy",
text="lowres, bad, text, error, missing, extra, fewer, cropped, jpeg artifacts, worst quality, bad quality, watermark, displeasing, unfinished, chromatic aberration, scan, scan artifacts"
text="nsfw, lowres, bad, text, error, missing, extra, fewer, cropped, jpeg artifacts, worst quality, bad quality, watermark, displeasing, unfinished, chromatic aberration, scan, scan artifacts"
),
UcPrompt(
category="light",
name="light",
text="lowres, jpeg artifacts, worst quality, watermark, blurry, very displeasing"
text="nsfw, lowres, jpeg artifacts, worst quality, watermark, blurry, very displeasing"
),
UcPrompt(
category="none",
Expand All @@ -723,17 +723,17 @@ def get_uc_preset(model: ModelTypeAlias) -> List[UcPrompt]:
UcPrompt(
category="heavy",
name="heavy",
text="lowres, {bad}, error, fewer, extra, missing, worst quality, jpeg artifacts, bad quality, watermark, unfinished, displeasing, chromatic aberration, signature, extra digits, artistic error, username, scan, [abstract]"
text="nsfw, lowres, {bad}, error, fewer, extra, missing, worst quality, jpeg artifacts, bad quality, watermark, unfinished, displeasing, chromatic aberration, signature, extra digits, artistic error, username, scan, [abstract]"
),
UcPrompt(
category="light",
name="light",
text="lowres, jpeg artifacts, worst quality, watermark, blurry, very displeasing"
text="nsfw, lowres, jpeg artifacts, worst quality, watermark, blurry, very displeasing"
),
UcPrompt(
category="human",
name="humanFocus",
text="lowres, {bad}, error, fewer, extra, missing, worst quality, jpeg artifacts, bad quality, watermark, unfinished, displeasing, chromatic aberration, signature, extra digits, artistic error, username, scan, [abstract], bad anatomy, bad hands, @_@, mismatched pupils, heart-shaped pupils, glowing eyes"
text="nsfw, lowres, {bad}, error, fewer, extra, missing, worst quality, jpeg artifacts, bad quality, watermark, unfinished, displeasing, chromatic aberration, signature, extra digits, artistic error, username, scan, [abstract], bad anatomy, bad hands, @_@, mismatched pupils, heart-shaped pupils, glowing eyes"
),
UcPrompt(
category="none",
Expand All @@ -749,12 +749,12 @@ def get_uc_preset(model: ModelTypeAlias) -> List[UcPrompt]:
UcPrompt(
category="heavy",
name="heavy",
text="{{worst quality}}, [displeasing], {unusual pupils}, guide lines, {{unfinished}}, {bad}, url, artist name, {{tall image}}, mosaic, {sketch page}, comic panel, impact (font), [dated], {logo}, ych, {what}, {where is your god now}, {distorted text}, repeated text, {floating head}, {1994}, {widescreen}, absolutely everyone, sequence, {compression artifacts}, hard translated, {cropped}, {commissioner name}, unknown text, high contrast"
text="nsfw, {{worst quality}}, [displeasing], {unusual pupils}, guide lines, {{unfinished}}, {bad}, url, artist name, {{tall image}}, mosaic, {sketch page}, comic panel, impact (font), [dated], {logo}, ych, {what}, {where is your god now}, {distorted text}, repeated text, {floating head}, {1994}, {widescreen}, absolutely everyone, sequence, {compression artifacts}, hard translated, {cropped}, {commissioner name}, unknown text, high contrast"
),
UcPrompt(
category="light",
name="light",
text="{worst quality}, guide lines, unfinished, bad, url, tall image, widescreen, compression artifacts, unknown text"
text="nsfw, {worst quality}, guide lines, unfinished, bad, url, tall image, widescreen, compression artifacts, unknown text"
),
UcPrompt(
category="none",
Expand Down Expand Up @@ -791,12 +791,12 @@ def get_uc_preset(model: ModelTypeAlias) -> List[UcPrompt]:
UcPrompt(
category="heavy",
name="heavy",
text="blurry, lowres, error, film grain, scan artifacts, worst quality, bad quality, jpeg artifacts, very displeasing, chromatic aberration, multiple views, logo, too many watermarks, white blank page, blank page"
text="nsfw, blurry, lowres, error, film grain, scan artifacts, worst quality, bad quality, jpeg artifacts, very displeasing, chromatic aberration, multiple views, logo, too many watermarks, white blank page, blank page"
),
UcPrompt(
category="light",
name="light",
text="blurry, lowres, error, worst quality, bad quality, jpeg artifacts, very displeasing, white blank page, blank page"
text="nsfw, blurry, lowres, error, worst quality, bad quality, jpeg artifacts, very displeasing, white blank page, blank page"
),
UcPrompt(
category="none",
Expand Down Expand Up @@ -839,22 +839,22 @@ def get_uc_preset(model: ModelTypeAlias) -> List[UcPrompt]:
UcPrompt(
category="heavy",
name="heavy",
text="lowres, artistic error, film grain, scan artifacts, worst quality, bad quality, jpeg artifacts, very displeasing, chromatic aberration, dithering, halftone, screentone, multiple views, logo, too many watermarks, negative space, blank page"
text="nsfw, lowres, artistic error, film grain, scan artifacts, worst quality, bad quality, jpeg artifacts, very displeasing, chromatic aberration, dithering, halftone, screentone, multiple views, logo, too many watermarks, negative space, blank page"
),
UcPrompt(
category="light",
name="light",
text="lowres, artistic error, scan artifacts, worst quality, bad quality, jpeg artifacts, multiple views, very displeasing, too many watermarks, negative space, blank page"
text="nsfw, lowres, artistic error, scan artifacts, worst quality, bad quality, jpeg artifacts, multiple views, very displeasing, too many watermarks, negative space, blank page"
),
UcPrompt(
category="furry",
name="furryFocus",
text="{worst quality}, distracting watermark, unfinished, bad quality, {widescreen}, upscale, {sequence}, {{grandfathered content}}, blurred foreground, chromatic aberration, sketch, everyone, [sketch background], simple, [flat colors], ych (character), outline, multiple scenes, [[horror (theme)]], comic"
text="nsfw, {worst quality}, distracting watermark, unfinished, bad quality, {widescreen}, upscale, {sequence}, {{grandfathered content}}, blurred foreground, chromatic aberration, sketch, everyone, [sketch background], simple, [flat colors], ych (character), outline, multiple scenes, [[horror (theme)]], comic"
),
UcPrompt(
category="human",
name="humanFocus",
text="lowres, artistic error, film grain, scan artifacts, worst quality, bad quality, jpeg artifacts, very displeasing, chromatic aberration, dithering, halftone, screentone, multiple views, logo, too many watermarks, negative space, blank page, @_@, mismatched pupils, glowing eyes, bad anatomy"
text="nsfw, lowres, artistic error, film grain, scan artifacts, worst quality, bad quality, jpeg artifacts, very displeasing, chromatic aberration, dithering, halftone, screentone, multiple views, logo, too many watermarks, negative space, blank page, @_@, mismatched pupils, glowing eyes, bad anatomy"
),
UcPrompt(
category="none",
Expand Down
26 changes: 23 additions & 3 deletions src/novelai_python/sdk/ai/generate_image/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,16 @@ def set_mutual_exclusion(self, value: bool):
action: Union[str, Action] = Field(Action.GENERATE, description="Mode for img generate")
parameters: Union[Params]
model_config = ConfigDict(extra="ignore")

# forced params integration
def model_dump(self, *args, **kwargs):
"""
Overrides model_dump for own features
"""
data = super().model_dump(*args, **kwargs)
data["parameters"] = self.parameters.model_dump(*args, **kwargs)

return data

@override
def model_post_init(self, *args) -> None:
Expand Down Expand Up @@ -158,6 +168,13 @@ def enhance_message(_prompt):
if key in uc_prompt:
uc_prompt.pop(key)
self.parameters.negative_prompt = ",".join(uc_prompt.values())

# Instantly remove nsfw if input contains it
elif "nsfw" in self.input and "nsfw" in self.parameters.negative_prompt:
uc_prompt = {x.strip(): x for x in self.parameters.negative_prompt.split(",")}
uc_prompt.pop("nsfw", None)

self.parameters.negative_prompt = ",".join(uc_prompt.values())

@model_validator(mode="after")
def _build_nai4_prompt(self):
Expand Down Expand Up @@ -187,9 +204,9 @@ def _build_nai4_prompt(self):
if not get_supported_params(self.model).vibetransfer:
if self.parameters.reference_image_multiple:
logger.warning("Vibe transfer is not supported for this model.")
self.parameters.reference_image_multiple = []
self.parameters.reference_information_extracted_multiple = []
self.parameters.reference_strength_multiple = []
self.parameters.reference_image_multiple = None # Auto exclude None values
self.parameters.reference_information_extracted_multiple = None # Auto exclude None values
self.parameters.reference_strength_multiple = None # Auto exclude None values

if not get_supported_params(self.model).controlnet:
if self.parameters.controlnet_condition is not None:
Expand All @@ -210,6 +227,9 @@ def _backend_logic(self):
"""
if self.parameters.characterPrompts:
self.parameters.use_coords = any([c.center != PositionMap.AUTO for c in self.parameters.characterPrompts])

if get_supported_params(self.model).v4Prompts and self.parameters.v4_prompt is not None:
self.parameters.v4_prompt.use_coords = self.parameters.use_coords
# Mix Prompt Warning
if self.input.count('|') > 6:
logger.warning("Maximum prompt mixes exceeded. Extra will be ignored.")
Expand Down
40 changes: 36 additions & 4 deletions src/novelai_python/sdk/ai/generate_image/params.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import base64
import random
from io import BytesIO
from typing import Optional, List, Union, Tuple
from typing import Optional, List, OrderedDict, Set, Union, Tuple

import cv2
import numpy as np
Expand Down Expand Up @@ -62,6 +62,8 @@ class Params(BaseModel):
"""Use Coordinates"""
legacy_uc: bool = False
normalize_reference_strength_multiple: bool = True
inpaintImg2ImgStrength: Optional[float] = Field(None, ge=0, le=1, multiple_of=0.01)
"""For SameFeel"""
seed: int = Field(
default_factory=lambda: random.randint(0, 4294967295 - 7),
gt=0,
Expand Down Expand Up @@ -107,15 +109,45 @@ class Params(BaseModel):
"""Extra Noise Seed"""
color_correct: Optional[bool] = None
"""For Inpaint"""
inpaintImg2ImgStrength: Optional[float] = Field(None, ge=0, le=1, multiple_of=0.01)
"""For SameFeel"""
controlnet_condition: Optional[str] = None
"""ControlNet Condition"""
controlnet_model: Optional[ControlNetModel] = None
"""ControlNet Model"""
uncond_scale: Optional[float] = Field(None, ge=0, le=1.5, multiple_of=0.05)
"""Undesired Content Strength"""


########## Next code wants custom BaseModel
__strong_values__: Set[str] = {
"skip_cfg_above_sigma", # See models before Anime V3
}
"""Settings with none value to strongly include"""

def force_include(self, value: str):
"""
Force include some params to json
"""
if value not in self.__dict__:
raise ValueError("Wrong value in params:", value)

self.__strong_values__.add(value)

# Also integrated into GenerateImageInfer
def model_dump(self, *args, **kwargs):
"""
Overrides model_dump for own features
"""
data = super().model_dump(*args, **kwargs)
ordered_fields = list(self.__fields__.keys())
new_data = OrderedDict()

for field in ordered_fields:
if field in data:
new_data[field] = data[field]
elif field in self.__strong_values__:
new_data[field] = getattr(self, field, None)
return new_data
#########

@model_validator(mode="after")
def v_character(self):
if len(self.characterPrompts) > 6:
Expand Down
4 changes: 2 additions & 2 deletions src/novelai_python/sdk/ai/generate_image/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,14 +84,14 @@ class Caption(BaseModel):

class V4Prompt(BaseModel):
caption: Caption = Field(default_factory=Caption, description="Caption")
use_coords: bool = Field(True, description="Use Coordinates")
use_coords: bool = Field(False, description="Use Coordinates")
use_order: bool = Field(True, description="Use Order")

@classmethod
def build_from_character_prompts(cls,
base_caption: str,
character_prompts: List[Character],
use_coords: bool = True,
use_coords: bool = False,
use_order: bool = True
) -> "V4Prompt":
"""
Expand Down