novelai-python 0.4.13__tar.gz → 0.4.14__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {novelai_python-0.4.13 → novelai_python-0.4.14}/PKG-INFO +1 -1
- {novelai_python-0.4.13 → novelai_python-0.4.14}/pyproject.toml +1 -1
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/credential/ApiToken.py +6 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/credential/JwtToken.py +6 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/credential/UserAuth.py +5 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/_enum.py +57 -7
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/generate_image/__init__.py +53 -26
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/server.py +45 -2
- {novelai_python-0.4.13 → novelai_python-0.4.14}/tests/test_server_run.py +1 -1
- {novelai_python-0.4.13 → novelai_python-0.4.14}/LICENSE +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/NOTICE.MD +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/README.md +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/__init__.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/_exceptions.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/_response/__init__.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/_response/ai/__init__.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/_response/ai/generate.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/_response/ai/generate_image.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/_response/ai/generate_stream.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/_response/ai/generate_voice.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/_response/ai/upscale.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/_response/schema.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/_response/user/__init__.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/_response/user/information.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/_response/user/login.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/_response/user/subscription.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/credential/__init__.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/credential/_base.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/__init__.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/LICENSE +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/__init__.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/_const.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/_cost.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/augment_image/__init__.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/augment_image/_enum.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/generate/__init__.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/generate/_const.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/generate/_enum.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/generate/_preset.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/generate_image/suggest_tags.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/generate_stream.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/generate_voice/__init__.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/generate_voice/_enum.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/upscale.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/schema.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/user/__init__.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/user/information.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/user/login.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/user/subscription.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tokenizer/NOTICE.MD +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tokenizer/__init__.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tokenizer/bpe_simple_vocab_16e6.txt.gz +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tokenizer/gpt2-genji_tokenizer.json +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tokenizer/gpt2_tokenizer.json +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tokenizer/nerdstash_v1.model +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tokenizer/nerdstash_v2.model +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tokenizer/novelai.model +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tokenizer/novelai_v2.model +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tokenizer/pile_tokenizer.json +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tokenizer/simple_tokenizer.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tool/__init__.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tool/image_metadata/__init__.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tool/image_metadata/lsb_extractor.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tool/image_metadata/lsb_injector.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tool/paint_mask/__init__.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tool/random_prompt/__init__.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tool/random_prompt/tag.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tool/random_prompt/tag_character.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tool/random_prompt/tag_nsfw.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/utils/__init__.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/utils/encode.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/utils/useful.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/tests/__init__.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/tests/test_generate_voice.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/tests/test_random_prompt.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/tests/test_server.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/tests/test_upscale.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/tests/test_user_information.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/tests/test_user_login.py +0 -0
- {novelai_python-0.4.13 → novelai_python-0.4.14}/tests/test_user_subscription.py +0 -0
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
# @File : ApiToken.py
|
|
5
5
|
# @Software: PyCharm
|
|
6
6
|
|
|
7
|
+
import datetime
|
|
8
|
+
|
|
9
|
+
import shortuuid
|
|
7
10
|
from curl_cffi.requests import AsyncSession
|
|
8
11
|
from loguru import logger
|
|
9
12
|
from pydantic import SecretStr, Field, field_validator
|
|
@@ -16,6 +19,7 @@ class ApiCredential(CredentialBase):
|
|
|
16
19
|
ApiCredential is the base class for all credential.
|
|
17
20
|
"""
|
|
18
21
|
api_token: SecretStr = Field(None, description="api token")
|
|
22
|
+
_x_correlation_id: str = shortuuid.uuid()[0:6]
|
|
19
23
|
|
|
20
24
|
async def get_session(self, timeout: int = 180, update_headers: dict = None):
|
|
21
25
|
headers = {
|
|
@@ -26,6 +30,8 @@ class ApiCredential(CredentialBase):
|
|
|
26
30
|
"Content-Type": "application/json",
|
|
27
31
|
"Origin": "https://novelai.net",
|
|
28
32
|
"Referer": "https://novelai.net/",
|
|
33
|
+
"x-correlation-id": self._x_correlation_id,
|
|
34
|
+
"x-initiated-at": f"{datetime.datetime.now(datetime.UTC).isoformat()}Z",
|
|
29
35
|
}
|
|
30
36
|
|
|
31
37
|
if update_headers:
|
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
# @Author : sudoskys
|
|
4
4
|
# @File : JwtToken.py
|
|
5
5
|
# @Software: PyCharm
|
|
6
|
+
import datetime
|
|
7
|
+
|
|
8
|
+
import shortuuid
|
|
6
9
|
from curl_cffi.requests import AsyncSession
|
|
7
10
|
from loguru import logger
|
|
8
11
|
from pydantic import SecretStr, Field, field_validator
|
|
@@ -15,6 +18,7 @@ class JwtCredential(CredentialBase):
|
|
|
15
18
|
JwtCredential is the base class for all credential.
|
|
16
19
|
"""
|
|
17
20
|
jwt_token: SecretStr = Field(None, description="jwt token")
|
|
21
|
+
_x_correlation_id: str = shortuuid.uuid()[0:6]
|
|
18
22
|
|
|
19
23
|
async def get_session(self, timeout: int = 180, update_headers: dict = None):
|
|
20
24
|
headers = {
|
|
@@ -25,6 +29,8 @@ class JwtCredential(CredentialBase):
|
|
|
25
29
|
"Content-Type": "application/json",
|
|
26
30
|
"Origin": "https://novelai.net",
|
|
27
31
|
"Referer": "https://novelai.net/",
|
|
32
|
+
"x-correlation-id": self._x_correlation_id,
|
|
33
|
+
"x-initiated-at": f"{datetime.datetime.now(datetime.UTC).isoformat()}Z",
|
|
28
34
|
}
|
|
29
35
|
|
|
30
36
|
if update_headers:
|
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
# @Time : 2024/2/7 下午12:14
|
|
3
3
|
# @Author : sudoskys
|
|
4
4
|
# @File : UserAuth.py
|
|
5
|
+
import datetime
|
|
5
6
|
import time
|
|
6
7
|
from typing import Optional
|
|
7
8
|
|
|
9
|
+
import shortuuid
|
|
8
10
|
from curl_cffi.requests import AsyncSession
|
|
9
11
|
from pydantic import SecretStr, Field
|
|
10
12
|
|
|
@@ -19,6 +21,7 @@ class LoginCredential(CredentialBase):
|
|
|
19
21
|
password: SecretStr = Field(None, description="password")
|
|
20
22
|
_session_headers: dict = {}
|
|
21
23
|
_update_at: Optional[int] = None
|
|
24
|
+
_x_correlation_id: str = shortuuid.uuid()[0:6]
|
|
22
25
|
|
|
23
26
|
async def get_session(self, timeout: int = 180, update_headers: dict = None):
|
|
24
27
|
headers = {
|
|
@@ -29,6 +32,8 @@ class LoginCredential(CredentialBase):
|
|
|
29
32
|
"Content-Type": "application/json",
|
|
30
33
|
"Origin": "https://novelai.net",
|
|
31
34
|
"Referer": "https://novelai.net/",
|
|
35
|
+
"x-correlation-id": self._x_correlation_id,
|
|
36
|
+
"x-initiated-at": f"{datetime.datetime.now(datetime.UTC).isoformat()}Z",
|
|
32
37
|
}
|
|
33
38
|
|
|
34
39
|
# 30 天有效期
|
|
@@ -4,25 +4,25 @@
|
|
|
4
4
|
# @File : _enum.py
|
|
5
5
|
# @Software: PyCharm
|
|
6
6
|
from enum import Enum, IntEnum
|
|
7
|
+
from typing import List
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
class Sampler(Enum):
|
|
11
|
+
PLMS = "plms"
|
|
12
|
+
DDIM = "ddim"
|
|
10
13
|
K_EULER = "k_euler"
|
|
11
14
|
K_EULER_ANCESTRAL = "k_euler_ancestral"
|
|
12
|
-
K_DPMPP_2S_ANCESTRAL = "k_dpmpp_2s_ancestral"
|
|
13
|
-
K_DPMPP_2M = "k_dpmpp_2m"
|
|
14
|
-
K_DPMPP_SDE = "k_dpmpp_sde"
|
|
15
|
-
DDIM_V3 = "ddim_v3"
|
|
16
|
-
|
|
17
|
-
DDIM = "ddim"
|
|
18
|
-
PLMS = "plms"
|
|
19
15
|
K_DPM_2 = "k_dpm_2"
|
|
20
16
|
K_DPM_2_ANCESTRAL = "k_dpm_2_ancestral"
|
|
21
17
|
K_LMS = "k_lms"
|
|
18
|
+
K_DPMPP_2S_ANCESTRAL = "k_dpmpp_2s_ancestral"
|
|
19
|
+
K_DPMPP_SDE = "k_dpmpp_sde"
|
|
20
|
+
K_DPMPP_2M = "k_dpmpp_2m"
|
|
22
21
|
K_DPM_ADAPTIVE = "k_dpm_adaptive"
|
|
23
22
|
K_DPM_FAST = "k_dpm_fast"
|
|
24
23
|
K_DPMPP_2M_SDE = "k_dpmpp_2m_sde"
|
|
25
24
|
K_DPMPP_3M_SDE = "k_dpmpp_3m_sde"
|
|
25
|
+
DDIM_V3 = "ddim_v3"
|
|
26
26
|
NAI_SMEA = "nai_smea"
|
|
27
27
|
NAI_SMEA_DYN = "nai_smea_dyn"
|
|
28
28
|
|
|
@@ -34,6 +34,56 @@ class NoiseSchedule(Enum):
|
|
|
34
34
|
POLYEXPONENTIAL = "polyexponential"
|
|
35
35
|
|
|
36
36
|
|
|
37
|
+
def get_supported_noise_schedule(sample_type: Sampler) -> List[NoiseSchedule]:
|
|
38
|
+
"""
|
|
39
|
+
Get supported noise schedule for a given sample type
|
|
40
|
+
:param sample_type: Sampler
|
|
41
|
+
:return: List[NoiseSchedule]
|
|
42
|
+
"""
|
|
43
|
+
if sample_type in [
|
|
44
|
+
Sampler.K_EULER_ANCESTRAL,
|
|
45
|
+
Sampler.K_DPMPP_2S_ANCESTRAL,
|
|
46
|
+
Sampler.K_DPMPP_2M,
|
|
47
|
+
Sampler.K_DPMPP_2M_SDE,
|
|
48
|
+
Sampler.K_DPMPP_SDE,
|
|
49
|
+
Sampler.K_EULER
|
|
50
|
+
]:
|
|
51
|
+
return [
|
|
52
|
+
NoiseSchedule.NATIVE,
|
|
53
|
+
NoiseSchedule.KARRAS,
|
|
54
|
+
NoiseSchedule.EXPONENTIAL,
|
|
55
|
+
NoiseSchedule.POLYEXPONENTIAL
|
|
56
|
+
]
|
|
57
|
+
elif sample_type in [Sampler.K_DPM_2]:
|
|
58
|
+
return [
|
|
59
|
+
NoiseSchedule.EXPONENTIAL,
|
|
60
|
+
NoiseSchedule.POLYEXPONENTIAL
|
|
61
|
+
]
|
|
62
|
+
else:
|
|
63
|
+
return []
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def get_default_noise_schedule(sample_type: Sampler) -> NoiseSchedule:
|
|
67
|
+
"""
|
|
68
|
+
Get default noise schedule for a given sample type
|
|
69
|
+
:param sample_type: Sampler
|
|
70
|
+
:return: NoiseSchedule
|
|
71
|
+
"""
|
|
72
|
+
if sample_type in [
|
|
73
|
+
Sampler.K_EULER_ANCESTRAL,
|
|
74
|
+
Sampler.K_DPMPP_2S_ANCESTRAL,
|
|
75
|
+
Sampler.K_DPMPP_2M,
|
|
76
|
+
Sampler.K_DPMPP_2M_SDE,
|
|
77
|
+
Sampler.K_DPMPP_SDE,
|
|
78
|
+
Sampler.K_EULER
|
|
79
|
+
]:
|
|
80
|
+
return NoiseSchedule.KARRAS
|
|
81
|
+
elif sample_type in [Sampler.K_DPM_2]:
|
|
82
|
+
return NoiseSchedule.EXPONENTIAL
|
|
83
|
+
else:
|
|
84
|
+
return NoiseSchedule.NATIVE
|
|
85
|
+
|
|
86
|
+
|
|
37
87
|
class UCPreset(IntEnum):
|
|
38
88
|
TYPE0 = 0
|
|
39
89
|
TYPE1 = 1
|
{novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/generate_image/__init__.py
RENAMED
|
@@ -23,8 +23,9 @@ from pydantic import BaseModel, ConfigDict, PrivateAttr, field_validator, model_
|
|
|
23
23
|
from tenacity import retry, stop_after_attempt, wait_random, retry_if_exception
|
|
24
24
|
from typing_extensions import override
|
|
25
25
|
|
|
26
|
-
from novelai_python.sdk.ai._enum import Model, Sampler, NoiseSchedule, ControlNetModel, Action, UCPreset, INPAINTING_MODEL_LIST
|
|
27
26
|
from novelai_python.sdk.ai._cost import CostCalculator
|
|
27
|
+
from novelai_python.sdk.ai._enum import Model, Sampler, NoiseSchedule, ControlNetModel, Action, UCPreset, \
|
|
28
|
+
INPAINTING_MODEL_LIST, get_default_noise_schedule, get_supported_noise_schedule
|
|
28
29
|
from ...schema import ApiBaseModel
|
|
29
30
|
from ...._exceptions import APIError, AuthError, ConcurrentGenerationError, SessionHttpError
|
|
30
31
|
from ...._response.ai.generate_image import ImageGenerateResp, RequestParams
|
|
@@ -52,7 +53,7 @@ class Params(BaseModel):
|
|
|
52
53
|
controlnet_strength: Optional[float] = Field(1.0, ge=0.1, le=2, multiple_of=0.1)
|
|
53
54
|
"""ControlNet Strength"""
|
|
54
55
|
dynamic_thresholding: Optional[bool] = False
|
|
55
|
-
"""Reduce artifacts caused by high prompt guidance values"""
|
|
56
|
+
"""Decrisp:Reduce artifacts caused by high prompt guidance values"""
|
|
56
57
|
height: Optional[int] = Field(1216, ge=64, le=49152)
|
|
57
58
|
"""Height For Generate Image"""
|
|
58
59
|
image: Optional[Union[str, bytes]] = None
|
|
@@ -69,7 +70,7 @@ class Params(BaseModel):
|
|
|
69
70
|
"""Number of samples"""
|
|
70
71
|
negative_prompt: Optional[str] = ''
|
|
71
72
|
"""Negative Prompt"""
|
|
72
|
-
noise_schedule: Optional[NoiseSchedule] =
|
|
73
|
+
noise_schedule: Optional[NoiseSchedule] = None
|
|
73
74
|
"""Noise Schedule"""
|
|
74
75
|
# Misc
|
|
75
76
|
params_version: Optional[int] = 1
|
|
@@ -112,7 +113,7 @@ class Params(BaseModel):
|
|
|
112
113
|
# TODO: find out the usage
|
|
113
114
|
qualityToggle: Optional[bool] = True
|
|
114
115
|
"""Whether to add the quality prompt"""
|
|
115
|
-
sampler: Optional[Sampler] = Sampler.
|
|
116
|
+
sampler: Optional[Sampler] = Sampler.K_EULER_ANCESTRAL
|
|
116
117
|
"""Sampler For Generate Image"""
|
|
117
118
|
scale: Optional[float] = Field(6.0, ge=0, le=10, multiple_of=0.1)
|
|
118
119
|
"""Prompt Guidance"""
|
|
@@ -123,6 +124,8 @@ class Params(BaseModel):
|
|
|
123
124
|
le=4294967295 - 7,
|
|
124
125
|
)
|
|
125
126
|
"""Seed"""
|
|
127
|
+
skip_cfg_above_sigma: Optional[int] = None
|
|
128
|
+
"""Variety Boost, a new feature to improve the diversity of samples."""
|
|
126
129
|
extra_noise_seed: Optional[int] = Field(
|
|
127
130
|
default_factory=lambda: random.randint(0, 4294967295 - 7),
|
|
128
131
|
gt=0,
|
|
@@ -133,7 +136,7 @@ class Params(BaseModel):
|
|
|
133
136
|
# TODO: find out the usage
|
|
134
137
|
sm_dyn: Optional[bool] = False
|
|
135
138
|
# TODO: find out the usage
|
|
136
|
-
steps: Optional[int] = Field(
|
|
139
|
+
steps: Optional[int] = Field(23, ge=1, le=50)
|
|
137
140
|
"""Steps"""
|
|
138
141
|
ucPreset: Optional[UCPreset] = 0
|
|
139
142
|
"""The Negative Prompt Preset"""
|
|
@@ -212,6 +215,16 @@ class Params(BaseModel):
|
|
|
212
215
|
# Validators
|
|
213
216
|
@model_validator(mode="after")
|
|
214
217
|
def image_validator(self):
|
|
218
|
+
# Noise schedule check
|
|
219
|
+
if self.noise_schedule is None:
|
|
220
|
+
self.noise_schedule = get_default_noise_schedule(self.sampler)
|
|
221
|
+
supported_noise_schedule = get_supported_noise_schedule(self.sampler)
|
|
222
|
+
if supported_noise_schedule:
|
|
223
|
+
if self.noise_schedule not in supported_noise_schedule:
|
|
224
|
+
raise ValueError(f"Invalid noise_schedule, must be one of {supported_noise_schedule}")
|
|
225
|
+
else:
|
|
226
|
+
logger.warning(f"Inactive sampler {self.sampler} does not support noise_schedule.")
|
|
227
|
+
# Check the noise value
|
|
215
228
|
if self.sampler:
|
|
216
229
|
if self.sampler in [Sampler.DDIM, Sampler.DDIM_V3]:
|
|
217
230
|
self.sm = False
|
|
@@ -223,6 +236,7 @@ class Params(BaseModel):
|
|
|
223
236
|
self.sm_dyn = True
|
|
224
237
|
if not self.sm_dyn:
|
|
225
238
|
logger.warning("sm and sm_dyn is enabled when using nai_smea_dyn sampler.")
|
|
239
|
+
# Make sure the image is base64 encoded
|
|
226
240
|
if isinstance(self.image, str) and self.image.startswith("data:"):
|
|
227
241
|
raise ValueError("Invalid `image` format, must be base64 encoded directly.")
|
|
228
242
|
if isinstance(self.mask, str) and self.mask.startswith("data:"):
|
|
@@ -430,7 +444,10 @@ class GenerateImageInfer(ApiBaseModel):
|
|
|
430
444
|
height: int = 1216,
|
|
431
445
|
qualityToggle: bool = None,
|
|
432
446
|
image: Union[str, bytes] = None,
|
|
447
|
+
decrisp_mode: bool = False,
|
|
448
|
+
variety_boost: bool = False,
|
|
433
449
|
noise: float = 0,
|
|
450
|
+
noise_schedule: Union[NoiseSchedule, str] = None,
|
|
434
451
|
reference_image_multiple: List[Union[str, bytes]] = None,
|
|
435
452
|
reference_strength_multiple: List[float] = None,
|
|
436
453
|
reference_information_extracted_multiple: List[float] = None,
|
|
@@ -450,6 +467,10 @@ class GenerateImageInfer(ApiBaseModel):
|
|
|
450
467
|
"""
|
|
451
468
|
The build function, more convenient to create a GenerateImageInfer instance.
|
|
452
469
|
构建函数,更方便地创建一个GenerateImageInfer实例。
|
|
470
|
+
:param decrisp_mode: Reduce artifacts caused by high prompt guidance values.
|
|
471
|
+
减少由高提示引导值引起的伪影。
|
|
472
|
+
:param variety_boost: A new feature to improve the diversity of samples.
|
|
473
|
+
一项新功能,用于提高样本的多样性。
|
|
453
474
|
:param reference_information_extracted_multiple: The reference information extracted for Vibe mode.
|
|
454
475
|
Vibe模式的提取的参考信息。
|
|
455
476
|
:param reference_image_multiple: The reference image for Vibe mode.
|
|
@@ -459,52 +480,53 @@ class GenerateImageInfer(ApiBaseModel):
|
|
|
459
480
|
:param ucPreset: 0: Heavy, 1: Light, 2: Character
|
|
460
481
|
0: 重量级, 1: 轻量级, 2: 角色
|
|
461
482
|
:param qualityToggle: add the quality prompt or not.
|
|
462
|
-
|
|
483
|
+
是否添加质量提示。
|
|
463
484
|
:param prompt: input prompt for generation.
|
|
464
|
-
|
|
485
|
+
生成的输入提示。
|
|
465
486
|
:param model: select a model.
|
|
466
|
-
|
|
487
|
+
选择一个模型。
|
|
467
488
|
:param action: mode for image generation [generate, img2img, infill].
|
|
468
|
-
|
|
489
|
+
图像生成模式 [生成, 图像到图像, 填充]。
|
|
469
490
|
:param negative_prompt: the content of negative prompt.
|
|
470
491
|
负面提示的内容。
|
|
471
492
|
:param seed: the seed for generate image.
|
|
472
|
-
|
|
493
|
+
生成图像的种子。
|
|
473
494
|
:param steps: the steps for generate image.
|
|
474
|
-
|
|
495
|
+
生成图像的步骤。
|
|
475
496
|
:param scale: the scale for generate image.
|
|
476
|
-
|
|
497
|
+
生成图像的比例。
|
|
477
498
|
:param cfg_rescale: prompt guidance rescale 0-1 lower is more creative.
|
|
478
499
|
提示引导的重新缩放0-1,越低则越富有创造性。
|
|
479
500
|
:param sampler: the sampler for generate image.
|
|
480
501
|
生成图像的采样器。
|
|
481
502
|
:param width: the width of the image.
|
|
482
|
-
|
|
503
|
+
图像的宽度。
|
|
483
504
|
:param height: the height of the image.
|
|
484
|
-
|
|
505
|
+
图像的高度。
|
|
485
506
|
:param image: the input image.
|
|
486
|
-
|
|
507
|
+
输入图像。
|
|
487
508
|
:param noise: the noise to be added in the image.
|
|
488
|
-
|
|
509
|
+
要添加到图像中的噪声。
|
|
510
|
+
:param noise_schedule: the noise schedule for generate image.
|
|
511
|
+
生成图像的噪声计划。
|
|
489
512
|
:param add_original_image: Overlay Original Image. Prevents the existing image from changing, only for IMG2IMG mode.
|
|
490
|
-
|
|
513
|
+
叠加原始图像。防止现有图像发生更改,仅适用于IMG2IMG模式。
|
|
491
514
|
:param strength: the strength of IMG2IMG mode.
|
|
492
|
-
|
|
515
|
+
IMG2IMG模式的强度。
|
|
493
516
|
:param mask: the inpainting mask.
|
|
494
|
-
|
|
517
|
+
纹理绘制掩码。
|
|
495
518
|
:param controlnet_model: the model used for the control network.
|
|
496
|
-
|
|
519
|
+
用于控制网络的模型。
|
|
497
520
|
:param controlnet_condition: the condition used for the control network.
|
|
498
|
-
|
|
521
|
+
用于控制网络的条件。
|
|
499
522
|
:param sm: whether to use sm.
|
|
500
|
-
|
|
523
|
+
是否使用sm。
|
|
501
524
|
:param sm_dyn: whether to use dynamic sm.
|
|
502
|
-
|
|
525
|
+
是否使用动态sm。
|
|
503
526
|
:param uncond_scale: the strength of the unrelated content.
|
|
504
|
-
|
|
527
|
+
无关内容的强度。
|
|
505
528
|
:param kwargs: any additional parameters.
|
|
506
|
-
|
|
507
|
-
|
|
529
|
+
其他任何参数。
|
|
508
530
|
:return: self
|
|
509
531
|
返回:自身
|
|
510
532
|
"""
|
|
@@ -528,6 +550,7 @@ class GenerateImageInfer(ApiBaseModel):
|
|
|
528
550
|
"sm_dyn": sm_dyn,
|
|
529
551
|
"sm": sm,
|
|
530
552
|
"uncond_scale": uncond_scale,
|
|
553
|
+
"noise_schedule": noise_schedule,
|
|
531
554
|
})
|
|
532
555
|
|
|
533
556
|
def _merge_param(v1, v2):
|
|
@@ -579,6 +602,10 @@ class GenerateImageInfer(ApiBaseModel):
|
|
|
579
602
|
"noise": noise,
|
|
580
603
|
}
|
|
581
604
|
)
|
|
605
|
+
if decrisp_mode:
|
|
606
|
+
kwargs.update({"dynamic_thresholding": True})
|
|
607
|
+
if variety_boost:
|
|
608
|
+
kwargs.update({"skip_cfg_above_sigma": 19})
|
|
582
609
|
# 清理空值
|
|
583
610
|
param = {k: v for k, v in kwargs.items() if v is not None}
|
|
584
611
|
_build_prop = Params(**param)
|
|
@@ -15,6 +15,7 @@ from loguru import logger
|
|
|
15
15
|
from starlette.responses import JSONResponse, StreamingResponse
|
|
16
16
|
|
|
17
17
|
from novelai_python import LLMStream, LLMStreamResp
|
|
18
|
+
from novelai_python.sdk.ai.augment_image import ReqType, Moods, AugmentImageInfer
|
|
18
19
|
from .credential import JwtCredential, SecretStr
|
|
19
20
|
from .sdk.ai.generate import LLM
|
|
20
21
|
from .sdk.ai.generate_image import GenerateImageInfer, Model
|
|
@@ -123,7 +124,7 @@ async def upscale(
|
|
|
123
124
|
return JSONResponse(status_code=500, content=e.__dict__)
|
|
124
125
|
|
|
125
126
|
|
|
126
|
-
@app.get("/ai/
|
|
127
|
+
@app.get("/ai/generate-image/suggest_tags")
|
|
127
128
|
async def suggest_tags(
|
|
128
129
|
model: Model,
|
|
129
130
|
prompt: str,
|
|
@@ -145,7 +146,7 @@ async def suggest_tags(
|
|
|
145
146
|
return JSONResponse(status_code=500, content=e.__dict__)
|
|
146
147
|
|
|
147
148
|
|
|
148
|
-
@app.post("/ai/
|
|
149
|
+
@app.post("/ai/generate-image")
|
|
149
150
|
async def generate_image(
|
|
150
151
|
req: GenerateImageInfer,
|
|
151
152
|
current_token: str = Depends(get_current_token)
|
|
@@ -244,6 +245,48 @@ async def generate_voice(
|
|
|
244
245
|
return JSONResponse(status_code=500, content=e.__dict__)
|
|
245
246
|
|
|
246
247
|
|
|
248
|
+
@app.post("/ai/augment-image")
|
|
249
|
+
async def augment_image(
|
|
250
|
+
req_type: ReqType,
|
|
251
|
+
image: bytes,
|
|
252
|
+
mood: Optional[Moods] = None,
|
|
253
|
+
prompt: Optional[str] = None,
|
|
254
|
+
defry: Optional[int] = None,
|
|
255
|
+
current_token: str = Depends(get_current_token)
|
|
256
|
+
):
|
|
257
|
+
"""
|
|
258
|
+
生成图片
|
|
259
|
+
:param current_token: Authorization
|
|
260
|
+
:param req_type: ReqType
|
|
261
|
+
:param image: bytes
|
|
262
|
+
:param mood: Optional[Moods]
|
|
263
|
+
:param prompt: Optional[str]
|
|
264
|
+
:param defry: Optional[int]
|
|
265
|
+
:return:
|
|
266
|
+
"""
|
|
267
|
+
try:
|
|
268
|
+
req = AugmentImageInfer.build(
|
|
269
|
+
req_type=req_type,
|
|
270
|
+
image=image,
|
|
271
|
+
mood=mood,
|
|
272
|
+
prompt=prompt,
|
|
273
|
+
defry=defry,
|
|
274
|
+
)
|
|
275
|
+
_result = await req.request(session=get_session(current_token))
|
|
276
|
+
zip_file_bytes = io.BytesIO()
|
|
277
|
+
with zipfile.ZipFile(zip_file_bytes, mode="w", compression=zipfile.ZIP_DEFLATED) as zip_file:
|
|
278
|
+
for file in _result.files:
|
|
279
|
+
zip_file.writestr(zinfo_or_arcname=file[0], data=file[1])
|
|
280
|
+
# return the zip file
|
|
281
|
+
zip_file_bytes.seek(0)
|
|
282
|
+
return StreamingResponse(zip_file_bytes, media_type='application/zip', headers={
|
|
283
|
+
'Content-Disposition': 'attachment;filename=image.zip'
|
|
284
|
+
})
|
|
285
|
+
except Exception as e:
|
|
286
|
+
logger.exception(e)
|
|
287
|
+
return JSONResponse(status_code=500, content=e.__dict__)
|
|
288
|
+
|
|
289
|
+
|
|
247
290
|
# 获取输入参数
|
|
248
291
|
def usage():
|
|
249
292
|
print("Usage: python -m novelai_python.server -h <host> -p <port>")
|
|
@@ -30,7 +30,7 @@ def test_subscription_without_api_key(mock_subscription):
|
|
|
30
30
|
def test_generate_image_without_api_key(mock_generate_image):
|
|
31
31
|
mock_generate_image.return_value.request.return_value = {"status": "image generated"}
|
|
32
32
|
response = client.post("/ai/generate_image")
|
|
33
|
-
assert response.status_code ==
|
|
33
|
+
assert response.status_code == 404
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
def test_get_session_new_token():
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/_response/ai/generate_image.py
RENAMED
|
File without changes
|
{novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/_response/ai/generate_stream.py
RENAMED
|
File without changes
|
{novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/_response/ai/generate_voice.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/_response/user/__init__.py
RENAMED
|
File without changes
|
{novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/_response/user/information.py
RENAMED
|
File without changes
|
|
File without changes
|
{novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/_response/user/subscription.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/augment_image/__init__.py
RENAMED
|
File without changes
|
{novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/augment_image/_enum.py
RENAMED
|
File without changes
|
{novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/generate/__init__.py
RENAMED
|
File without changes
|
{novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/generate/_const.py
RENAMED
|
File without changes
|
|
File without changes
|
{novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/generate/_preset.py
RENAMED
|
File without changes
|
|
File without changes
|
{novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/generate_stream.py
RENAMED
|
File without changes
|
{novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/generate_voice/__init__.py
RENAMED
|
File without changes
|
{novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/generate_voice/_enum.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tokenizer/gpt2_tokenizer.json
RENAMED
|
File without changes
|
{novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tokenizer/nerdstash_v1.model
RENAMED
|
File without changes
|
{novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tokenizer/nerdstash_v2.model
RENAMED
|
File without changes
|
|
File without changes
|
{novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tokenizer/novelai_v2.model
RENAMED
|
File without changes
|
{novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tokenizer/pile_tokenizer.json
RENAMED
|
File without changes
|
{novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tokenizer/simple_tokenizer.py
RENAMED
|
File without changes
|
|
File without changes
|
{novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tool/image_metadata/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tool/paint_mask/__init__.py
RENAMED
|
File without changes
|
{novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tool/random_prompt/__init__.py
RENAMED
|
File without changes
|
{novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tool/random_prompt/tag.py
RENAMED
|
File without changes
|
|
File without changes
|
{novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tool/random_prompt/tag_nsfw.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|