Bikatr7 commited on
Commit
e3c1552
1 Parent(s): 12a3f4b

moved to v3.4.6

Browse files
README.md CHANGED
@@ -74,7 +74,7 @@ They both have a debug field, but neither module really uses it.
74
 
75
  ## **Translator**<a name="translator"></a>
76
 
77
- Kudasai supports 3 different translation methods at the moment, OpenAI's GPT, Google's Gemini, and DeepL.
78
 
79
  For OpenAI, you'll need an API key, you can get one [here](https://platform.openai.com/docs/api-reference/authentication). This is a paid service with no free tier.
80
 
@@ -82,13 +82,15 @@ For Gemini, you'll also need an API key, you can get one [here](https://ai.googl
82
 
83
  For DeepL, you'll need an API key too, you can get one [here](https://www.deepl.com/pro#developer). DeepL is also a paid service but is free under 500k characters a month.
84
 
 
 
85
  I'd recommend using GPT for most things, as it's generally better at translation.
86
 
87
- Mostly straightforward, choose your translation method, fill in your API key, and select your text. You'll also need to add your settings file if on HuggingFace if you want to tune the output, but the default is generally fine.
88
 
89
  You can calculate costs here or just translate. Output will show in the appropriate fields.
90
 
91
- For further details on the settings file, see [here](#translation-with-llms-settings).
92
 
93
  ---------------------------------------------------------------------------------------------------------------------------------------------------
94
 
 
74
 
75
  ## **Translator**<a name="translator"></a>
76
 
77
+ Kudasai supports 4 different translation methods at the moment, OpenAI's GPT, Google's Gemini & Google Translate, and DeepL.
78
 
79
  For OpenAI, you'll need an API key, you can get one [here](https://platform.openai.com/docs/api-reference/authentication). This is a paid service with no free tier.
80
 
 
82
 
83
  For DeepL, you'll need an API key too, you can get one [here](https://www.deepl.com/pro#developer). DeepL is also a paid service but is free under 500k characters a month.
84
 
85
+ And for Google Translate, you'll need a Google Cloud API key, you can get one [here](https://cloud.google.com/translate/docs/setup). Google Translate is a paid service, but is free under 500k characters a month. Kudasai uses v2 of the API so make sure you follow the instructions to get credentials for that.
86
+
87
  I'd recommend using GPT for most things, as it's generally better at translation.
88
 
89
+ Mostly straightforward, choose your translation method, fill in your API key, and select your text. You'll also need to add your settings file if on HuggingFace if you want to tune the output, but the default is generally fine. Although for google translate this needs to be the contents of your service key json, all one one line too.
90
 
91
  You can calculate costs here or just translate. Output will show in the appropriate fields.
92
 
93
+ For further details on the settings file, see [here](#translation-with-llms-settings). Note that Google Translate has no settings.
94
 
95
  ---------------------------------------------------------------------------------------------------------------------------------------------------
96
 
handlers/json_handler.py CHANGED
@@ -25,7 +25,6 @@ class JsonHandler:
25
  with open(FileEnsurer.translation_settings_description_path, 'r', encoding='utf-8') as file:
26
  translation_settings_message = file.read()
27
 
28
-
29
  ##-------------------start-of-validate_json()--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
30
 
31
  @staticmethod
@@ -125,6 +124,12 @@ class JsonHandler:
125
  assert all(key in gemini_settings for key in gemini_keys), "gemini settings keys missing"
126
  assert all(key in deepl_settings for key in deepl_keys), "deepl settings keys missing"
127
 
 
 
 
 
 
 
128
  ## validate each key using the validation rules
129
  for key, validate in validation_rules.items():
130
  if(key in base_translation_settings and not validate(base_translation_settings[key])):
 
25
  with open(FileEnsurer.translation_settings_description_path, 'r', encoding='utf-8') as file:
26
  translation_settings_message = file.read()
27
 
 
28
  ##-------------------start-of-validate_json()--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
29
 
30
  @staticmethod
 
124
  assert all(key in gemini_settings for key in gemini_keys), "gemini settings keys missing"
125
  assert all(key in deepl_settings for key in deepl_keys), "deepl settings keys missing"
126
 
127
+ ## ensure that those sections don't have any extra keys
128
+ assert all(key in base_translation_keys for key in base_translation_settings), "base translation settings has extra keys"
129
+ assert all(key in openai_keys for key in openai_settings), "openai settings has extra keys"
130
+ assert all(key in gemini_keys for key in gemini_settings), "gemini settings has extra keys"
131
+ assert all(key in deepl_keys for key in deepl_settings), "deepl settings has extra keys"
132
+
133
  ## validate each key using the validation rules
134
  for key, validate in validation_rules.items():
135
  if(key in base_translation_settings and not validate(base_translation_settings[key])):
kudasai.py CHANGED
@@ -6,7 +6,6 @@ import asyncio
6
  import re
7
  import typing
8
  import logging
9
- import argparse
10
 
11
  ## third-party libraries
12
  from kairyou import Kairyou
@@ -307,11 +306,12 @@ async def main() -> None:
307
 
308
  if(len(sys.argv) <= 1):
309
  await run_console_version()
310
-
311
  elif(len(sys.argv) in [2, 3, 4, 5, 6]):
312
  await run_cli_version()
313
 
314
  else:
 
315
  print_usage_statement()
316
 
317
  except Exception as e:
@@ -346,8 +346,6 @@ async def run_console_version():
346
 
347
  raise e
348
 
349
- print("In progress...")
350
-
351
  await Kudasai.run_kudasai()
352
 
353
  ##-------------------start-of-run_cli_version()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -369,7 +367,7 @@ async def run_cli_version():
369
  """
370
 
371
  conditions = [
372
- (lambda arg: arg in ["deepl", "openai", "gemini"], "translation_method"),
373
  (lambda arg: os.path.exists(arg) and not ".json" in arg, "text_to_translate"),
374
  (lambda arg: len(arg) > 10 and not os.path.exists(arg), "api_key"),
375
  (lambda arg: arg == "translate", "identifier"),
@@ -378,11 +376,12 @@ async def run_cli_version():
378
 
379
  for condition, result in conditions:
380
  if(condition(arg)):
381
- print(result)
 
382
  return result
383
-
384
- raise Exception("Invalid argument. Please use 'deepl', 'openai', or 'gemini'.")
385
-
386
  mode = ""
387
 
388
  try:
@@ -419,7 +418,9 @@ async def run_cli_version():
419
  method_to_translation_mode = {
420
  "openai": "1",
421
  "gemini": "2",
422
- "deepl": "3"
 
 
423
  }
424
 
425
  Kudasai.text_to_preprocess = FileEnsurer.standard_read_file(sys.argv[arg_indices['text_to_translate_index']].strip('"'))
@@ -498,6 +499,7 @@ Modes:
498
  Additional Notes:
499
  - All arguments should be enclosed in double quotes if they contain spaces. But double quotes are optional and will be striped. Single quotes are not allowed
500
  - For more information, refer to the documentation at README.md
 
501
  """)
502
 
503
 
 
6
  import re
7
  import typing
8
  import logging
 
9
 
10
  ## third-party libraries
11
  from kairyou import Kairyou
 
306
 
307
  if(len(sys.argv) <= 1):
308
  await run_console_version()
309
+
310
  elif(len(sys.argv) in [2, 3, 4, 5, 6]):
311
  await run_cli_version()
312
 
313
  else:
314
+ print(f"Invalid number of arguments ({len(sys.argv)}), max of 6. Please use --help for more information.")
315
  print_usage_statement()
316
 
317
  except Exception as e:
 
346
 
347
  raise e
348
 
 
 
349
  await Kudasai.run_kudasai()
350
 
351
  ##-------------------start-of-run_cli_version()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 
367
  """
368
 
369
  conditions = [
370
+ (lambda arg: arg in ["deepl", "openai", "gemini", "google_translate"], "translation_method"),
371
  (lambda arg: os.path.exists(arg) and not ".json" in arg, "text_to_translate"),
372
  (lambda arg: len(arg) > 10 and not os.path.exists(arg), "api_key"),
373
  (lambda arg: arg == "translate", "identifier"),
 
376
 
377
  for condition, result in conditions:
378
  if(condition(arg)):
379
+ print(f"Determined argument for '{arg}' as '{result}'")
380
+ logging.debug(f"Determined argument for '{arg}' as '{result}'")
381
  return result
382
+
383
+ raise Exception("Invalid argument. Please use 'deepl', 'openai', or 'gemini', or 'google_translate')")
384
+
385
  mode = ""
386
 
387
  try:
 
418
  method_to_translation_mode = {
419
  "openai": "1",
420
  "gemini": "2",
421
+ "deepl": "3",
422
+ "google_translate": "4",
423
+ "google translate": "4"
424
  }
425
 
426
  Kudasai.text_to_preprocess = FileEnsurer.standard_read_file(sys.argv[arg_indices['text_to_translate_index']].strip('"'))
 
499
  Additional Notes:
500
  - All arguments should be enclosed in double quotes if they contain spaces. But double quotes are optional and will be striped. Single quotes are not allowed
501
  - For more information, refer to the documentation at README.md
502
+ - For google translate, enter the method as 'google_translate', also google_translate doesn't support the api_key argument
503
  """)
