diff --git a/src/novelai_python/sdk/ai/_enum.py b/src/novelai_python/sdk/ai/_enum.py index ec91f93..b24425e 100644 --- a/src/novelai_python/sdk/ai/_enum.py +++ b/src/novelai_python/sdk/ai/_enum.py @@ -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, @@ -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", @@ -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", @@ -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", @@ -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", @@ -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", @@ -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", @@ -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", diff --git a/src/novelai_python/sdk/ai/generate_image/__init__.py b/src/novelai_python/sdk/ai/generate_image/__init__.py index a8e710c..a39f3c5 100755 --- a/src/novelai_python/sdk/ai/generate_image/__init__.py +++ b/src/novelai_python/sdk/ai/generate_image/__init__.py @@ -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: @@ -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): @@ -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: @@ -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.") diff --git a/src/novelai_python/sdk/ai/generate_image/params.py b/src/novelai_python/sdk/ai/generate_image/params.py index d730a32..b78b0b8 100644 --- a/src/novelai_python/sdk/ai/generate_image/params.py +++ b/src/novelai_python/sdk/ai/generate_image/params.py @@ -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 @@ -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, @@ -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: diff --git a/src/novelai_python/sdk/ai/generate_image/schema.py b/src/novelai_python/sdk/ai/generate_image/schema.py index c4af2f6..0ffcd40 100644 --- a/src/novelai_python/sdk/ai/generate_image/schema.py +++ b/src/novelai_python/sdk/ai/generate_image/schema.py @@ -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": """