novelai-python 0.7.12__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.
Files changed (165) hide show
  1. novelai_python-0.8.1/NOTICE.MD +8 -0
  2. novelai_python-0.8.1/PKG-INFO +368 -0
  3. novelai_python-0.7.12/PKG-INFO → novelai_python-0.8.1/README.md +118 -51
  4. novelai_python-0.8.1/pyproject.toml +98 -0
  5. novelai_python-0.8.1/src/novelai_python/__init__.py +104 -0
  6. {novelai_python-0.7.12 → novelai_python-0.8.1}/src/novelai_python/_enum.py +23 -7
  7. novelai_python-0.8.1/src/novelai_python/_exceptions.py +126 -0
  8. {novelai_python-0.7.12 → novelai_python-0.8.1}/src/novelai_python/_response/__init__.py +1 -7
  9. {novelai_python-0.7.12 → novelai_python-0.8.1}/src/novelai_python/_response/ai/__init__.py +0 -1
  10. novelai_python-0.8.1/src/novelai_python/_response/ai/generate.py +20 -0
  11. novelai_python-0.8.1/src/novelai_python/_response/ai/generate_image.py +81 -0
  12. novelai_python-0.8.1/src/novelai_python/_response/ai/generate_stream.py +25 -0
  13. {novelai_python-0.7.12 → novelai_python-0.8.1}/src/novelai_python/_response/ai/upscale.py +2 -4
  14. {novelai_python-0.7.12 → novelai_python-0.8.1}/src/novelai_python/_response/schema.py +0 -1
  15. {novelai_python-0.7.12 → novelai_python-0.8.1}/src/novelai_python/_response/user/__init__.py +0 -1
  16. novelai_python-0.8.1/src/novelai_python/_response/user/data.py +31 -0
  17. {novelai_python-0.7.12 → novelai_python-0.8.1}/src/novelai_python/_response/user/information.py +11 -2
  18. {novelai_python-0.7.12 → novelai_python-0.8.1}/src/novelai_python/_response/user/login.py +0 -1
  19. novelai_python-0.8.1/src/novelai_python/_response/user/priority.py +11 -0
  20. novelai_python-0.8.1/src/novelai_python/_response/user/subscription.py +115 -0
  21. novelai_python-0.8.1/src/novelai_python/_response/user/trial_status.py +28 -0
  22. novelai_python-0.8.1/src/novelai_python/_retry.py +43 -0
  23. novelai_python-0.8.1/src/novelai_python/credential/ApiToken.py +31 -0
  24. novelai_python-0.8.1/src/novelai_python/credential/JwtToken.py +31 -0
  25. novelai_python-0.8.1/src/novelai_python/credential/UserAuth.py +90 -0
  26. {novelai_python-0.7.12 → novelai_python-0.8.1}/src/novelai_python/credential/__init__.py +2 -9
  27. novelai_python-0.8.1/src/novelai_python/credential/_base.py +164 -0
  28. novelai_python-0.8.1/src/novelai_python/sdk/__init__.py +29 -0
  29. {novelai_python-0.7.12 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/__init__.py +0 -1
  30. novelai_python-0.8.1/src/novelai_python/sdk/ai/_cost.py +259 -0
  31. {novelai_python-0.7.12 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/_enum.py +315 -164
  32. {novelai_python-0.7.12 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/augment_image/__init__.py +64 -127
  33. {novelai_python-0.7.12 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/augment_image/_enum.py +4 -1
  34. novelai_python-0.8.1/src/novelai_python/sdk/ai/encode_vibe.py +69 -0
  35. {novelai_python-0.7.12 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/generate/__init__.py +163 -138
  36. {novelai_python-0.7.12 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/generate/_const.py +6 -6
  37. {novelai_python-0.7.12 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/generate/_enum.py +320 -276
  38. {novelai_python-0.7.12 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/generate/_schema.py +58 -57
  39. novelai_python-0.8.1/src/novelai_python/sdk/ai/generate_image/__init__.py +1320 -0
  40. novelai_python-0.8.1/src/novelai_python/sdk/ai/generate_image/auto_text.py +121 -0
  41. {novelai_python-0.7.12 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/generate_image/params.py +185 -130
  42. novelai_python-0.8.1/src/novelai_python/sdk/ai/generate_image/schema.py +187 -0
  43. novelai_python-0.8.1/src/novelai_python/sdk/ai/generate_image/suggest_tags.py +92 -0
  44. novelai_python-0.8.1/src/novelai_python/sdk/ai/generate_image/tokenizer.py +27 -0
  45. novelai_python-0.8.1/src/novelai_python/sdk/ai/generate_stream.py +170 -0
  46. novelai_python-0.8.1/src/novelai_python/sdk/ai/generate_voice/__init__.py +119 -0
  47. {novelai_python-0.7.12 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/generate_voice/_enum.py +4 -1
  48. novelai_python-0.8.1/src/novelai_python/sdk/ai/openai_compat.py +169 -0
  49. novelai_python-0.8.1/src/novelai_python/sdk/ai/upscale.py +114 -0
  50. novelai_python-0.8.1/src/novelai_python/sdk/schema.py +161 -0
  51. {novelai_python-0.7.12 → novelai_python-0.8.1}/src/novelai_python/sdk/user/__init__.py +0 -1
  52. novelai_python-0.8.1/src/novelai_python/sdk/user/data.py +36 -0
  53. novelai_python-0.8.1/src/novelai_python/sdk/user/information.py +35 -0
  54. novelai_python-0.8.1/src/novelai_python/sdk/user/login.py +135 -0
  55. novelai_python-0.8.1/src/novelai_python/sdk/user/persistent_token.py +41 -0
  56. novelai_python-0.8.1/src/novelai_python/sdk/user/priority.py +26 -0
  57. novelai_python-0.8.1/src/novelai_python/sdk/user/subscription.py +35 -0
  58. novelai_python-0.8.1/src/novelai_python/sdk/user/trial_status.py +35 -0
  59. novelai_python-0.8.1/src/novelai_python/server.py +368 -0
  60. novelai_python-0.8.1/src/novelai_python/tokenizer/__init__.py +280 -0
  61. novelai_python-0.8.1/src/novelai_python/tokenizer/clip_tokenizer.py +85 -0
  62. {novelai_python-0.7.12/tests → novelai_python-0.8.1/src/novelai_python/tool}/__init__.py +0 -0
  63. {novelai_python-0.7.12 → novelai_python-0.8.1}/src/novelai_python/tool/image_metadata/__init__.py +155 -101
  64. novelai_python-0.8.1/src/novelai_python/tool/image_metadata/bch.py +186 -0
  65. {novelai_python-0.7.12 → novelai_python-0.8.1}/src/novelai_python/tool/image_metadata/bch_utils.py +29 -23
  66. {novelai_python-0.7.12 → novelai_python-0.8.1}/src/novelai_python/tool/image_metadata/lsb_extractor.py +22 -19
  67. {novelai_python-0.7.12 → novelai_python-0.8.1}/src/novelai_python/tool/image_metadata/lsb_injector.py +16 -16
  68. novelai_python-0.8.1/src/novelai_python/tool/paint_mask/__init__.py +66 -0
  69. novelai_python-0.8.1/src/novelai_python/tool/random_prompt/__init__.py +130 -0
  70. novelai_python-0.8.1/src/novelai_python/tool/random_prompt/data/__init__.py +0 -0
  71. novelai_python-0.8.1/src/novelai_python/tool/random_prompt/data/anime_v3_data.py +1925 -0
  72. novelai_python-0.7.12/src/novelai_python/tool/random_prompt/generate_scene_composition.py → novelai_python-0.8.1/src/novelai_python/tool/random_prompt/data/anime_v4_data.py +557 -976
  73. novelai_python-0.8.1/src/novelai_python/tool/random_prompt/data/furry_data.py +1704 -0
  74. novelai_python-0.8.1/src/novelai_python/tool/random_prompt/data/holiday.py +33 -0
  75. novelai_python-0.8.1/src/novelai_python/tool/random_prompt/data/nsfw_data.py +87 -0
  76. novelai_python-0.8.1/src/novelai_python/tool/random_prompt/generate_scene_composition.py +479 -0
  77. {novelai_python-0.7.12 → novelai_python-0.8.1}/src/novelai_python/tool/random_prompt/generate_scene_tags.py +59 -154
  78. {novelai_python-0.7.12 → novelai_python-0.8.1}/src/novelai_python/tool/random_prompt/generate_tags.py +53 -51
  79. novelai_python-0.8.1/src/novelai_python/tool/random_prompt/generators/__init__.py +0 -0
  80. novelai_python-0.8.1/src/novelai_python/tool/random_prompt/generators/anime_v3.py +245 -0
  81. novelai_python-0.8.1/src/novelai_python/tool/random_prompt/generators/anime_v4.py +246 -0
  82. novelai_python-0.8.1/src/novelai_python/tool/random_prompt/generators/furry.py +485 -0
  83. novelai_python-0.8.1/src/novelai_python/tool/random_prompt/generators/holiday.py +44 -0
  84. novelai_python-0.8.1/src/novelai_python/tool/random_prompt/logic.py +85 -0
  85. {novelai_python-0.7.12 → novelai_python-0.8.1}/src/novelai_python/utils/__init__.py +5 -6
  86. novelai_python-0.8.1/src/novelai_python/utils/daily_limit.py +198 -0
  87. {novelai_python-0.7.12 → novelai_python-0.8.1}/src/novelai_python/utils/encode.py +21 -24
  88. {novelai_python-0.7.12 → novelai_python-0.8.1}/src/novelai_python/utils/useful.py +8 -10
  89. novelai_python-0.8.1/tests/__init__.py +0 -0
  90. novelai_python-0.8.1/tests/conftest.py +33 -0
  91. novelai_python-0.8.1/tests/fixtures/bch_vectors.json +1 -0
  92. novelai_python-0.8.1/tests/fixtures/dependency_golden.json +111 -0
  93. novelai_python-0.8.1/tests/fixtures/mask_ori.png +0 -0
  94. novelai_python-0.8.1/tests/fixtures/mask_sketch.png +0 -0
  95. novelai_python-0.8.1/tests/fixtures/v5_signed.webp +0 -0
  96. novelai_python-0.8.1/tests/test_auto_text.py +134 -0
  97. novelai_python-0.8.1/tests/test_bch.py +38 -0
  98. novelai_python-0.8.1/tests/test_browser_identity.py +62 -0
  99. novelai_python-0.8.1/tests/test_cost.py +100 -0
  100. novelai_python-0.8.1/tests/test_daily_limit.py +93 -0
  101. novelai_python-0.8.1/tests/test_dependency_golden.py +57 -0
  102. novelai_python-0.8.1/tests/test_from_metadata.py +121 -0
  103. novelai_python-0.8.1/tests/test_generate_image_v5.py +411 -0
  104. novelai_python-0.8.1/tests/test_generate_text.py +42 -0
  105. {novelai_python-0.7.12 → novelai_python-0.8.1}/tests/test_generate_voice.py +6 -13
  106. novelai_python-0.8.1/tests/test_image_metadata_v5.py +44 -0
  107. novelai_python-0.8.1/tests/test_login_proxy.py +129 -0
  108. novelai_python-0.8.1/tests/test_new_endpoints.py +361 -0
  109. novelai_python-0.8.1/tests/test_presets_and_usage.py +128 -0
  110. novelai_python-0.8.1/tests/test_random_prompt.py +98 -0
  111. novelai_python-0.8.1/tests/test_retry_session.py +42 -0
  112. novelai_python-0.8.1/tests/test_server.py +18 -0
  113. novelai_python-0.8.1/tests/test_server_roundtrip.py +108 -0
  114. novelai_python-0.8.1/tests/test_server_run.py +133 -0
  115. novelai_python-0.8.1/tests/test_suggest_tags.py +32 -0
  116. novelai_python-0.8.1/tests/test_tokenizer.py +93 -0
  117. {novelai_python-0.7.12 → novelai_python-0.8.1}/tests/test_upscale.py +23 -22
  118. {novelai_python-0.7.12 → novelai_python-0.8.1}/tests/test_user_information.py +59 -17
  119. {novelai_python-0.7.12 → novelai_python-0.8.1}/tests/test_user_login.py +18 -28
  120. {novelai_python-0.7.12 → novelai_python-0.8.1}/tests/test_user_subscription.py +39 -44
  121. novelai_python-0.7.12/NOTICE.MD +0 -10
  122. novelai_python-0.7.12/README.md +0 -233
  123. novelai_python-0.7.12/pyproject.toml +0 -63
  124. novelai_python-0.7.12/src/novelai_python/__init__.py +0 -63
  125. novelai_python-0.7.12/src/novelai_python/_exceptions.py +0 -90
  126. novelai_python-0.7.12/src/novelai_python/_response/ai/generate.py +0 -26
  127. novelai_python-0.7.12/src/novelai_python/_response/ai/generate_image.py +0 -34
  128. novelai_python-0.7.12/src/novelai_python/_response/ai/generate_stream.py +0 -26
  129. novelai_python-0.7.12/src/novelai_python/_response/user/subscription.py +0 -80
  130. novelai_python-0.7.12/src/novelai_python/credential/ApiToken.py +0 -41
  131. novelai_python-0.7.12/src/novelai_python/credential/JwtToken.py +0 -41
  132. novelai_python-0.7.12/src/novelai_python/credential/UserAuth.py +0 -47
  133. novelai_python-0.7.12/src/novelai_python/credential/_base.py +0 -18
  134. novelai_python-0.7.12/src/novelai_python/sdk/__init__.py +0 -16
  135. novelai_python-0.7.12/src/novelai_python/sdk/ai/_cost.py +0 -163
  136. novelai_python-0.7.12/src/novelai_python/sdk/ai/generate_image/__init__.py +0 -831
  137. novelai_python-0.7.12/src/novelai_python/sdk/ai/generate_image/schema.py +0 -133
  138. novelai_python-0.7.12/src/novelai_python/sdk/ai/generate_image/suggest_tags.py +0 -94
  139. novelai_python-0.7.12/src/novelai_python/sdk/ai/generate_image/tokenizer.py +0 -22
  140. novelai_python-0.7.12/src/novelai_python/sdk/ai/generate_stream.py +0 -163
  141. novelai_python-0.7.12/src/novelai_python/sdk/ai/generate_voice/__init__.py +0 -154
  142. novelai_python-0.7.12/src/novelai_python/sdk/ai/upscale.py +0 -178
  143. novelai_python-0.7.12/src/novelai_python/sdk/schema.py +0 -87
  144. novelai_python-0.7.12/src/novelai_python/sdk/user/information.py +0 -85
  145. novelai_python-0.7.12/src/novelai_python/sdk/user/login.py +0 -103
  146. novelai_python-0.7.12/src/novelai_python/sdk/user/subscription.py +0 -85
  147. novelai_python-0.7.12/src/novelai_python/server.py +0 -308
  148. novelai_python-0.7.12/src/novelai_python/tokenizer/__init__.py +0 -239
  149. novelai_python-0.7.12/src/novelai_python/tokenizer/clip_simple_tokenizer.py +0 -155
  150. novelai_python-0.7.12/src/novelai_python/tokenizer/nerdstash_v1.model +0 -0
  151. novelai_python-0.7.12/src/novelai_python/tokenizer/nerdstash_v2.model +0 -0
  152. novelai_python-0.7.12/src/novelai_python/tokenizer/novelai.model +0 -0
  153. novelai_python-0.7.12/src/novelai_python/tokenizer/novelai_v2.model +0 -0
  154. novelai_python-0.7.12/src/novelai_python/tool/__init__.py +0 -1
  155. novelai_python-0.7.12/src/novelai_python/tool/paint_mask/__init__.py +0 -76
  156. novelai_python-0.7.12/src/novelai_python/tool/random_prompt/__init__.py +0 -95
  157. novelai_python-0.7.12/tests/test_random_prompt.py +0 -61
  158. novelai_python-0.7.12/tests/test_server.py +0 -23
  159. novelai_python-0.7.12/tests/test_server_run.py +0 -46
  160. novelai_python-0.7.12/tests/test_tokenizer.py +0 -32
  161. {novelai_python-0.7.12 → novelai_python-0.8.1}/LICENSE +0 -0
  162. {novelai_python-0.7.12 → novelai_python-0.8.1}/src/novelai_python/_response/ai/generate_voice.py +0 -0
  163. {novelai_python-0.7.12 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/LICENSE +0 -0
  164. {novelai_python-0.7.12 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/_const.py +0 -0
  165. {novelai_python-0.7.12 → novelai_python-0.8.1}/src/novelai_python/sdk/ai/generate/themes.json +0 -0
@@ -0,0 +1,8 @@
1
+ # NOTICE OF THIS PROJECT
2
+
3
+ ## MIT License
4
+
5
+ The MIT license applies to the files in:
6
+
7
+ file: "src/novelai_python/sdk/ai/generate_image/__init__.py" from https://github.com/HanaokaYuzu/NovelAI-API
8
+ file: "src/novelai_python/tool/image_metadata/lsb_injector.py" from https://github.com/NovelAI/novelai-image-metadata
@@ -0,0 +1,368 @@
1
+ Metadata-Version: 2.1
2
+ Name: novelai-python
3
+ Version: 0.8.1
4
+ Summary: NovelAI Python Binding With Pydantic
5
+ Author-Email: sudoskys <coldlando@hotmail.com>
6
+ License: Apache License 2.0
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Programming Language :: Python :: 3.12
9
+ Classifier: Programming Language :: Python :: 3.13
10
+ Classifier: Programming Language :: Python :: 3.14
11
+ Project-URL: Repository, https://github.com/LlmKira/novelai-python/
12
+ Project-URL: Issues, https://github.com/LlmKira/novelai-python/issues
13
+ Requires-Python: >=3.12
14
+ Requires-Dist: pydantic>=2.14
15
+ Requires-Dist: curl-cffi>=0.16.3
16
+ Requires-Dist: msgpack>=1.2
17
+ Requires-Dist: Pillow>=12.3
18
+ Requires-Dist: numpy>=2.5
19
+ Requires-Dist: pynacl>=1.6
20
+ Requires-Dist: tokenizers>=0.23
21
+ Provides-Extra: server
22
+ Requires-Dist: fastapi>=0.143; extra == "server"
23
+ Requires-Dist: uvicorn[standard]>=0.54; extra == "server"
24
+ Provides-Extra: testing
25
+ Requires-Dist: novelai-python[server]; extra == "testing"
26
+ Requires-Dist: httpx>=0.28; extra == "testing"
27
+ Requires-Dist: pytest>=9.1; extra == "testing"
28
+ Requires-Dist: pytest-asyncio>=1.4; extra == "testing"
29
+ Description-Content-Type: text/markdown
30
+
31
+ ![banner](https://github.com/LlmKira/novelai-python/blob/dev/playground/banner-raw.png?raw=true)
32
+
33
+ ---
34
+
35
+ [![PyPI version](https://badge.fury.io/py/novelai-python.svg)](https://badge.fury.io/py/novelai-python)
36
+ [![Downloads](https://pepy.tech/badge/novelai_python)](https://pepy.tech/project/novelai_python)
37
+
38
+
39
+ >**Declaration** (2025/06/04)
40
+ >
41
+ >**I have nothing to do with NovelAI.**
42
+ >
43
+ >Due to various considerations, such as NovelAI's confusing project architecture and "can't learn anything from it", this project will be in a *non-active* maintenance state. If you have any questions, please *raise an issue*.
44
+ >
45
+ >This project is designed to be a sample project for me to write Python SDK. It turns out that Pydantic is very powerful.
46
+ >
47
+ >*I will invest more time in open source projects that are more beneficial to society.*
48
+ >
49
+
50
+ ✨ NovelAI api python sdk with Pydantic, modern and user-friendly.
51
+
52
+ The goal of this repository is to use Pydantic to build legitimate requests to access
53
+ the [NovelAI API service](https://image.novelai.net/docs).
54
+
55
+ > Python >= 3.12 is required (tested on 3.12 – 3.14).
56
+
57
+ ### 📰 News
58
+
59
+ - **NovelAI Diffusion V5** family: `nai-diffusion-5-full`, `-full-medium` (fast, 14 steps), `-curated` and their
60
+ `-inpainting` variants, with the web client's quality presets (`standard` / `light` / `none`) and negative
61
+ presets. Every model uses `params_version` 4 (`ucPresetId` / `qualityPresetId`) and the
62
+ `multipart/form-data` body the web client sends.
63
+ - **Streaming**: `async for event in gen.request_stream(session)` on `/ai/generate-image-stream` yields
64
+ intermediate previews and the final image per sample.
65
+ - New: character reference (V4.5), `EncodeVibe`, transparent background (V5), `Upscale` on the image host,
66
+ `UserData`, `TrialStatus`, `Priority`, `CreatePersistentToken`, the OpenAI-compatible text API (`/oa/v1`),
67
+ and `GenerateImageInfer.from_metadata()` to rebuild a request from an image's metadata.
68
+ - Fewer dependencies: pydantic, curl_cffi, msgpack, Pillow, numpy, pynacl and tokenizers. httpx, opencv,
69
+ argon2-cffi, ftfy/regex and `bchlib` are gone (`bchlib` has no Python 3.14 wheel; a NumPy BCH codec
70
+ replaces it).
71
+ - Optional local image budget (`limiter=True`, see below).
72
+
73
+ ### ⬆️ Upgrading from 0.7
74
+
75
+ Some changes do not raise an error, so check these when you upgrade:
76
+
77
+ - **`HTTP(S)_PROXY` is ignored.** Sessions use `trust_env=False`, so a system proxy no longer routes NovelAI
78
+ traffic by accident. Pass `proxy="http://user:pass@host:port"` to the credential (`ApiCredential`,
79
+ `LoginCredential`, ...) or to `Login`; tokenizer downloads and tag suggestions read `NOVELAI_PROXY`.
80
+ - **The default model is V5** (`nai-diffusion-5-full`) in `GenerateImageInfer` and `build_generate`.
81
+ - **Images come back as PNG** by default (`image_format`), with the metadata in text chunks; set `parameters.image_format = ImageFormat.WEBP` for smaller files.
82
+ - **`auto_text`** (V5 only, on by default): quoted text in the prompt is appended as a `, teXt: ...` block, as
83
+ novelai.net does. Pass `auto_text=False` to send the prompt untouched.
84
+ - **Image and user endpoints moved to `image.novelai.net`**; `api.novelai.net` rejects third-party clients
85
+ there.
86
+ - **Browser identity**: requests carry the headers of Chrome 155 on Windows, as the web client sends them.
87
+ Accept-Language is English (`en-US,en;q=0.9`) unless the credential says otherwise:
88
+ `ApiCredential(..., accept_language="en-sg")` (see `ACCEPT_LANGUAGES`) or a full header value.
89
+ - **The image budget is off by default.** Pass `limiter=True` to `request()` / `request_stream()` for the
90
+ process-wide budget (`NOVELAI_DAILY_IMAGE_LIMIT`, default 2500 per 24h, saved to
91
+ `~/.novelai_python/image_limit.json`), or a `DailyImageLimiter` of your own. The budget is shared by all
92
+ tokens and by every limiter, in any process, that uses the same state file.
93
+ - **Server: `POST /ai/augment-image` takes the image as the request body** (`application/octet-stream`); the
94
+ other fields stay query parameters. Send `Authorization: Bearer <token>` or the bare token.
95
+
96
+ - [New Model. No Restrictions. V4.5 Full Is Here.](https://blog.novelai.net/novelai-diffusion-v4-5-full-release-678318c86205)
97
+ - [NovelAI Diffusion V4.5 Curated is Here!](https://blog.novelai.net/novelai-diffusion-v4-5-curated-is-here-9e5ba1f628f3)
98
+ - [Image Generation Model Release — NovelAI Anime Diffusion V4 Curated Preview (EN)](https://blog.novelai.net/release-novelai-anime-diffusion-v4-curated-preview-en-ca4b0b11e671)
99
+ - [Tutorial: Creating Consistent Characters with NovelAI Diffusion Anime [Female]](https://blog.novelai.net/tutorial-en-creating-consistent-characters-with-novelai-diffusion-anime-female-538b4b678a4e)
100
+
101
+ ### 📦 Usage
102
+
103
+ ```shell
104
+ pip install -U novelai-python
105
+ ```
106
+
107
+ All API users must adhere to the NovelAI Terms of Service: https://novelai.net/terms.
108
+
109
+ **More examples can be found in the [playground](https://github.com/LlmKira/novelai-python/tree/main/playground)
110
+ directory, read code as documentation.**
111
+
112
+ ```python
113
+ import asyncio
114
+ import os
115
+
116
+ from pydantic import SecretStr
117
+
118
+ from novelai_python import GenerateImageInfer, ImageGenerateResp, ApiCredential
119
+ from novelai_python.sdk.ai.generate_image import Model, Character, Sampler, UCPreset
120
+ from novelai_python.sdk.ai.generate_image.schema import PositionMap
121
+
122
+ session = ApiCredential(api_token=SecretStr(os.getenv("NOVELAI_JWT"))) # pst-***
123
+ # For security reasons, storing user credentials in plaintext is strongly discouraged.
124
+
125
+ prompt = "2girls, fisheye, closeup, from above"
126
+
127
+
128
+ async def main():
129
+ gen = GenerateImageInfer.build_generate(
130
+ prompt=prompt,
131
+ model=Model.NAI_DIFFUSION_5_FULL, # or NAI_DIFFUSION_4_5_FULL
132
+ character_prompts=[
133
+ Character(
134
+ prompt="1girl, head tilt, short hair, black hair, grey eyes, small breasts, looking at viewer",
135
+ uc="red hair",
136
+ center=PositionMap.B2
137
+ ),
138
+ Character(
139
+ prompt="1girl, fox ears, fox tail, white hair, white tail, white ears",
140
+ uc="black hair",
141
+ center=PositionMap.D2
142
+ )
143
+ ],
144
+ sampler=Sampler.K_EULER_ANCESTRAL,
145
+ ucPreset=UCPreset.TYPE0,
146
+ # Recommended, using preset negative_prompt depends on selected model
147
+ qualityToggle=True,
148
+ decrisp_mode=False,
149
+ variety_boost=True,
150
+ furry_mode=False,
151
+ # Checkbox in novelai.net
152
+ )
153
+ cost = gen.calculate_cost(is_opus=True)
154
+ print(f"charge: {cost} if you are vip3")
155
+ resp = await gen.request(session=session) # raises DailyLimitExceeded once the local budget is spent
156
+ resp: ImageGenerateResp
157
+ print(resp.meta)
158
+ print(resp.save("./output")) # auto-download every returned image
159
+
160
+ # streaming previews (V5 family)
161
+ async for event in gen.request_stream(session=session):
162
+ if event.is_final:
163
+ open(f"./output/sample_{event.samp_ix}.webp", "wb").write(event.image)
164
+ elif event.event_type == "intermediate":
165
+ print("preview", event.samp_ix, "step", event.step_ix, len(event.image), "bytes")
166
+
167
+
168
+ loop = asyncio.get_event_loop()
169
+ loop.run_until_complete(main())
170
+
171
+ ```
172
+
173
+ #### 🔋 Anlas / limit monitoring
174
+
175
+ ```python
176
+ from novelai_python import Subscription, UserData, TrialStatus, get_default_limiter
177
+
178
+ sub = await Subscription().request(session=session)
179
+ print(sub.anlas_left, sub.tier_name, sub.is_unlimited_image_generation)
180
+
181
+ data = await UserData().request(session=session) # subscription + information in one call
182
+ print(data.anlas_left)
183
+
184
+ trial = await TrialStatus().request(session=session)
185
+ print(trial.trialImagesLeft)
186
+
187
+ # only when requests opt in with limiter=True
188
+ print(get_default_limiter().status()) # {'limit': 2500, 'used': ..., 'remaining': ..., 'reset_at': ...}
189
+ ```
190
+
191
+ `sub.usage` is the Opus V5 usage bar: `percent`, `purchasedPercent` (bought extra, 0-300),
192
+ `isNegative`, `timeUntilNextPercent`. `Priority().request(session)` returns the task priority balance;
193
+ `CreatePersistentToken(overwrite=True).request(jwt_session)` creates a `pst-...` API key.
194
+
195
+ #### 🖼️ Transparent background, character reference, vibes
196
+
197
+ ```python
198
+ from novelai_python import CharacterReference, EncodeVibe, GenerateImageInfer
199
+ from novelai_python.sdk.ai._enum import Model
200
+
201
+ # V5: "Transparent BG" of the web client (tag before the quality suffix + straight alpha)
202
+ gen = GenerateImageInfer.build_generate("1girl, standing", transparent_background=True)
203
+
204
+ # V4.5: Precise Reference (character / style / costume / character&style / delta)
205
+ gen = GenerateImageInfer.build_generate(
206
+ "1girl", model=Model.NAI_DIFFUSION_4_5_FULL,
207
+ character_references=[CharacterReference(image=open("ref.png", "rb").read(), fidelity=0.8)],
208
+ )
209
+
210
+ # V4 / V4.5 vibe transfer takes encoded vibes: encode once, reuse the result
211
+ vibe = await EncodeVibe(image=open("vibe.png", "rb").read(), information_extracted=0.7).request(session)
212
+ gen = GenerateImageInfer.build_generate(
213
+ "1girl", model=Model.NAI_DIFFUSION_4_5_FULL,
214
+ reference_image_multiple=[vibe.vibe_b64], reference_strength_multiple=[0.6],
215
+ reference_information_extracted_multiple=[0.7],
216
+ )
217
+ ```
218
+
219
+ V5 has no vibe transfer and no character reference; it takes up to 32 characters (V4/V4.5: 6).
220
+
221
+ Environment:
222
+
223
+ | variable | default | meaning |
224
+ |---|---|---|
225
+ | `NOVELAI_DAILY_IMAGE_LIMIT` | `2500` | images per 24h window, `0` disables |
226
+ | `NOVELAI_LIMIT_STATE_FILE` | `~/.novelai_python/image_limit.json` | where the counter is persisted |
227
+
228
+ #### 📦 LLM
229
+
230
+ ```python
231
+ import asyncio
232
+ import os
233
+
234
+ from pydantic import SecretStr
235
+
236
+ from novelai_python import APIError, LoginCredential
237
+ from novelai_python.sdk.ai.generate import TextLLMModel, LLM, get_default_preset, AdvanceLLMSetting
238
+ from novelai_python.sdk.ai.generate._enum import get_model_preset
239
+
240
+ username = os.getenv("NOVELAI_USER", None)
241
+ assert username is not None
242
+ # credential = JwtCredential(jwt_token=SecretStr(jwt))
243
+ login_credential = LoginCredential(
244
+ username=os.getenv("NOVELAI_USER"),
245
+ password=SecretStr(os.getenv("NOVELAI_PASS"))
246
+ )
247
+
248
+
249
+ async def chat(prompt: str):
250
+ try:
251
+ model = TextLLMModel.ERATO # llama3
252
+ parameters = get_default_preset(model).parameters
253
+ agent = LLM.build(
254
+ prompt=prompt,
255
+ model=model,
256
+ # parameters=None, # Auto Select or get from preset
257
+ parameters=get_model_preset(TextLLMModel.ERATO).get_all_presets()[0].parameters, # Select from enum preset
258
+ advanced_setting=AdvanceLLMSetting(
259
+ min_length=1,
260
+ max_length=None, # Auto
261
+ )
262
+ )
263
+ # NOTE:parameter > advanced_setting, which logic in generate/__init__.py
264
+ # If you not pass the parameter, it will use the default preset.
265
+ # So if you want to set the generation params, you should pass your own params.
266
+ # Only if you want to use some params not affect the generation, you can use advanced_setting.
267
+ result = await agent.request(session=login_credential)
268
+ except APIError as e:
269
+ raise Exception(f"Error: {e.message}")
270
+ print(f"Result: \n{result.text}")
271
+
272
+
273
+ loop = asyncio.get_event_loop()
274
+ loop.run_until_complete(chat("Hello"))
275
+ ```
276
+
277
+ OpenAI-compatible text API (`text.novelai.net/oa/v1`), responses in OpenAI format:
278
+
279
+ ```python
280
+ from novelai_python import OAIChatCompletion, OAIChatMessage, OAIModels
281
+
282
+ models = await OAIModels().request(session)
283
+ req = OAIChatCompletion(model=models.data[0].id, messages=[OAIChatMessage(role="user", content="Hello")])
284
+ print((await req.request(session))["choices"][0]["message"]["content"])
285
+ async for chunk in req.stream(session):
286
+ print(chunk["choices"][0]["delta"].get("content", ""), end="")
287
+ ```
288
+
289
+ #### 📦 Random Prompt
290
+
291
+ ```python
292
+ from novelai_python.tool.random_prompt import RandomPromptGenerator
293
+
294
+ generator = RandomPromptGenerator()
295
+ for i in range(10):
296
+ print(generator.generate_common_tags(nsfw=False))
297
+ print(generator.generate_scene_tags())
298
+ print(generator.generate_scene_composition())
299
+ print(generator.get_holiday_themed_tags())
300
+ ```
301
+
302
+ #### 📦 Run A Server
303
+
304
+ ```shell
305
+ pip install "novelai-python[server]"
306
+ python3 -m novelai_python.server -h '127.0.0.1' -p 7888
307
+ ```
308
+
309
+ #### 📦 Tokenizer
310
+
311
+ ```python
312
+ from novelai_python._enum import get_tokenizer_model, TextLLMModel, TextTokenizerGroup
313
+ from novelai_python.tokenizer import NaiTokenizer
314
+
315
+ # Through llm model name to get the tokenizer
316
+ tokenizer_package = NaiTokenizer(get_tokenizer_model(TextLLMModel.ERATO))
317
+ # Directly use the tokenizer
318
+ clip_tokenizer = NaiTokenizer(TextTokenizerGroup.CLIP)
319
+
320
+ # Tokenize a text
321
+ t_text = "a fox jumped over the lazy dog"
322
+ encode_tokens = tokenizer_package.encode(t_text)
323
+ print(tokenizer_package.tokenize_text(t_text))
324
+ print(f"Tokenized text: {encode_tokens}")
325
+ print(tokenizer_package.decode(tokenizer_package.encode(t_text)))
326
+
327
+ ```
328
+
329
+ ### 🔨 Roadmap
330
+
331
+ - [x] tool.random_prompt
332
+ - [x] tool.paint_mask
333
+ - [x] tool.image_metadata
334
+ - [x] tokenizer
335
+ - [x] /ai/generate-image
336
+ - [x] /user/subscription
337
+ - [x] /user/login
338
+ - [x] /user/information
339
+ - [x] /ai/upscale
340
+ - [x] /ai/generate-image/suggest-tags
341
+ - [x] /ai/generate-voice
342
+ - [x] /ai/generate-stream
343
+ - [x] /ai/generate
344
+ - [x] /ai/augment-image
345
+ - [ ] /ai/annotate-image
346
+ - [ ] /ai/classify
347
+ - [ ] /ai/generate-prompt
348
+
349
+ > GenerateImageInfer.calculate_cost is correct in most cases, but please request account information to get accurate
350
+ > consumption information.
351
+
352
+ > This repo is maintained by me personally now. If you have any questions, please feel free to open an issue.
353
+
354
+ ## 🚫 About Nsfw
355
+
356
+ You might need some solutions for identifying NSFW content and adding a mosaic to prevent operational mishaps.
357
+
358
+ https://dghs-imgutils.deepghs.org/main/api_doc/detect/nudenet.html
359
+
360
+ https://dghs-imgutils.deepghs.org/main/api_doc/operate/censor.html
361
+
362
+ ## 🙏 Acknowledgements
363
+
364
+ [novelai-api](https://github.com/Aedial/novelai-api)
365
+
366
+ [NovelAI-API](https://github.com/HanaokaYuzu/NovelAI-API)
367
+
368
+
@@ -1,41 +1,3 @@
1
- Metadata-Version: 2.1
2
- Name: novelai-python
3
- Version: 0.7.12
4
- Summary: NovelAI Python Binding With Pydantic
5
- Author-Email: sudoskys <coldlando@hotmail.com>
6
- License: Apache License 2.0
7
- Project-URL: Repository, https://github.com/LlmKira/novelai-python/
8
- Project-URL: Issues, https://github.com/LlmKira/novelai-python/issues
9
- Requires-Python: >=3.9
10
- Requires-Dist: elara>=0.5.5
11
- Requires-Dist: loguru>=0.7.2
12
- Requires-Dist: pydantic-settings>=2.1.0
13
- Requires-Dist: pydantic>=2.9.0
14
- Requires-Dist: httpx>=0.26.0
15
- Requires-Dist: shortuuid>=1.0.11
16
- Requires-Dist: Pillow>=10.2.0
17
- Requires-Dist: curl-cffi>=0.11.3
18
- Requires-Dist: fastapi>=0.109.0
19
- Requires-Dist: uvicorn[standard]>=0.27.0.post1
20
- Requires-Dist: numpy>=1.24.4
21
- Requires-Dist: argon2-cffi>=23.1.0
22
- Requires-Dist: opencv-python>=4.8.1.78
23
- Requires-Dist: fake-useragent>=1.4.0
24
- Requires-Dist: tenacity>=8.2.3
25
- Requires-Dist: sentencepiece>=0.2.0
26
- Requires-Dist: pynacl>=1.5.0
27
- Requires-Dist: ftfy>=6.2.0
28
- Requires-Dist: regex>=2023.12.25
29
- Requires-Dist: tokenizers>=0.15.2
30
- Requires-Dist: json-repair>=0.29.4
31
- Requires-Dist: robust-downloader>=0.0.2
32
- Requires-Dist: bchlib>=2.1.3
33
- Requires-Dist: arrow>=1.3.0
34
- Provides-Extra: testing
35
- Requires-Dist: pytest>=7.4.4; extra == "testing"
36
- Requires-Dist: pytest-asyncio>=0.23.4; extra == "testing"
37
- Description-Content-Type: text/markdown
38
-
39
1
  ![banner](https://github.com/LlmKira/novelai-python/blob/dev/playground/banner-raw.png?raw=true)
40
2
 
41
3
  ---
@@ -58,12 +20,49 @@ Description-Content-Type: text/markdown
58
20
  ✨ NovelAI api python sdk with Pydantic, modern and user-friendly.
59
21
 
60
22
  The goal of this repository is to use Pydantic to build legitimate requests to access
61
- the [NovelAI API service](https://api.novelai.net/docs).
23
+ the [NovelAI API service](https://image.novelai.net/docs).
62
24
 
63
- > Python >= 3.9 <3.13 is required.
25
+ > Python >= 3.12 is required (tested on 3.12 – 3.14).
64
26
 
65
27
  ### 📰 News
66
28
 
29
+ - **NovelAI Diffusion V5** family: `nai-diffusion-5-full`, `-full-medium` (fast, 14 steps), `-curated` and their
30
+ `-inpainting` variants, with the web client's quality presets (`standard` / `light` / `none`) and negative
31
+ presets. Every model uses `params_version` 4 (`ucPresetId` / `qualityPresetId`) and the
32
+ `multipart/form-data` body the web client sends.
33
+ - **Streaming**: `async for event in gen.request_stream(session)` on `/ai/generate-image-stream` yields
34
+ intermediate previews and the final image per sample.
35
+ - New: character reference (V4.5), `EncodeVibe`, transparent background (V5), `Upscale` on the image host,
36
+ `UserData`, `TrialStatus`, `Priority`, `CreatePersistentToken`, the OpenAI-compatible text API (`/oa/v1`),
37
+ and `GenerateImageInfer.from_metadata()` to rebuild a request from an image's metadata.
38
+ - Fewer dependencies: pydantic, curl_cffi, msgpack, Pillow, numpy, pynacl and tokenizers. httpx, opencv,
39
+ argon2-cffi, ftfy/regex and `bchlib` are gone (`bchlib` has no Python 3.14 wheel; a NumPy BCH codec
40
+ replaces it).
41
+ - Optional local image budget (`limiter=True`, see below).
42
+
43
+ ### ⬆️ Upgrading from 0.7
44
+
45
+ Some changes do not raise an error, so check these when you upgrade:
46
+
47
+ - **`HTTP(S)_PROXY` is ignored.** Sessions use `trust_env=False`, so a system proxy no longer routes NovelAI
48
+ traffic by accident. Pass `proxy="http://user:pass@host:port"` to the credential (`ApiCredential`,
49
+ `LoginCredential`, ...) or to `Login`; tokenizer downloads and tag suggestions read `NOVELAI_PROXY`.
50
+ - **The default model is V5** (`nai-diffusion-5-full`) in `GenerateImageInfer` and `build_generate`.
51
+ - **Images come back as PNG** by default (`image_format`), with the metadata in text chunks; set `parameters.image_format = ImageFormat.WEBP` for smaller files.
52
+ - **`auto_text`** (V5 only, on by default): quoted text in the prompt is appended as a `, teXt: ...` block, as
53
+ novelai.net does. Pass `auto_text=False` to send the prompt untouched.
54
+ - **Image and user endpoints moved to `image.novelai.net`**; `api.novelai.net` rejects third-party clients
55
+ there.
56
+ - **Browser identity**: requests carry the headers of Chrome 155 on Windows, as the web client sends them.
57
+ Accept-Language is English (`en-US,en;q=0.9`) unless the credential says otherwise:
58
+ `ApiCredential(..., accept_language="en-sg")` (see `ACCEPT_LANGUAGES`) or a full header value.
59
+ - **The image budget is off by default.** Pass `limiter=True` to `request()` / `request_stream()` for the
60
+ process-wide budget (`NOVELAI_DAILY_IMAGE_LIMIT`, default 2500 per 24h, saved to
61
+ `~/.novelai_python/image_limit.json`), or a `DailyImageLimiter` of your own. The budget is shared by all
62
+ tokens and by every limiter, in any process, that uses the same state file.
63
+ - **Server: `POST /ai/augment-image` takes the image as the request body** (`application/octet-stream`); the
64
+ other fields stay query parameters. Send `Authorization: Bearer <token>` or the bare token.
65
+
67
66
  - [New Model. No Restrictions. V4.5 Full Is Here.](https://blog.novelai.net/novelai-diffusion-v4-5-full-release-678318c86205)
68
67
  - [NovelAI Diffusion V4.5 Curated is Here!](https://blog.novelai.net/novelai-diffusion-v4-5-curated-is-here-9e5ba1f628f3)
69
68
  - [Image Generation Model Release — NovelAI Anime Diffusion V4 Curated Preview (EN)](https://blog.novelai.net/release-novelai-anime-diffusion-v4-curated-preview-en-ca4b0b11e671)
@@ -72,7 +71,7 @@ the [NovelAI API service](https://api.novelai.net/docs).
72
71
  ### 📦 Usage
73
72
 
74
73
  ```shell
75
- pip -U install novelai-python
74
+ pip install -U novelai-python
76
75
  ```
77
76
 
78
77
  All API users must adhere to the NovelAI Terms of Service: https://novelai.net/terms.
@@ -84,14 +83,12 @@ directory, read code as documentation.**
84
83
  import asyncio
85
84
  import os
86
85
 
87
- from dotenv import load_dotenv
88
86
  from pydantic import SecretStr
89
87
 
90
88
  from novelai_python import GenerateImageInfer, ImageGenerateResp, ApiCredential
91
89
  from novelai_python.sdk.ai.generate_image import Model, Character, Sampler, UCPreset
92
90
  from novelai_python.sdk.ai.generate_image.schema import PositionMap
93
91
 
94
- load_dotenv()
95
92
  session = ApiCredential(api_token=SecretStr(os.getenv("NOVELAI_JWT"))) # pst-***
96
93
  # For security reasons, storing user credentials in plaintext is strongly discouraged.
97
94
 
@@ -101,7 +98,7 @@ prompt = "2girls, fisheye, closeup, from above"
101
98
  async def main():
102
99
  gen = GenerateImageInfer.build_generate(
103
100
  prompt=prompt,
104
- model=Model.NAI_DIFFUSION_4_5_FULL,
101
+ model=Model.NAI_DIFFUSION_5_FULL, # or NAI_DIFFUSION_4_5_FULL
105
102
  character_prompts=[
106
103
  Character(
107
104
  prompt="1girl, head tilt, short hair, black hair, grey eyes, small breasts, looking at viewer",
@@ -125,12 +122,17 @@ async def main():
125
122
  )
126
123
  cost = gen.calculate_cost(is_opus=True)
127
124
  print(f"charge: {cost} if you are vip3")
128
- resp = await gen.request(session=session)
125
+ resp = await gen.request(session=session) # raises DailyLimitExceeded once the local budget is spent
129
126
  resp: ImageGenerateResp
130
127
  print(resp.meta)
131
- file = resp.files[0]
132
- with open(file[0], "wb") as f:
133
- f.write(file[1])
128
+ print(resp.save("./output")) # auto-download every returned image
129
+
130
+ # streaming previews (V5 family)
131
+ async for event in gen.request_stream(session=session):
132
+ if event.is_final:
133
+ open(f"./output/sample_{event.samp_ix}.webp", "wb").write(event.image)
134
+ elif event.event_type == "intermediate":
135
+ print("preview", event.samp_ix, "step", event.step_ix, len(event.image), "bytes")
134
136
 
135
137
 
136
138
  loop = asyncio.get_event_loop()
@@ -138,20 +140,73 @@ loop.run_until_complete(main())
138
140
 
139
141
  ```
140
142
 
143
+ #### 🔋 Anlas / limit monitoring
144
+
145
+ ```python
146
+ from novelai_python import Subscription, UserData, TrialStatus, get_default_limiter
147
+
148
+ sub = await Subscription().request(session=session)
149
+ print(sub.anlas_left, sub.tier_name, sub.is_unlimited_image_generation)
150
+
151
+ data = await UserData().request(session=session) # subscription + information in one call
152
+ print(data.anlas_left)
153
+
154
+ trial = await TrialStatus().request(session=session)
155
+ print(trial.trialImagesLeft)
156
+
157
+ # only when requests opt in with limiter=True
158
+ print(get_default_limiter().status()) # {'limit': 2500, 'used': ..., 'remaining': ..., 'reset_at': ...}
159
+ ```
160
+
161
+ `sub.usage` is the Opus V5 usage bar: `percent`, `purchasedPercent` (bought extra, 0-300),
162
+ `isNegative`, `timeUntilNextPercent`. `Priority().request(session)` returns the task priority balance;
163
+ `CreatePersistentToken(overwrite=True).request(jwt_session)` creates a `pst-...` API key.
164
+
165
+ #### 🖼️ Transparent background, character reference, vibes
166
+
167
+ ```python
168
+ from novelai_python import CharacterReference, EncodeVibe, GenerateImageInfer
169
+ from novelai_python.sdk.ai._enum import Model
170
+
171
+ # V5: "Transparent BG" of the web client (tag before the quality suffix + straight alpha)
172
+ gen = GenerateImageInfer.build_generate("1girl, standing", transparent_background=True)
173
+
174
+ # V4.5: Precise Reference (character / style / costume / character&style / delta)
175
+ gen = GenerateImageInfer.build_generate(
176
+ "1girl", model=Model.NAI_DIFFUSION_4_5_FULL,
177
+ character_references=[CharacterReference(image=open("ref.png", "rb").read(), fidelity=0.8)],
178
+ )
179
+
180
+ # V4 / V4.5 vibe transfer takes encoded vibes: encode once, reuse the result
181
+ vibe = await EncodeVibe(image=open("vibe.png", "rb").read(), information_extracted=0.7).request(session)
182
+ gen = GenerateImageInfer.build_generate(
183
+ "1girl", model=Model.NAI_DIFFUSION_4_5_FULL,
184
+ reference_image_multiple=[vibe.vibe_b64], reference_strength_multiple=[0.6],
185
+ reference_information_extracted_multiple=[0.7],
186
+ )
187
+ ```
188
+
189
+ V5 has no vibe transfer and no character reference; it takes up to 32 characters (V4/V4.5: 6).
190
+
191
+ Environment:
192
+
193
+ | variable | default | meaning |
194
+ |---|---|---|
195
+ | `NOVELAI_DAILY_IMAGE_LIMIT` | `2500` | images per 24h window, `0` disables |
196
+ | `NOVELAI_LIMIT_STATE_FILE` | `~/.novelai_python/image_limit.json` | where the counter is persisted |
197
+
141
198
  #### 📦 LLM
142
199
 
143
200
  ```python
144
201
  import asyncio
145
202
  import os
146
203
 
147
- from dotenv import load_dotenv
148
204
  from pydantic import SecretStr
149
205
 
150
206
  from novelai_python import APIError, LoginCredential
151
207
  from novelai_python.sdk.ai.generate import TextLLMModel, LLM, get_default_preset, AdvanceLLMSetting
152
208
  from novelai_python.sdk.ai.generate._enum import get_model_preset
153
209
 
154
- load_dotenv()
155
210
  username = os.getenv("NOVELAI_USER", None)
156
211
  assert username is not None
157
212
  # credential = JwtCredential(jwt_token=SecretStr(jwt))
@@ -189,6 +244,18 @@ loop = asyncio.get_event_loop()
189
244
  loop.run_until_complete(chat("Hello"))
190
245
  ```
191
246
 
247
+ OpenAI-compatible text API (`text.novelai.net/oa/v1`), responses in OpenAI format:
248
+
249
+ ```python
250
+ from novelai_python import OAIChatCompletion, OAIChatMessage, OAIModels
251
+
252
+ models = await OAIModels().request(session)
253
+ req = OAIChatCompletion(model=models.data[0].id, messages=[OAIChatMessage(role="user", content="Hello")])
254
+ print((await req.request(session))["choices"][0]["message"]["content"])
255
+ async for chunk in req.stream(session):
256
+ print(chunk["choices"][0]["delta"].get("content", ""), end="")
257
+ ```
258
+
192
259
  #### 📦 Random Prompt
193
260
 
194
261
  ```python
@@ -205,7 +272,7 @@ for i in range(10):
205
272
  #### 📦 Run A Server
206
273
 
207
274
  ```shell
208
- pip install novelai_python
275
+ pip install "novelai-python[server]"
209
276
  python3 -m novelai_python.server -h '127.0.0.1' -p 7888
210
277
  ```
211
278