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.
Files changed (80) hide show
  1. {novelai_python-0.4.13 → novelai_python-0.4.14}/PKG-INFO +1 -1
  2. {novelai_python-0.4.13 → novelai_python-0.4.14}/pyproject.toml +1 -1
  3. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/credential/ApiToken.py +6 -0
  4. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/credential/JwtToken.py +6 -0
  5. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/credential/UserAuth.py +5 -0
  6. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/_enum.py +57 -7
  7. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/generate_image/__init__.py +53 -26
  8. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/server.py +45 -2
  9. {novelai_python-0.4.13 → novelai_python-0.4.14}/tests/test_server_run.py +1 -1
  10. {novelai_python-0.4.13 → novelai_python-0.4.14}/LICENSE +0 -0
  11. {novelai_python-0.4.13 → novelai_python-0.4.14}/NOTICE.MD +0 -0
  12. {novelai_python-0.4.13 → novelai_python-0.4.14}/README.md +0 -0
  13. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/__init__.py +0 -0
  14. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/_exceptions.py +0 -0
  15. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/_response/__init__.py +0 -0
  16. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/_response/ai/__init__.py +0 -0
  17. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/_response/ai/generate.py +0 -0
  18. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/_response/ai/generate_image.py +0 -0
  19. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/_response/ai/generate_stream.py +0 -0
  20. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/_response/ai/generate_voice.py +0 -0
  21. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/_response/ai/upscale.py +0 -0
  22. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/_response/schema.py +0 -0
  23. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/_response/user/__init__.py +0 -0
  24. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/_response/user/information.py +0 -0
  25. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/_response/user/login.py +0 -0
  26. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/_response/user/subscription.py +0 -0
  27. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/credential/__init__.py +0 -0
  28. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/credential/_base.py +0 -0
  29. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/__init__.py +0 -0
  30. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/LICENSE +0 -0
  31. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/__init__.py +0 -0
  32. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/_const.py +0 -0
  33. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/_cost.py +0 -0
  34. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/augment_image/__init__.py +0 -0
  35. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/augment_image/_enum.py +0 -0
  36. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/generate/__init__.py +0 -0
  37. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/generate/_const.py +0 -0
  38. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/generate/_enum.py +0 -0
  39. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/generate/_preset.py +0 -0
  40. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/generate_image/suggest_tags.py +0 -0
  41. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/generate_stream.py +0 -0
  42. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/generate_voice/__init__.py +0 -0
  43. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/generate_voice/_enum.py +0 -0
  44. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/ai/upscale.py +0 -0
  45. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/schema.py +0 -0
  46. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/user/__init__.py +0 -0
  47. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/user/information.py +0 -0
  48. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/user/login.py +0 -0
  49. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/sdk/user/subscription.py +0 -0
  50. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tokenizer/NOTICE.MD +0 -0
  51. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tokenizer/__init__.py +0 -0
  52. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tokenizer/bpe_simple_vocab_16e6.txt.gz +0 -0
  53. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tokenizer/gpt2-genji_tokenizer.json +0 -0
  54. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tokenizer/gpt2_tokenizer.json +0 -0
  55. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tokenizer/nerdstash_v1.model +0 -0
  56. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tokenizer/nerdstash_v2.model +0 -0
  57. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tokenizer/novelai.model +0 -0
  58. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tokenizer/novelai_v2.model +0 -0
  59. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tokenizer/pile_tokenizer.json +0 -0
  60. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tokenizer/simple_tokenizer.py +0 -0
  61. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tool/__init__.py +0 -0
  62. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tool/image_metadata/__init__.py +0 -0
  63. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tool/image_metadata/lsb_extractor.py +0 -0
  64. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tool/image_metadata/lsb_injector.py +0 -0
  65. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tool/paint_mask/__init__.py +0 -0
  66. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tool/random_prompt/__init__.py +0 -0
  67. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tool/random_prompt/tag.py +0 -0
  68. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tool/random_prompt/tag_character.py +0 -0
  69. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/tool/random_prompt/tag_nsfw.py +0 -0
  70. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/utils/__init__.py +0 -0
  71. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/utils/encode.py +0 -0
  72. {novelai_python-0.4.13 → novelai_python-0.4.14}/src/novelai_python/utils/useful.py +0 -0
  73. {novelai_python-0.4.13 → novelai_python-0.4.14}/tests/__init__.py +0 -0
  74. {novelai_python-0.4.13 → novelai_python-0.4.14}/tests/test_generate_voice.py +0 -0
  75. {novelai_python-0.4.13 → novelai_python-0.4.14}/tests/test_random_prompt.py +0 -0
  76. {novelai_python-0.4.13 → novelai_python-0.4.14}/tests/test_server.py +0 -0
  77. {novelai_python-0.4.13 → novelai_python-0.4.14}/tests/test_upscale.py +0 -0
  78. {novelai_python-0.4.13 → novelai_python-0.4.14}/tests/test_user_information.py +0 -0
  79. {novelai_python-0.4.13 → novelai_python-0.4.14}/tests/test_user_login.py +0 -0
  80. {novelai_python-0.4.13 → novelai_python-0.4.14}/tests/test_user_subscription.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: novelai-python
3
- Version: 0.4.13
3
+ Version: 0.4.14
4
4
  Summary: NovelAI Python Binding With Pydantic
5
5
  Author-Email: sudoskys <coldlando@hotmail.com>
6
6
  License: Apache License 2.0
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "novelai-python"
3
- version = "0.4.13"
3
+ version = "0.4.14"
4
4
  description = "NovelAI Python Binding With Pydantic"
5
5
  authors = [
6
6
  { name = "sudoskys", email = "coldlando@hotmail.com" },
@@ -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
@@ -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] = NoiseSchedule.NATIVE
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.K_EULER
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(28, ge=1, le=50)
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
- 叠加原始图像。防止现有图像发生更改,仅适用于IMG2IMG模式。
513
+ 叠加原始图像。防止现有图像发生更改,仅适用于IMG2IMG模式。
491
514
  :param strength: the strength of IMG2IMG mode.
492
- IMG2IMG模式的强度。
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
- 是否使用sm。
523
+ 是否使用sm。
501
524
  :param sm_dyn: whether to use dynamic sm.
502
- 是否使用动态sm。
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/generate_image/suggest_tags")
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/generate_image")
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 == 403
33
+ assert response.status_code == 404
34
34
 
35
35
 
36
36
  def test_get_session_new_token():
File without changes