Bikatr7 commited on
Commit
1480a44
1 Parent(s): e36b105

push v3.4.3 files

Browse files
README.md CHANGED
@@ -32,7 +32,7 @@ This readme is for the Hugging Space instance of Kudasai's WebGUI and the WebGUI
32
 
33
  Streamlining Japanese-English Translation with Advanced Preprocessing and Integrated Translation Technologies.
34
 
35
- Preprocessor is sourced from an external package, which I also designed, called [Kairyou](https://github.com/Bikatr7/Kairyou).
36
 
37
  Kudasai has a public trello board, you can find it [here](https://trello.com/b/Wsuwr24S/kudasai) to see what I'm working on.
38
 
 
32
 
33
  Streamlining Japanese-English Translation with Advanced Preprocessing and Integrated Translation Technologies.
34
 
35
+ Preprocessor and Translation logic is sourced from external packages, which I also designed, see [Kairyou](https://github.com/Bikatr7/Kairyou) and [EasyTL](https://github.com/Bikatr7/easytl) for more information.
36
 
37
  Kudasai has a public trello board, you can find it [here](https://trello.com/b/Wsuwr24S/kudasai) to see what I'm working on.
38
 
custom_classes/messages.py DELETED
@@ -1,54 +0,0 @@
1
- ##-------------------start-of-Message--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2
-
3
- class Message:
4
-
5
- """
6
-
7
- Message is a class that is used to send translation batches to the OpenAI API.
8
-
9
- """
10
-
11
- def __init__(self, content: str):
12
- self._content = content
13
-
14
- @property
15
- def role(self):
16
- raise NotImplementedError
17
-
18
- @property
19
- def content(self):
20
- return self._content
21
-
22
- def to_dict(self):
23
- return {
24
- 'role': self.role,
25
- 'content': self.content
26
- }
27
-
28
- ##-------------------start-of-SystemTranslationMessage--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
29
-
30
- class SystemTranslationMessage(Message):
31
-
32
- """
33
-
34
- SystemTranslationMessage is a class that is used to send the system message to the OpenAI API.
35
-
36
- """
37
-
38
- @property
39
- def role(self):
40
- return 'system'
41
-
42
- ##-------------------start-of-ModelTranslationMessage--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
43
-
44
- class ModelTranslationMessage(Message):
45
-
46
- """
47
-
48
- ModelTranslationMessage is a class that is used to send the model/user message to the OpenAI API.
49
-
50
- """
51
-
52
- @property
53
- def role(self):
54
- return 'user'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
handlers/json_handler.py CHANGED
@@ -2,6 +2,9 @@
2
  import json
3
  import typing
4
 
 
 
 
5
  ## custom modules
6
  from modules.common.file_ensurer import FileEnsurer
7
  from modules.common.logger import Logger
@@ -144,13 +147,13 @@ gemini_stream, gemini_stop_sequences and gemini_candidate_count are included for
144
  "number_of_malformed_batch_retries": lambda x: isinstance(x, int) and x >= 0,
145
  "batch_retry_timeout": lambda x: isinstance(x, int) and x >= 0,
146
  "number_of_concurrent_batches": lambda x: isinstance(x, int) and x >= 0,
147
- "openai_model": lambda x: isinstance(x, str) and x in FileEnsurer.ALLOWED_OPENAI_MODELS,
148
  "openai_system_message": lambda x: x not in ["", "None", None],
149
  "openai_temperature": lambda x: isinstance(x, float) and 0 <= x <= 2,
150
  "openai_top_p": lambda x: isinstance(x, float) and 0 <= x <= 1,
151
  "openai_max_tokens": lambda x: x is None or isinstance(x, int) and x > 0,
152
  "openai_presence_penalty": lambda x: isinstance(x, float) and -2 <= x <= 2,
153
- "gemini_model": lambda x: isinstance(x, str) and x in FileEnsurer.ALLOWED_GEMINI_MODELS,
154
  "gemini_prompt": lambda x: x not in ["", "None", None],
155
  "gemini_temperature": lambda x: isinstance(x, float) and 0 <= x <= 2,
156
  "gemini_top_p": lambda x: x is None or (isinstance(x, float) and 0 <= x <= 2),
@@ -360,7 +363,7 @@ gemini_stream, gemini_stop_sequences and gemini_candidate_count are included for
360
  "number_of_malformed_batch_retries": {"type": int, "constraints": lambda x: x >= 0},
361
  "batch_retry_timeout": {"type": int, "constraints": lambda x: x >= 0},
362
  "number_of_concurrent_batches": {"type": int, "constraints": lambda x: x >= 0},
363
- "openai_model": {"type": str, "constraints": lambda x: x in FileEnsurer.ALLOWED_OPENAI_MODELS},
364
  "openai_system_message": {"type": str, "constraints": lambda x: x not in ["", "None", None]},
365
  "openai_temperature": {"type": float, "constraints": lambda x: 0 <= x <= 2},
366
  "openai_top_p": {"type": float, "constraints": lambda x: 0 <= x <= 2},
@@ -371,7 +374,7 @@ gemini_stream, gemini_stop_sequences and gemini_candidate_count are included for
371
  "openai_max_tokens": {"type": int, "constraints": lambda x: x is None or isinstance(x, int)},
372
  "openai_presence_penalty": {"type": float, "constraints": lambda x: -2 <= x <= 2},
373
  "openai_frequency_penalty": {"type": float, "constraints": lambda x: -2 <= x <= 2},
374
- "gemini_model": {"type": str, "constraints": lambda x: x in FileEnsurer.ALLOWED_GEMINI_MODELS},
375
  "gemini_prompt": {"type": str, "constraints": lambda x: x not in ["", "None", None]},
376
  "gemini_temperature": {"type": float, "constraints": lambda x: 0 <= x <= 2},
377
  "gemini_top_p": {"type": float, "constraints": lambda x: x is None or (isinstance(x, float) and 0 <= x <= 2)},
 
2
  import json
3
  import typing
4
 
5
+ ## third-party libraries
6
+ from easytl import ALLOWED_GEMINI_MODELS, ALLOWED_OPENAI_MODELS
7
+
8
  ## custom modules
9
  from modules.common.file_ensurer import FileEnsurer
10
  from modules.common.logger import Logger
 
147
  "number_of_malformed_batch_retries": lambda x: isinstance(x, int) and x >= 0,
148
  "batch_retry_timeout": lambda x: isinstance(x, int) and x >= 0,
149
  "number_of_concurrent_batches": lambda x: isinstance(x, int) and x >= 0,
150
+ "openai_model": lambda x: isinstance(x, str) and x in ALLOWED_OPENAI_MODELS,
151
  "openai_system_message": lambda x: x not in ["", "None", None],
152
  "openai_temperature": lambda x: isinstance(x, float) and 0 <= x <= 2,
153
  "openai_top_p": lambda x: isinstance(x, float) and 0 <= x <= 1,
154
  "openai_max_tokens": lambda x: x is None or isinstance(x, int) and x > 0,
155
  "openai_presence_penalty": lambda x: isinstance(x, float) and -2 <= x <= 2,
156
+ "gemini_model": lambda x: isinstance(x, str) and x in ALLOWED_GEMINI_MODELS,
157
  "gemini_prompt": lambda x: x not in ["", "None", None],
158
  "gemini_temperature": lambda x: isinstance(x, float) and 0 <= x <= 2,
159
  "gemini_top_p": lambda x: x is None or (isinstance(x, float) and 0 <= x <= 2),
 
363
  "number_of_malformed_batch_retries": {"type": int, "constraints": lambda x: x >= 0},
364
  "batch_retry_timeout": {"type": int, "constraints": lambda x: x >= 0},
365
  "number_of_concurrent_batches": {"type": int, "constraints": lambda x: x >= 0},
366
+ "openai_model": {"type": str, "constraints": lambda x: x in ALLOWED_OPENAI_MODELS},
367
  "openai_system_message": {"type": str, "constraints": lambda x: x not in ["", "None", None]},
368
  "openai_temperature": {"type": float, "constraints": lambda x: 0 <= x <= 2},
369
  "openai_top_p": {"type": float, "constraints": lambda x: 0 <= x <= 2},
 
374
  "openai_max_tokens": {"type": int, "constraints": lambda x: x is None or isinstance(x, int)},
375
  "openai_presence_penalty": {"type": float, "constraints": lambda x: -2 <= x <= 2},
376
  "openai_frequency_penalty": {"type": float, "constraints": lambda x: -2 <= x <= 2},
377
+ "gemini_model": {"type": str, "constraints": lambda x: x in ALLOWED_GEMINI_MODELS},
378
  "gemini_prompt": {"type": str, "constraints": lambda x: x not in ["", "None", None]},
379
  "gemini_temperature": {"type": float, "constraints": lambda x: 0 <= x <= 2},
380
  "gemini_top_p": {"type": float, "constraints": lambda x: x is None or (isinstance(x, float) and 0 <= x <= 2)},
models/kaiseki.py CHANGED
@@ -1,5 +1,6 @@
1
  ## Basically Deprecated, use Kijiku instead. Currently only maintained for backwards compatibility.
2
  ##---------------------------------------
 
3
  ## built-in libraries
4
  import string
5
  import time
@@ -7,8 +8,10 @@ import re
7
  import base64
8
  import time
9
 
 
 
 
10
  ## custom modules
11
- from translation_services.deepl_service import DeepLService
12
  from modules.common.toolkit import Toolkit
13
  from modules.common.file_ensurer import FileEnsurer
14
  from modules.common.logger import Logger
@@ -105,8 +108,10 @@ class Kaiseki:
105
  with open(FileEnsurer.deepl_api_key_path, 'r', encoding='utf-8') as file:
106
  api_key = base64.b64decode((file.read()).encode('utf-8')).decode('utf-8')
107
 
108
- DeepLService.set_api_key(api_key)
109
- DeepLService.test_api_key_validity()
 
 
110
 
111
  Logger.log_action("Used saved api key in " + FileEnsurer.deepl_api_key_path, output=True)
112
 
@@ -118,8 +123,10 @@ class Kaiseki:
118
  ## if valid save the api key
119
  try:
120
 
121
- DeepLService.set_api_key(api_key)
122
- DeepLService.test_api_key_validity()
 
 
123
 
124
  time.sleep(.1)
125
 
@@ -136,7 +143,7 @@ class Kaiseki:
136
 
137
  Toolkit.pause_console()
138
 
139
- raise e
140
 
141
  ## other error, alert user and raise it
142
  except Exception as e:
@@ -452,7 +459,9 @@ class Kaiseki:
452
  single_quote_active = True
453
 
454
  try:
455
- results = DeepLService.translate(Kaiseki.sentence_parts[i], source_lang= "JA", target_lang="EN-US")
 
 
456
 
457
  translated_part = results.rstrip(''.join(c for c in string.punctuation if c not in "'\""))
458
  translated_part = translated_part.rstrip()
@@ -464,7 +473,9 @@ class Kaiseki:
464
 
465
  ## translates the quote and re-adds it back to the sentence part
466
  if(single_quote_active == True):
467
- quote = DeepLService.translate(quote, source_lang= "JA", target_lang="EN-US")
 
 
468
 
469
  quote = quote.rstrip(''.join(c for c in string.punctuation if c not in "'\""))
470
  quote = quote.rstrip()
 
1
  ## Basically Deprecated, use Kijiku instead. Currently only maintained for backwards compatibility.
2
  ##---------------------------------------
3
+ ##---------------------------------------
4
  ## built-in libraries
5
  import string
6
  import time
 
8
  import base64
9
  import time
10
 
11
+ ## third-party libraries
12
+ from easytl import EasyTL
13
+
14
  ## custom modules
 
15
  from modules.common.toolkit import Toolkit
16
  from modules.common.file_ensurer import FileEnsurer
17
  from modules.common.logger import Logger
 
108
  with open(FileEnsurer.deepl_api_key_path, 'r', encoding='utf-8') as file:
109
  api_key = base64.b64decode((file.read()).encode('utf-8')).decode('utf-8')
110
 
111
+ EasyTL.set_api_key("deepl", api_key)
112
+ is_valid, e = EasyTL.test_api_key_validity("deepl")
113
+
114
+ assert is_valid == True, e
115
 
116
  Logger.log_action("Used saved api key in " + FileEnsurer.deepl_api_key_path, output=True)
117
 
 
123
  ## if valid save the api key
124
  try:
125
 
126
+ EasyTL.set_api_key("deepl", api_key)
127
+ is_valid, e = EasyTL.test_api_key_validity("deepl")
128
+
129
+ assert is_valid, e
130
 
131
  time.sleep(.1)
132
 
 
143
 
144
  Toolkit.pause_console()
145
 
146
+ raise e # type: ignore
147
 
148
  ## other error, alert user and raise it
149
  except Exception as e:
 
459
  single_quote_active = True
460
 
461
  try:
462
+ results = EasyTL.deepl_translate(text=Kaiseki.sentence_parts[i], source_lang= "JA", target_lang="EN-US")
463
+
464
+ assert isinstance(results, str), "ValueError: " + str(results)
465
 
466
  translated_part = results.rstrip(''.join(c for c in string.punctuation if c not in "'\""))
467
  translated_part = translated_part.rstrip()
 
473
 
474
  ## translates the quote and re-adds it back to the sentence part
475
  if(single_quote_active == True):
476
+ results = EasyTL.deepl_translate(text=Kaiseki.sentence_parts[i], source_lang= "JA", target_lang="EN-US")
477
+
478
+ assert isinstance(results, str), "ValueError: " + str(results)
479
 
480
  quote = quote.rstrip(''.join(c for c in string.punctuation if c not in "'\""))
481
  quote = quote.rstrip()
models/kijiku.py CHANGED
@@ -9,8 +9,8 @@ import os
9
 
10
  ## third party modules
11
  from kairyou import KatakanaUtil
 
12
 
13
- import tiktoken
14
  import backoff
15
 
16
  ## custom modules
@@ -22,11 +22,6 @@ from modules.common.toolkit import Toolkit
22
  from modules.common.exceptions import AuthenticationError, MaxBatchDurationExceededException, AuthenticationError, InternalServerError, RateLimitError, APITimeoutError, GoogleAuthError
23
  from modules.common.decorators import permission_error_decorator
24
 
25
- from custom_classes.messages import SystemTranslationMessage, ModelTranslationMessage, Message
26
-
27
- from translation_services.openai_service import OpenAIService
28
- from translation_services.gemini_service import GeminiService
29
-
30
  ##-------------------start-of-Kijiku--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
31
 
32
  class Kijiku:
@@ -48,7 +43,7 @@ class Kijiku:
48
 
49
  ## the messages that will be sent to the api, contains a system message and a model message, system message is the instructions,
50
  ## model message is the text that will be translated
51
- openai_translation_batches:typing.List[Message] = []
52
 
53
  ## meanwhile for gemini, we just need to send the prompt and the text to be translated concatenated together
54
  gemini_translation_batches:typing.List[str] = []
@@ -74,6 +69,8 @@ class Kijiku:
74
  batch_retry_timeout:float
75
  num_concurrent_batches:int
76
 
 
 
77
  ##-------------------start-of-get_max_batch_duration()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
78
 
79
  @staticmethod
@@ -196,10 +193,10 @@ class Kijiku:
196
  Toolkit.clear_console()
197
 
198
  if(Kijiku.LLM_TYPE == "openai"):
199
- await Kijiku.init_api_key("OpenAI", FileEnsurer.openai_api_key_path, OpenAIService.set_api_key, OpenAIService.test_api_key_validity)
200
 
201
  else:
202
- await Kijiku.init_api_key("Gemini", FileEnsurer.gemini_api_key_path, GeminiService.set_api_key, GeminiService.test_api_key_validity)
203
 
204
  ## try to load the kijiku rules
205
  try:
@@ -232,17 +229,14 @@ class Kijiku:
232
 
233
  """
234
 
235
- if(service != "OpenAI"):
236
- GeminiService.redefine_client()
237
-
238
  ## get saved API key if exists
239
  try:
240
  with open(api_key_path, 'r', encoding='utf-8') as file:
241
  api_key = base64.b64decode((file.read()).encode('utf-8')).decode('utf-8')
242
 
243
- api_key_setter(api_key)
244
 
245
- is_valid, e = await api_key_tester()
246
 
247
  ## if not valid, raise the exception that caused the test to fail
248
  if(not is_valid and e is not None):
@@ -263,9 +257,9 @@ class Kijiku:
263
  ## if valid save the API key
264
  try:
265
 
266
- api_key_setter(api_key)
267
 
268
- is_valid, e = await api_key_tester()
269
 
270
  if(not is_valid and e is not None):
271
  raise e
@@ -365,14 +359,14 @@ class Kijiku:
365
  if(os.path.exists(FileEnsurer.openai_api_key_path)):
366
 
367
  os.remove(FileEnsurer.openai_api_key_path)
368
- await Kijiku.init_api_key("OpenAI", FileEnsurer.openai_api_key_path, OpenAIService.set_api_key, OpenAIService.test_api_key_validity)
369
 
370
  else:
371
 
372
  if(os.path.exists(FileEnsurer.gemini_api_key_path)):
373
 
374
  os.remove(FileEnsurer.gemini_api_key_path)
375
- await Kijiku.init_api_key("Gemini", FileEnsurer.gemini_api_key_path, GeminiService.set_api_key, GeminiService.test_api_key_validity)
376
 
377
  Toolkit.clear_console()
378
 
@@ -409,41 +403,34 @@ class Kijiku:
409
 
410
  Kijiku._semaphore = asyncio.Semaphore(Kijiku.num_concurrent_batches)
411
 
412
- OpenAIService.model = JsonHandler.current_kijiku_rules["openai settings"]["openai_model"]
413
- OpenAIService.system_message = JsonHandler.current_kijiku_rules["openai settings"]["openai_system_message"]
414
- OpenAIService.temperature = float(JsonHandler.current_kijiku_rules["openai settings"]["openai_temperature"])
415
- OpenAIService.top_p = float(JsonHandler.current_kijiku_rules["openai settings"]["openai_top_p"])
416
- OpenAIService.n = int(JsonHandler.current_kijiku_rules["openai settings"]["openai_n"])
417
- OpenAIService.stream = bool(JsonHandler.current_kijiku_rules["openai settings"]["openai_stream"])
418
- OpenAIService.stop = JsonHandler.current_kijiku_rules["openai settings"]["openai_stop"]
419
- OpenAIService.logit_bias = JsonHandler.current_kijiku_rules["openai settings"]["openai_logit_bias"]
420
- OpenAIService.max_tokens = JsonHandler.current_kijiku_rules["openai settings"]["openai_max_tokens"]
421
- OpenAIService.presence_penalty = float(JsonHandler.current_kijiku_rules["openai settings"]["openai_presence_penalty"])
422
- OpenAIService.frequency_penalty = float(JsonHandler.current_kijiku_rules["openai settings"]["openai_frequency_penalty"])
423
-
424
- GeminiService.model = JsonHandler.current_kijiku_rules["gemini settings"]["gemini_model"]
425
- GeminiService.prompt = JsonHandler.current_kijiku_rules["gemini settings"]["gemini_prompt"]
426
- GeminiService.temperature = float(JsonHandler.current_kijiku_rules["gemini settings"]["gemini_temperature"])
427
- GeminiService.top_p = JsonHandler.current_kijiku_rules["gemini settings"]["gemini_top_p"]
428
- GeminiService.top_k = JsonHandler.current_kijiku_rules["gemini settings"]["gemini_top_k"]
429
- GeminiService.candidate_count = JsonHandler.current_kijiku_rules["gemini settings"]["gemini_candidate_count"]
430
- GeminiService.stream = bool(JsonHandler.current_kijiku_rules["gemini settings"]["gemini_stream"])
431
- GeminiService.stop_sequences = JsonHandler.current_kijiku_rules["gemini settings"]["gemini_stop_sequences"]
432
- GeminiService.max_output_tokens = JsonHandler.current_kijiku_rules["gemini settings"]["gemini_max_output_tokens"]
433
 
434
- if(Kijiku.LLM_TYPE == "openai"):
435
 
436
- ## set the decorator to use
437
- decorator_to_use = backoff.on_exception(backoff.expo, max_time=lambda: Kijiku.get_max_batch_duration(), exception=(AuthenticationError, InternalServerError, RateLimitError, APITimeoutError), on_backoff=lambda details: Kijiku.log_retry(details), on_giveup=lambda details: Kijiku.log_failure(details), raise_on_giveup=False)
438
-
439
- OpenAIService.set_decorator(decorator_to_use)
440
 
441
  else:
442
-
443
- decorator_to_use = backoff.on_exception(backoff.expo, max_time=lambda: Kijiku.get_max_batch_duration(), exception=(Exception), on_backoff=lambda details: Kijiku.log_retry(details), on_giveup=lambda details: Kijiku.log_failure(details), raise_on_giveup=False)
444
-
445
- GeminiService.redefine_client()
446
- GeminiService.set_decorator(decorator_to_use)
447
 
448
  Toolkit.clear_console()
449
 
@@ -453,7 +440,7 @@ class Kijiku:
453
 
454
  Kijiku.build_translation_batches()
455
 
456
- model = OpenAIService.model if Kijiku.LLM_TYPE == "openai" else GeminiService.model
457
 
458
  await Kijiku.handle_cost_estimate_prompt(model, omit_prompt=is_webgui)
459
 
@@ -519,7 +506,14 @@ class Kijiku:
519
  translation_batches = Kijiku.openai_translation_batches if Kijiku.LLM_TYPE == "openai" else Kijiku.gemini_translation_batches
520
 
521
  for i in range(0, len(translation_batches), 2):
522
- async_requests.append(Kijiku.handle_translation(model, i, len(translation_batches), translation_batches[i], translation_batches[i+1]))
 
 
 
 
 
 
 
523
 
524
  return async_requests
525
 
@@ -601,16 +595,16 @@ class Kijiku:
601
  if(Kijiku.LLM_TYPE == 'openai'):
602
 
603
  if(Kijiku.prompt_assembly_mode == 1):
604
- system_msg = SystemTranslationMessage(content=str(OpenAIService.system_message))
605
  else:
606
- system_msg = ModelTranslationMessage(content=str(OpenAIService.system_message))
607
 
608
  Kijiku.openai_translation_batches.append(system_msg)
609
  model_msg = ModelTranslationMessage(content=batch)
610
  Kijiku.openai_translation_batches.append(model_msg)
611
 
612
  else:
613
- Kijiku.gemini_translation_batches.append(GeminiService.prompt)
614
  Kijiku.gemini_translation_batches.append(batch)
615
 
616
  Logger.log_barrier()
@@ -630,177 +624,6 @@ class Kijiku:
630
 
631
  Logger.log_action(message)
632
 
633
- ##-------------------start-of-estimate_cost()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
634
-
635
- @staticmethod
636
- def estimate_cost(model:str, price_case:int | None = None) -> typing.Tuple[int, float, str]:
637
-
638
- """
639
-
640
- Attempts to estimate cost.
641
-
642
- Parameters:
643
- model (string) : the model used to translate the text.
644
- price_case (int) : the price case used to calculate the cost.
645
-
646
- Returns:
647
- num_tokens (int) : the number of tokens used.
648
- min_cost (float) : the minimum cost of translation.
649
- model (string) : the model used to translate the text.
650
-
651
- """
652
-
653
- MODEL_COSTS = {
654
- "gpt-3.5-turbo": {"price_case": 2, "input_cost": 0.0010, "output_cost": 0.0020},
655
- "gpt-4": {"price_case": 4, "input_cost": 0.01, "output_cost": 0.03},
656
- "gpt-4-turbo-preview": {"price_case": 4, "input_cost": 0.01, "output_cost": 0.03},
657
- "gpt-3.5-turbo-0613": {"price_case": 1, "input_cost": 0.0015, "output_cost": 0.0020},
658
- "gpt-3.5-turbo-0301": {"price_case": 1, "input_cost": 0.0015, "output_cost": 0.0020},
659
- "gpt-3.5-turbo-1106": {"price_case": 2, "input_cost": 0.0010, "output_cost": 0.0020},
660
- "gpt-3.5-turbo-0125": {"price_case": 7, "input_cost": 0.0005, "output_cost": 0.0015},
661
- "gpt-3.5-turbo-16k-0613": {"price_case": 3, "input_cost": 0.0030, "output_cost": 0.0040},
662
- "gpt-4-1106-preview": {"price_case": 4, "input_cost": 0.01, "output_cost": 0.03},
663
- "gpt-4-0125-preview": {"price_case": 4, "input_cost": 0.01, "output_cost": 0.03},
664
- "gpt-4-0314": {"price_case": 5, "input_cost": 0.03, "output_cost": 0.06},
665
- "gpt-4-0613": {"price_case": 5, "input_cost": 0.03, "output_cost": 0.06},
666
- "gpt-4-32k-0314": {"price_case": 6, "input_cost": 0.06, "output_cost": 0.012},
667
- "gpt-4-32k-0613": {"price_case": 6, "input_cost": 0.06, "output_cost": 0.012},
668
- "gemini-1.0-pro-001": {"price_case": 8, "input_cost": 0.0, "output_cost": 0.0},
669
- "gemini-1.0-pro-vision-001": {"price_case": 8, "input_cost": 0.0, "output_cost": 0.0},
670
- "gemini-1.0-pro": {"price_case": 8, "input_cost": 0.0, "output_cost": 0.0},
671
- "gemini-1.0-pro-vision": {"price_case": 8, "input_cost": 0.0, "output_cost": 0.0},
672
- "gemini-1.0-pro-latest": {"price_case": 8, "input_cost": 0.0, "output_cost": 0.0},
673
- "gemini-1.0-pro-vision-latest": {"price_case": 8, "input_cost": 0.0, "output_cost": 0.0},
674
- "gemini-1.5-pro-latest": {"price_case": 8, "input_cost": 0.0, "output_cost": 0.0},
675
- "gemini-1.0-ultra-latest": {"price_case": 8, "input_cost": 0.0, "output_cost": 0.0},
676
- "gemini-pro": {"price_case": 8, "input_cost": 0.0, "output_cost": 0.0},
677
- "gemini-pro-vision": {"price_case": 8, "input_cost": 0.0, "output_cost": 0.0},
678
- "gemini-ultra": {"price_case": 8, "input_cost": 0.0, "output_cost": 0.0}
679
- }
680
-
681
- assert model in FileEnsurer.ALLOWED_OPENAI_MODELS or model in FileEnsurer.ALLOWED_GEMINI_MODELS, f"""Kudasai does not support : {model}"""
682
-
683
- ## default models are first, then the rest are sorted by price case
684
- if(price_case is None):
685
-
686
- if(model == "gpt-3.5-turbo"):
687
- print("Warning: gpt-3.5-turbo may change over time. Returning num tokens assuming gpt-3.5-turbo-1106 as it is the most recent version of gpt-3.5-turbo.")
688
- return Kijiku.estimate_cost("gpt-3.5-turbo-1106", price_case=2)
689
-
690
- elif(model == "gpt-4"):
691
- print("Warning: gpt-4 may change over time. Returning num tokens assuming gpt-4-1106-preview as it is the most recent version of gpt-4.")
692
- return Kijiku.estimate_cost("gpt-4-1106-preview", price_case=4)
693
-
694
- elif(model == "gpt-4-turbo-preview"):
695
- print("Warning: gpt-4-turbo-preview may change over time. Returning num tokens assuming gpt-4-0125-preview as it is the most recent version of gpt-4-turbo-preview.")
696
- return Kijiku.estimate_cost("gpt-4-0125-preview", price_case=4)
697
-
698
- elif(model == "gpt-3.5-turbo-0613"):
699
- print("Warning: gpt-3.5-turbo-0613 is considered depreciated by OpenAI as of November 6, 2023 and could be shutdown as early as June 13, 2024. Consider switching to gpt-3.5-turbo-1106.")
700
- return Kijiku.estimate_cost(model, price_case=1)
701
-
702
- elif(model == "gpt-3.5-turbo-0301"):
703
- print("Warning: gpt-3.5-turbo-0301 is considered depreciated by OpenAI as of June 13, 2023 and could be shutdown as early as June 13, 2024. Consider switching to gpt-3.5-turbo-1106 unless you are specifically trying to break the filter.")
704
- return Kijiku.estimate_cost(model, price_case=1)
705
-
706
- elif(model == "gpt-3.5-turbo-1106"):
707
- return Kijiku.estimate_cost(model, price_case=2)
708
-
709
- elif(model == "gpt-3.5-turbo-0125"):
710
- return Kijiku.estimate_cost(model, price_case=7)
711
-
712
- elif(model == "gpt-3.5-turbo-16k-0613"):
713
- print("Warning: gpt-3.5-turbo-16k-0613 is considered depreciated by OpenAI as of November 6, 2023 and could be shutdown as early as June 13, 2024. Consider switching to gpt-3.5-turbo-1106.")
714
- return Kijiku.estimate_cost(model, price_case=3)
715
-
716
- elif(model == "gpt-4-1106-preview"):
717
- return Kijiku.estimate_cost(model, price_case=4)
718
-
719
- elif(model == "gpt-4-0125-preview"):
720
- return Kijiku.estimate_cost(model, price_case=4)
721
-
722
- elif(model == "gpt-4-0314"):
723
- print("Warning: gpt-4-0314 is considered depreciated by OpenAI as of June 13, 2023 and could be shutdown as early as June 13, 2024. Consider switching to gpt-4-0613.")
724
- return Kijiku.estimate_cost(model, price_case=5)
725
-
726
- elif(model == "gpt-4-0613"):
727
- return Kijiku.estimate_cost(model, price_case=5)
728
-
729
- elif(model == "gpt-4-32k-0314"):
730
- print("Warning: gpt-4-32k-0314 is considered depreciated by OpenAI as of June 13, 2023 and could be shutdown as early as June 13, 2024. Consider switching to gpt-4-32k-0613.")
731
- return Kijiku.estimate_cost(model, price_case=6)
732
-
733
- elif(model == "gpt-4-32k-0613"):
734
- return Kijiku.estimate_cost(model, price_case=6)
735
-
736
- elif(model == "gemini-pro"):
737
- print(f"Warning: gemini-pro may change over time. Returning num tokens assuming gemini-1.0-pro-001 as it is the most recent version of gemini-1.0-pro.")
738
- return Kijiku.estimate_cost("gemini-1.0-pro-001", price_case=8)
739
-
740
- elif(model == "gemini-pro-vision"):
741
- print("Warning: gemini-pro-vision may change over time. Returning num tokens assuming gemini-1.0-pro-vision-001 as it is the most recent version of gemini-1.0-pro-vision.")
742
- return Kijiku.estimate_cost("gemini-1.0-pro-vision-001", price_case=8)
743
-
744
- elif(model == "gemini-ultra"):
745
- return Kijiku.estimate_cost(model, price_case=8)
746
-
747
- elif(model == "gemini-1.0-pro"):
748
- print(f"Warning: gemini-1.0-pro may change over time. Returning num tokens assuming gemini-1.0-pro-001 as it is the most recent version of gemini-1.0-pro.")
749
- return Kijiku.estimate_cost(model, price_case=8)
750
-
751
- elif(model == "gemini-1.0-pro-vision"):
752
- print("Warning: gemini-1.0-pro-vision may change over time. Returning num tokens assuming gemini-1.0-pro-vision-001 as it is the most recent version of gemini-1.0-pro-vision.")
753
- return Kijiku.estimate_cost(model, price_case=8)
754
-
755
- elif(model == "gemini-1.0-pro-latest"):
756
- print(f"Warning: gemini-1.0-pro-latest may change over time. Returning num tokens assuming gemini-1.0-pro-001 as it is the most recent version of gemini-1.0-pro.")
757
- return Kijiku.estimate_cost("gemini-1.0-pro-001", price_case=8)
758
-
759
- elif(model == "gemini-1.0-pro-vision-latest"):
760
- print("Warning: gemini-1.0-pro-vision-latest may change over time. Returning num tokens assuming gemini-1.0-pro-vision-001 as it is the most recent version of gemini-1.0-pro-vision.")
761
- return Kijiku.estimate_cost("gemini-1.0-pro-vision-001", price_case=8)
762
-
763
- elif(model == "gemini-1.5-pro-latest"):
764
- return Kijiku.estimate_cost(model, price_case=8)
765
-
766
- elif(model == "gemini-1.0-ultra-latest"):
767
- return Kijiku.estimate_cost(model, price_case=8)
768
-
769
- elif(model == "gemini-1.0-pro-001"):
770
- return Kijiku.estimate_cost(model, price_case=8)
771
-
772
- elif(model == "gemini-1.0-pro-vision-001"):
773
- return Kijiku.estimate_cost(model, price_case=8)
774
-
775
- else:
776
-
777
- cost_details = MODEL_COSTS.get(model)
778
-
779
- if(not cost_details):
780
- raise ValueError(f"Cost details not found for model: {model}.")
781
-
782
- ## break down the text into a string than into tokens
783
- text = ''.join(Kijiku.text_to_translate)
784
-
785
- if(Kijiku.LLM_TYPE == "openai"):
786
- encoding = tiktoken.encoding_for_model(model)
787
- num_tokens = len(encoding.encode(text))
788
-
789
- else:
790
- num_tokens = GeminiService.count_tokens(text)
791
-
792
- input_cost = cost_details["input_cost"]
793
- output_cost = cost_details["output_cost"]
794
-
795
- min_cost_for_input = (num_tokens / 1000) * input_cost
796
- min_cost_for_output = (num_tokens / 1000) * output_cost
797
- min_cost = min_cost_for_input + min_cost_for_output
798
-
799
- return num_tokens, min_cost, model
800
-
801
- ## type checker doesn't like the chance of None being returned, so we raise an exception here if it gets to this point
802
- raise Exception("An unknown error occurred while calculating the minimum cost of translation.")
803
-
804
  ##-------------------start-of-handle_cost_estimate_prompt()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
805
 
806
  @staticmethod
@@ -819,17 +642,19 @@ class Kijiku:
819
 
820
  """
821
 
 
 
822
  ## get cost estimate and confirm
823
- num_tokens, min_cost, model = Kijiku.estimate_cost(model)
824
 
825
- print("\nNote that the cost estimate is not always accurate, and may be higher than the actual cost. However cost calculation now includes output tokens.\n")
826
 
827
  Logger.log_barrier()
828
  Logger.log_action("Calculating cost")
829
  Logger.log_barrier()
830
 
831
  if(Kijiku.LLM_TYPE == "gemini"):
832
- Logger.log_action(f"As of Kudasai {Toolkit.CURRENT_VERSION}, Gemini Pro 1.0 is free to use under 60 requests per minute, Gemini Pro 1.5 is free to use under 2 requests per minute.\nIt is up to you to set these in the settings json.\nIt is currently unknown whether the ultra model parameter is connecting to the actual ultra model and not a pro one. As it works, but does not appear on any documentation.\n", output=True, omit_timestamp=True)
833
 
834
  Logger.log_action("Estimated number of tokens : " + str(num_tokens), output=True, omit_timestamp=True)
835
  Logger.log_action("Estimated minimum cost : " + str(min_cost) + " USD", output=True, omit_timestamp=True)
@@ -849,7 +674,7 @@ class Kijiku:
849
  ##-------------------start-of-handle_translation()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
850
 
851
  @staticmethod
852
- async def handle_translation(model:str, index:int, length:int, translation_instructions:typing.Union[str, Message], translation_prompt:typing.Union[str, Message]) -> tuple[int, typing.Union[str, Message], str]:
853
 
854
  """
855
 
@@ -885,19 +710,39 @@ class Kijiku:
885
  try:
886
 
887
  if(Kijiku.LLM_TYPE == "openai"):
888
- translated_message = await OpenAIService.translate_message(translation_instructions, translation_prompt) # type: ignore
 
 
 
 
 
 
 
 
 
889
 
890
  else:
891
- translated_message = await GeminiService.translate_message(translation_instructions, translation_prompt) # type: ignore
 
 
 
 
 
 
 
 
 
 
892
 
893
  ## will only occur if the max_batch_duration is exceeded, so we just return the untranslated text
894
  except MaxBatchDurationExceededException:
895
- translated_message = translation_prompt.content if isinstance(translation_prompt, Message) else translation_prompt
896
  Logger.log_error(f"Batch {message_number} of {length//2} was not translated due to exceeding the max request duration, returning the untranslated text...", output=True)
897
  break
898
 
899
  ## do not even bother if not a gpt 4 model, because gpt-3 seems unable to format properly
900
- if("gpt-4" not in model):
 
901
  break
902
 
903
  if(await Kijiku.check_if_translation_is_good(translated_message, translation_prompt)):
@@ -913,12 +758,18 @@ class Kijiku:
913
  Logger.log_error(f"Batch {message_number} of {length//2} was malformed, retrying...", output=True)
914
  Kijiku.num_occurred_malformed_batches += 1
915
 
 
 
 
 
 
 
916
  return index, translation_prompt, translated_message
917
 
918
  ##-------------------start-of-check_if_translation_is_good()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
919
 
920
  @staticmethod
921
- async def check_if_translation_is_good(translated_message:str, translation_prompt:typing.Union[Message, str]) -> bool:
922
 
923
  """
924
 
@@ -938,6 +789,9 @@ class Kijiku:
938
 
939
  else:
940
  prompt = translation_prompt
 
 
 
941
 
942
  is_valid = False
943
 
 
9
 
10
  ## third party modules
11
  from kairyou import KatakanaUtil
12
+ from easytl import EasyTL, Message, SystemTranslationMessage, ModelTranslationMessage
13
 
 
14
  import backoff
15
 
16
  ## custom modules
 
22
  from modules.common.exceptions import AuthenticationError, MaxBatchDurationExceededException, AuthenticationError, InternalServerError, RateLimitError, APITimeoutError, GoogleAuthError
23
  from modules.common.decorators import permission_error_decorator
24
 
 
 
 
 
 
25
  ##-------------------start-of-Kijiku--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
26
 
27
  class Kijiku:
 
43
 
44
  ## the messages that will be sent to the api, contains a system message and a model message, system message is the instructions,
45
  ## model message is the text that will be translated
46
+ openai_translation_batches:typing.List[SystemTranslationMessage | ModelTranslationMessage] = []
47
 
48
  ## meanwhile for gemini, we just need to send the prompt and the text to be translated concatenated together
49
  gemini_translation_batches:typing.List[str] = []
 
69
  batch_retry_timeout:float
70
  num_concurrent_batches:int
71
 
72
+ decorator_to_use:typing.Callable
73
+
74
  ##-------------------start-of-get_max_batch_duration()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
75
 
76
  @staticmethod
 
193
  Toolkit.clear_console()
194
 
195
  if(Kijiku.LLM_TYPE == "openai"):
196
+ await Kijiku.init_api_key("OpenAI", FileEnsurer.openai_api_key_path, EasyTL.set_api_key, EasyTL.test_api_key_validity)
197
 
198
  else:
199
+ await Kijiku.init_api_key("Gemini", FileEnsurer.gemini_api_key_path, EasyTL.set_api_key, EasyTL.test_api_key_validity)
200
 
201
  ## try to load the kijiku rules
202
  try:
 
229
 
230
  """
231
 
 
 
 
232
  ## get saved API key if exists
233
  try:
234
  with open(api_key_path, 'r', encoding='utf-8') as file:
235
  api_key = base64.b64decode((file.read()).encode('utf-8')).decode('utf-8')
236
 
237
+ api_key_setter(service.lower(), api_key)
238
 
239
+ is_valid, e = api_key_tester(service.lower())
240
 
241
  ## if not valid, raise the exception that caused the test to fail
242
  if(not is_valid and e is not None):
 
257
  ## if valid save the API key
258
  try:
259
 
260
+ api_key_setter(service.lower(), api_key)
261
 
262
+ is_valid, e = api_key_tester(service.lower())
263
 
264
  if(not is_valid and e is not None):
265
  raise e
 
359
  if(os.path.exists(FileEnsurer.openai_api_key_path)):
360
 
361
  os.remove(FileEnsurer.openai_api_key_path)
362
+ await Kijiku.init_api_key("OpenAI", FileEnsurer.openai_api_key_path, EasyTL.set_api_key, EasyTL.test_api_key_validity)
363
 
364
  else:
365
 
366
  if(os.path.exists(FileEnsurer.gemini_api_key_path)):
367
 
368
  os.remove(FileEnsurer.gemini_api_key_path)
369
+ await Kijiku.init_api_key("Gemini", FileEnsurer.gemini_api_key_path, EasyTL.set_api_key, EasyTL.test_api_key_validity)
370
 
371
  Toolkit.clear_console()
372
 
 
403
 
404
  Kijiku._semaphore = asyncio.Semaphore(Kijiku.num_concurrent_batches)
405
 
406
+ Kijiku.openai_model = JsonHandler.current_kijiku_rules["openai settings"]["openai_model"]
407
+ Kijiku.openai_system_message = JsonHandler.current_kijiku_rules["openai settings"]["openai_system_message"]
408
+ Kijiku.openai_temperature = float(JsonHandler.current_kijiku_rules["openai settings"]["openai_temperature"])
409
+ Kijiku.openai_top_p = float(JsonHandler.current_kijiku_rules["openai settings"]["openai_top_p"])
410
+ Kijiku.openai_n = int(JsonHandler.current_kijiku_rules["openai settings"]["openai_n"])
411
+ Kijiku.openai_stream = bool(JsonHandler.current_kijiku_rules["openai settings"]["openai_stream"])
412
+ Kijiku.openai_stop = JsonHandler.current_kijiku_rules["openai settings"]["openai_stop"]
413
+ Kijiku.openai_logit_bias = JsonHandler.current_kijiku_rules["openai settings"]["openai_logit_bias"]
414
+ Kijiku.openai_max_tokens = JsonHandler.current_kijiku_rules["openai settings"]["openai_max_tokens"]
415
+ Kijiku.openai_presence_penalty = float(JsonHandler.current_kijiku_rules["openai settings"]["openai_presence_penalty"])
416
+ Kijiku.openai_frequency_penalty = float(JsonHandler.current_kijiku_rules["openai settings"]["openai_frequency_penalty"])
417
+
418
+ Kijiku.gemini_model = JsonHandler.current_kijiku_rules["gemini settings"]["gemini_model"]
419
+ Kijiku.gemini_prompt = JsonHandler.current_kijiku_rules["gemini settings"]["gemini_prompt"]
420
+ Kijiku.gemini_temperature = float(JsonHandler.current_kijiku_rules["gemini settings"]["gemini_temperature"])
421
+ Kijiku.gemini_top_p = JsonHandler.current_kijiku_rules["gemini settings"]["gemini_top_p"]
422
+ Kijiku.gemini_top_k = JsonHandler.current_kijiku_rules["gemini settings"]["gemini_top_k"]
423
+ Kijiku.gemini_candidate_count = JsonHandler.current_kijiku_rules["gemini settings"]["gemini_candidate_count"]
424
+ Kijiku.gemini_stream = bool(JsonHandler.current_kijiku_rules["gemini settings"]["gemini_stream"])
425
+ Kijiku.gemini_stop_sequences = JsonHandler.current_kijiku_rules["gemini settings"]["gemini_stop_sequences"]
426
+ Kijiku.gemini_max_output_tokens = JsonHandler.current_kijiku_rules["gemini settings"]["gemini_max_output_tokens"]
427
 
 
428
 
429
+ if(Kijiku.LLM_TYPE == "openai"):
430
+ Kijiku.decorator_to_use = backoff.on_exception(backoff.expo, max_time=lambda: Kijiku.get_max_batch_duration(), exception=(AuthenticationError, InternalServerError, RateLimitError, APITimeoutError), on_backoff=lambda details: Kijiku.log_retry(details), on_giveup=lambda details: Kijiku.log_failure(details), raise_on_giveup=False)
 
 
431
 
432
  else:
433
+ Kijiku.decorator_to_use = backoff.on_exception(backoff.expo, max_time=lambda: Kijiku.get_max_batch_duration(), exception=(Exception), on_backoff=lambda details: Kijiku.log_retry(details), on_giveup=lambda details: Kijiku.log_failure(details), raise_on_giveup=False)
 
 
 
 
434
 
435
  Toolkit.clear_console()
436
 
 
440
 
441
  Kijiku.build_translation_batches()
442
 
443
+ model = JsonHandler.current_kijiku_rules["openai settings"]["openai_model"] if Kijiku.LLM_TYPE == "openai" else JsonHandler.current_kijiku_rules["gemini settings"]["gemini_model"]
444
 
445
  await Kijiku.handle_cost_estimate_prompt(model, omit_prompt=is_webgui)
446
 
 
506
  translation_batches = Kijiku.openai_translation_batches if Kijiku.LLM_TYPE == "openai" else Kijiku.gemini_translation_batches
507
 
508
  for i in range(0, len(translation_batches), 2):
509
+
510
+ instructions = translation_batches[i]
511
+ prompt = translation_batches[i+1]
512
+
513
+ assert isinstance(instructions, SystemTranslationMessage) or isinstance(instructions, str)
514
+ assert isinstance(prompt, ModelTranslationMessage) or isinstance(prompt, str)
515
+
516
+ async_requests.append(Kijiku.handle_translation(model, i, len(translation_batches), instructions, prompt))
517
 
518
  return async_requests
519
 
 
595
  if(Kijiku.LLM_TYPE == 'openai'):
596
 
597
  if(Kijiku.prompt_assembly_mode == 1):
598
+ system_msg = SystemTranslationMessage(content=str(Kijiku.openai_system_message))
599
  else:
600
+ system_msg = SystemTranslationMessage(content=str(Kijiku.openai_system_message))
601
 
602
  Kijiku.openai_translation_batches.append(system_msg)
603
  model_msg = ModelTranslationMessage(content=batch)
604
  Kijiku.openai_translation_batches.append(model_msg)
605
 
606
  else:
607
+ Kijiku.gemini_translation_batches.append(Kijiku.gemini_prompt)
608
  Kijiku.gemini_translation_batches.append(batch)
609
 
610
  Logger.log_barrier()
 
624
 
625
  Logger.log_action(message)
626
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
627
  ##-------------------start-of-handle_cost_estimate_prompt()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
628
 
629
  @staticmethod
 
642
 
643
  """
644
 
645
+ translation_instructions = Kijiku.openai_system_message if Kijiku.LLM_TYPE == "openai" else Kijiku.gemini_prompt
646
+
647
  ## get cost estimate and confirm
648
+ num_tokens, min_cost, model = EasyTL.calculate_cost(text=Kijiku.text_to_translate, service=Kijiku.LLM_TYPE, model=model,translation_instructions=translation_instructions)
649
 
650
+ print("Note that the cost estimate is not always accurate, and may be higher than the actual cost. However cost calculation now includes output tokens.\n")
651
 
652
  Logger.log_barrier()
653
  Logger.log_action("Calculating cost")
654
  Logger.log_barrier()
655
 
656
  if(Kijiku.LLM_TYPE == "gemini"):
657
+ Logger.log_action(f"As of Kudasai {Toolkit.CURRENT_VERSION}, Gemini Pro 1.0 is free to use under 15 requests per minute, Gemini Pro 1.5 is free to use under 2 requests per minute. Requests correspond to number_of_current_batches in kijiku_settings.", output=True, omit_timestamp=True)
658
 
659
  Logger.log_action("Estimated number of tokens : " + str(num_tokens), output=True, omit_timestamp=True)
660
  Logger.log_action("Estimated minimum cost : " + str(min_cost) + " USD", output=True, omit_timestamp=True)
 
674
  ##-------------------start-of-handle_translation()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
675
 
676
  @staticmethod
677
+ async def handle_translation(model:str, index:int, length:int, translation_instructions:typing.Union[str, SystemTranslationMessage], translation_prompt:typing.Union[str, ModelTranslationMessage]) -> tuple[int, str, str]:
678
 
679
  """
680
 
 
710
  try:
711
 
712
  if(Kijiku.LLM_TYPE == "openai"):
713
+ translated_message = await EasyTL.openai_translate_async(text=translation_prompt,
714
+ decorator=Kijiku.decorator_to_use,
715
+ translation_instructions=translation_instructions,
716
+ model=model,
717
+ temperature=Kijiku.openai_temperature,
718
+ top_p=Kijiku.openai_top_p,
719
+ stop=Kijiku.openai_stop,
720
+ max_tokens=Kijiku.openai_max_tokens,
721
+ presence_penalty=Kijiku.openai_presence_penalty,
722
+ frequency_penalty=Kijiku.openai_frequency_penalty)
723
 
724
  else:
725
+
726
+ assert isinstance(translation_prompt, str)
727
+
728
+ translated_message = await EasyTL.gemini_translate_async(text=translation_prompt,
729
+ decorator=Kijiku.decorator_to_use,
730
+ model=model,
731
+ temperature=Kijiku.gemini_temperature,
732
+ top_p=Kijiku.gemini_top_p,
733
+ top_k=Kijiku.gemini_top_k,
734
+ stop_sequences=Kijiku.gemini_stop_sequences,
735
+ max_output_tokens=Kijiku.gemini_max_output_tokens)
736
 
737
  ## will only occur if the max_batch_duration is exceeded, so we just return the untranslated text
738
  except MaxBatchDurationExceededException:
739
+
740
  Logger.log_error(f"Batch {message_number} of {length//2} was not translated due to exceeding the max request duration, returning the untranslated text...", output=True)
741
  break
742
 
743
  ## do not even bother if not a gpt 4 model, because gpt-3 seems unable to format properly
744
+ ## since gemini is free, we can just try again if it's malformed
745
+ if("gpt-4" not in model and Kijiku.LLM_TYPE != "gemini"):
746
  break
747
 
748
  if(await Kijiku.check_if_translation_is_good(translated_message, translation_prompt)):
 
758
  Logger.log_error(f"Batch {message_number} of {length//2} was malformed, retrying...", output=True)
759
  Kijiku.num_occurred_malformed_batches += 1
760
 
761
+ if(isinstance(translation_prompt, ModelTranslationMessage)):
762
+ translation_prompt = translation_prompt.content
763
+
764
+ if(isinstance(translated_message, typing.List)):
765
+ translated_message = ''.join(translated_message)
766
+
767
  return index, translation_prompt, translated_message
768
 
769
  ##-------------------start-of-check_if_translation_is_good()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
770
 
771
  @staticmethod
772
+ async def check_if_translation_is_good(translated_message:typing.Union[typing.List[str], str], translation_prompt:typing.Union[ModelTranslationMessage, str]) -> bool:
773
 
774
  """
775
 
 
789
 
790
  else:
791
  prompt = translation_prompt
792
+
793
+ if(isinstance(translated_message, list)):
794
+ translated_message = ''.join(translated_message)
795
 
796
  is_valid = False
797
 
modules/common/exceptions.py CHANGED
@@ -1,9 +1,8 @@
1
  ## third-party libraries
2
-
3
  ## for importing, other scripts will use from common.exceptions instead of from the third-party libraries themselves
4
- from openai import AuthenticationError, InternalServerError, RateLimitError, APITimeoutError
5
- from deepl.exceptions import AuthorizationException, QuotaExceededException
6
- from google.auth.exceptions import GoogleAuthError
7
 
8
  ##-------------------start-of-MaxBatchDurationExceededException--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
9
 
@@ -15,7 +14,16 @@ class MaxBatchDurationExceededException(Exception):
15
 
16
  """
17
 
18
- pass
 
 
 
 
 
 
 
 
 
19
 
20
  ##-------------------start-of-InvalidAPIKeyException--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
21
 
 
1
  ## third-party libraries
 
2
  ## for importing, other scripts will use from common.exceptions instead of from the third-party libraries themselves
3
+ from easytl import AuthenticationError, InternalServerError, RateLimitError, APITimeoutError
4
+ from easytl import AuthorizationException, QuotaExceededException
5
+ from easytl import GoogleAuthError
6
 
7
  ##-------------------start-of-MaxBatchDurationExceededException--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
8
 
 
14
 
15
  """
16
 
17
+ def __init__(self, message:str) -> None:
18
+
19
+ """
20
+
21
+ Parameters:
22
+ message (string) : The message to display.
23
+
24
+ """
25
+
26
+ self.message = message
27
 
28
  ##-------------------start-of-InvalidAPIKeyException--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
29
 
modules/common/file_ensurer.py CHANGED
@@ -105,39 +105,6 @@ class FileEnsurer():
105
  "gemini_max_output_tokens": None
106
  }
107
  }
108
-
109
-
110
- ALLOWED_OPENAI_MODELS = [
111
- "gpt-3.5-turbo",
112
- "gpt-4",
113
- "gpt-4-turbo-preview",
114
- "gpt-3.5-turbo-0301",
115
- "gpt-4-0314",
116
- "gpt-4-32k-0314",
117
- "gpt-3.5-turbo-0613",
118
- "gpt-3.5-turbo-0125",
119
- "gpt-3.5-turbo-16k-0613",
120
- "gpt-3.5-turbo-1106",
121
- "gpt-4-0613",
122
- "gpt-4-32k-0613",
123
- "gpt-4-1106-preview",
124
- "gpt-4-0125-preview"
125
- ]
126
-
127
- ALLOWED_GEMINI_MODELS = [
128
- "gemini-1.0-pro-001",
129
- "gemini-1.0-pro-vision-001",
130
- "gemini-1.0-pro",
131
- "gemini-1.0-pro-vision",
132
- "gemini-1.0-pro-latest",
133
- "gemini-1.0-pro-vision-latest",
134
- "gemini-1.5-pro-latest",
135
- "gemini-1.0-ultra-latest",
136
- "gemini-pro",
137
- "gemini-pro-vision",
138
- "gemini-ultra"
139
- ]
140
-
141
  INVALID_KIJIKU_RULES_PLACEHOLDER = {
142
  "INVALID JSON":
143
  {
@@ -262,6 +229,7 @@ class FileEnsurer():
262
  else:
263
  with open(thing, "w", encoding="utf-8") as file:
264
  file.truncate()
 
265
  ##--------------------start-of-standard_create_directory()------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
266
 
267
  @staticmethod
 
105
  "gemini_max_output_tokens": None
106
  }
107
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  INVALID_KIJIKU_RULES_PLACEHOLDER = {
109
  "INVALID JSON":
110
  {
 
229
  else:
230
  with open(thing, "w", encoding="utf-8") as file:
231
  file.truncate()
232
+
233
  ##--------------------start-of-standard_create_directory()------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
234
 
235
  @staticmethod
modules/common/toolkit.py CHANGED
@@ -14,7 +14,7 @@ class Toolkit():
14
 
15
  """
16
 
17
- CURRENT_VERSION = "v3.4.1"
18
 
19
  ##-------------------start-of-clear_console()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
20
 
 
14
 
15
  """
16
 
17
+ CURRENT_VERSION = "v3.4.3"
18
 
19
  ##-------------------start-of-clear_console()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
20
 
requirements.txt CHANGED
@@ -1,8 +1,5 @@
1
- deepl==1.16.1
2
- openai==1.13.3
3
  backoff==2.2.1
4
- tiktoken==0.6.0
5
  gradio==4.19.2
6
  kairyou==1.4.1
7
- google-generativeai==0.4.0
8
  ja_core_news_lg @ https://github.com/explosion/spacy-models/releases/download/ja_core_news_lg-3.7.0/ja_core_news_lg-3.7.0-py3-none-any.whl#sha256=f08eecb4d40523045c9478ce59a67564fd71edd215f32c076fa91dc1f05cc7fd
 
 
 
1
  backoff==2.2.1
 
2
  gradio==4.19.2
3
  kairyou==1.4.1
4
+ easytl==0.1.0
5
  ja_core_news_lg @ https://github.com/explosion/spacy-models/releases/download/ja_core_news_lg-3.7.0/ja_core_news_lg-3.7.0-py3-none-any.whl#sha256=f08eecb4d40523045c9478ce59a67564fd71edd215f32c076fa91dc1f05cc7fd
translation_services/deepl_service.py DELETED
@@ -1,85 +0,0 @@
1
- ## built-in libraries
2
- import typing
3
-
4
- ## third-party libraries
5
- from deepl.translator import Translator
6
-
7
- class DeepLService:
8
-
9
- api_key:str
10
- translator:Translator
11
-
12
- ##-------------------start-of-translate()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
13
-
14
- @staticmethod
15
- def translate(text:str, target_lang:str, source_lang:str) -> str:
16
-
17
- """
18
-
19
- Translates the text to the target language.
20
-
21
- Parameters:
22
- text (string) : The text to translate.
23
- target_lang (string) : The target language.
24
- source_lang (string) : The source language.
25
-
26
- Returns:
27
- translation (string) : The translated text.
28
-
29
- """
30
-
31
- try:
32
-
33
- translation = DeepLService.translator.translate_text(text, target_lang=target_lang, source_lang=source_lang)
34
-
35
- return str(translation)
36
-
37
- except Exception as e:
38
- raise e
39
-
40
- ##-------------------start-of-set_api_key()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
41
-
42
- @staticmethod
43
- def set_api_key(api_key:str) -> None:
44
-
45
- """
46
-
47
- Sets the API key for the DeepL client.
48
-
49
- Parameters:
50
- api_key (string) : The API key to set.
51
-
52
- """
53
-
54
- DeepLService.api_key = api_key
55
-
56
- ##-------------------start-of-test_api_key_validity()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
57
-
58
- @staticmethod
59
- def test_api_key_validity() -> typing.Tuple[bool, typing.Union[Exception, None]]:
60
-
61
- """
62
-
63
- Tests the validity of the API key.
64
-
65
- Returns:
66
- validity (bool) : True if the API key is valid, False if it is not.
67
- e (Exception) : The exception that was raised, if any.
68
-
69
- """
70
-
71
- validity = False
72
-
73
- try:
74
-
75
- DeepLService.translator = Translator(DeepLService.api_key)
76
-
77
- DeepLService.translator.translate_text("test", target_lang="JA")
78
-
79
- validity = True
80
-
81
- return validity, None
82
-
83
- except Exception as e:
84
-
85
- return validity, e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
translation_services/gemini_service.py DELETED
@@ -1,215 +0,0 @@
1
- ## built-in libraries
2
- import typing
3
-
4
- ## third party libraries
5
- from google.generativeai import GenerationConfig
6
- import google.generativeai as genai
7
-
8
- class GeminiService:
9
-
10
- model:str = "gemini-pro"
11
- prompt:str = ""
12
- temperature:float = 0.5
13
- top_p:float = 0.9
14
- top_k:int = 40
15
- candidate_count:int = 1
16
- stream:bool = False
17
- stop_sequences:typing.List[str] | None = None
18
- max_output_tokens:int | None = None
19
-
20
- client:genai.GenerativeModel
21
- generation_config:GenerationConfig
22
-
23
- decorator_to_use:typing.Union[typing.Callable, None] = None
24
-
25
- safety_settings = [
26
- {
27
- "category": "HARM_CATEGORY_DANGEROUS",
28
- "threshold": "BLOCK_NONE",
29
- },
30
- {
31
- "category": "HARM_CATEGORY_HARASSMENT",
32
- "threshold": "BLOCK_NONE",
33
- },
34
- {
35
- "category": "HARM_CATEGORY_HATE_SPEECH",
36
- "threshold": "BLOCK_NONE",
37
- },
38
- {
39
- "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
40
- "threshold": "BLOCK_NONE",
41
- },
42
- {
43
- "category": "HARM_CATEGORY_DANGEROUS_CONTENT",
44
- "threshold": "BLOCK_NONE",
45
- },
46
- ]
47
-
48
- ##-------------------start-of-set_api_key()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
49
-
50
- @staticmethod
51
- def set_api_key(api_key:str) -> None:
52
-
53
- """
54
-
55
- Sets the API key for the Gemini client.
56
-
57
- Parameters:
58
- api_key (string) : The API key to set.
59
-
60
- """
61
-
62
- genai.configure(api_key=api_key)
63
-
64
- ##-------------------start-of-set_decorator()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
65
-
66
- @staticmethod
67
- def set_decorator(decorator:typing.Callable) -> None:
68
-
69
- """
70
-
71
- Sets the decorator to use for the Gemini service. Should be a callable that returns a decorator.
72
-
73
- Parameters:
74
- decorator (callable) : The decorator to use.
75
-
76
- """
77
-
78
- GeminiService.decorator_to_use = decorator
79
-
80
- ##-------------------start-of-setup_client()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
81
-
82
- @staticmethod
83
- def redefine_client() -> None:
84
-
85
- """
86
-
87
- Redefines the Gemini client and generation config. This should be called before making any requests to the Gemini service, or after changing any of the service's settings.
88
-
89
- """
90
-
91
- GeminiService.client = genai.GenerativeModel(GeminiService.model)
92
- GeminiService.generation_config = GenerationConfig(candidate_count=GeminiService.candidate_count,
93
- max_output_tokens=GeminiService.max_output_tokens,
94
- stop_sequences=GeminiService.stop_sequences,
95
- temperature=GeminiService.temperature,
96
- top_p=GeminiService.top_p,
97
- top_k=GeminiService.top_k)
98
-
99
- ##-------------------start-of-count_tokens()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
100
-
101
- @staticmethod
102
- def count_tokens(prompt:str) -> int:
103
-
104
- """
105
-
106
- Counts the number of tokens in a prompt.
107
-
108
- Parameters:
109
- prompt (string) : The prompt to count the tokens of.
110
-
111
- Returns:
112
- count (int) : The number of tokens in the prompt.
113
-
114
- """
115
-
116
- return genai.GenerativeModel(GeminiService.model).count_tokens(prompt).total_tokens
117
-
118
- ##-------------------start-of-trans()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
119
-
120
- @staticmethod
121
- async def translate_message(translation_instructions:str, translation_prompt:str) -> str:
122
-
123
- """
124
-
125
- Translates a prompt.
126
-
127
- Parameters:
128
- translation_prompt (object - ModelTranslationMessage) : The prompt to translate.
129
-
130
- Returns:
131
- output (string) : The translation.
132
-
133
- """
134
-
135
- if(GeminiService.decorator_to_use is None):
136
- return await GeminiService._translate_message(translation_instructions, translation_prompt)
137
-
138
- decorated_function = GeminiService.decorator_to_use(GeminiService._translate_message)
139
- return await decorated_function(translation_instructions, translation_prompt)
140
-
141
- ##-------------------start-of-_translate_message()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
142
-
143
- @staticmethod
144
- async def _translate_message(translation_instructions:str, translation_prompt:str) -> str:
145
-
146
- """
147
-
148
- Translates a prompt.
149
-
150
- Parameters:
151
- translation_prompt (string) : The prompt to translate.
152
-
153
- Returns:
154
- output (string) a string that gpt gives to us also known as the translation.
155
-
156
- """
157
-
158
- response = await GeminiService.client.generate_content_async(
159
- contents=translation_instructions + "\n" + translation_prompt,
160
- generation_config=GeminiService.generation_config,
161
- safety_settings=GeminiService.safety_settings,
162
- stream=GeminiService.stream
163
- )
164
-
165
- return response.text
166
-
167
- ##-------------------start-of-test_api_key_validity()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
168
-
169
- @staticmethod
170
- async def test_api_key_validity() -> typing.Tuple[bool, typing.Union[Exception, None]]:
171
-
172
- """
173
-
174
- Tests the validity of the API key.
175
-
176
- Returns:
177
- validity (bool) : True if the API key is valid, False if it is not.
178
- e (Exception) : The exception that was raised, if any.
179
-
180
- """
181
-
182
- validity = False
183
-
184
- try:
185
-
186
- generation_config = GenerationConfig(candidate_count=1, max_output_tokens=1)
187
-
188
- await GeminiService.client.generate_content_async(
189
- "Respond to this prompt with 1",generation_config=generation_config
190
-
191
- )
192
-
193
- validity = True
194
-
195
- return validity, None
196
-
197
- except Exception as e:
198
-
199
- return validity, e
200
-
201
- ##-------------------start-of-get_decorator()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
202
-
203
- @staticmethod
204
- def get_decorator() -> typing.Union[typing.Callable, None]:
205
-
206
- """
207
-
208
- Returns the decorator to use for the Gemini service.
209
-
210
- Returns:
211
- decorator (callable) : The decorator to use.
212
-
213
- """
214
-
215
- return GeminiService.decorator_to_use
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
translation_services/openai_service.py DELETED
@@ -1,180 +0,0 @@
1
- ## built-in libraries
2
- import typing
3
-
4
- ## third-party libraries
5
- from openai import AsyncOpenAI
6
-
7
- ## custom modules
8
- from modules.common.exceptions import InvalidAPIKeyException
9
- from custom_classes.messages import SystemTranslationMessage, Message
10
-
11
- class OpenAIService:
12
-
13
- ## async client session
14
- client = AsyncOpenAI(max_retries=0, api_key="DummyKey")
15
-
16
- model:str
17
- system_message:typing.Optional[typing.Union[SystemTranslationMessage, str]] = None
18
- temperature:float
19
- top_p:float
20
- n:int
21
- stream:bool
22
- stop:typing.List[str] | None
23
- logit_bias:typing.Dict[str, float] | None
24
- max_tokens:int | None
25
- presence_penalty:float
26
- frequency_penalty:float
27
-
28
- decorator_to_use:typing.Union[typing.Callable, None] = None
29
-
30
- ##-------------------start-of-set_api_key()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
31
-
32
- @staticmethod
33
- def set_api_key(api_key:str) -> None:
34
-
35
- """
36
-
37
- Sets the API key for the OpenAI client.
38
-
39
- Parameters:
40
- api_key (string) : The API key to set.
41
-
42
- """
43
-
44
- OpenAIService.client.api_key = api_key
45
-
46
- ##-------------------start-of-set_decorator()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
47
-
48
- @staticmethod
49
- def set_decorator(decorator:typing.Callable) -> None:
50
-
51
- """
52
-
53
- Sets the decorator to use for the OpenAI service. Should be a callable that returns a decorator.
54
-
55
- Parameters:
56
- decorator (callable) : The decorator to use.
57
-
58
- """
59
-
60
- OpenAIService.decorator_to_use = decorator
61
-
62
- ##-------------------start-of-trans()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
63
-
64
- @staticmethod
65
- async def translate_message(translation_instructions:Message, translation_prompt:Message) -> str:
66
-
67
- """
68
-
69
- Translates a system and user message.
70
-
71
- Parameters:
72
- translation_instructions (object - SystemTranslationMessage | ModelTranslationMessage) : The system message also known as the instructions.
73
- translation_prompt (object - ModelTranslationMessage) : The user message also known as the prompt.
74
-
75
- Returns:
76
- output (string) a string that gpt gives to us also known as the translation.
77
-
78
- """
79
-
80
- if(OpenAIService.decorator_to_use == None):
81
- return await OpenAIService._translate_message(translation_instructions, translation_prompt)
82
-
83
- decorated_function = OpenAIService.decorator_to_use(OpenAIService._translate_message)
84
- return await decorated_function(translation_instructions, translation_prompt)
85
-
86
- ##-------------------start-of-_translate_message()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
87
-
88
- ## backoff wrapper for retrying on errors, As of OpenAI > 1.0.0, it comes with a built in backoff system, but I've grown accustomed to this one so I'm keeping it.
89
- @staticmethod
90
- async def _translate_message(translation_instructions:Message, translation_prompt:Message) -> str:
91
-
92
- """
93
-
94
- Translates a system and user message.
95
-
96
- Parameters:
97
- translation_instructions (object - SystemTranslationMessage | ModelTranslationMessage) : The system message also known as the instructions.
98
- translation_prompt (object - ModelTranslationMessage) : The user message also known as the prompt.
99
-
100
- Returns:
101
- output (string) a string that gpt gives to us also known as the translation.
102
-
103
- """
104
-
105
- if(OpenAIService.client.api_key == "DummyKey"):
106
- raise InvalidAPIKeyException("OpenAI")
107
-
108
- ## logit bias is currently excluded due to a lack of need, and the fact that i am lazy
109
-
110
- response = await OpenAIService.client.chat.completions.create(
111
- model=OpenAIService.model,
112
- messages=[
113
- translation_instructions.to_dict(),
114
- translation_prompt.to_dict()
115
- ], # type: ignore
116
-
117
- temperature = OpenAIService.temperature,
118
- top_p = OpenAIService.top_p,
119
- n = OpenAIService.n,
120
- stream = OpenAIService.stream,
121
- stop = OpenAIService.stop,
122
- presence_penalty = OpenAIService.presence_penalty,
123
- frequency_penalty = OpenAIService.frequency_penalty,
124
- max_tokens = OpenAIService.max_tokens
125
-
126
- )
127
-
128
- ## if anyone knows how to type hint this please let me know
129
- output = response.choices[0].message.content
130
-
131
- return output
132
-
133
- ##-------------------start-of-test_api_key_validity()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
134
-
135
- @staticmethod
136
- async def test_api_key_validity() -> typing.Tuple[bool, typing.Union[Exception, None]]:
137
-
138
- """
139
-
140
- Tests the validity of the API key.
141
-
142
- Returns:
143
- validity (bool) : True if the API key is valid, False if it is not.
144
- e (Exception) : The exception that was raised, if any.
145
-
146
- """
147
-
148
- validity = False
149
-
150
- try:
151
-
152
- await OpenAIService.client.chat.completions.create(
153
- model="gpt-3.5-turbo",
154
- messages=[{"role":"user","content":"This is a test."}],
155
- max_tokens=1
156
- )
157
-
158
- validity = True
159
-
160
- return validity, None
161
-
162
- except Exception as e:
163
-
164
- return validity, e
165
-
166
- ##-------------------start-of-get_decorator()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
167
-
168
- @staticmethod
169
- def get_decorator() -> typing.Union[typing.Callable, None]:
170
-
171
- """
172
-
173
- Returns the decorator to use for the OpenAI service.
174
-
175
- Returns:
176
- decorator (callable) : The decorator to use.
177
-
178
- """
179
-
180
- return OpenAIService.decorator_to_use
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
util/token_counter.py CHANGED
@@ -11,9 +11,11 @@ parent_dir = current_dir.parent
11
  ## Add the parent directory to sys.path so 'modules' can be found
12
  sys.path.append(str(parent_dir))
13
 
 
 
 
14
  ## custom modules
15
  from modules.common.toolkit import Toolkit
16
- from models.kijiku import Kijiku
17
 
18
  class TokenCounter:
19
 
@@ -37,28 +39,6 @@ class TokenCounter:
37
 
38
  self.MODEL:str = ""
39
 
40
- ##-------------------start-of-count_characters()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
41
-
42
- def count_characters(self) -> int:
43
-
44
- """
45
-
46
- Counts the number of characters in a string.
47
-
48
- Parameters:
49
- self (object - TokenCounter) : The TokenCounter object.
50
-
51
- Returns:
52
- num_characters (int) The number of characters in the text.
53
-
54
- """
55
-
56
- Toolkit.clear_console()
57
-
58
- num_characters = len(self.text)
59
-
60
- return num_characters
61
-
62
  ##-------------------start-of-estimate_cost()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
63
 
64
  def estimate_cost(self, text_file:str) -> None:
@@ -78,17 +58,19 @@ class TokenCounter:
78
  self.text = file.read()
79
 
80
  self.MODEL = input("Please enter model : ")
 
81
 
82
- ## lazy workaround for now
83
- Kijiku.text_to_translate = [line for line in self.text.splitlines()]
84
 
85
- num_tokens, min_cost, self.MODEL = Kijiku.estimate_cost(self.MODEL)
86
- num_characters = self.count_characters()
87
 
88
- print("This is an estimate of the cost of translating a text using Kudasai. The actual cost may be higher or lower depending on the model used and the number of tokens in the text.\n")
89
- print("Estimated Number of Tokens in Text : " + str(num_tokens))
90
- print("Estimated Minimum Cost of Translation : " + str(min_cost))
91
- print("Number of Characters in Text : " + str(num_characters) + "\n")
 
 
 
92
 
93
  Toolkit.pause_console()
94
 
 
11
  ## Add the parent directory to sys.path so 'modules' can be found
12
  sys.path.append(str(parent_dir))
13
 
14
+ ## third-party libraries
15
+ from easytl import EasyTL
16
+
17
  ## custom modules
18
  from modules.common.toolkit import Toolkit
 
19
 
20
  class TokenCounter:
21
 
 
39
 
40
  self.MODEL:str = ""
41
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  ##-------------------start-of-estimate_cost()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
43
 
44
  def estimate_cost(self, text_file:str) -> None:
 
58
  self.text = file.read()
59
 
60
  self.MODEL = input("Please enter model : ")
61
+ self.service = "openai" if "gpt" in self.MODEL else "gemini"
62
 
63
+ text_to_translate = [line for line in self.text.splitlines()]
 
64
 
65
+ num_tokens, min_cost, self.MODEL = EasyTL.calculate_cost(text=text_to_translate, service=self.service, model=self.MODEL)
 
66
 
67
+ print("\nNote that the cost estimate is not always accurate, and may be higher than the actual cost. However cost calculation now includes output tokens.\n")
68
+
69
+ if(self.service == "gemini"):
70
+ print(f"As of Kudasai {Toolkit.CURRENT_VERSION}, Gemini Pro 1.0 is free to use under 60 requests per minute, Gemini Pro 1.5 is free to use under 2 requests per minute.\nIt is up to you to set these in the settings json.\nIt is currently unknown whether the ultra model parameter is connecting to the actual ultra model and not a pro one. As it works, but does not appear on any documentation.\n")
71
+
72
+ print("Estimated number of tokens : " + str(num_tokens))
73
+ print("Estimated minimum cost : " + str(min_cost) + " USD")
74
 
75
  Toolkit.pause_console()
76
 
webgui.py CHANGED
@@ -7,7 +7,9 @@ import gradio as gr
7
 
8
  from kairyou import Indexer
9
  from kairyou import Kairyou
10
- from kairyou.exceptions import InvalidReplacementJsonKeys
 
 
11
 
12
  ## custom modules
13
  from modules.common.toolkit import Toolkit
@@ -21,10 +23,6 @@ from handlers.json_handler import JsonHandler
21
 
22
  from models.kaiseki import Kaiseki
23
  from models.kijiku import Kijiku
24
- from translation_services.deepl_service import DeepLService
25
-
26
- from translation_services.openai_service import OpenAIService
27
- from translation_services.gemini_service import GeminiService
28
 
29
  from kudasai import Kudasai
30
 
@@ -165,15 +163,14 @@ class KudasaiGUI:
165
  ## next api key
166
  try:
167
  if(Kijiku.LLM_TYPE == "openai"):
168
- OpenAIService.set_api_key(str(api_key))
169
- is_valid, e = await OpenAIService.test_api_key_validity()
170
 
171
 
172
  else:
173
 
174
- GeminiService.redefine_client()
175
- GeminiService.set_api_key(str(api_key))
176
- is_valid, e = await GeminiService.test_api_key_validity()
177
 
178
  if(is_valid == False and e is not None):
179
  raise e
@@ -498,7 +495,7 @@ class KudasaiGUI:
498
 
499
  self.openai_model_input_field = gr.Dropdown(label="OpenAI Model",
500
  value=str(GuiJsonUtil.fetch_kijiku_setting_key_values("openai settings","openai_model")),
501
- choices=[model for model in FileEnsurer.ALLOWED_OPENAI_MODELS],
502
  info="ID of the model to use. Kijiku only works with 'chat' models.",
503
  show_label=True,
504
  interactive=True,
@@ -600,7 +597,7 @@ class KudasaiGUI:
600
 
601
  self.gemini_model_input_field = gr.Dropdown(label="Gemini Model",
602
  value=str(GuiJsonUtil.fetch_kijiku_setting_key_values("gemini settings","gemini_model")),
603
- choices=[model for model in FileEnsurer.ALLOWED_GEMINI_MODELS],
604
  info="The model to use. Currently only supports gemini-pro and gemini-pro-vision, the 1.0 model and it's aliases.",
605
  show_label=True,
606
  interactive=True,
@@ -905,9 +902,9 @@ class KudasaiGUI:
905
  text_to_translate = input_text
906
 
907
  try:
908
- DeepLService.set_api_key(str(api_key_input))
909
 
910
- is_valid, e = DeepLService.test_api_key_validity()
911
 
912
  if(is_valid == False and e is not None):
913
  raise e
@@ -1064,8 +1061,6 @@ class KudasaiGUI:
1064
  else:
1065
  Kijiku.LLM_TYPE = "gemini"
1066
 
1067
- ## normally done in Kijiku.commence_translation, but since we're not translating, we need to do it here
1068
- GeminiService.redefine_client()
1069
 
1070
  await set_kijiku_api_key(api_key)
1071
 
@@ -1077,15 +1072,15 @@ class KudasaiGUI:
1077
  else:
1078
  text_to_translate = input_text
1079
 
1080
- ## need to convert to list of strings
1081
- Kijiku.text_to_translate = [line for line in str(text_to_translate).splitlines()]
1082
 
1083
- num_tokens, estimated_cost, model = Kijiku.estimate_cost(model)
1084
 
1085
  if(Kijiku.LLM_TYPE == "gemini"):
1086
- cost_estimation = f"As of Kudasai {Toolkit.CURRENT_VERSION}, Gemini Pro is Free to use\n"
1087
 
1088
  cost_estimation += "Estimated number of tokens : " + str(num_tokens) + "\n" + "Estimated minimum cost : " + str(estimated_cost) + " USD"
 
1089
 
1090
  gr.Info(cost_estimation)
1091
 
@@ -1401,7 +1396,7 @@ class KudasaiGUI:
1401
  gemini_max_output_tokens_value
1402
  ]
1403
 
1404
- gr.Info("Kijiku Settings Reset to Default")
1405
 
1406
  return return_batch
1407
 
 
7
 
8
  from kairyou import Indexer
9
  from kairyou import Kairyou
10
+ from kairyou import InvalidReplacementJsonKeys
11
+
12
+ from easytl import EasyTL, ALLOWED_GEMINI_MODELS, ALLOWED_OPENAI_MODELS
13
 
14
  ## custom modules
15
  from modules.common.toolkit import Toolkit
 
23
 
24
  from models.kaiseki import Kaiseki
25
  from models.kijiku import Kijiku
 
 
 
 
26
 
27
  from kudasai import Kudasai
28
 
 
163
  ## next api key
164
  try:
165
  if(Kijiku.LLM_TYPE == "openai"):
166
+ EasyTL.set_api_key(Kijiku.LLM_TYPE, str(api_key))
167
+ is_valid, e = EasyTL.test_api_key_validity(Kijiku.LLM_TYPE)
168
 
169
 
170
  else:
171
 
172
+ EasyTL.set_api_key(Kijiku.LLM_TYPE, str(api_key))
173
+ is_valid, e = EasyTL.test_api_key_validity(Kijiku.LLM_TYPE)
 
174
 
175
  if(is_valid == False and e is not None):
176
  raise e
 
495
 
496
  self.openai_model_input_field = gr.Dropdown(label="OpenAI Model",
497
  value=str(GuiJsonUtil.fetch_kijiku_setting_key_values("openai settings","openai_model")),
498
+ choices=[model for model in ALLOWED_OPENAI_MODELS],
499
  info="ID of the model to use. Kijiku only works with 'chat' models.",
500
  show_label=True,
501
  interactive=True,
 
597
 
598
  self.gemini_model_input_field = gr.Dropdown(label="Gemini Model",
599
  value=str(GuiJsonUtil.fetch_kijiku_setting_key_values("gemini settings","gemini_model")),
600
+ choices=[model for model in ALLOWED_GEMINI_MODELS],
601
  info="The model to use. Currently only supports gemini-pro and gemini-pro-vision, the 1.0 model and it's aliases.",
602
  show_label=True,
603
  interactive=True,
 
902
  text_to_translate = input_text
903
 
904
  try:
905
+ EasyTL.set_api_key("deepl", str(api_key_input))
906
 
907
+ is_valid, e = EasyTL.test_api_key_validity("deepl")
908
 
909
  if(is_valid == False and e is not None):
910
  raise e
 
1061
  else:
1062
  Kijiku.LLM_TYPE = "gemini"
1063
 
 
 
1064
 
1065
  await set_kijiku_api_key(api_key)
1066
 
 
1072
  else:
1073
  text_to_translate = input_text
1074
 
1075
+ translation_instructions = GuiJsonUtil.fetch_kijiku_setting_key_values("openai settings","openai_system_message") if Kijiku.LLM_TYPE == "openai" else GuiJsonUtil.fetch_kijiku_setting_key_values("gemini settings","gemini_prompt")
 
1076
 
1077
+ num_tokens, estimated_cost, model = EasyTL.calculate_cost(text=text_to_translate, service=Kijiku.LLM_TYPE, model=model, translation_instructions=translation_instructions)
1078
 
1079
  if(Kijiku.LLM_TYPE == "gemini"):
1080
+ cost_estimation = f"As of Kudasai {Toolkit.CURRENT_VERSION}, Gemini Pro 1.0 is free to use under 60 requests per minute, Gemini Pro 1.5 is free to use under 2 requests per minute.\nIt is up to you to set these in the settings json.\nIt is currently unknown whether the ultra model parameter is connecting to the actual ultra model and not a pro one. As it works, but does not appear on any documentation.\n"
1081
 
1082
  cost_estimation += "Estimated number of tokens : " + str(num_tokens) + "\n" + "Estimated minimum cost : " + str(estimated_cost) + " USD"
1083
+ cost_estimation += "\nThis is a rough estimate, please remember to check actual cost on the appropriate platform when needed"
1084
 
1085
  gr.Info(cost_estimation)
1086
 
 
1396
  gemini_max_output_tokens_value
1397
  ]
1398
 
1399
+ gr.Info("Kijiku Settings Reset to Default. Make sure to press the Apply button to apply the changes.")
1400
 
1401
  return return_batch
1402