novelai-python 0.3.5__tar.gz → 0.3.7__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 (50) hide show
  1. {novelai_python-0.3.5 → novelai_python-0.3.7}/PKG-INFO +2 -2
  2. {novelai_python-0.3.5 → novelai_python-0.3.7}/pyproject.toml +2 -2
  3. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/sdk/ai/generate_image/__init__.py +250 -104
  4. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/sdk/ai/generate_image/_enum.py +8 -0
  5. {novelai_python-0.3.5 → novelai_python-0.3.7}/LICENSE +0 -0
  6. {novelai_python-0.3.5 → novelai_python-0.3.7}/NOTICE.MD +0 -0
  7. {novelai_python-0.3.5 → novelai_python-0.3.7}/README.md +0 -0
  8. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/__init__.py +0 -0
  9. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/_exceptions.py +0 -0
  10. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/_response/__init__.py +0 -0
  11. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/_response/ai/__init__.py +0 -0
  12. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/_response/ai/generate_image.py +0 -0
  13. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/_response/ai/upscale.py +0 -0
  14. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/_response/schema.py +0 -0
  15. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/_response/user/__init__.py +0 -0
  16. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/_response/user/information.py +0 -0
  17. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/_response/user/login.py +0 -0
  18. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/_response/user/subscription.py +0 -0
  19. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/credential/ApiToken.py +0 -0
  20. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/credential/JwtToken.py +0 -0
  21. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/credential/UserAuth.py +0 -0
  22. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/credential/__init__.py +0 -0
  23. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/credential/_base.py +0 -0
  24. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/sdk/__init__.py +0 -0
  25. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/sdk/ai/LICENSE +0 -0
  26. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/sdk/ai/__init__.py +0 -0
  27. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/sdk/ai/generate_image/suggest_tags.py +0 -0
  28. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/sdk/ai/upscale.py +0 -0
  29. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/sdk/schema.py +0 -0
  30. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/sdk/user/__init__.py +0 -0
  31. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/sdk/user/information.py +0 -0
  32. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/sdk/user/login.py +0 -0
  33. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/sdk/user/subscription.py +0 -0
  34. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/server.py +0 -0
  35. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/utils/__init__.py +0 -0
  36. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/utils/encode.py +0 -0
  37. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/utils/hash.py +0 -0
  38. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/utils/random_prompt/__init__.py +0 -0
  39. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/utils/random_prompt/tag.py +0 -0
  40. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/utils/random_prompt/tag_character.py +0 -0
  41. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/utils/random_prompt/tag_nsfw.py +0 -0
  42. {novelai_python-0.3.5 → novelai_python-0.3.7}/src/novelai_python/utils/useful.py +0 -0
  43. {novelai_python-0.3.5 → novelai_python-0.3.7}/tests/__init__.py +0 -0
  44. {novelai_python-0.3.5 → novelai_python-0.3.7}/tests/test_random_prompt.py +0 -0
  45. {novelai_python-0.3.5 → novelai_python-0.3.7}/tests/test_server.py +0 -0
  46. {novelai_python-0.3.5 → novelai_python-0.3.7}/tests/test_server_run.py +0 -0
  47. {novelai_python-0.3.5 → novelai_python-0.3.7}/tests/test_upscale.py +0 -0
  48. {novelai_python-0.3.5 → novelai_python-0.3.7}/tests/test_user_information.py +0 -0
  49. {novelai_python-0.3.5 → novelai_python-0.3.7}/tests/test_user_login.py +0 -0
  50. {novelai_python-0.3.5 → novelai_python-0.3.7}/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.3.5
3
+ Version: 0.3.7
4
4
  Summary: Novelai Python Binding With Pydantic
5
5
  Author-Email: sudoskys <coldlando@hotmail.com>
6
6
  License: Apache License 2.0
@@ -14,7 +14,7 @@ Requires-Dist: pydantic>=2.5.3
14
14
  Requires-Dist: httpx>=0.26.0
