diff --git a/pdm.lock b/pdm.lock index d04e3ba..c13fd08 100755 --- a/pdm.lock +++ b/pdm.lock @@ -415,7 +415,7 @@ files = [ [[package]] name = "curl-cffi" -version = "0.10.0" +version = "0.11.3" requires_python = ">=3.9" summary = "libcurl ffi bindings for Python, with impersonation support." groups = ["default"] @@ -424,16 +424,15 @@ dependencies = [ "cffi>=1.12.0", ] files = [ - {file = "curl_cffi-0.10.0-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:15053d01c6a3e3c4c5331ce9e07e1dc31ca5aa063babca05d18b1b5aad369fac"}, - {file = "curl_cffi-0.10.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:3969e4260ad4dab638fb6dbe349623f9f5f022435c7fd21daf760231380367fa"}, - {file = "curl_cffi-0.10.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:458f53c41bd76d90d8974d60c3a8a0dd902a1af1f9056215cf24f454bcedc6fd"}, - {file = "curl_cffi-0.10.0-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfc74f09e44d2d8d61b8e8fda3a7004b5bc0217a703fbbe9e16ef8caa1f3d4e4"}, - {file = "curl_cffi-0.10.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f03f4b17dc679c82bd3c946feb1ad38749b2ad731d7c26daefaac857d1c72fd9"}, - {file = "curl_cffi-0.10.0-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:f1b0c7b7b81afca15a0e56c593d3c2bdcd4fd4c9ca49b9ded5b9d8076ba78ff9"}, - {file = "curl_cffi-0.10.0-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:04b1d23f0f54f94b8298ed417e6bece85a635d674723cde2b155da686efbf78f"}, - {file = "curl_cffi-0.10.0-cp39-abi3-win32.whl", hash = "sha256:1e60b8ecc80bfb0da4ff73ac9d194e80482b50ecbb8aefec1b0edaf45fafd80e"}, - {file = "curl_cffi-0.10.0-cp39-abi3-win_amd64.whl", hash = "sha256:59389773a1556e087120e91eac1e33f84f1599d853e1bc168b153e4cdf360002"}, - {file = "curl_cffi-0.10.0.tar.gz", hash = "sha256:3e37b35268ca58492f54ed020ae4b50c33ee0debad4145db9f746f04ed466eb0"}, + {file = "curl_cffi-0.11.3-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:fb5bdec1a6c3717ab4945bfa95a84d19239ae94cb7e1d1388a7e6eb2fb2e30ee"}, + {file = "curl_cffi-0.11.3-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:0ba33cf5486a018ffa10824d4d941f76c7bd90fe280e01c14f156a2ee0ecf8dc"}, + {file = "curl_cffi-0.11.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e03592a12e28cc43d8180713b26b8fbffe08c9d26ace9daa287a500590d4295b"}, + {file = "curl_cffi-0.11.3-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3852e75fe5e424cfd0fff5dec55a2833a45323c3b90275f6fd44bbf633ada3de"}, + {file = "curl_cffi-0.11.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e83065bc89b6725a4d72bafaf3cbdddf56bb4f014bc63be73f87f1b3903fd0ae"}, + {file = "curl_cffi-0.11.3-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:f1368594ff2544088eb7f5f3a534e3067e8086b4afb14815bd0af009d25f4ff4"}, + {file = "curl_cffi-0.11.3-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:6ae31e513718e108f37889d28d7dc506102399fc753f91b85bdcbb11e79b2860"}, + {file = "curl_cffi-0.11.3-cp39-abi3-win_amd64.whl", hash = "sha256:953d6ef5b964b6bf2f3e6ba11034adc108faf45b2e18d081de84d797a4d9f328"}, + {file = "curl_cffi-0.11.3.tar.gz", hash = "sha256:0b21f39980bce3fb5aeea8d64d76bd465825c54a45e2933ca4df5ec0f041ba49"}, ] [[package]] diff --git a/playground/generate_image.py b/playground/generate_image.py index 0810079..52a3ecc 100755 --- a/playground/generate_image.py +++ b/playground/generate_image.py @@ -4,6 +4,7 @@ # @File : __init__.py.py import asyncio +import base64 import os import pathlib import random @@ -55,7 +56,7 @@ async def generate( scene = prompt_generator.generate_scene_composition() if prompt is None: prompt = scene.pop(0) + ','.join([ - 'muelsyse (arknights) ' + 'muelsyse (arknights)' ]) character = [ Character( @@ -74,11 +75,11 @@ async def generate( # Generate try: agent = GenerateImageInfer.build_generate( - prompt=prompt, - width=832, - height=1216, + prompt=os.getenv("TEST_TAG", prompt), + width=1024, + height=1024, model=model, - character_prompts=character, + character_prompts=None if os.getenv("TEST_TAG") else character, sampler=Sampler.K_EULER_ANCESTRAL, ucPreset=UCPreset.TYPE0, # Recommended, using preset negative_prompt depends on selected model @@ -110,7 +111,7 @@ async def direct_use(): :return: """ credential = ApiCredential(api_token=SecretStr("pst-5555")) - result = await GenerateImageInfer( + result: ImageGenerateResp = await GenerateImageInfer( input="1girl", model=Model.NAI_DIFFUSION_4_5_FULL, parameters=Params( @@ -127,6 +128,9 @@ async def direct_use(): ) ).request(session=credential) print(f"Meta: {result.meta}") + file = result.files[0] + with open(f"{pathlib.Path(__file__).stem}.png", "wb") as f: + f.write(file[1]) load_dotenv() diff --git a/playground/generate_image_img2img.py b/playground/generate_image_img2img.py index d2af2b1..6327897 100755 --- a/playground/generate_image_img2img.py +++ b/playground/generate_image_img2img.py @@ -14,6 +14,7 @@ from novelai_python import APIError, LoginCredential from novelai_python import GenerateImageInfer, ImageGenerateResp, ApiCredential +from novelai_python.sdk.ai._enum import Model from novelai_python.sdk.ai.generate_image import Action, Sampler from novelai_python.utils.useful import enum_to_list @@ -42,11 +43,10 @@ async def generate( image = base64.b64encode(f.read()).decode() # image = f.read() # Or you can use the raw bytes agent = GenerateImageInfer.build_img2img( + model=Model.NAI_DIFFUSION_4_5_FULL, prompt=prompt, sampler=Sampler.K_DPMPP_SDE, image=image, - seed=123456789, - extra_noise_seed=123123123, ) print(f"charge: {agent.calculate_cost(is_opus=True)} if you are vip3") print(f"charge: {agent.calculate_cost(is_opus=False)} if you are not vip3") diff --git a/pyproject.toml b/pyproject.toml index 9bcdaf6..06db6f6 100755 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "novelai-python" -version = "0.7.10" +version = "0.7.11" description = "NovelAI Python Binding With Pydantic" authors = [ { name = "sudoskys", email = "coldlando@hotmail.com" }, @@ -13,7 +13,7 @@ dependencies = [ "httpx>=0.26.0", "shortuuid>=1.0.11", "Pillow>=10.2.0", - "curl-cffi>=0.9.0", + "curl-cffi>=0.11.3", "fastapi>=0.109.0", "uvicorn[standard]>=0.27.0.post1", "numpy>=1.24.4", diff --git a/src/novelai_python/credential/ApiToken.py b/src/novelai_python/credential/ApiToken.py index 78f40b9..094ef4d 100755 --- a/src/novelai_python/credential/ApiToken.py +++ b/src/novelai_python/credential/ApiToken.py @@ -10,7 +10,7 @@ from loguru import logger from pydantic import SecretStr, Field, field_validator -from ._base import CredentialBase, FAKE_UA +from ._base import CredentialBase class ApiCredential(CredentialBase): @@ -22,13 +22,8 @@ class ApiCredential(CredentialBase): async def get_session(self, timeout: int = 180, update_headers: dict = None): headers = { - "Accept": "*/*", - "Accept-Encoding": "gzip, deflate, br", - "User-Agent": FAKE_UA.edge, "Authorization": f"Bearer {self.api_token.get_secret_value()}", "Content-Type": "application/json", - "Origin": "https://novelai.net", - "Referer": "https://novelai.net/", "x-correlation-id": self.x_correlation_id, "x-initiated-at": f"{arrow.utcnow().isoformat()}Z", } @@ -37,10 +32,10 @@ async def get_session(self, timeout: int = 180, update_headers: dict = None): assert isinstance(update_headers, dict), "update_headers must be a dict" headers.update(update_headers) - return AsyncSession(timeout=timeout, headers=headers, impersonate="edge101") + return AsyncSession(timeout=timeout, headers=headers, impersonate="chrome136") @field_validator('api_token') def check_api_token(cls, v: SecretStr): if not v.get_secret_value().startswith("pst"): logger.warning("api token should start with `pst-`") - return v + return v \ No newline at end of file diff --git a/src/novelai_python/credential/JwtToken.py b/src/novelai_python/credential/JwtToken.py index 6fcfc50..4603b13 100755 --- a/src/novelai_python/credential/JwtToken.py +++ b/src/novelai_python/credential/JwtToken.py @@ -10,7 +10,7 @@ from loguru import logger from pydantic import SecretStr, Field, field_validator -from ._base import CredentialBase, FAKE_UA +from ._base import CredentialBase class JwtCredential(CredentialBase): @@ -22,13 +22,8 @@ class JwtCredential(CredentialBase): async def get_session(self, timeout: int = 180, update_headers: dict = None): headers = { - "Accept": "*/*", - "User-Agent": FAKE_UA.edge, - "Accept-Encoding": "gzip, deflate, br", "Authorization": f"Bearer {self.jwt_token.get_secret_value()}", "Content-Type": "application/json", - "Origin": "https://novelai.net", - "Referer": "https://novelai.net/", "x-correlation-id": self.x_correlation_id, "x-initiated-at": f"{arrow.utcnow().isoformat()}Z", } @@ -37,10 +32,10 @@ async def get_session(self, timeout: int = 180, update_headers: dict = None): assert isinstance(update_headers, dict), "update_headers must be a dict" headers.update(update_headers) - return AsyncSession(timeout=timeout, headers=headers, impersonate="edge101") + return AsyncSession(timeout=timeout, headers=headers, impersonate="chrome136") @field_validator('jwt_token') def check_jwt_token(cls, v: SecretStr): if not v.get_secret_value().startswith("ey"): logger.warning("jwt_token should start with ey") - return v + return v \ No newline at end of file diff --git a/src/novelai_python/credential/UserAuth.py b/src/novelai_python/credential/UserAuth.py index 61c7925..0cce3cb 100755 --- a/src/novelai_python/credential/UserAuth.py +++ b/src/novelai_python/credential/UserAuth.py @@ -10,7 +10,7 @@ from curl_cffi.requests import AsyncSession from pydantic import SecretStr, Field -from ._base import CredentialBase, FAKE_UA +from ._base import CredentialBase class LoginCredential(CredentialBase): @@ -25,13 +25,8 @@ class LoginCredential(CredentialBase): async def get_session(self, timeout: int = 180, update_headers: dict = None): headers = { - "Accept": "*/*", - "User-Agent": FAKE_UA.edge, - "Accept-Encoding": "gzip, deflate, br", "Authorization": "Bearer ", "Content-Type": "application/json", - "Origin": "https://novelai.net", - "Referer": "https://novelai.net/", "x-correlation-id": self.x_correlation_id, "x-initiated-at": f"{arrow.utcnow().isoformat()}Z", } @@ -49,4 +44,4 @@ async def get_session(self, timeout: int = 180, update_headers: dict = None): if update_headers: headers.update(update_headers) - return AsyncSession(timeout=timeout, headers=headers, impersonate="edge101") + return AsyncSession(timeout=timeout, headers=headers, impersonate="chrome136") diff --git a/src/novelai_python/sdk/ai/_enum.py b/src/novelai_python/sdk/ai/_enum.py index cafd343..ec91f93 100644 --- a/src/novelai_python/sdk/ai/_enum.py +++ b/src/novelai_python/sdk/ai/_enum.py @@ -217,12 +217,17 @@ class SupportCondition: img2imgInpainting: bool -def get_supported_params(model: Model): +def get_supported_params(model: ModelTypeAlias): """ Get supported parameters for a given model :param model: Model :return: SupportCondition """ + if isinstance(model, str): + try: + model = Model(model) + except ValueError: + pass if model in [ Model.STABLE_DIFFUSION, Model.NAI_DIFFUSION, diff --git a/src/novelai_python/sdk/ai/augment_image/__init__.py b/src/novelai_python/sdk/ai/augment_image/__init__.py index 859737a..b9f4684 100644 --- a/src/novelai_python/sdk/ai/augment_image/__init__.py +++ b/src/novelai_python/sdk/ai/augment_image/__init__.py @@ -174,28 +174,6 @@ def build(cls, prompt=prompt, ) - async def necessary_headers(self, request_data) -> dict: - """ - :param request_data: - :return: - """ - return { - "Host": urlparse(self.endpoint).netloc, - "Accept": "*/*", - "Accept-Encoding": "gzip, deflate, br", - "Referer": "https://novelai.net/", - "Content-Type": "application/json", - "Origin": "https://novelai.net", - "Content-Length": str(len(json.dumps(request_data).encode("utf-8"))), - "Connection": "keep-alive", - "Sec-Fetch-Dest": "empty", - "Sec-Fetch-Mode": "cors", - "Sec-Fetch-Site": "same-site", - "Pragma": "no-cache", - "Cache-Control": "no-cache", - 'priority': "u=1, i" - } - @retry( wait=wait_random(min=1, max=3), stop=stop_after_attempt(3), @@ -216,7 +194,6 @@ async def request(self, # Prepare request data request_data = self.model_dump(mode="json", exclude_none=True) async with session if isinstance(session, AsyncSession) else await session.get_session() as sess: - sess.headers.update(await self.necessary_headers(request_data)) if override_headers: sess.headers.clear() sess.headers.update(override_headers) diff --git a/src/novelai_python/sdk/ai/generate/__init__.py b/src/novelai_python/sdk/ai/generate/__init__.py index 7a89a2f..b5826e5 100644 --- a/src/novelai_python/sdk/ai/generate/__init__.py +++ b/src/novelai_python/sdk/ai/generate/__init__.py @@ -65,22 +65,6 @@ def endpoint(self, value): def base_url(self): return f"{self.endpoint.strip('/')}/ai/generate" - async def necessary_headers(self, request_data) -> dict: - """ - :param request_data: dict - :return: dict - """ - return { - "Host": urlparse(self.endpoint).netloc, - "accept": "*/*", - "accept-language": "zh-CN,zh;q=0.9", - "cache-control": "no-cache", - "content-type": "application/json", - "pragma": "no-cache", - "Referer": "https://novelai.net/", - "Referrer-Policy": "strict-origin-when-cross-origin" - } - @model_validator(mode="after") def normalize_model(self): if self.model in [ @@ -361,7 +345,6 @@ async def request(self, } async with session if isinstance(session, AsyncSession) else await session.get_session() as sess: # Header - sess.headers.update(await self.necessary_headers(request_data)) if override_headers: sess.headers.clear() sess.headers.update(override_headers) diff --git a/src/novelai_python/sdk/ai/generate_image/__init__.py b/src/novelai_python/sdk/ai/generate_image/__init__.py index 51c7ac2..a8e710c 100755 --- a/src/novelai_python/sdk/ai/generate_image/__init__.py +++ b/src/novelai_python/sdk/ai/generate_image/__init__.py @@ -9,7 +9,6 @@ from enum import Enum from io import BytesIO from typing import Optional, Union, List -from urllib.parse import urlparse from zipfile import ZipFile, BadZipFile import curl_cffi @@ -61,9 +60,9 @@ def set_mutual_exclusion(self, value: bool): self._mutual_exclusion = bool(value) return self - action: Union[str, Action] = Field(Action.GENERATE, description="Mode for img generate") input: str = "1girl, best quality, amazing quality, very aesthetic, absurdres" model: ModelTypeAlias = "nai-diffusion-3" + action: Union[str, Action] = Field(Action.GENERATE, description="Mode for img generate") parameters: Union[Params] model_config = ConfigDict(extra="ignore") @@ -489,12 +488,12 @@ def build_generate( def build_img2img( prompt: str, *, + model: Union[Model, str] = Model.NAI_DIFFUSION_4_5_FULL, image: Union[bytes, str], strength: float = None, noise: float = None, seed: int = None, extra_noise_seed: int = None, - model: Union[Model, str] = Model.NAI_DIFFUSION_4_5_CURATED, negative_prompt: str = None, ucPreset: UCPresetTypeAlias = None, steps: int = None, @@ -523,7 +522,7 @@ def build_img2img( :param reference_strength_multiple: :param reference_image_multiple: :param prompt: Given prompt. - :param model: Model for generation. + :param model: Model for generation, which NOT end with 'inpainting'. :param negative_prompt: The things you don't want to see in the image. :param ucPreset: The negative prompt preset. :param steps: The steps for generation. @@ -592,10 +591,10 @@ def build_img2img( def build_infill( prompt: str, *, + model: Union[Model, str], image: Union[bytes, str], mask: Union[bytes, str], strength: float = None, - model: Union[Model, str] = Model.NAI_DIFFUSION_4_5_CURATED, negative_prompt: str = None, ucPreset: UCPresetTypeAlias = None, steps: int = None, @@ -645,7 +644,7 @@ def build_infill( # Update only explicitly set parameters params.image = image # image is required for infill - params.mask = mask # mask is required for infill + params.mask = mask # mask is required for infill if strength is not None: params.strength = strength if negative_prompt is not None: @@ -686,28 +685,6 @@ def build_infill( parameters=params ) - async def necessary_headers(self, request_data) -> dict: - """ - :param request_data: - :return: - """ - return { - "Host": urlparse(self.endpoint).netloc, - "Accept": "*/*", - - "Accept-Encoding": "gzip, deflate, br", - "Referer": "https://novelai.net/", - "Content-Type": "application/json", - "Origin": "https://novelai.net", - "Content-Length": str(len(json.dumps(request_data).encode("utf-8"))), - "Connection": "keep-alive", - "Sec-Fetch-Dest": "empty", - "Sec-Fetch-Mode": "cors", - "Sec-Fetch-Site": "same-site", - "Pragma": "no-cache", - "Cache-Control": "no-cache", - } - @retry( wait=wait_random(min=1, max=3), stop=stop_after_attempt(3), @@ -738,7 +715,6 @@ async def request( # Prepare request data request_data = self.model_dump(mode="json", exclude_none=True) async with session if isinstance(session, AsyncSession) else await session.get_session() as sess: - sess.headers.update(await self.necessary_headers(request_data)) if override_headers: sess.headers.clear() sess.headers.update(override_headers) diff --git a/src/novelai_python/sdk/ai/generate_image/params.py b/src/novelai_python/sdk/ai/generate_image/params.py index 563995d..d730a32 100644 --- a/src/novelai_python/sdk/ai/generate_image/params.py +++ b/src/novelai_python/sdk/ai/generate_image/params.py @@ -20,6 +20,8 @@ def is_multiple_of_01(num, precision=1e-10): class Params(BaseModel): + params_version: int = 3 + """Params Version For Request""" width: int = Field(832, ge=64, le=49152) """Width For Image""" height: int = Field(1216, ge=64, le=49152) @@ -32,42 +34,66 @@ class Params(BaseModel): """Steps""" n_samples: int = Field(1, ge=1, le=8) """Number of samples""" - strength: Optional[float] = Field(0.7, ge=0.01, le=0.99, multiple_of=0.01) - """Strength for img2img""" - noise: Optional[float] = Field(0, ge=0, le=0.99, multiple_of=0.01) - """Noise for img2img""" ucPreset: UCPresetTypeAlias = Field(None, ge=0) """The Negative Prompt Preset, Bigger or equal to 0""" qualityToggle: bool = True """Whether to add the quality prompt""" - sm: Optional[bool] = False - # TODO: find out the usage - sm_dyn: Optional[bool] = False - # TODO: find out the usage + autoSmea: Optional[bool] = False dynamic_thresholding: bool = False """Decrisp:Reduce artifacts caused by high prompt guidance values""" controlnet_strength: float = Field(1.0, ge=0.1, le=2, multiple_of=0.1) """ControlNet Strength""" legacy: bool = False """Legacy Mode""" + add_original_image: Optional[bool] = Field(False, description="Overlay Original Image") + """ + Overlay Original Image.Prevents the existing image from changing, + but can introduce seams along the edge of the mask. + """ cfg_rescale: Optional[float] = Field(0, ge=0, le=1, multiple_of=0.02) """Prompt Guidance Rescale""" noise_schedule: Optional[NoiseSchedule] = None """Noise Schedule""" legacy_v3_extend: Optional[bool] = False """Legacy V3 Extend""" - mask: ImageBytesTypeAlias = None - """Mask for Inpainting""" + skip_cfg_above_sigma: Optional[int] = None + """Variety Boost, a new feature to improve the diversity of samples.""" + use_coords: bool = Field(False, description="Use Coordinates") + """Use Coordinates""" + legacy_uc: bool = False + normalize_reference_strength_multiple: bool = True seed: int = Field( default_factory=lambda: random.randint(0, 4294967295 - 7), gt=0, le=4294967295 - 7, ) """Seed""" - image: ImageBytesTypeAlias = None - """Image for img2img""" + characterPrompts: List[Character] = Field(default_factory=list) + """Character Prompts""" + v4_prompt: Optional[V4Prompt] = Field(None, description="V4 Prompt") + """V4 Prompt""" + v4_negative_prompt: Optional[V4NegativePrompt] = Field(None, description="V4 Negative Prompt") + """V4 Negative Prompt""" negative_prompt: Optional[str] = '' """Negative Prompt""" + deliberate_euler_ancestral_bug: Optional[bool] = Field(False, description="Deliberate Euler Ancestral Bug") + """Deliberate Euler Ancestral Bug""" + prefer_brownian: bool = Field(True, description="Prefer Brownian") + """Prefer Brownian""" + + # Other fields + strength: Optional[float] = Field(0.7, ge=0.01, le=0.99, multiple_of=0.01) + """Strength for img2img""" + noise: Optional[float] = Field(0, ge=0, le=0.99, multiple_of=0.01) + """Noise for img2img""" + sm: Optional[bool] = False + # TODO: find out the usage + sm_dyn: Optional[bool] = False + # TODO: find out the usage + mask: ImageBytesTypeAlias = None + """Mask for Inpainting""" + image: ImageBytesTypeAlias = None + """Image for img2img""" reference_image_multiple: Optional[List[Union[str, bytes]]] = Field(default_factory=list) """Reference Image For Vibe Mode""" reference_information_extracted_multiple: Optional[List[float]] = Field(default_factory=list) @@ -79,49 +105,17 @@ class Params(BaseModel): """Reference Strength For Vibe Mode""" extra_noise_seed: Optional[int] = Field(None, gt=0, le=4294967295 - 7) """Extra Noise Seed""" - - # ====Version3 ==== - params_version: int = 3 - """Params Version For Request""" - add_original_image: Optional[bool] = Field(False, description="Overlay Original Image") - """ - Overlay Original Image.Prevents the existing image from changing, - but can introduce seams along the edge of the mask. - """ - use_coords: bool = Field(False, description="Use Coordinates") - """Use Coordinates""" - characterPrompts: List[Character] = Field(default_factory=list) - """Character Prompts""" - color_correct: Optional[bool] = None """For Inpaint""" inpaintImg2ImgStrength: Optional[float] = Field(None, ge=0, le=1, multiple_of=0.01) """For SameFeel""" - - v4_prompt: Optional[V4Prompt] = Field(None, description="V4 Prompt") - """V4 Prompt""" - v4_negative_prompt: Optional[V4NegativePrompt] = Field(None, description="V4 Negative Prompt") - """V4 Negative Prompt""" - - deliberate_euler_ancestral_bug: Optional[bool] = Field(False, description="Deliberate Euler Ancestral Bug") - """Deliberate Euler Ancestral Bug""" - prefer_brownian: bool = Field(True, description="Prefer Brownian") - """Prefer Brownian""" - - # ======== V1 ======== controlnet_condition: Optional[str] = None """ControlNet Condition""" controlnet_model: Optional[ControlNetModel] = None """ControlNet Model""" - skip_cfg_above_sigma: Optional[int] = None - """Variety Boost, a new feature to improve the diversity of samples.""" uncond_scale: Optional[float] = Field(None, ge=0, le=1.5, multiple_of=0.05) """Undesired Content Strength""" - autoSmea: Optional[bool] = False - normalize_reference_strength_multiple: bool = True - legacy_uc: bool = False - @model_validator(mode="after") def v_character(self): if len(self.characterPrompts) > 6: diff --git a/src/novelai_python/sdk/ai/generate_image/suggest_tags.py b/src/novelai_python/sdk/ai/generate_image/suggest_tags.py index 653bca3..ad8cf4d 100755 --- a/src/novelai_python/sdk/ai/generate_image/suggest_tags.py +++ b/src/novelai_python/sdk/ai/generate_image/suggest_tags.py @@ -37,25 +37,6 @@ def endpoint(self, value): def base_url(self): return f"{self.endpoint.strip('/')}/ai/generate-image/suggest-tags" - async def necessary_headers(self, request_data) -> dict: - return { - "Host": urlparse(self.endpoint).netloc, - "Accept": "*/*", - - "Accept-Encoding": "gzip, deflate, br", - "Access-Control-Allow-Origin": "*", - "Referer": "https://novelai.net/", - "Content-Type": "application/json", - "Origin": "https://novelai.net", - "Connection": "keep-alive", - "Sec-Fetch-Dest": "empty", - "Sec-Fetch-Mode": "cors", - "Sec-Fetch-Site": "same-site", - "Pragma": "no-cache", - "Cache-Control": "no-cache", - "TE": "trailers", - } - async def request(self, session: Union[AsyncSession, CredentialBase], *, @@ -70,9 +51,9 @@ async def request(self, # Data Build request_data = self.model_dump(mode="json", exclude_none=True) if isinstance(session, AsyncSession): - session.headers.update(await self.necessary_headers(request_data)) + pass elif isinstance(session, CredentialBase): - session = await session.get_session(update_headers=await self.necessary_headers(request_data)) + pass # Header if override_headers: session.headers.clear() diff --git a/src/novelai_python/sdk/ai/generate_stream.py b/src/novelai_python/sdk/ai/generate_stream.py index ab3c71a..dbd7b31 100644 --- a/src/novelai_python/sdk/ai/generate_stream.py +++ b/src/novelai_python/sdk/ai/generate_stream.py @@ -87,7 +87,6 @@ async def request(self, } async with session if isinstance(session, AsyncSession) else await session.get_session() as sess: # Header - sess.headers.update(await self.necessary_headers(request_data)) if override_headers: sess.headers.clear() sess.headers.update(override_headers) diff --git a/src/novelai_python/sdk/ai/generate_voice/__init__.py b/src/novelai_python/sdk/ai/generate_voice/__init__.py index 0b7f155..af1180e 100644 --- a/src/novelai_python/sdk/ai/generate_voice/__init__.py +++ b/src/novelai_python/sdk/ai/generate_voice/__init__.py @@ -57,27 +57,6 @@ def endpoint(self): def endpoint(self, value): self._endpoint = value - async def necessary_headers(self, request_data) -> dict: - """ - :param request_data: dict - :return: dict - "Sec-Ch-Ua": '"Edge";v="123", "Not:A-Brand";v="8"', - "Sec-Ch-Ua-Mobile": "?0", - "Sec-Ch-Ua-Platform": '"Windows"', - "Sec-Fetch-Dest": "empty", - "Sec-Fetch-Mode": "cors", - "Sec-Fetch-Site": "same-site", - """ - return { - "Host": urlparse(self.endpoint).netloc, - "Accept": "*/*", - "Accept-Language": "zh-CN,zh;q=0.9", - "Cache-Control": "no-cache", - "Origin": "https://novelai.net", - "Pragma": "no-cache", - "Referer": "https://novelai.net/", - } - @classmethod def build(cls, text: str, @@ -133,7 +112,6 @@ async def request(self, request_data = self.model_dump(mode="json", exclude_none=True) async with session if isinstance(session, AsyncSession) else await session.get_session() as sess: # Header - sess.headers.update(await self.necessary_headers(request_data)) if override_headers: sess.headers.clear() sess.headers.update(override_headers) diff --git a/src/novelai_python/sdk/ai/upscale.py b/src/novelai_python/sdk/ai/upscale.py index 5d8d633..df28ac9 100755 --- a/src/novelai_python/sdk/ai/upscale.py +++ b/src/novelai_python/sdk/ai/upscale.py @@ -66,28 +66,6 @@ def endpoint(self): def endpoint(self, value): self._endpoint = value - async def necessary_headers(self, request_data) -> dict: - """ - :param request_data: - :return: - """ - return { - "Host": urlparse(self.endpoint).netloc, - "Accept": "*/*", - - "Accept-Encoding": "gzip, deflate, br", - "Referer": "https://novelai.net/", - "Content-Type": "application/json", - "Origin": "https://novelai.net", - "Content-Length": str(len(json.dumps(request_data).encode("utf-8"))), - "Connection": "keep-alive", - "Sec-Fetch-Dest": "empty", - "Sec-Fetch-Mode": "cors", - "Sec-Fetch-Site": "same-site", - "Pragma": "no-cache", - "Cache-Control": "no-cache", - } - @retry( wait=wait_random(min=1, max=3), stop=stop_after_attempt(3), @@ -108,7 +86,6 @@ async def request(self, # Prepare request data request_data = self.model_dump(mode="json", exclude_none=True) async with session if isinstance(session, AsyncSession) else await session.get_session() as sess: - sess.headers.update(await self.necessary_headers(request_data)) if override_headers: sess.headers.clear() sess.headers.update(override_headers) diff --git a/src/novelai_python/sdk/schema.py b/src/novelai_python/sdk/schema.py index 020de32..1d310d9 100755 --- a/src/novelai_python/sdk/schema.py +++ b/src/novelai_python/sdk/schema.py @@ -31,10 +31,6 @@ def endpoint(self): def endpoint(self, value): self._endpoint = value - @abstractmethod - async def necessary_headers(self, request_data) -> dict: - raise NotImplementedError() - @staticmethod def ensure_session_has_post_method(session): if not hasattr(session, "post"): diff --git a/src/novelai_python/sdk/user/information.py b/src/novelai_python/sdk/user/information.py index f4347e5..9269c93 100755 --- a/src/novelai_python/sdk/user/information.py +++ b/src/novelai_python/sdk/user/information.py @@ -33,17 +33,6 @@ def endpoint(self): def endpoint(self, value): self._endpoint = value - async def necessary_headers(self, request_data) -> dict: - return { - "Host": urlparse(self.endpoint).netloc, - "Accept": "*/*", - - "Accept-Encoding": "gzip, deflate, br", - "Referer": "https://novelai.net/", - "Content-Type": "application/json", - "Origin": "https://novelai.net" - } - async def request(self, session: Union[AsyncSession, CredentialBase], *, @@ -58,7 +47,6 @@ async def request(self, request_data = {} async with session if isinstance(session, AsyncSession) else await session.get_session() as sess: # Header - sess.headers.update(await self.necessary_headers(request_data)) if override_headers: sess.headers.clear() sess.headers.update(override_headers) diff --git a/src/novelai_python/sdk/user/login.py b/src/novelai_python/sdk/user/login.py index 47caf1f..ad8736d 100755 --- a/src/novelai_python/sdk/user/login.py +++ b/src/novelai_python/sdk/user/login.py @@ -53,9 +53,6 @@ def build(cls, *, user_name: str, password: str): """ return cls(key=encode_access_key(user_name, password)) - async def necessary_headers(self, request_data) -> dict: - return {} - async def request(self, session: Union[AsyncSession, CredentialBase] = None, *, @@ -70,7 +67,6 @@ async def request(self, async with session if isinstance(session, AsyncSession) else self.session as sess: # Header - sess.headers.update(await self.necessary_headers(request_data)) if override_headers: sess.headers.clear() sess.headers.update(override_headers) diff --git a/src/novelai_python/sdk/user/subscription.py b/src/novelai_python/sdk/user/subscription.py index 17a9b44..c95631c 100755 --- a/src/novelai_python/sdk/user/subscription.py +++ b/src/novelai_python/sdk/user/subscription.py @@ -33,24 +33,6 @@ def endpoint(self): def endpoint(self, value): self._endpoint = value - async def necessary_headers(self, request_data) -> dict: - return { - "Host": urlparse(self.endpoint).netloc, - "Accept": "*/*", - - "Accept-Encoding": "gzip, deflate, br", - "Referer": "https://novelai.net/", - "Content-Type": "application/json", - "Origin": "https://novelai.net", - "Connection": "keep-alive", - "Sec-Fetch-Dest": "empty", - "Sec-Fetch-Mode": "cors", - "Sec-Fetch-Site": "same-site", - "Pragma": "no-cache", - "Cache-Control": "no-cache", - "TE": "trailers", - } - async def request(self, session: Union[AsyncSession, CredentialBase], *, @@ -66,7 +48,6 @@ async def request(self, request_data = {} async with session if isinstance(session, AsyncSession) else await session.get_session() as sess: # Header - sess.headers.update(await self.necessary_headers(request_data)) if override_headers: sess.headers.clear() sess.headers.update(override_headers)