novelai-python 0.4.9__tar.gz → 0.4.10__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 (77) hide show
  1. {novelai_python-0.4.9 → novelai_python-0.4.10}/PKG-INFO +1 -1
  2. {novelai_python-0.4.9 → novelai_python-0.4.10}/pyproject.toml +1 -1
  3. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/_response/ai/generate.py +1 -1
  4. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/_response/ai/generate_stream.py +1 -1
  5. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/sdk/ai/generate/__init__.py +3 -2
  6. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/tokenizer/__init__.py +46 -48
  7. {novelai_python-0.4.9 → novelai_python-0.4.10}/LICENSE +0 -0
  8. {novelai_python-0.4.9 → novelai_python-0.4.10}/NOTICE.MD +0 -0
  9. {novelai_python-0.4.9 → novelai_python-0.4.10}/README.md +0 -0
  10. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/__init__.py +0 -0
  11. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/_exceptions.py +0 -0
  12. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/_response/__init__.py +0 -0
  13. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/_response/ai/__init__.py +0 -0
  14. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/_response/ai/generate_image.py +0 -0
  15. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/_response/ai/generate_voice.py +0 -0
  16. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/_response/ai/upscale.py +0 -0
  17. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/_response/schema.py +0 -0
  18. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/_response/user/__init__.py +0 -0
  19. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/_response/user/information.py +0 -0
  20. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/_response/user/login.py +0 -0
  21. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/_response/user/subscription.py +0 -0
  22. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/credential/ApiToken.py +0 -0
  23. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/credential/JwtToken.py +0 -0
  24. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/credential/UserAuth.py +0 -0
  25. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/credential/__init__.py +0 -0
  26. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/credential/_base.py +0 -0
  27. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/sdk/__init__.py +0 -0
  28. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/sdk/ai/LICENSE +0 -0
  29. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/sdk/ai/__init__.py +0 -0
  30. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/sdk/ai/generate/_const.py +0 -0
  31. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/sdk/ai/generate/_enum.py +0 -0
  32. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/sdk/ai/generate/_preset.py +0 -0
  33. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/sdk/ai/generate_image/__init__.py +0 -0
  34. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/sdk/ai/generate_image/_const.py +0 -0
  35. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/sdk/ai/generate_image/_enum.py +0 -0
  36. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/sdk/ai/generate_image/suggest_tags.py +0 -0
  37. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/sdk/ai/generate_stream.py +0 -0
  38. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/sdk/ai/generate_voice/__init__.py +0 -0
  39. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/sdk/ai/generate_voice/_enum.py +0 -0
  40. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/sdk/ai/upscale.py +0 -0
  41. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/sdk/schema.py +0 -0
  42. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/sdk/user/__init__.py +0 -0
  43. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/sdk/user/information.py +0 -0
  44. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/sdk/user/login.py +0 -0
  45. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/sdk/user/subscription.py +0 -0
  46. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/server.py +0 -0
  47. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/tokenizer/NOTICE.MD +0 -0
  48. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/tokenizer/bpe_simple_vocab_16e6.txt.gz +0 -0
  49. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/tokenizer/gpt2-genji_tokenizer.json +0 -0
  50. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/tokenizer/gpt2_tokenizer.json +0 -0
  51. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/tokenizer/nerdstash_v1.model +0 -0
  52. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/tokenizer/nerdstash_v2.model +0 -0
  53. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/tokenizer/novelai.model +0 -0
  54. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/tokenizer/novelai_v2.model +0 -0
  55. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/tokenizer/pile_tokenizer.json +0 -0
  56. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/tokenizer/simple_tokenizer.py +0 -0
  57. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/tool/__init__.py +0 -0
  58. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/tool/image_metadata/__init__.py +0 -0
  59. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/tool/image_metadata/lsb_extractor.py +0 -0
  60. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/tool/image_metadata/lsb_injector.py +0 -0
  61. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/tool/paint_mask/__init__.py +0 -0
  62. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/tool/random_prompt/__init__.py +0 -0
  63. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/tool/random_prompt/tag.py +0 -0
  64. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/tool/random_prompt/tag_character.py +0 -0
  65. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/tool/random_prompt/tag_nsfw.py +0 -0
  66. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/utils/__init__.py +0 -0
  67. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/utils/encode.py +0 -0
  68. {novelai_python-0.4.9 → novelai_python-0.4.10}/src/novelai_python/utils/useful.py +0 -0
  69. {novelai_python-0.4.9 → novelai_python-0.4.10}/tests/__init__.py +0 -0
  70. {novelai_python-0.4.9 → novelai_python-0.4.10}/tests/test_generate_voice.py +0 -0
  71. {novelai_python-0.4.9 → novelai_python-0.4.10}/tests/test_random_prompt.py +0 -0
  72. {novelai_python-0.4.9 → novelai_python-0.4.10}/tests/test_server.py +0 -0
  73. {novelai_python-0.4.9 → novelai_python-0.4.10}/tests/test_server_run.py +0 -0
  74. {novelai_python-0.4.9 → novelai_python-0.4.10}/tests/test_upscale.py +0 -0
  75. {novelai_python-0.4.9 → novelai_python-0.4.10}/tests/test_user_information.py +0 -0
  76. {novelai_python-0.4.9 → novelai_python-0.4.10}/tests/test_user_login.py +0 -0
  77. {novelai_python-0.4.9 → novelai_python-0.4.10}/tests/test_user_subscription.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: novelai-python