15
15
  Requires-Dist: shortuuid>=1.0.11
16
16
  Requires-Dist: Pillow>=10.2.0
17
- Requires-Dist: curl-cffi>=0.5.10
17
+ Requires-Dist: curl-cffi>=0.6.0
18
18
  Requires-Dist: fastapi>=0.109.0
19
19
  Requires-Dist: uvicorn[standard]>=0.27.0.post1
20
20
  Requires-Dist: numpy>=1.24.4
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "novelai-python"
3
- version = "0.3.5"
3
+ version = "0.3.7"
4
4
  description = "Novelai Python Binding With Pydantic"
5
5
  authors = [
6
6
  { name = "sudoskys", email = "coldlando@hotmail.com" },
@@ -13,7 +13,7 @@ dependencies = [
13
13
  "httpx>=0.26.0",
14
14
  "shortuuid>=1.0.11",
15
15
  "Pillow>=10.2.0",
16
- "curl-cffi>=0.5.10",
16
+ "curl-cffi>=0.6.0",
17
17
  "fastapi>=0.109.0",
18
18
  "uvicorn[standard]>=0.27.0.post1",
19
19
  "numpy>=1.24.4",
@@ -21,61 +21,79 @@ from pydantic import BaseModel, ConfigDict, PrivateAttr, field_validator, model_
21
21
  from tenacity import retry, stop_after_attempt, wait_random, retry_if_exception
22
22
  from typing_extensions import override
23
23
 
24
- from ._enum import Model, Sampler, NoiseSchedule, ControlNetModel, Action, UCPreset
24
+ from ._enum import Model, Sampler, NoiseSchedule, ControlNetModel, Action, UCPreset, INPAINTING_MODEL_LIST
25
25
  from ...schema import ApiBaseModel
26
26
  from ...._exceptions import APIError, AuthError, ConcurrentGenerationError, SessionHttpError
27
27
  from ...._response.ai.generate_image import ImageGenerateResp
28
28
  from ....credential import CredentialBase
29
29
  from ....utils import try_jsonfy, NovelAiMetadata
30
+ from PIL import Image
30
31
 
31
32
 
32
33
  class GenerateImageInfer(ApiBaseModel):
33
- _endpoint: Optional[str] = PrivateAttr("https://api.novelai.net")
34
+ _endpoint: Optional[str] = PrivateAttr("https://image.novelai.net")
34
35
 
35
36
  class Params(BaseModel):
36
- # Inpaint
37
- add_original_image: Optional[bool] = False # FIXME: 未知作用
38
- mask: Optional[Union[str, bytes]] = None # img2img,base64
39
-
37
+ add_original_image: Optional[bool] = Field(True, description="Overlay Original Image")
38
+ """
39
+ Overlay Original Image.Prevents the existing image from changing,
40
+ but can introduce seams along the edge of the mask.
41
+ 叠加原始图像
42
+ 防止现有图像发生更改,但可能会沿蒙版边缘引入接缝。
43
+ """
44
+ mask: Optional[Union[str, bytes]] = None
45
+ """Mask for Inpainting"""
40
46
  cfg_rescale: Optional[float] = Field(0, ge=0, le=1, multiple_of=0.02)
41
47
  """Prompt Guidance Rescale"""
42
48
  controlnet_strength: Optional[float] = Field(1.0, ge=0.1, le=2, multiple_of=0.1)
43
49
  """ControlNet Strength"""
44
50
  dynamic_thresholding: Optional[bool] = False
45
- """Reduce artifacts caused by high prompt guidance values."""
51
+ """Reduce artifacts caused by high prompt guidance values"""
46
52
  height: Optional[int] = Field(1216, ge=64, le=49152)
47
- # Img2Img
48
- image: Optional[Union[str, bytes]] = None # img2img,base64
53
+ """Height For Generate Image"""
54
+ image: Optional[Union[str, bytes]] = None
55
+ """Image for img2img"""
49
56
  strength: Optional[float] = Field(default=0.5, ge=0.01, le=0.99, multiple_of=0.01)
57
+ """Strength for img2img"""
50
58
  noise: Optional[float] = Field(default=0, ge=0, le=0.99, multiple_of=0.01)
59
+ """Noise for img2img"""
51
60
  controlnet_condition: Optional[str] = None
61
+ """ControlNet Condition"""
52
62
  controlnet_model: Optional[ControlNetModel] = None
53
-
63
+ """ControlNet Model"""
54
64
  n_samples: Optional[int] = Field(1, ge=1, le=8)
65
+ """Number of samples"""
55
66
  negative_prompt: Optional[str] = ''
67
+ """Negative Prompt"""
56
68
  noise_schedule: Optional[NoiseSchedule] = NoiseSchedule.NATIVE
57
-
69
+ """Noise Schedule"""
58
70
  # Misc
59
71
  params_version: Optional[int] = 1
72
+ """Params Version For Request"""
60
73
  reference_image: Optional[Union[str, bytes]] = None
74
+ """Reference Image For Vibe Mode"""
61
75
  reference_information_extracted: Optional[float] = Field(1,
62
76
  ge=0,
63
77
  le=1,
64
78
  multiple_of=0.01,
65
79
  description="extracting concepts or features"
66
80
  )
81
+ """Reference Information Extracted For Vibe Mode"""
67
82
  reference_strength: Optional[float] = Field(0.6,
68
83
  ge=0,
69
84
  le=1,
70
85
  multiple_of=0.01,
71
86
  description="the stronger the AI will try to emulate visual cues."
72
87
  )
73
-
88
+ """Reference Strength For Vibe Mode"""
74
89
  legacy: Optional[bool] = False
90
+ # TODO: find out the usage
75
91
  legacy_v3_extend: Optional[bool] = False
76
-
92
+ # TODO: find out the usage
77
93
  qualityToggle: Optional[bool] = True
94
+ """Whether to add the quality prompt"""
78
95
  sampler: Optional[Sampler] = Sampler.K_EULER
96
+ """Sampler For Generate Image"""
79
97
  scale: Optional[float] = Field(6.0, ge=0, le=10, multiple_of=0.1)
80
98
  """Prompt Guidance"""
81
99
  # Seed
@@ -84,50 +102,114 @@ class GenerateImageInfer(ApiBaseModel):
84
102
  gt=0,
85
103
  le=4294967295 - 7,
86
104
  )
105
+ """Seed"""
87
106
  extra_noise_seed: Optional[int] = Field(
88
107
  default_factory=lambda: random.randint(0, 4294967295 - 7),
89
108
  gt=0,
90
109
  le=4294967295 - 7,
91
110
  )
92
-
111
+ """Extra Noise Seed"""
93
112
  sm: Optional[bool] = False
113
+ # TODO: find out the usage
94
114
  sm_dyn: Optional[bool] = False
115
+ # TODO: find out the usage
95
116
  steps: Optional[int] = Field(28, ge=1, le=50)
117
+ """Steps"""
96
118
  ucPreset: Optional[UCPreset] = 0
119
+ """The Negative Prompt Preset"""
97
120
  uncond_scale: Optional[float] = Field(1.0, ge=0, le=1.5, multiple_of=0.05)
98
121
  """Undesired Content Strength"""
99
122
  width: Optional[int] = Field(832, ge=64, le=49152)
123
+ """Width For Image"""
100
124
 
101
- @field_validator('mask')
102
- def mask_validator(cls, v: Union[str, bytes]):
103
- if isinstance(v, str) and v.startswith("data:image/"):
104
- raise ValueError("Invalid image format, must be base64 encoded.")
105
- if isinstance(v, bytes):
106
- return base64.b64encode(v).decode("utf-8")
107
- return v
125
+ @staticmethod
126
+ def resize_image(image: Union[str, bytes], width: int, height: int):
127
+ """
128
+ Resize the image to the specified size.
129
+ :param image: The image to be resized
130
+ :param width: The width of the image
131
+ :param height: The height of the image
132
+ :return: The resized image
133
+ """
134
+ if isinstance(image, str):
135
+ image = base64.b64decode(image)
136
+ open_image = Image.open(BytesIO(image))
137
+ # 如果尺寸相同,直接返回
138
+ if open_image.width == width and open_image.height == height:
139
+ logger.debug("Image size is same, return directly.")
140
+ if isinstance(image, bytes):
141
+ return base64.b64encode(image).decode("utf-8")
142
+ return image
143
+ open_image = open_image.resize((width, height), Image.Resampling.BICUBIC)
144
+ buffered = BytesIO()
145
+ open_image.save(buffered, format="PNG")
146
+ return base64.b64encode(buffered.getvalue()).decode("utf-8")
108
147
 
109
- @field_validator('image')
110
- def image_validator(cls, v: Union[str, bytes]):
111
- if isinstance(v, str) and v.startswith("data:image/"):
112
- raise ValueError("Invalid image format, must be base64 encoded.")
113
- if isinstance(v, bytes):
114
- return base64.b64encode(v).decode("utf-8")
115
- return v
148
+ @staticmethod
149
+ def add_image_to_black_background(image: Union[str, bytes], width: int = 448, height: int = 448):
150
+ """
151
+ 将图像缩放到一个指定的黑背景上,使其最大,比例不变。
152
+ :param image: 图像
153
+ :param width: 宽
154
+ :param height: 高
155
+ :return: 新图像
156
+ """
157
+ if isinstance(image, str):
158
+ image = base64.b64decode(image)
116
159
 
117
- @field_validator('reference_image')
118
- def image_validator(cls, v: Union[str, bytes]):
119
- if isinstance(v, str) and v.startswith("data:image/"):
120
- raise ValueError("Invalid image format, must be base64 encoded.")
121
- if isinstance(v, bytes):
122
- return base64.b64encode(v).decode("utf-8")
123
- return v
160
+ open_image = Image.open(BytesIO(image))
161
+ # 如果尺寸相同,直接返回
162
+ if open_image.width == width and open_image.height == height:
163
+ return base64.b64encode(image).decode("utf-8")
164
+
165
+ # 计算正确的缩放因子
166
+ width_ratio = width / open_image.width
167
+ height_ratio = height / open_image.height
168
+ ratio = min(width_ratio, height_ratio)
169
+
170
+ new_image_size = (int(open_image.width * ratio), int(open_image.height * ratio))
171
+ open_image = open_image.resize(new_image_size, Image.Resampling.BICUBIC)
172
+
173
+ # 创建一个黑色背景的新图像
174
+ new_image = Image.new("RGB", (width, height), (0, 0, 0))
175
+
176
+ # 计算居中位置
177
+ position = ((width - open_image.width) // 2, (height - open_image.height) // 2)
178
+
179
+ # 粘贴图像
180
+ new_image.paste(open_image, position)
181
+
182
+ buffered = BytesIO()
183
+ new_image.save(buffered, format="PNG")
184
+ return base64.b64encode(buffered.getvalue()).decode("utf-8")
185
+
186
+ # Validators
187
+ @model_validator(mode="after")
188
+ def image_validator(self):
189
+ if isinstance(self.image, str) and self.image.startswith("data:"):
190
+ raise ValueError("Invalid `image` format, must be base64 encoded directly.")
191
+ if isinstance(self.reference_image, str) and self.reference_image.startswith("data:"):
192
+ raise ValueError("Invalid `reference_image` format, must be base64 encoded directly.")
193
+ if isinstance(self.mask, str) and self.mask.startswith("data:"):
194
+ raise ValueError("Invalid `mask` format, must be base64 encoded directly.")
195
+ if isinstance(self.image, bytes):
196
+ self.image = base64.b64encode(self.image).decode("utf-8")
197
+ if isinstance(self.reference_image, bytes):
198
+ self.reference_image = base64.b64encode(self.reference_image).decode("utf-8")
199
+ if isinstance(self.mask, bytes):
200
+ self.mask = base64.b64encode(self.mask).decode("utf-8")
201
+ if self.image is not None:
202
+ self.image = self.resize_image(self.image, self.width, self.height)
203
+ if self.reference_image is not None:
204
+ self.reference_image = self.add_image_to_black_background(self.reference_image, width=448, height=448)
205
+ return self
124
206
 
125
207
  @field_validator('width')
126
208
  def width_validator(cls, v: int):
127
209
  """
128
- 必须是 64 的倍数
210
+ Must be multiple of 64
129
211
  :param v:
130
- :return:
212
+ :return: fixed value
131
213
  """
132
214
  if v % 64 != 0:
133
215
  raise ValueError("Invalid width, must be multiple of 64.")
@@ -136,9 +218,9 @@ class GenerateImageInfer(ApiBaseModel):
136
218
  @field_validator('height')
137
219
  def height_validator(cls, v: int):
138
220
  """
139
- 必须是 64 的倍数
221
+ Must be multiple of 64
140
222
  :param v:
141
- :return:
223
+ :return: fixed value
142
224
  """
143
225
  if v % 64 != 0:
144
226
  raise ValueError("Invalid height, must be multiple of 64.")
@@ -162,48 +244,70 @@ class GenerateImageInfer(ApiBaseModel):
162
244
  def model_post_init(self, *args) -> None:
163
245
  """
164
246
  Post-initialization hook.
165
- :return:
247
+ Simulate website logic to add negative prompt based on ucPreset and qualityToggle.
248
+ :param args: Any
249
+ :return: None
166
250
  """
251
+ if self.parameters.negative_prompt is None:
252
+ self.parameters.negative_prompt = ""
167
253
  if self.parameters.ucPreset == 0:
168
254
  # 0: 重型
169
- self.parameters.negative_prompt += str(
170
- ", lowres, {bad}, error, fewer, extra, missing, worst quality, jpeg artifacts, bad quality, "
255
+ self.parameters.negative_prompt = (
256
+ "lowres, {bad}, error, fewer, extra, missing, worst quality, jpeg artifacts, bad quality, "
171
257
  "watermark, unfinished, displeasing, chromatic aberration, signature, extra digits, artistic error, "
172
258
  "username, scan, [abstract], bad anatomy, bad hands, @_@, mismatched pupils, heart-shaped pupils, "
173
259
  "glowing eyes, nsfw, lowres, bad anatomy, bad hands, text, error, missing fingers, "
174
260
  "extra digit, fewer digits, cropped, worst quality, low quality, normal quality, "
175
- "jpeg artifacts, signature, watermark, username, blurry"
261
+ f"jpeg artifacts, signature, watermark, username, blurry "
262
+ f",{self.parameters.negative_prompt}"
176
263
  )
177
264
  elif self.parameters.ucPreset == 1:
178
265
  # 1: 轻型
179
- self.parameters.negative_prompt += (", lowres, jpeg artifacts, worst quality"
180
- ", watermark, blurry, very displeasing")
266
+ self.parameters.negative_prompt = (f"lowres, jpeg artifacts, worst quality, watermark, blurry, "
267
+ f"very displeasing"
268
+ f",{self.parameters.negative_prompt}")
181
269
  elif self.parameters.ucPreset == 2:
182
270
  # 2: 人物
183
- self.parameters.negative_prompt += (", lowres, {bad}, error, fewer, extra, missing, worst quality, "
184
- "jpeg artifacts, bad quality, watermark, unfinished, displeasing, "
185
- "chromatic aberration, signature, extra digits, artistic error, "
186
- "username, scan, [abstract], bad anatomy, bad hands, @_@, mismatched "
187
- "pupils, heart-shaped pupils, glowing eyes")
271
+ self.parameters.negative_prompt = ("lowres, {bad}, error, fewer, extra, missing, worst quality, "
272
+ "jpeg artifacts, bad quality, watermark, unfinished, displeasing, "
273
+ "chromatic aberration, signature, extra digits, artistic error, "
274
+ "username, scan, [abstract], bad anatomy, bad hands, @_@, mismatched "
275
+ f"pupils, heart-shaped pupils, glowing eyes "
276
+ f",{self.parameters.negative_prompt}")
188
277
  if self.parameters.qualityToggle:
189
278
  self.input += ", best quality, amazing quality, very aesthetic, absurdres"
190
279
 
191
280
  @model_validator(mode="after")
192
281
  def validate_model(self):
282
+ """
283
+ Check the conflict between parameters and simulate website logic.
284
+ :return: self
285
+ """
286
+ # Text2Img mode
287
+ if self.action == Action.GENERATE:
288
+ if self.parameters.image is not None:
289
+ raise ValueError("image is not required for non-generate mode.")
290
+ if self.parameters.mask is not None:
291
+ raise ValueError("mask is not required for non-generate mode.")
292
+ # Infill mode
193
293
  if self.action == Action.INFILL:
294
+ if self.model not in INPAINTING_MODEL_LIST:
295
+ raise ValueError(f"You must use {INPAINTING_MODEL_LIST}")
194
296
  if not self.parameters.mask:
195
- logger.warning("Mask maybe required for infill mode.")
297
+ logger.warning("Mask maybe required for infill mode!")
298
+ # Sync seed
196
299
  if self.action != Action.GENERATE:
197
300
  self.parameters.extra_noise_seed = self.parameters.seed
301
+ # Img2Img mode
198
302
  if self.action == Action.IMG2IMG:
303
+ if self.parameters.sm_dyn is True:
304
+ logger.warning("sm_dyn is disabled when sm in Img2Img mode.")
305
+ if self.parameters.sm is True:
306
+ logger.warning("sm is disabled when sm_dyn in Img2Img mode.")
199
307
  self.parameters.sm = False
200
308
  self.parameters.sm_dyn = False
201
- if not self.parameters.image:
309
+ if self.parameters.image is None:
202
310
  raise ValueError("image is must required for img2img mode.")
203
- if not self.parameters.add_original_image:
204
- raise ValueError("add_original_image is must required for img2img mode.")
205
- if self.parameters.image and self.parameters.reference_image:
206
- logger.warning("image and reference_image should not be used together.")
207
311
  return self
208
312
 
209
313
  @property
@@ -258,49 +362,90 @@ class GenerateImageInfer(ApiBaseModel):
258
362
  model: Union[Model, str] = "nai-diffusion-3",
259
363
  action: Union[Action, str] = 'generate',
260
364
  negative_prompt: str = "",
261
- seed: int = None,
365
+ ucPreset: Union[UCPreset, int] = UCPreset.TYPE0,
262
366
  steps: int = 28,
263
- scale: float = 6.0,
367
+ seed: int = None,
368
+ scale: float = 5.0,
264
369
  cfg_rescale: float = 0,
265
- sampler: Union[Sampler, str] = Sampler.K_EULER,
370
+ sampler: Union[Sampler, str] = None,
266
371
  width: int = 832,
267
372
  height: int = 1216,
268
- qualityToggle: bool = True,
269
- ucPreset: Union[UCPreset, int] = UCPreset.TYPE0,
373
+ qualityToggle: bool = None,
270
374
  image: Union[str, bytes] = None,
271
- reference_mode: bool = False,
272
- add_original_image: bool = None,
375
+ noise: float = 0,
376
+ reference_image: Union[str, bytes] = None,
377
+ reference_strength: float = None,
378
+ reference_information_extracted: float = None,
379
+ add_original_image: bool = True,
273
380
  strength: float = None,
274
381
  mask: Union[str, bytes] = None,
275
382
  controlnet_model: Union[ControlNetModel, str] = None,
276
383
  controlnet_condition: str = None,
384
+ sm: bool = False,
277
385
  sm_dyn: bool = False,
386
+ uncond_scale: float = None,
278
387
  **kwargs
279
388
  ):
280
389
  """
281
- The build Function, more convenient to create a GenerateImageInfer instance.
282
- :param ucPreset: 0: Heavy, 1: Light, 2: Character
283
- :param qualityToggle: Is quality toggle
284
- :param prompt: Input prompt for generate image
285
- :param model: The model for generate image
286
- :param action: Mode for img generate [generate, img2img, infill]
287
- :param negative_prompt: The content of negative prompt
288
- :param seed: The seed for generate image
289
- :param steps: The steps for generate image
290
- :param scale: The scale for generate image
291
- :param cfg_rescale: Prompt Guidance Rescale 0-1 lower is more creative
292
- :param sampler: The sampler for generate image
293
- :param width: 宽
294
- :param height: 高
295
- :param image: 图片
296
- :param reference_mode: 是否是参考模式
297
- :param add_original_image: 是否添加原始图片
298
- :param strength: IMG2IMG 强度
299
- :param mask: Inpainting mask
300
- :param controlnet_model: 控制网络模型
301
- :param controlnet_condition: 控制网络条件
302
- :param sm_dyn: 是否使用动态sm
390
+ The build function, more convenient to create a GenerateImageInfer instance.
391
+ 构建函数,更方便地创建一个GenerateImageInfer实例。
392
+ :param ucPreset: 0: Heavy, 1: Light, 2: Character
393
+ 0: 重量级, 1: 轻量级, 2: 角色
394
+ :param qualityToggle: add the quality prompt or not.
395
+ 是否添加质量提示。
396
+ :param prompt: input prompt for generation.
397
+ 生成的输入提示。
398
+ :param model: select a model.
399
+ 选择一个模型。
400
+ :param action: mode for image generation [generate, img2img, infill].
401
+ 图像生成模式 [生成, 图像到图像, 填充]。
402
+ :param negative_prompt: the content of negative prompt.
403
+ 负面提示的内容。
404
+ :param seed: the seed for generate image.
405
+ 生成图像的种子。
406
+ :param steps: the steps for generate image.
407
+ 生成图像的步骤。
408
+ :param scale: the scale for generate image.
409
+ 生成图像的比例。
410
+ :param cfg_rescale: prompt guidance rescale 0-1 lower is more creative.
411
+ 提示引导的重新缩放0-1,越低则越富有创造性。
412
+ :param sampler: the sampler for generate image.
413
+ 生成图像的采样器。
414
+ :param width: the width of the image.
415
+ 图像的宽度。
416
+ :param height: the height of the image.
417
+ 图像的高度。
418
+ :param image: the input image.
419
+ 输入图像。
420
+ :param noise: the noise to be added in the image.
421
+ 要添加到图像中的噪声。
422
+ :param reference_image: the reference image for Vibe mode.
423
+ Vibe模式的参考图像。
424
+ :param reference_strength: the strength of the reference image used in Vibe mode.
425
+ 在Vibe模式中使用的参考图像的强度。
426
+ :param reference_information_extracted: whether to extract concept or features, for Vibe mode.
427
+ 是否提取概念或特征,用于Vibe模式。
428
+ :param add_original_image: Overlay Original Image. Prevents the existing image from changing, only for IMG2IMG mode.
429
+ 叠加原始图像。防止现有图像发生更改,仅适用于IMG2IMG模式。
430
+ :param strength: the strength of IMG2IMG mode.
431
+ IMG2IMG模式的强度。
432
+ :param mask: the inpainting mask.
433
+ 纹理绘制掩码。
434
+ :param controlnet_model: the model used for the control network.
435
+ 用于控制网络的模型。
436
+ :param controlnet_condition: the condition used for the control network.
437
+ 用于控制网络的条件。
438
+ :param sm: whether to use sm.
439
+ 是否使用sm。
440
+ :param sm_dyn: whether to use dynamic sm.
441
+ 是否使用动态sm。
442
+ :param uncond_scale: the strength of the unrelated content.
443
+ 无关内容的强度。
444
+ :param kwargs: any additional parameters.
445
+ 其他任何参数。
446
+
303
447
  :return: self
448
+ 返回:自身
304
449
  """
305
450
  assert isinstance(prompt, str)
306
451
  _negative_prompt = negative_prompt
@@ -320,17 +465,23 @@ class GenerateImageInfer(ApiBaseModel):
320
465
  "controlnet_model": controlnet_model,
321
466
  "controlnet_condition": controlnet_condition,
322
467
  "sm_dyn": sm_dyn,
468
+ "sm": sm,
469
+ "uncond_scale": uncond_scale,
323
470
  })
