moved to v3.4.6
Browse files- README.md +5 -3
- handlers/json_handler.py +6 -1
- kudasai.py +12 -10
- lib/gui/HUGGING_FACE_README.md +5 -3
- modules/common/file_ensurer.py +1 -0
- modules/common/toolkit.py +1 -1
- modules/common/translator.py +102 -52
- requirements.txt +2 -2
- webgui.py +31 -21
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
|
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
|
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.
|
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
|
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"] = "
|
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 |
-
|
|
|
|
|
|
|
|
|
|
|
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 |
-
|
252 |
-
|
|
|
|
|
|
|
253 |
|
254 |
api_key_setter(service.lower(), api_key)
|
255 |
|
256 |
-
is_valid, e =
|
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(
|
|
|
|
|
|
|
|
|
|
|
|
|
272 |
|
273 |
-
## if valid save the API key
|
274 |
try:
|
275 |
|
276 |
api_key_setter(service.lower(), api_key)
|
277 |
|
278 |
-
is_valid, e =
|
279 |
|
280 |
if(not is_valid and e is not None):
|
281 |
raise e
|
282 |
-
|
283 |
-
|
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 = "
|
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)
|
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
|
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,
|
|
|
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,
|
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}
|
583 |
|
584 |
elif(non_word_pattern.match(sentence) or KatakanaUtil.is_punctuation(sentence) and not has_quotes):
|
585 |
-
logging.debug(f"Sentence : {sentence}
|
586 |
|
587 |
elif(sentence):
|
588 |
prompt.append(f'{sentence}\n')
|
589 |
-
logging.debug(f"Sentence : {sentence}
|
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 |
-
|
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
|
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 |
-
|
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 |
-
|
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 |
-
|
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 |
-
|
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
|
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
|
808 |
break
|
809 |
|
810 |
else:
|
811 |
num_tries += 1
|
812 |
-
logging.warning(f"Batch {batch_number} of {length_of_batch
|
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
|
822 |
|
823 |
-
return
|
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
|
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.
|
4 |
-
easytl==0.4.0-alpha-
|
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 |
-
|
|
|
|
|
|
|
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="
|
357 |
|
358 |
with gr.Row():
|
359 |
-
self.translator_api_key_input = gr.Textbox(label='API Key', value=get_saved_api_key("
|
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
|
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 |
-
|
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": "
|
|
|
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 |
-
|
1038 |
|
1039 |
-
cost_estimation += f"Estimated number of {
|
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 |
|