novelai-python 0.8.0__tar.gz → 0.8.1__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.8.0 → novelai_python-0.8.1}/PKG-INFO +2 -2
- {novelai_python-0.8.0 → novelai_python-0.8.1}/README.md +1 -1
- {novelai_python-0.8.0 → novelai_python-0.8.1}/pyproject.toml +1 -1
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/_response/user/subscription.py +1 -1
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/credential/UserAuth.py +22 -1
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/_enum.py +8 -3
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/generate_voice/__init__.py +3 -2
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/server.py +4 -2
- {novelai_python-0.8.0 → novelai_python-0.8.1}/tests/test_from_metadata.py +15 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/tests/test_login_proxy.py +30 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/tests/test_presets_and_usage.py +1 -2
- {novelai_python-0.8.0 → novelai_python-0.8.1}/LICENSE +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/NOTICE.MD +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/__init__.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/_enum.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/_exceptions.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/_response/__init__.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/_response/ai/__init__.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/_response/ai/generate.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/_response/ai/generate_image.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/_response/ai/generate_stream.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/_response/ai/generate_voice.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/_response/ai/upscale.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/_response/schema.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/_response/user/__init__.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/_response/user/data.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/_response/user/information.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/_response/user/login.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/_response/user/priority.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/_response/user/trial_status.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/_retry.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/credential/ApiToken.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/credential/JwtToken.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/credential/__init__.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/credential/_base.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/__init__.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/LICENSE +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/__init__.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/_const.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/_cost.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/augment_image/__init__.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/augment_image/_enum.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/encode_vibe.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/generate/__init__.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/generate/_const.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/generate/_enum.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/generate/_schema.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/generate/themes.json +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/generate_image/__init__.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/generate_image/auto_text.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/generate_image/params.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/generate_image/schema.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/generate_image/suggest_tags.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/generate_image/tokenizer.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/generate_stream.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/generate_voice/_enum.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/openai_compat.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/upscale.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/schema.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/user/__init__.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/user/data.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/user/information.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/user/login.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/user/persistent_token.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/user/priority.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/user/subscription.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/user/trial_status.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tokenizer/__init__.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tokenizer/clip_tokenizer.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tool/__init__.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tool/image_metadata/__init__.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tool/image_metadata/bch.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tool/image_metadata/bch_utils.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tool/image_metadata/lsb_extractor.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tool/image_metadata/lsb_injector.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tool/paint_mask/__init__.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tool/random_prompt/__init__.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tool/random_prompt/data/__init__.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tool/random_prompt/data/anime_v3_data.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tool/random_prompt/data/anime_v4_data.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tool/random_prompt/data/furry_data.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tool/random_prompt/data/holiday.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tool/random_prompt/data/nsfw_data.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tool/random_prompt/generate_scene_composition.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tool/random_prompt/generate_scene_tags.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tool/random_prompt/generate_tags.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tool/random_prompt/generators/__init__.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tool/random_prompt/generators/anime_v3.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tool/random_prompt/generators/anime_v4.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tool/random_prompt/generators/furry.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tool/random_prompt/generators/holiday.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tool/random_prompt/logic.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/utils/__init__.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/utils/daily_limit.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/utils/encode.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/utils/useful.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/tests/__init__.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/tests/conftest.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/tests/fixtures/bch_vectors.json +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/tests/fixtures/dependency_golden.json +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/tests/fixtures/mask_ori.png +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/tests/fixtures/mask_sketch.png +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/tests/fixtures/v5_signed.webp +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/tests/test_auto_text.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/tests/test_bch.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/tests/test_browser_identity.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/tests/test_cost.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/tests/test_daily_limit.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/tests/test_dependency_golden.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/tests/test_generate_image_v5.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/tests/test_generate_text.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/tests/test_generate_voice.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/tests/test_image_metadata_v5.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/tests/test_new_endpoints.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/tests/test_random_prompt.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/tests/test_retry_session.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/tests/test_server.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/tests/test_server_roundtrip.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/tests/test_server_run.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/tests/test_suggest_tags.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/tests/test_tokenizer.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/tests/test_upscale.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/tests/test_user_information.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/tests/test_user_login.py +0 -0
- {novelai_python-0.8.0 → novelai_python-0.8.1}/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.8.
|
|
3
|
+
Version: 0.8.1
|
|
4
4
|
Summary: NovelAI Python Binding With Pydantic
|
|
5
5
|
Author-Email: sudoskys <coldlando@hotmail.com>
|
|
6
6
|
License: Apache License 2.0
|
|
@@ -101,7 +101,7 @@ Some changes do not raise an error, so check these when you upgrade:
|
|
|
101
101
|
### 📦 Usage
|
|
102
102
|
|
|
103
103
|
```shell
|
|
104
|
-
pip -U
|
|
104
|
+
pip install -U novelai-python
|
|
105
105
|
```
|
|
106
106
|
|
|
107
107
|
All API users must adhere to the NovelAI Terms of Service: https://novelai.net/terms.
|
|
@@ -71,7 +71,7 @@ Some changes do not raise an error, so check these when you upgrade:
|
|
|
71
71
|
### 📦 Usage
|
|
72
72
|
|
|
73
73
|
```shell
|
|
74
|
-
pip -U
|
|
74
|
+
pip install -U novelai-python
|
|
75
75
|
```
|
|
76
76
|
|
|
77
77
|
All API users must adhere to the NovelAI Terms of Service: https://novelai.net/terms.
|
{novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/_response/user/subscription.py
RENAMED
|
@@ -63,7 +63,7 @@ class SubscriptionResp(RespBase):
|
|
|
63
63
|
active: bool = Field(..., description="Subscription status")
|
|
64
64
|
expiresAt: int = Field(..., description="Subscription expiration time")
|
|
65
65
|
perks: Perks = Field(..., description="Subscription perks")
|
|
66
|
-
paymentProcessorData: dict[Any, Any] | None
|
|
66
|
+
paymentProcessorData: dict[Any, Any] | None = None # absent or null on some accounts
|
|
67
67
|
trainingStepsLeft: TrainingSteps = Field(..., description="Training steps left")
|
|
68
68
|
accountType: int = Field(..., description="Account type")
|
|
69
69
|
usage: SubscriptionUsage | None = Field(default=None, description="Opus V5 usage bar (absent on non-Opus)")
|
|
@@ -10,6 +10,20 @@ from pydantic import Field, PrivateAttr, SecretStr
|
|
|
10
10
|
from ._base import CredentialBase, _correlation_id, _initiated_at, browser_headers
|
|
11
11
|
|
|
12
12
|
|
|
13
|
+
class _LoginSession(AsyncSession):
|
|
14
|
+
"""A session that drops the credential's cached token when NovelAI answers 401 to it."""
|
|
15
|
+
|
|
16
|
+
def __init__(self, credential: "LoginCredential", **kwargs) -> None:
|
|
17
|
+
super().__init__(**kwargs)
|
|
18
|
+
self._credential = credential
|
|
19
|
+
|
|
20
|
+
async def request(self, *args, **kwargs): # pyright: ignore[reportIncompatibleMethodOverride]
|
|
21
|
+
response = await super().request(*args, **kwargs)
|
|
22
|
+
if response.status_code == 401:
|
|
23
|
+
self._credential.forget_token(self.headers.get("authorization"))
|
|
24
|
+
return response
|
|
25
|
+
|
|
26
|
+
|
|
13
27
|
class LoginCredential(CredentialBase):
|
|
14
28
|
"""
|
|
15
29
|
JwtCredential is the base class for all credential.
|
|
@@ -31,6 +45,13 @@ class LoginCredential(CredentialBase):
|
|
|
31
45
|
not self.session_headers or self.update_at is None or int(time.time()) - self.update_at > 29 * 24 * 60 * 60
|
|
32
46
|
)
|
|
33
47
|
|
|
48
|
+
def forget_token(self, authorization: str | None = None) -> None:
|
|
49
|
+
"""Log in again on the next request. With ``authorization``, only if that is still the cached token
|
|
50
|
+
(a session made before a newer login must not drop the newer token)."""
|
|
51
|
+
if authorization is None or self.session_headers.get("authorization") == authorization:
|
|
52
|
+
self.session_headers = {}
|
|
53
|
+
self.update_at = None
|
|
54
|
+
|
|
34
55
|
def _lock(self) -> asyncio.Lock:
|
|
35
56
|
# an asyncio.Lock belongs to one event loop; a credential can outlive it (several asyncio.run)
|
|
36
57
|
loop = asyncio.get_running_loop()
|
|
@@ -66,4 +87,4 @@ class LoginCredential(CredentialBase):
|
|
|
66
87
|
**(update_headers or {}),
|
|
67
88
|
}
|
|
68
89
|
)
|
|
69
|
-
return
|
|
90
|
+
return _LoginSession(self, **self.session_kwargs(timeout, headers))
|
|
@@ -263,6 +263,12 @@ PROMOTION = {
|
|
|
263
263
|
"NovelAI Diffusion V4 7ABFFA2A": Model.NAI_DIFFUSION_4_CURATED_PREVIEW,
|
|
264
264
|
"NovelAI Diffusion V4 C1CCBA86": Model.NAI_DIFFUSION_4_CURATED_PREVIEW,
|
|
265
265
|
"NovelAI Diffusion V4 770A9E12": Model.NAI_DIFFUSION_4_CURATED_PREVIEW,
|
|
266
|
+
# the web client's metadata import (rQ): the V5 Source names no variant, only the hash
|
|
267
|
+
"NovelAI Diffusion V5 657484A5": Model.NAI_DIFFUSION_5_FULL,
|
|
268
|
+
"NovelAI Diffusion V5 0ADF9AB7": Model.NAI_DIFFUSION_5_FULL,
|
|
269
|
+
"NovelAI Diffusion V5 93F4BD30": Model.NAI_DIFFUSION_5_FULL_MEDIUM,
|
|
270
|
+
"NovelAI Diffusion V5 70AB5786": Model.NAI_DIFFUSION_5_FULL_MEDIUM,
|
|
271
|
+
"NovelAI Diffusion V5 DB276663": Model.NAI_DIFFUSION_5_CURATED,
|
|
266
272
|
}
|
|
267
273
|
|
|
268
274
|
ModelTypeAlias = Model | str | None
|
|
@@ -604,9 +610,8 @@ def get_quality_suffix(model: ModelTypeAlias, preset_id: str | QualityPreset | N
|
|
|
604
610
|
|
|
605
611
|
def find_model_by_hashcode(hashcode: str) -> ModelTypeAlias:
|
|
606
612
|
if "NovelAI Diffusion V5" in hashcode:
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
return PROMOTION.get(hashcode, Model.NAI_DIFFUSION_5_FULL)
|
|
613
|
+
# an unknown V5 hash is Curated, as in the web client
|
|
614
|
+
return PROMOTION.get(hashcode, Model.NAI_DIFFUSION_5_CURATED)
|
|
610
615
|
if "NovelAI Diffusion V4.5" in hashcode:
|
|
611
616
|
return PROMOTION.get(hashcode, Model.NAI_DIFFUSION_4_5_FULL)
|
|
612
617
|
if "NovelAI Diffusion V4" in hashcode:
|
{novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/generate_voice/__init__.py
RENAMED
|
@@ -91,9 +91,10 @@ class VoiceGenerate(ApiBaseModel):
|
|
|
91
91
|
# Request
|
|
92
92
|
try:
|
|
93
93
|
response = await sess.post(url=self.base_url, json=request_data)
|
|
94
|
-
|
|
94
|
+
# opus=true answers WebM/Opus, maybe as 'audio/webm;codecs="opus"'
|
|
95
|
+
media_type = (response.headers.get("Content-Type") or "").split(";")[0].strip().lower()
|
|
95
96
|
if (
|
|
96
|
-
|
|
97
|
+
media_type not in ["audio/mpeg", "audio/ogg", "audio/opus", "audio/wav", "audio/webm"]
|
|
97
98
|
or response.status_code >= 400
|
|
98
99
|
):
|
|
99
100
|
self._raise_for_status(
|
|
@@ -299,10 +299,12 @@ async def generate_voice(
|
|
|
299
299
|
"""
|
|
300
300
|
req = VoiceGenerate(text=text, voice=voice, seed=seed, opus=opus, version=version)
|
|
301
301
|
result = await req.request(session=get_session(current_token))
|
|
302
|
+
# opus=true is WebM/Opus, as the web client plays it; otherwise MP3
|
|
303
|
+
media_type, filename = ("audio/webm", "audio.webm") if opus else ("audio/mpeg", "audio.mp3")
|
|
302
304
|
return StreamingResponse(
|
|
303
305
|
io.BytesIO(result.audio),
|
|
304
|
-
media_type=
|
|
305
|
-
headers={"Content-Disposition": "attachment;filename=
|
|
306
|
+
media_type=media_type,
|
|
307
|
+
headers={"Content-Disposition": f"attachment;filename={filename}"},
|
|
306
308
|
)
|
|
307
309
|
|
|
308
310
|
|
|
@@ -94,6 +94,21 @@ def test_img2img_needs_the_source_image():
|
|
|
94
94
|
assert (p.strength, p.noise, p.extra_noise_seed, p.color_correct) == (0.8, 0.1, 41, False)
|
|
95
95
|
|
|
96
96
|
|
|
97
|
+
@pytest.mark.parametrize(
|
|
98
|
+
("source", "model"),
|
|
99
|
+
[
|
|
100
|
+
("NovelAI Diffusion V5 0ADF9AB7", Model.NAI_DIFFUSION_5_FULL),
|
|
101
|
+
("NovelAI Diffusion V5 93F4BD30", Model.NAI_DIFFUSION_5_FULL_MEDIUM),
|
|
102
|
+
("NovelAI Diffusion V5 DB276663", Model.NAI_DIFFUSION_5_CURATED),
|
|
103
|
+
("NovelAI Diffusion V5 00000000", Model.NAI_DIFFUSION_5_CURATED), # the web client's default
|
|
104
|
+
],
|
|
105
|
+
)
|
|
106
|
+
def test_v5_model_from_source_hash(source, model):
|
|
107
|
+
from novelai_python.sdk.ai._enum import find_model_by_hashcode
|
|
108
|
+
|
|
109
|
+
assert find_model_by_hashcode(source) == model
|
|
110
|
+
|
|
111
|
+
|
|
97
112
|
def test_unknown_model_and_missing_comment():
|
|
98
113
|
with pytest.raises(ValueError):
|
|
99
114
|
GenerateImageInfer.from_metadata(ImageMetadata(Comment=CommentModel(prompt="x"), Source="Stable Diffusion"))
|
|
@@ -97,3 +97,33 @@ def test_a_request_body_cannot_set_the_login_proxy():
|
|
|
97
97
|
login = Login.model_validate({"key": "x", "proxy": "http://attacker:1"})
|
|
98
98
|
assert login.session.proxies in (None, {})
|
|
99
99
|
assert "proxy" not in login.model_dump()
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@pytest.mark.asyncio
|
|
103
|
+
async def test_a_401_drops_the_cached_login_token():
|
|
104
|
+
import asyncio
|
|
105
|
+
import time
|
|
106
|
+
|
|
107
|
+
from novelai_python import LoginCredential
|
|
108
|
+
|
|
109
|
+
async def handle(reader, writer):
|
|
110
|
+
await reader.readuntil(b"\r\n\r\n")
|
|
111
|
+
writer.write(b"HTTP/1.1 401 Unauthorized\r\nContent-Length: 2\r\nConnection: close\r\n\r\n{}")
|
|
112
|
+
await writer.drain()
|
|
113
|
+
writer.close()
|
|
114
|
+
|
|
115
|
+
server = await asyncio.start_server(handle, "127.0.0.1", 0)
|
|
116
|
+
port = server.sockets[0].getsockname()[1]
|
|
117
|
+
credential = LoginCredential(
|
|
118
|
+
username="a@b.c", password="pw", session_headers={"authorization": "Bearer old"}, update_at=int(time.time())
|
|
119
|
+
)
|
|
120
|
+
stale = await credential.get_session()
|
|
121
|
+
credential.session_headers = {"authorization": "Bearer newer"} # a newer login happened meanwhile
|
|
122
|
+
async with stale as sess:
|
|
123
|
+
await sess.get(f"http://127.0.0.1:{port}/")
|
|
124
|
+
assert credential.session_headers == {"authorization": "Bearer newer"}
|
|
125
|
+
|
|
126
|
+
async with await credential.get_session() as sess:
|
|
127
|
+
await sess.get(f"http://127.0.0.1:{port}/")
|
|
128
|
+
assert credential.session_headers == {} and credential.update_at is None
|
|
129
|
+
server.close()
|
|
@@ -33,8 +33,7 @@ def test_subscription_usage_is_optional_and_derived():
|
|
|
33
33
|
"tier": 3,
|
|
34
34
|
"active": True,
|
|
35
35
|
"expiresAt": 1,
|
|
36
|
-
"
|
|
37
|
-
"accountType": 0,
|
|
36
|
+
"accountType": 0, # no paymentProcessorData: some accounts omit it
|
|
38
37
|
"trainingStepsLeft": {"fixedTrainingStepsLeft": 10000, "purchasedTrainingSteps": 0},
|
|
39
38
|
"perks": {
|
|
40
39
|
"maxPriorityActions": 1,
|
|
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.8.0 → novelai_python-0.8.1}/src/novelai_python/_response/ai/generate_image.py
RENAMED
|
File without changes
|
{novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/_response/ai/generate_stream.py
RENAMED
|
File without changes
|
{novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/_response/ai/generate_voice.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/_response/user/information.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/_response/user/trial_status.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.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/augment_image/__init__.py
RENAMED
|
File without changes
|
{novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/augment_image/_enum.py
RENAMED
|
File without changes
|
|
File without changes
|
{novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/generate/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/generate/themes.json
RENAMED
|
File without changes
|
{novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/generate_image/__init__.py
RENAMED
|
File without changes
|
{novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/generate_image/auto_text.py
RENAMED
|
File without changes
|
{novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/generate_image/params.py
RENAMED
|
File without changes
|
{novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/generate_image/schema.py
RENAMED
|
File without changes
|
|
File without changes
|
{novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/generate_image/tokenizer.py
RENAMED
|
File without changes
|
|
File without changes
|
{novelai_python-0.8.0 → novelai_python-0.8.1}/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
|
{novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/sdk/user/persistent_token.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tokenizer/clip_tokenizer.py
RENAMED
|
File without changes
|
|
File without changes
|
{novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tool/image_metadata/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tool/image_metadata/bch_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
{novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tool/image_metadata/lsb_injector.py
RENAMED
|
File without changes
|
{novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tool/paint_mask/__init__.py
RENAMED
|
File without changes
|
{novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tool/random_prompt/__init__.py
RENAMED
|
File without changes
|
{novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tool/random_prompt/data/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tool/random_prompt/data/holiday.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tool/random_prompt/generate_tags.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{novelai_python-0.8.0 → novelai_python-0.8.1}/src/novelai_python/tool/random_prompt/logic.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
|
|
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
|
|
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
|