324
- if reference_mode:
325
- kwargs.update({
326
- "reference_image": image,
327
- "reference_strength": strength,
328
- })
329
- else:
330
- kwargs.update({
471
+ kwargs.update(
472
+ {
473
+ "reference_image": reference_image,
474
+ "reference_strength": reference_strength,
475
+ "reference_information_extracted": reference_information_extracted,
476
+ }
477
+ )
478
+ kwargs.update(
479
+ {
331
480
  "image": image,
332
481
  "strength": strength,
333
- })
482
+ "noise": noise,
483
+ }
484
+ )
334
485
  # 清理空值
335
486
  param = {k: v for k, v in kwargs.items() if v is not None}
336
487
  return cls(
@@ -394,17 +545,12 @@ class GenerateImageInfer(ApiBaseModel):
394
545
  session.headers.update(override_headers)
395
546
  try:
396
547
  _log_data = deepcopy(request_data)
397
- if self.action == Action.GENERATE:
398
- _log_data.get("parameters", {}).update({
399
- "reference_image": "base64 data" if self.parameters.reference_image else None,
400
- })
401
- logger.debug(f"Request Data: {_log_data}")
402
- else:
403
- _log_data.get("parameters", {}).update({
404
- "image": "base64 data" if self.parameters.image else None,
405
- "mask": "base64 data" if self.parameters.mask else None,
406
- })
407
- logger.debug(f"Request Data: {_log_data}")
548
+ _log_data.get("parameters", {}).update({
549
+ "image": "base64 data" if self.parameters.image else None,
550
+ "mask": "base64 data" if self.parameters.mask else None,
551
+ "reference_image": "base64 data" if self.parameters.reference_image else None,
552
+ })
553
+ logger.debug(f"Request Data: {_log_data}")
408
554
  del _log_data
409
555
  except Exception as e:
410
556
  logger.warning(f"Error when print log data: {e}")
@@ -64,6 +64,7 @@ class Resolution(Enum):
64
64
  RES_1088_1920 = (1088, 1920)
65
65
  RES_1920_1088 = (1920, 1088)
66
66
 
67
+
67
68
  class Model(Enum):
68
69
  NAI_DIFFUSION_3 = "nai-diffusion-3"
69
70
  NAI_DIFFUSION_3_INPAINTING = "nai-diffusion-3-inpainting"
@@ -76,3 +77,10 @@ class Model(Enum):
76
77
 
77
78
  NAI_DIFFUSION_FURRY = "nai-diffusion-furry"
78
79
  FURRY_DIFFUSION_INPAINTING = "furry-diffusion-inpainting"
80
+
81
+
82
+ INPAINTING_MODEL_LIST = [Model.NAI_DIFFUSION_3_INPAINTING,
83
+ Model.NAI_DIFFUSION_INPAINTING,
84
+ Model.SAFE_DIFFUSION_INPAINTING,
85
+ Model.FURRY_DIFFUSION_INPAINTING
86
+ ]
File without changes
File without changes
File without changes