3
- Version: 0.4.9
3
+ Version: 0.4.10
4
4
  Summary: NovelAI Python Binding With Pydantic
5
5
  Author-Email: sudoskys <coldlando@hotmail.com>
6
6
  License: Apache License 2.0
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "novelai-python"
3
- version = "0.4.9"
3
+ version = "0.4.10"
4
4
  description = "NovelAI Python Binding With Pydantic"
5
5
  authors = [
6
6
  { name = "sudoskys", email = "coldlando@hotmail.com" },
@@ -20,4 +20,4 @@ class LLMResp(BaseModel):
20
20
 
21
21
  @staticmethod
22
22
  def decode_token(token_str, model: TextLLMModel) -> str:
23
- return LLMTokenizer.decode(b64_to_tokens(token_str), tokenizer_name=TOKENIZER.get(model))
23
+ return LLMTokenizer().decode(b64_to_tokens(token_str), tokenizer_name=TOKENIZER.get(model))
@@ -20,4 +20,4 @@ class LLMStreamResp(BaseModel):
20
20
 
21
21
  @staticmethod
22
22
  def decode(token_str, model: TextLLMModel) -> str:
23
- return LLMTokenizer.decode(b64_to_tokens(token_str), tokenizer_name=TOKENIZER.get(model))
23
+ return LLMTokenizer().decode(b64_to_tokens(token_str), tokenizer_name=TOKENIZER.get(model))
@@ -64,8 +64,9 @@ class LLM(ApiBaseModel):
64
64
 
65
65
  @model_validator(mode="after")
66
66
  def validate_model(self):
67
+ tokenizer = LLMTokenizer()
67
68
  if isinstance(self.input, str):
68
- prompt = LLMTokenizer.encode(self.input, tokenizer_name=TOKENIZER.get(self.model))
69
+ prompt = tokenizer.encode(self.input, tokenizer_name=TOKENIZER.get(self.model))
69
70
  self.input = tokens_to_b64(prompt)
70
71
  if self.parameters.stop_sequences:
71
72
  if not isinstance(self.parameters.stop_sequences, list):
@@ -73,7 +74,7 @@ class LLM(ApiBaseModel):
73
74
  stop_sequences = []
74
75
  for i, obj in enumerate(self.parameters.stop_sequences):
75
76
  if isinstance(obj, str):
76
- stop_sequences.append(LLMTokenizer.encode(obj, tokenizer_name=TOKENIZER.get(self.model)))
77
+ stop_sequences.append(tokenizer.encode(obj, tokenizer_name=TOKENIZER.get(self.model)))
77
78
  elif not isinstance(obj, list):
78
79
  raise ValueError(
79
80
  f"Expected type 'str' or 'list' for item #{i} of 'stop_sequences', " f"but got '{type(obj)}'"
@@ -117,68 +117,66 @@ class SentencePiece(sentencepiece.SentencePieceProcessor):
117
117
  return "".join((decoded_parts[0], *itertools.chain.from_iterable(zip(junctions, decoded_parts[1:]))))
118
118
 
119
119
 
120
+ def singleton(cls):
121
+ instances = {}
122
+
123
+ def wrapper(*args, **kwargs):
124
+ if cls not in instances:
125
+ instances[cls] = cls(*args, **kwargs)
126
+ return instances[cls]
127
+
128
+ return wrapper
129
+
130
+
120
131
  # MIT: https://github.com/Aedial/novelai-api/blob/794c4f3d89cc86df3c7d2c401b320f1822822ac0/novelai_api/Tokenizer.py#L118
132
+ @singleton
121
133
  class LLMTokenizer:
122
134
  """
123
135
  Abstraction of the tokenizer behind each Model
124
136
  """
125
137
 
126
- _GPT2_PATH = tokenizers_path / "gpt2_tokenizer.json"
127
- _GPT2_TOKENIZER = tokenizers.Tokenizer.from_file(str(_GPT2_PATH))
128
-
129
- _GENJI_PATH = tokenizers_path / "gpt2-genji_tokenizer.json"
130
- _GENJI_TOKENIZER = tokenizers.Tokenizer.from_file(str(_GENJI_PATH))
131
-
132
- _PILE_PATH = tokenizers_path / "pile_tokenizer.json"
133
- _PILE_TOKENIZER = tokenizers.Tokenizer.from_file(str(_PILE_PATH))
134
-
138
+ _GPT2_PATH = "gpt2_tokenizer.json"
139
+ _GENJI_PATH = "gpt2-genji_tokenizer.json"
140
+ _PILE_PATH = "pile_tokenizer.json"
135
141
  # ORIGIN TODO: check differences from NAI tokenizer (from my limited testing, there is None)
136
- _CLIP_TOKENIZER = SimpleTokenizer()
137
-
138
- _NERDSTASH_TOKENIZER_v1_PATH = str(tokenizers_path / "nerdstash_v1.model")
139
- _NERDSTASH_TOKENIZER_v1 = SentencePiece(_NERDSTASH_TOKENIZER_v1_PATH)
140
-
141
- _NERDSTASH_TOKENIZER_v2_PATH = str(tokenizers_path / "nerdstash_v2.model")
142
- _NERDSTASH_TOKENIZER_v2 = SentencePiece(_NERDSTASH_TOKENIZER_v2_PATH)
143
-
144
- _tokenizers = {
145
- "gpt2": _GPT2_TOKENIZER,
146
- "gpt2-genji": _GENJI_TOKENIZER,
147
- "pile": _PILE_TOKENIZER,
148
- "clip": _CLIP_TOKENIZER,
149
- "nerdstash_v1": _NERDSTASH_TOKENIZER_v1,
150
- "nerdstash_v2": _NERDSTASH_TOKENIZER_v2,
151
- }
152
-
153
- @classmethod
154
- def decode(cls, o: List[int], tokenizer_name: str) -> str:
155
- """
156
- Decode the provided tokens using the chosen tokenizer
157
- :param tokenizer_name: Name of the tokenizer to use
158
- :param o: List of tokens to decode
142
+ _NERDSTASH_TOKENIZER_v1_PATH = "nerdstash_v1.model"
143
+ _NERDSTASH_TOKENIZER_v2_PATH = "nerdstash_v2.model"
144
+
145
+ def __init__(self, tokenizer_path=tokenizers_path):
146
+ self._GPT2_TOKENIZER = tokenizers.Tokenizer.from_file(str(tokenizer_path / self._GPT2_PATH))
147
+ self._GENJI_TOKENIZER = tokenizers.Tokenizer.from_file(str(tokenizer_path / self._GENJI_PATH))
148
+ self._PILE_TOKENIZER = tokenizers.Tokenizer.from_file(str(tokenizer_path / self._PILE_PATH))
149
+ self._CLIP_TOKENIZER = SimpleTokenizer()
150
+ try:
151
+ self._NERDSTASH_TOKENIZER_v1 = SentencePiece(str(tokenizer_path / self._NERDSTASH_TOKENIZER_v1_PATH))
152
+ self._NERDSTASH_TOKENIZER_v2 = SentencePiece(str(tokenizer_path / self._NERDSTASH_TOKENIZER_v2_PATH))
153
+ except FileNotFoundError as exc:
154
+ logger.warning(
155
+ "Nerdstash tokenizers not found, please check model path or "
156
+ "there cannot be special text such as foreign languages, spaces, etc. in your model path."
157
+ )
158
+ raise exc
159
+ self._tokenizers = {
160
+ "gpt2": self._GPT2_TOKENIZER,
161
+ "gpt2-genji": self._GENJI_TOKENIZER,
162
+ "pile": self._PILE_TOKENIZER,
163
+ "clip": self._CLIP_TOKENIZER,
164
+ "nerdstash_v1": self._NERDSTASH_TOKENIZER_v1,
165
+ "nerdstash_v2": self._NERDSTASH_TOKENIZER_v2,
166
+ }
159
167
 
160
- :return: Text the provided tokens decode into
161
- """
162
- if tokenizer_name not in cls._tokenizers:
168
+ def decode(self, o: List[int], tokenizer_name: str) -> str:
169
+ if tokenizer_name not in self._tokenizers:
163
170
  raise NotImplementedError(f"Tokenizer {tokenizer_name} not recognized")
164
- tokenizer = cls._tokenizers[tokenizer_name]
171
+ tokenizer = self._tokenizers[tokenizer_name]
165
172
 
166
173
  return tokenizer.decode(o)
167
174
 
168
- @classmethod
169
- def encode(cls, o: str, tokenizer_name: str) -> List[int]:
170
- """
171
- Encode the provided text using the chosen tokenizer
172
-
173
- :param tokenizer_name: Name of the tokenizer to use
174
- :param o: Text to encode
175
-
176
- :return: List of tokens the provided text encodes into
177
- """
178
- if tokenizer_name not in cls._tokenizers:
175
+ def encode(self, o: str, tokenizer_name: str) -> List[int]:
176
+ if tokenizer_name not in self._tokenizers:
179
177
  raise NotImplementedError(f"Tokenizer {tokenizer_name} not recognized")
180
178
 
181
- tokenizer = cls._tokenizers[tokenizer_name]
179
+ tokenizer = self._tokenizers[tokenizer_name]
182
180
  if isinstance(tokenizer, tokenizers.Tokenizer):
183
181
  return tokenizer.encode(o).ids
184
182
  if isinstance(tokenizer, (SimpleTokenizer, sentencepiece.SentencePieceProcessor)):
File without changes