504
 
505
 
lib/gui/HUGGING_FACE_README.md CHANGED
@@ -74,7 +74,7 @@ They both have a debug field, but neither module really uses it.
74
 
75
  ## **Translator**<a name="translator"></a>
76
 
77
- Kudasai supports 3 different translation methods at the moment, OpenAI's GPT, Google's Gemini, and DeepL.
78
 
79
  For OpenAI, you'll need an API key, you can get one [here](https://platform.openai.com/docs/api-reference/authentication). This is a paid service with no free tier.
80
 
@@ -82,13 +82,15 @@ For Gemini, you'll also need an API key, you can get one [here](https://ai.googl
82
 
83
  For DeepL, you'll need an API key too, you can get one [here](https://www.deepl.com/pro#developer). DeepL is also a paid service but is free under 500k characters a month.
84
 
 
 
85
  I'd recommend using GPT for most things, as it's generally better at translation.
86
 
87
- Mostly straightforward, choose your translation method, fill in your API key, and select your text. You'll also need to add your settings file if on HuggingFace if you want to tune the output, but the default is generally fine.
88
 
89
  You can calculate costs here or just translate. Output will show in the appropriate fields.
90
 
91
- For further details on the settings file, see [here](#translation-with-llms-settings).
92
 
93
  ---------------------------------------------------------------------------------------------------------------------------------------------------
94
 
 
74
 
75
  ## **Translator**<a name="translator"></a>
76
 
77
+ Kudasai supports 4 different translation methods at the moment, OpenAI's GPT, Google's Gemini & Google Translate, and DeepL.
78
 
79
  For OpenAI, you'll need an API key, you can get one [here](https://platform.openai.com/docs/api-reference/authentication). This is a paid service with no free tier.
80
 
 
82
 
83
  For DeepL, you'll need an API key too, you can get one [here](https://www.deepl.com/pro#developer). DeepL is also a paid service but is free under 500k characters a month.
84
 
85
+ And for Google Translate, you'll need a Google Cloud API key, you can get one [here](https://cloud.google.com/translate/docs/setup). Google Translate is a paid service, but is free under 500k characters a month. Kudasai uses v2 of the API so make sure you follow the instructions to get credentials for that.
86
+
87
  I'd recommend using GPT for most things, as it's generally better at translation.
88
 
89
+ Mostly straightforward, choose your translation method, fill in your API key, and select your text. You'll also need to add your settings file if on HuggingFace if you want to tune the output, but the default is generally fine. Although for google translate this needs to be the contents of your service key json, all one one line too.
90
 
91
  You can calculate costs here or just translate. Output will show in the appropriate fields.
92
 
93
+ For further details on the settings file, see [here](#translation-with-llms-settings). Note that Google Translate has no settings.
94
 
95
  ---------------------------------------------------------------------------------------------------------------------------------------------------
96
 
modules/common/file_ensurer.py CHANGED
@@ -63,6 +63,7 @@ class FileEnsurer():
63
  deepl_api_key_path = os.path.join(secrets_dir, "deepl_api_key.txt")
64
  openai_api_key_path = os.path.join(secrets_dir,'openai_api_key.txt')
65
  gemini_api_key_path = os.path.join(secrets_dir,'gemini_api_key.txt')
 
66
 
67
  ## favicon
68
  favicon_path = os.path.join(gui_lib, "Kudasai_Logo.png")
 
63
  deepl_api_key_path = os.path.join(secrets_dir, "deepl_api_key.txt")
64
  openai_api_key_path = os.path.join(secrets_dir,'openai_api_key.txt')
65
  gemini_api_key_path = os.path.join(secrets_dir,'gemini_api_key.txt')
66
+ google_translate_service_key_json_path = os.path.join(secrets_dir, "google_translate_service_key.json")
67
 
68
  ## favicon
69
  favicon_path = os.path.join(gui_lib, "Kudasai_Logo.png")
modules/common/toolkit.py CHANGED
@@ -15,7 +15,7 @@ class Toolkit():
15
 
16
  """
17
 
18
- CURRENT_VERSION = "v3.4.5"
19
 
20
  ##-------------------start-of-clear_console()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
21
 
 
15
 
16
  """
17
 
18
+ CURRENT_VERSION = "v3.4.6"
19
 
20
  ##-------------------start-of-clear_console()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
21
 
modules/common/translator.py CHANGED
@@ -29,7 +29,7 @@ class Translator:
29
  """
30
 
31
  Translator is a class that is used to interact with translation methods and translate text.
32
- Currently supports OpenAI, Gemini, and DeepL.
33
 
34
  """
35
 
@@ -51,6 +51,9 @@ class Translator:
51
  ## same as above, but for deepl, just the text to be translated
52
  deepl_translation_batches:typing.List[str] = []
53
 
 
 
 
54
  num_occurred_malformed_batches = 0
55
 
56
  ## semaphore to limit the number of concurrent batches
@@ -58,7 +61,7 @@ class Translator:
58
 
59
  ##--------------------------------------------------------------------------------------------------------------------------
60
 
61
- TRANSLATION_METHOD:typing.Literal["openai", "gemini", "deepl"] = "openai"
62
 
63
  translation_print_result = ""
64
 
@@ -156,7 +159,7 @@ class Translator:
156
 
157
  JsonHandler.validate_json()
158
 
159
- if(not Translator.is_cli):
160
  await Translator.check_settings()
161
 
162
  ## set actual start time to the end of the settings configuration
@@ -194,10 +197,11 @@ class Translator:
194
  "1": ("openai", FileEnsurer.openai_api_key_path),
195
  "2": ("gemini", FileEnsurer.gemini_api_key_path),
196
  "3": ("deepl", FileEnsurer.deepl_api_key_path),
 
197
  }
198
 
199
  if(not Translator.is_cli):
200
- method = input("What method would you like to use for translation? (1 for OpenAI, 2 for Gemini, 3 for Deepl, or any other key to exit) : \n")
201
 
202
  if(method not in translation_methods.keys()):
203
  print("\nThank you for using Kudasai, goodbye.")
@@ -212,8 +216,14 @@ class Translator:
212
  Translator.TRANSLATION_METHOD, api_key_path = translation_methods.get(method, ("deepl", FileEnsurer.deepl_api_key_path))
213
 
214
  if(Translator.pre_provided_api_key != ""):
215
- encoded_key = base64.b64encode(Translator.pre_provided_api_key.encode('utf-8')).decode('utf-8')
 
 
 
 
 
216
  Translator.pre_provided_api_key = ""
 
217
  with open(api_key_path, 'w+', encoding='utf-8') as file:
218
  file.write(encoded_key)
219
 
@@ -246,14 +256,28 @@ class Translator:
246
 
247
  """
248
 
 
 
 
 
 
 
 
 
 
 
 
249
  ## get saved API key if exists
250
  try:
251
- with open(api_key_path, 'r', encoding='utf-8') as file:
252
- api_key = base64.b64decode((file.read()).encode('utf-8')).decode('utf-8')
 
 
 
253
 
254
  api_key_setter(service.lower(), api_key)
255
 
256
- is_valid, e = api_key_tester(service.lower())
257
 
258
  ## if not valid, raise the exception that caused the test to fail
259
  if(not is_valid and e is not None):
@@ -267,20 +291,31 @@ class Translator:
267
  except:
268
 
269
  Toolkit.clear_console()
 
 
 
 
 
 
270
 
271
- api_key = input(f"DO NOT DELETE YOUR COPY OF THE API KEY\n\nPlease enter the {service} API key you have : ")
 
 
 
 
 
 
272
 
273
- ## if valid save the API key
274
  try:
275
 
276
  api_key_setter(service.lower(), api_key)
277
 
278
- is_valid, e = api_key_tester(service.lower())
279
 
280
  if(not is_valid and e is not None):
281
  raise e
282
-
283
- FileEnsurer.standard_overwrite_file(api_key_path, base64.b64encode(api_key.encode('utf-8')).decode('utf-8'), omit=True)
284
 
285
  ## if invalid key exit
286
  except (GoogleAuthError, OpenAIAuthenticationError, DeepLAuthorizationException):
@@ -324,7 +359,7 @@ class Translator:
324
  Translator.gemini_translation_batches = []
325
  Translator.num_occurred_malformed_batches = 0
326
  Translator.translation_print_result = ""
327
- Translator.TRANSLATION_METHOD = "openai"
328
  Translator.pre_provided_api_key = ""
329
  Translator.is_cli = False
330
 
@@ -339,12 +374,13 @@ class Translator:
339
 
340
  """
341
 
342
- print("Are these settings okay? (1 for yes or 2 for no) : \n\n")
343
 
344
  method_to_section_dict = {
345
  "openai": ("openai settings", "OpenAI", FileEnsurer.openai_api_key_path),
346
  "gemini": ("gemini settings", "Gemini", FileEnsurer.gemini_api_key_path),
347
- "deepl": ("deepl settings", "DeepL", FileEnsurer.deepl_api_key_path)
 
348
  }
349
 
350
  section_to_target, method_name, api_key_path = method_to_section_dict[Translator.TRANSLATION_METHOD]
@@ -361,7 +397,7 @@ class Translator:
361
  JsonHandler.reset_translation_settings_to_default()
362
  JsonHandler.load_translation_settings()
363
 
364
- print("Are these settings okay? (1 for yes or 2 for no) : \n\n")
365
  JsonHandler.log_translation_settings(output_to_console=True, specific_section=section_to_target)
366
  else:
367
  FileEnsurer.exit_kudasai()
@@ -439,7 +475,8 @@ class Translator:
439
  exception_dict = {
440
  "openai": (OpenAIAuthenticationError, OpenAIInternalServerError, OpenAIRateLimitError, OpenAIAPITimeoutError, OpenAIAPIConnectionError, OpenAIAPIStatusError),
441
  "gemini": GoogleAPIError,
442
- "deepl": DeepLException
 
443
  }
444
 
445
  Translator.decorator_to_use = backoff.on_exception(
@@ -460,7 +497,8 @@ class Translator:
460
  translation_methods = {
461
  "openai": JsonHandler.current_translation_settings["openai settings"]["openai_model"],
462
  "gemini": JsonHandler.current_translation_settings["gemini settings"]["gemini_model"],
463
- "deepl": "deepl"
 
464
  }
465
 
466
  model = translation_methods[Translator.TRANSLATION_METHOD]
@@ -512,34 +550,36 @@ class Translator:
512
  """
513
 
514
  async_requests = []
515
-
516
  translation_batches_methods = {
517
  "openai": Translator.openai_translation_batches,
518
  "gemini": Translator.gemini_translation_batches,
519
- "deepl": Translator.deepl_translation_batches
 
520
  }
521
-
522
  translation_batches = translation_batches_methods[Translator.TRANSLATION_METHOD]
523
  batch_length = len(translation_batches)
524
-
525
- if(Translator.TRANSLATION_METHOD != "deepl"):
526
 
 
527
  for i in range(0, batch_length, 2):
528
  instructions = translation_batches[i]
529
- prompt = translation_batches[i+1]
530
-
531
  assert isinstance(instructions, (SystemTranslationMessage, str))
532
  assert isinstance(prompt, (ModelTranslationMessage, str))
533
-
534
- async_requests.append(Translator.handle_translation(model, i, batch_length, prompt, instructions))
 
535
 
536
  else:
537
  for i, batch in enumerate(translation_batches):
538
-
539
  assert isinstance(batch, str)
540
-
541
- async_requests.append(Translator.handle_translation(model, i, batch_length, batch, None))
542
-
 
543
  return async_requests
544
 
545
  ##-------------------start-of-generate_text_to_translate_batches()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -579,14 +619,14 @@ class Translator:
579
  if(len(prompt) < Translator.number_of_lines_per_batch):
580
  if(is_special_char or is_part_in_sentence or is_part_char):
581
  prompt.append(f'{sentence}\n')
582
- logging.debug(f"Sentence : {sentence}, Sentence is a pov change or part marker... adding to prompt.")
583
 
584
  elif(non_word_pattern.match(sentence) or KatakanaUtil.is_punctuation(sentence) and not has_quotes):
585
- logging.debug(f"Sentence : {sentence}, Sentence is punctuation... skipping.")
586
 
587
  elif(sentence):
588
  prompt.append(f'{sentence}\n')
589
- logging.debug(f"Sentence : {sentence}, Sentence is a valid sentence... adding to prompt.")
590
  else:
591
  return prompt, index
592
 
@@ -627,15 +667,19 @@ class Translator:
627
  Translator.gemini_translation_batches.append(Translator.gemini_prompt)
628
  Translator.gemini_translation_batches.append(batch)
629
 
630
- else:
631
  Translator.deepl_translation_batches.append(batch)
632
 
 
 
 
633
  logging_message = "Built Messages: \n\n"
634
 
635
  batches_to_iterate = {
636
  "openai": Translator.openai_translation_batches,
637
  "gemini": Translator.gemini_translation_batches,
638
- "deepl": Translator.deepl_translation_batches
 
639
  }
640
 
641
  i = 0
@@ -648,7 +692,7 @@ class Translator:
648
 
649
  message = str(message) if Translator.TRANSLATION_METHOD != 'openai' else message.content # type: ignore
650
 
651
- if(i % 2 == 1 and Translator.TRANSLATION_METHOD != 'deepl'):
652
  logging_message += "\n" "------------------------" "\n"
653
 
654
  logging_message += message + "\n"
@@ -677,6 +721,7 @@ class Translator:
677
  "openai": Translator.openai_system_message,
678
  "gemini": Translator.gemini_prompt,
679
  "deepl": None,
 
680
  }
681
 
682
  translation_instructions = translation_instructions_methods[Translator.TRANSLATION_METHOD]
@@ -689,6 +734,8 @@ class Translator:
689
  if(Translator.TRANSLATION_METHOD == "gemini"):
690
  logging.info(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 the translation settings.")
691
 
 
 
692
  logging.info("Estimated number of tokens : " + str(num_tokens))
693
  logging.info("Estimated minimum cost : " + str(min_cost) + " USD")
694
 
@@ -706,7 +753,7 @@ class Translator:
706
 
707
  @staticmethod
708
  async def handle_translation(model:str,
709
- batch_index:int,
710
  length_of_batch:int,
711
  text_to_translate:typing.Union[str, ModelTranslationMessage],
712
  translation_instructions:typing.Union[str, SystemTranslationMessage, None]) -> tuple[int, str, str]:
@@ -717,13 +764,13 @@ class Translator:
717
 
718
  Parameters:
719
  model (string) : The model of the service used to translate the text.
720
- batch_index (int) : Which batch we are currently on.
721
  length_of_batch (int) : How long the batches are.
722
  text_to_translate (typing.Union[str, ModelTranslationMessage]) : The text to translate.
723
  translation_instructions (typing.Union[str, SystemTranslationMessage, None]) : The translation instructions.
724
 
725
  Returns:
726
- batch_index (int) : The batch index.
727
  text_to_translate (str) : The text to translate.
728
  translated_text (str) : The translated text
729
 
@@ -738,17 +785,16 @@ class Translator:
738
  ## For the webgui
739
  if(FileEnsurer.do_interrupt == True):
740
  raise Exception("Interrupted by user.")
741
-
742
- batch_number = (batch_index // 2) + 1
743
-
744
- logging.info(f"Trying translation for batch {batch_number} of {length_of_batch//2}...")
745
 
746
  try:
747
 
748
  translation_methods = {
749
  "openai": EasyTL.openai_translate_async,
750
  "gemini": EasyTL.gemini_translate_async,
751
- "deepl": EasyTL.deepl_translate_async
 
752
  }
753
 
754
  translation_params = {
@@ -781,6 +827,10 @@ class Translator:
781
  "split_sentences": Translator.deepl_split_sentences,
782
  "preserve_formatting": Translator.deepl_preserve_formatting,
783
  "formality": Translator.deepl_formality
 
 
 
 
784
  }
785
  }
786
 
@@ -791,7 +841,7 @@ class Translator:
791
  ## will only occur if the max_batch_duration is exceeded, so we just return the untranslated text
792
  except MaxBatchDurationExceededException:
793
 
794
- logging.error(f"Batch {batch_number} of {length_of_batch//2} was not translated due to exceeding the max request duration, returning the untranslated text...")
795
  break
796
 
797
  ## do not even bother if not a gpt 4 model, because gpt-3 seems unable to format properly
@@ -804,12 +854,12 @@ class Translator:
804
  break
805
 
806
  if(num_tries >= Translator.num_of_malform_retries):
807
- logging.warning(f"Batch {batch_number} of {length_of_batch//2} was malformed but exceeded the max number of retries ({Translator.num_of_malform_retries})")
808
  break
809
 
810
  else:
811
  num_tries += 1
812
- logging.warning(f"Batch {batch_number} of {length_of_batch//2} was malformed, retrying...")
813
  Translator.num_occurred_malformed_batches += 1
814
 
815
  if(isinstance(text_to_translate, ModelTranslationMessage)):
@@ -818,9 +868,9 @@ class Translator:
818
  if(isinstance(translated_message, typing.List)):
819
  translated_message = ''.join(translated_message) # type: ignore
820
 
821
- logging.info(f"Translation for batch {batch_number} of {length_of_batch//2} completed.")
822
 
823
- return batch_index, text_to_translate, translated_message # type: ignore
824
 
825
  ##-------------------start-of-check_if_translation_is_good()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
826
 
@@ -917,7 +967,7 @@ class Translator:
917
  index = patched_sentences.index(Translator.translated_text[i])
918
  Translator.translated_text[i] = patched_sentences[index]
919
 
920
- ## mode 2 just assumes the LLM formatted it properly
921
  elif(Translator.sentence_fragmenter_mode == 2):
922
 
923
  Translator.translated_text.append(translated_message + '\n\n')
 
29
  """
30
 
31
  Translator is a class that is used to interact with translation methods and translate text.
32
+ Currently supports OpenAI, Gemini, DeepL, and Google Translate.
33
 
34
  """
35
 
 
51
  ## same as above, but for deepl, just the text to be translated
52
  deepl_translation_batches:typing.List[str] = []
53
 
54
+ ## also the same for google translate
55
+ google_translate_translation_batches:typing.List[str] = []
56
+
57
  num_occurred_malformed_batches = 0
58
 
59
  ## semaphore to limit the number of concurrent batches
 
61
 
62
  ##--------------------------------------------------------------------------------------------------------------------------
63
 
64
+ TRANSLATION_METHOD:typing.Literal["openai", "gemini", "deepl", "google translate"] = "deepl"
65
 
66
  translation_print_result = ""
67
 
 
159
 
160
  JsonHandler.validate_json()
161
 
162
+ if(not Translator.is_cli and Translator.TRANSLATION_METHOD != "google translate"):
163
  await Translator.check_settings()
164
 
165
  ## set actual start time to the end of the settings configuration
 
197
  "1": ("openai", FileEnsurer.openai_api_key_path),
198
  "2": ("gemini", FileEnsurer.gemini_api_key_path),
199
  "3": ("deepl", FileEnsurer.deepl_api_key_path),
200
+ "4": ("google translate", FileEnsurer.google_translate_service_key_json_path)
201
  }
202
 
203
  if(not Translator.is_cli):
204
+ method = input("What method would you like to use for translation? (1 for OpenAI, 2 for Gemini, 3 for Deepl, 4 for Google Translate), or any other key to exit) : \n")
205
 
206
  if(method not in translation_methods.keys()):
207
  print("\nThank you for using Kudasai, goodbye.")
 
216
  Translator.TRANSLATION_METHOD, api_key_path = translation_methods.get(method, ("deepl", FileEnsurer.deepl_api_key_path))
217
 
218
  if(Translator.pre_provided_api_key != ""):
219
+ if(Translator.TRANSLATION_METHOD == "google translate"):
220
+ encoded_key = base64.b64encode(Translator.pre_provided_api_key.encode('utf-8')).decode('utf-8')
221
+
222
+ else:
223
+ encoded_key = Translator.pre_provided_api_key
224
+
225
  Translator.pre_provided_api_key = ""
226
+
227
  with open(api_key_path, 'w+', encoding='utf-8') as file:
228
  file.write(encoded_key)
229
 
 
256
 
257
  """
258
 
259
+ def get_api_key_from_file():
260
+ with open(api_key_path, 'r', encoding='utf-8') as file:
261
+ return base64.b64decode((file.read()).encode('utf-8')).decode('utf-8')
262
+
263
+ def save_api_key(api_key):
264
+ if(service != "Google translate"):
265
+ encoded_key = base64.b64encode(api_key.encode('utf-8')).decode('utf-8')
266
+ FileEnsurer.standard_overwrite_file(api_key_path, encoded_key, omit=True)
267
+ else:
268
+ FileEnsurer.standard_overwrite_file(api_key_path, api_key, omit=True)
269
+
270
  ## get saved API key if exists
271
  try:
272
+
273
+ if(service != "Google translate"):
274
+ api_key = get_api_key_from_file()
275
+ else:
276
+ api_key = api_key_path
277
 
278
  api_key_setter(service.lower(), api_key)
279
 
280
+ is_valid, e = api_key_tester(service.lower())
281
 
282
  ## if not valid, raise the exception that caused the test to fail
283
  if(not is_valid and e is not None):
 
291
  except:
292
 
293
  Toolkit.clear_console()
294
+
295
+ input_message = (
296
+ f"DO NOT DELETE YOUR COPY OF THE API KEY\n\nPlease enter the {service} API key you have : "
297
+ if(service != "Google translate")
298
+ else "DO NOT DELETE YOUR COPY OF THE SERVICE JSON\n\nPlease enter the contents of the service json file (on one line): "
299
+ )
300
 
301
+ api_key = input(input_message).strip('"').strip("'").strip()
302
+
303
+ ## preemptively save the api key for google translate
304
+ if(service == "Google translate"):
305
+ save_api_key(api_key)
306
+ time.sleep(1)
307
+ api_key = api_key_path
308
 
 
309
  try:
310
 
311
  api_key_setter(service.lower(), api_key)
312
 
313
+ is_valid, e = api_key_tester(service.lower())
314
 
315
  if(not is_valid and e is not None):
316
  raise e
317
+
318
+ save_api_key(api_key)
319
 
320
  ## if invalid key exit
321
  except (GoogleAuthError, OpenAIAuthenticationError, DeepLAuthorizationException):
 
359
  Translator.gemini_translation_batches = []
360
  Translator.num_occurred_malformed_batches = 0
361
  Translator.translation_print_result = ""
362
+ Translator.TRANSLATION_METHOD = "deepl"
363
  Translator.pre_provided_api_key = ""
364
  Translator.is_cli = False
365
 
 
374
 
375
  """
376
 
377
+ print("Are these settings okay? (1 for yes or 2 for no):")
378
 
379
  method_to_section_dict = {
380
  "openai": ("openai settings", "OpenAI", FileEnsurer.openai_api_key_path),
381
  "gemini": ("gemini settings", "Gemini", FileEnsurer.gemini_api_key_path),
382
+ "deepl": ("deepl settings", "DeepL", FileEnsurer.deepl_api_key_path),
383
+ "google translate": (None, None, FileEnsurer.google_translate_service_key_json_path)
384
  }
385
 
386
  section_to_target, method_name, api_key_path = method_to_section_dict[Translator.TRANSLATION_METHOD]
 
397
  JsonHandler.reset_translation_settings_to_default()
398
  JsonHandler.load_translation_settings()
399
 
400
+ print("Are these settings okay? (1 for yes or 2 for no) : \n")
401
  JsonHandler.log_translation_settings(output_to_console=True, specific_section=section_to_target)
402
  else:
403
  FileEnsurer.exit_kudasai()
 
475
  exception_dict = {
476
  "openai": (OpenAIAuthenticationError, OpenAIInternalServerError, OpenAIRateLimitError, OpenAIAPITimeoutError, OpenAIAPIConnectionError, OpenAIAPIStatusError),
477
  "gemini": GoogleAPIError,
478
+ "deepl": DeepLException,
479
+ "google translate": GoogleAPIError
480
  }
481
 
482
  Translator.decorator_to_use = backoff.on_exception(
 
497
  translation_methods = {
498
  "openai": JsonHandler.current_translation_settings["openai settings"]["openai_model"],
499
  "gemini": JsonHandler.current_translation_settings["gemini settings"]["gemini_model"],
500
+ "deepl": "deepl",
501
+ "google translate": "google translate"
502
  }
503
 
504
  model = translation_methods[Translator.TRANSLATION_METHOD]
 
550
  """
551
 
552
  async_requests = []
553
+
554
  translation_batches_methods = {
555
  "openai": Translator.openai_translation_batches,
556
  "gemini": Translator.gemini_translation_batches,
557
+ "deepl": Translator.deepl_translation_batches,
558
+ "google translate": Translator.google_translate_translation_batches
559
  }
560
+
561
  translation_batches = translation_batches_methods[Translator.TRANSLATION_METHOD]
562
  batch_length = len(translation_batches)
563
+ batch_number = 1 # Initialize batch number
 
564
 
565
+ if(Translator.TRANSLATION_METHOD not in ["deepl", "google translate"]):
566
  for i in range(0, batch_length, 2):
567
  instructions = translation_batches[i]
568
+ prompt = translation_batches[i + 1]
569
+
570
  assert isinstance(instructions, (SystemTranslationMessage, str))
571
  assert isinstance(prompt, (ModelTranslationMessage, str))
572
+
573
+ async_requests.append(Translator.handle_translation(model, batch_number, batch_length//2, prompt, instructions))
574
+ batch_number += 1
575
 
576
  else:
577
  for i, batch in enumerate(translation_batches):
 
578
  assert isinstance(batch, str)
579
+
580
+ async_requests.append(Translator.handle_translation(model, batch_number, batch_length, batch, None))
581
+ batch_number += 1
582
+
583
  return async_requests
584
 
585
  ##-------------------start-of-generate_text_to_translate_batches()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 
619
  if(len(prompt) < Translator.number_of_lines_per_batch):
620
  if(is_special_char or is_part_in_sentence or is_part_char):
621
  prompt.append(f'{sentence}\n')
622
+ logging.debug(f"Sentence : {sentence} Sentence is a pov change or part marker... adding to prompt.")
623
 
624
  elif(non_word_pattern.match(sentence) or KatakanaUtil.is_punctuation(sentence) and not has_quotes):
625
+ logging.debug(f"Sentence : {sentence} Sentence is punctuation or spacing... skipping.")
626
 
627
  elif(sentence):
628
  prompt.append(f'{sentence}\n')
629
+ logging.debug(f"Sentence : {sentence} Sentence is a valid sentence... adding to prompt.")
630
  else:
631
  return prompt, index
632
 
 
667
  Translator.gemini_translation_batches.append(Translator.gemini_prompt)
668
  Translator.gemini_translation_batches.append(batch)
669
 
670
+ elif(Translator.TRANSLATION_METHOD == 'deepl'):
671
  Translator.deepl_translation_batches.append(batch)
672
 
673
+ elif(Translator.TRANSLATION_METHOD == 'google translate'):
674
+ Translator.google_translate_translation_batches.append(batch)
675
+
676
  logging_message = "Built Messages: \n\n"
677
 
678
  batches_to_iterate = {
679
  "openai": Translator.openai_translation_batches,
680
  "gemini": Translator.gemini_translation_batches,
681
+ "deepl": Translator.deepl_translation_batches,
682
+ "google translate": Translator.google_translate_translation_batches
683
  }
684
 
685
  i = 0
 
692
 
693
  message = str(message) if Translator.TRANSLATION_METHOD != 'openai' else message.content # type: ignore
694
 
695
+ if(i % 2 == 1 and Translator.TRANSLATION_METHOD not in ['deepl', 'google_translate']):
696
  logging_message += "\n" "------------------------" "\n"
697
 
698
  logging_message += message + "\n"
 
721
  "openai": Translator.openai_system_message,
722
  "gemini": Translator.gemini_prompt,
723
  "deepl": None,
724
+ "google translate": None
725
  }
726
 
727
  translation_instructions = translation_instructions_methods[Translator.TRANSLATION_METHOD]
 
734
  if(Translator.TRANSLATION_METHOD == "gemini"):
735
  logging.info(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 the translation settings.")
736
 
737
+ entity_word = "tokens" if Translator.TRANSLATION_METHOD in ["openai", "gemini"] else "characters"
738
+
739
  logging.info("Estimated number of tokens : " + str(num_tokens))
740
  logging.info("Estimated minimum cost : " + str(min_cost) + " USD")
741
 
 
753
 
754
  @staticmethod
755
  async def handle_translation(model:str,
756
+ batch_number:int,
757
  length_of_batch:int,
758
  text_to_translate:typing.Union[str, ModelTranslationMessage],
759
  translation_instructions:typing.Union[str, SystemTranslationMessage, None]) -> tuple[int, str, str]:
 
764
 
765
  Parameters:
766
  model (string) : The model of the service used to translate the text.
767
+ batch_number (int) : Which batch we are currently on.
768
  length_of_batch (int) : How long the batches are.
769
  text_to_translate (typing.Union[str, ModelTranslationMessage]) : The text to translate.
770
  translation_instructions (typing.Union[str, SystemTranslationMessage, None]) : The translation instructions.
771
 
772
  Returns:
773
+ batch_number (int) : The batch index.
774
  text_to_translate (str) : The text to translate.
775
  translated_text (str) : The translated text
776
 
 
785
  ## For the webgui
786
  if(FileEnsurer.do_interrupt == True):
787
  raise Exception("Interrupted by user.")
788
+
789
+ logging.info(f"Trying translation for batch {batch_number} of {length_of_batch}...")
 
 
790
 
791
  try:
792
 
793
  translation_methods = {
794
  "openai": EasyTL.openai_translate_async,
795
  "gemini": EasyTL.gemini_translate_async,
796
+ "deepl": EasyTL.deepl_translate_async,
797
+ "google translate": EasyTL.googletl_translate_async
798
  }
799
 
800
  translation_params = {
 
827
  "split_sentences": Translator.deepl_split_sentences,
828
  "preserve_formatting": Translator.deepl_preserve_formatting,
829
  "formality": Translator.deepl_formality
830
+ },
831
+ "google translate": {
832
+ "text": text_to_translate,
833
+ "decorator": Translator.decorator_to_use
834
  }
835
  }
836
 
 
841
  ## will only occur if the max_batch_duration is exceeded, so we just return the untranslated text
842
  except MaxBatchDurationExceededException:
843
 
844
+ logging.error(f"Batch {batch_number} of {length_of_batch} was not translated due to exceeding the max request duration, returning the untranslated text...")
845
  break
846
 
847
  ## do not even bother if not a gpt 4 model, because gpt-3 seems unable to format properly
 
854
  break
855
 
856
  if(num_tries >= Translator.num_of_malform_retries):
857
+ logging.warning(f"Batch {batch_number} of {length_of_batch} was malformed but exceeded the max number of retries ({Translator.num_of_malform_retries})")
858
  break
859
 
860
  else:
861
  num_tries += 1
862
+ logging.warning(f"Batch {batch_number} of {length_of_batch} was malformed, retrying...")
863
  Translator.num_occurred_malformed_batches += 1
864
 
865
  if(isinstance(text_to_translate, ModelTranslationMessage)):
 
868
  if(isinstance(translated_message, typing.List)):
869
  translated_message = ''.join(translated_message) # type: ignore
870
 
871
+ logging.info(f"Translation for batch {batch_number} of {length_of_batch} completed.")
872
 
873
+ return batch_number, text_to_translate, translated_message # type: ignore
874
 
875
  ##-------------------start-of-check_if_translation_is_good()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
876
 
 
967
  index = patched_sentences.index(Translator.translated_text[i])
968
  Translator.translated_text[i] = patched_sentences[index]
969
 
970
+ ## mode 2 just assumes the translation method formatted it properly
971
  elif(Translator.sentence_fragmenter_mode == 2):
972
 
973
  Translator.translated_text.append(translated_message + '\n\n')
requirements.txt CHANGED
@@ -1,5 +1,5 @@
1
  backoff==2.2.1
2
  gradio==4.20.0
3
- kairyou==1.5.0
4
- easytl==0.4.0-alpha-2
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
 
1
  backoff==2.2.1
2
  gradio==4.20.0
3
+ kairyou==1.6.1
4
+ easytl==0.4.0-alpha-3
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
webgui.py CHANGED
@@ -1,6 +1,7 @@
1
  ## built-in libraries
2
  import typing
3
  import base64
 
4
 
5
  ## third-party libraries
6
  import gradio as gr
@@ -123,7 +124,7 @@ class KudasaiGUI:
123
  ##-------------------start-of-get_saved_api_key()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
124
 
125
  @staticmethod
126
- def get_saved_api_key(service_name:typing.Literal["openai","gemini","deepl"]) -> str:
127
 
128
  """
129
  Gets the saved api key from the config folder, if it exists.
@@ -139,13 +140,16 @@ class KudasaiGUI:
139
  service_to_path = {
140
  "openai": FileEnsurer.openai_api_key_path,
141
  "gemini": FileEnsurer.gemini_api_key_path,
142
- "deepl": FileEnsurer.deepl_api_key_path
 
143
  }
144
 
145
  api_key_path = service_to_path.get(service_name, "")
146
 
147
 
148
  try:
 
 
149
  ## Api key is encoded in base 64 so we need to decode it before returning
150
  return base64.b64decode(FileEnsurer.standard_read_file(api_key_path).encode('utf-8')).decode('utf-8')
151
 
@@ -165,6 +169,11 @@ class KudasaiGUI:
165
 
166
  """
167
 
 
 
 
 
 
168
  try:
169
 
170
  EasyTL.set_credentials(Translator.TRANSLATION_METHOD, str(api_key))
@@ -193,14 +202,18 @@ class KudasaiGUI:
193
  method_to_path = {
194
  "openai": FileEnsurer.openai_api_key_path,
195
  "gemini": FileEnsurer.gemini_api_key_path,
196
- "deepl": FileEnsurer.deepl_api_key_path
 
197
  }
198
 
199
  path_to_api_key = method_to_path.get(Translator.TRANSLATION_METHOD, None)
200
 
201
  assert path_to_api_key is not None, "Invalid translation method"
202
 
203
- FileEnsurer.standard_overwrite_file(path_to_api_key, base64.b64encode(str(api_key).encode('utf-8')).decode('utf-8'), omit=True)
 
 
 
204
 
205
  ##-------------------start-of-create_new_key_value_tuple_pairs()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
206
 
@@ -353,10 +366,10 @@ class KudasaiGUI:
353
  self.input_translation_rules_file = gr.File(value = FileEnsurer.config_translation_settings_path, label='Translation Settings File', file_count='single', file_types=['.json'], type='filepath')
354
 
355
  with gr.Row():
356
- self.llm_option_dropdown = gr.Dropdown(label='Translation Method', choices=["OpenAI", "Gemini", "DeepL"], value="OpenAI", show_label=True, interactive=True)
357
 
358
  with gr.Row():
359
- self.translator_api_key_input = gr.Textbox(label='API Key', value=get_saved_api_key("openai"), lines=1, max_lines=2, show_label=True, interactive=True, type='password')
360
 
361
  with gr.Row():
362
  self.translator_translate_button = gr.Button('Translate', variant="primary")
@@ -390,7 +403,7 @@ class KudasaiGUI:
390
 
391
  with gr.Column():
392
  gr.Markdown("Base Translation Settings")
393
- gr.Markdown("These settings are used for OpenAI, Gemini, and DeepL.")
394
  gr.Markdown("Please ensure to thoroughly read and understand these settings before making any modifications. Each setting has a specific impact on the translation methods. Some settings may affect one or two translation methods, but not the others. Incorrect adjustments could lead to unexpected results or errors in the translation process.")
395
 
396
 
@@ -931,9 +944,12 @@ class KudasaiGUI:
931
  elif(translation_method == "Gemini"):
932
  Translator.TRANSLATION_METHOD = "gemini"
933
 
934
- else:
935
  Translator.TRANSLATION_METHOD = "deepl"
936
 
 
 
 
937
  ## api key as well
938
  await set_translator_api_key(api_key)
939
 
@@ -988,13 +1004,7 @@ class KudasaiGUI:
988
 
989
  if(input_txt_file is None and input_text == ""):
990
  raise gr.Error("No TXT file or text selected")
991
-
992
- if(api_key == "" and translation_method not in ["OpenAI","DeepL"]):
993
- raise gr.Error("No API key provided. Does not charge for cost estimation, but is required for Gemini Cost Calculation")
994
-
995
- if(Kudasai.connection == False and translation_method != "OpenAI"):
996
- raise gr.Error("No internet connection detected, please connect to the internet and reload the page to calculate costs for Gemini")
997
-
998
  if(translation_settings_file is None):
999
  raise gr.Error("No Translation Settings File selected")
1000
 
@@ -1005,12 +1015,11 @@ class KudasaiGUI:
1005
 
1006
  Translator.TRANSLATION_METHOD = str(translation_method.lower()) # type: ignore
1007
 
1008
- await set_translator_api_key(api_key)
1009
-
1010
  translation_methods = {
1011
  "openai": GuiJsonUtil.fetch_translation_settings_key_values("openai settings","openai_model"),
1012
  "gemini": GuiJsonUtil.fetch_translation_settings_key_values("gemini settings","gemini_model"),
1013
- "deepl": "deep"
 
1014
  }
1015
 
1016
  model = translation_methods.get(Translator.TRANSLATION_METHOD)
@@ -1024,7 +1033,8 @@ class KudasaiGUI:
1024
  translation_instructions_dict = {
1025
  "openai": GuiJsonUtil.fetch_translation_settings_key_values("openai settings","openai_system_message"),
1026
  "gemini": GuiJsonUtil.fetch_translation_settings_key_values("gemini settings","gemini_prompt"),
1027
- "deepl": None
 
1028
  }
1029
 
1030
  translation_instructions = translation_instructions_dict.get(Translator.TRANSLATION_METHOD)
@@ -1034,9 +1044,9 @@ class KudasaiGUI:
1034
  if(Translator.TRANSLATION_METHOD == "gemini"):
1035
  cost_estimation = 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.\nIt is up to you to set these in the settings json.\n"
1036
 
1037
- token_type = "characters" if Translator.TRANSLATION_METHOD == "deepl" else "tokens"
1038
 
1039
- cost_estimation += f"Estimated number of {token_type} : {num_tokens}\nEstimated minimum cost : {estimated_cost} USD\nThis is a rough estimate, please remember to check actual cost on the appropriate platform when needed"
1040
 
1041
  gr.Info(cost_estimation)
1042
 
 
1
  ## built-in libraries
2
  import typing
3
  import base64
4
+ import asyncio
5
 
6
  ## third-party libraries
7
  import gradio as gr
 
124
  ##-------------------start-of-get_saved_api_key()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
125
 
126
  @staticmethod
127
+ def get_saved_api_key(service_name:typing.Literal["openai","gemini","deepl","google translate"]) -> str:
128
 
129
  """
130
  Gets the saved api key from the config folder, if it exists.
 
140
  service_to_path = {
141
  "openai": FileEnsurer.openai_api_key_path,
142
  "gemini": FileEnsurer.gemini_api_key_path,
143
+ "deepl": FileEnsurer.deepl_api_key_path,
144
+ "google_translate": FileEnsurer.google_translate_service_key_json_path
145
  }
146
 
147
  api_key_path = service_to_path.get(service_name, "")
148
 
149
 
150
  try:
151
+ if(service_name == "google translate"):
152
+ return api_key_path
153
  ## Api key is encoded in base 64 so we need to decode it before returning
154
  return base64.b64decode(FileEnsurer.standard_read_file(api_key_path).encode('utf-8')).decode('utf-8')
155
 
 
169
 
170
  """
171
 
172
+ if(Translator.TRANSLATION_METHOD == "google translate"):
173
+ FileEnsurer.standard_overwrite_file(FileEnsurer.google_translate_service_key_json_path, str(api_key), omit=True)
174
+ await asyncio.sleep(2)
175
+ api_key = FileEnsurer.google_translate_service_key_json_path
176
+
177
  try:
178
 
179
  EasyTL.set_credentials(Translator.TRANSLATION_METHOD, str(api_key))
 
202
  method_to_path = {
203
  "openai": FileEnsurer.openai_api_key_path,
204
  "gemini": FileEnsurer.gemini_api_key_path,
205
+ "deepl": FileEnsurer.deepl_api_key_path,
206
+ "google translate": FileEnsurer.google_translate_service_key_json_path
207
  }
208
 
209
  path_to_api_key = method_to_path.get(Translator.TRANSLATION_METHOD, None)
210
 
211
  assert path_to_api_key is not None, "Invalid translation method"
212
 
213
+ if(Translator.TRANSLATION_METHOD != "google translate"):
214
+ api_key = base64.b64encode(str(api_key).encode('utf-8')).decode('utf-8')
215
+
216
+ FileEnsurer.standard_overwrite_file(path_to_api_key, str(api_key), omit=True)
217
 
218
  ##-------------------start-of-create_new_key_value_tuple_pairs()---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
219
 
 
366
  self.input_translation_rules_file = gr.File(value = FileEnsurer.config_translation_settings_path, label='Translation Settings File', file_count='single', file_types=['.json'], type='filepath')
367
 
368
  with gr.Row():
369
+ self.llm_option_dropdown = gr.Dropdown(label='Translation Method', choices=["OpenAI", "Gemini", "DeepL", "Google Translate"], value="DeepL", show_label=True, interactive=True)
370
 
371
  with gr.Row():
372
+ self.translator_api_key_input = gr.Textbox(label='API Key', value=get_saved_api_key("deepl"), lines=1, max_lines=1, show_label=True, interactive=True, type='password')
373
 
374
  with gr.Row():
375
  self.translator_translate_button = gr.Button('Translate', variant="primary")
 
403
 
404
  with gr.Column():
405
  gr.Markdown("Base Translation Settings")
406
+ gr.Markdown("These settings are used for OpenAI, Gemini, DeepL, and Google Translate")
407
  gr.Markdown("Please ensure to thoroughly read and understand these settings before making any modifications. Each setting has a specific impact on the translation methods. Some settings may affect one or two translation methods, but not the others. Incorrect adjustments could lead to unexpected results or errors in the translation process.")
408
 
409
 
 
944
  elif(translation_method == "Gemini"):
945
  Translator.TRANSLATION_METHOD = "gemini"
946
 
947
+ elif(translation_method == "DeepL"):
948
  Translator.TRANSLATION_METHOD = "deepl"
949
 
950
+ elif(translation_method == "Google Translate"):
951
+ Translator.TRANSLATION_METHOD = "google translate"
952
+
953
  ## api key as well
954
  await set_translator_api_key(api_key)
955
 
 
1004
 
1005
  if(input_txt_file is None and input_text == ""):
1006
  raise gr.Error("No TXT file or text selected")
1007
+
 
 
 
 
 
 
1008
  if(translation_settings_file is None):
1009
  raise gr.Error("No Translation Settings File selected")
1010
 
 
1015
 
1016
  Translator.TRANSLATION_METHOD = str(translation_method.lower()) # type: ignore
1017
 
 
 
1018
  translation_methods = {
1019
  "openai": GuiJsonUtil.fetch_translation_settings_key_values("openai settings","openai_model"),
1020
  "gemini": GuiJsonUtil.fetch_translation_settings_key_values("gemini settings","gemini_model"),
1021
+ "deepl": "deepl",
1022
+ "google translate": "google translate"
1023
  }
1024
 
1025
  model = translation_methods.get(Translator.TRANSLATION_METHOD)
 
1033
  translation_instructions_dict = {
1034
  "openai": GuiJsonUtil.fetch_translation_settings_key_values("openai settings","openai_system_message"),
1035
  "gemini": GuiJsonUtil.fetch_translation_settings_key_values("gemini settings","gemini_prompt"),
1036
+ "deepl": None,
1037
+ "google translate": None
1038
  }
1039
 
1040
  translation_instructions = translation_instructions_dict.get(Translator.TRANSLATION_METHOD)
 
1044
  if(Translator.TRANSLATION_METHOD == "gemini"):
1045
  cost_estimation = 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.\nIt is up to you to set these in the settings json.\n"
1046
 
1047
+ entity_type = "characters" if Translator.TRANSLATION_METHOD in ["deepl", "google translate"] else "tokens"
1048
 
1049
+ cost_estimation += f"Estimated number of {entity_type} : {num_tokens}\nEstimated minimum cost : {estimated_cost} USD\nThis is a rough estimate, please remember to check actual cost on the appropriate platform when needed"
1050
 
1051
  gr.Info(cost_estimation)
1052