From 224eaf3cef18dd68e873b6b6a22c6350057ed979 Mon Sep 17 00:00:00 2001 From: misyaguziya <53165965+misyaguziya@users.noreply.github.com> Date: Mon, 15 Sep 2025 17:42:09 +0900 Subject: [PATCH] [Add] translation_gemini: Integrate Gemini translation model and authentication; [Update] controller: Implement methods for managing Gemini models and auth keys; [Update] mainloop: Add routes for Gemini model and auth key management; [Update] translation: Enhance Translator class for Gemini API support; [Update] translation_languages: Add Gemini language mappings --- src-python/config.py | 20 +++++ src-python/controller.py | 84 +++++++++++++++++++ src-python/mainloop.py | 6 ++ src-python/model.py | 4 + .../models/translation/translation_gemini.py | 82 +++++++++++------- .../translation/translation_languages.py | 47 +++++++++++ .../translation/translation_translator.py | 23 +++++ 7 files changed, 234 insertions(+), 32 deletions(-) diff --git a/src-python/config.py b/src-python/config.py index 7fec780f..5b425a38 100644 --- a/src-python/config.py +++ b/src-python/config.py @@ -10,6 +10,7 @@ from device_manager import device_manager from models.translation.translation_languages import translation_lang from models.translation.translation_utils import ctranslate2_weights from models.translation.translation_plamo import _MODELS as plamo_models +from models.translation.translation_gemini import _MODELS as gemini_models from models.transcription.transcription_languages import transcription_lang from models.transcription.transcription_whisper import _MODELS as whisper_models from utils import errorLogging, validateDictStructure @@ -124,6 +125,10 @@ class Config: def SELECTABLE_PLAMO_MODEL_LIST(self): return self._SELECTABLE_PLAMO_MODEL_LIST + @property + def SELECTABLE_GEMINI_MODEL_LIST(self): + return self._SELECTABLE_GEMINI_MODEL_LIST + @property def SELECTABLE_TRANSCRIPTION_ENGINE_LIST(self): return self._SELECTABLE_TRANSCRIPTION_ENGINE_LIST @@ -843,6 +848,18 @@ class Config: self._PLAMO_MODEL = value self.saveConfig(inspect.currentframe().f_code.co_name, value) + @property + @json_serializable('GEMINI_MODEL') + def GEMINI_MODEL(self): + return self._GEMINI_MODEL + + @GEMINI_MODEL.setter + def GEMINI_MODEL(self, value): + if isinstance(value, str): + if value in self.SELECTABLE_GEMINI_MODEL_LIST: + self._GEMINI_MODEL = value + self.saveConfig(inspect.currentframe().f_code.co_name, value) + @property @json_serializable('AUTO_CLEAR_MESSAGE_BOX') def AUTO_CLEAR_MESSAGE_BOX(self): @@ -1061,6 +1078,7 @@ class Config: self._SELECTABLE_WHISPER_WEIGHT_TYPE_LIST = whisper_models.keys() self._SELECTABLE_TRANSLATION_ENGINE_LIST = translation_lang.keys() self._SELECTABLE_PLAMO_MODEL_LIST = plamo_models + self._SELECTABLE_GEMINI_MODEL_LIST = gemini_models self._SELECTABLE_TRANSCRIPTION_ENGINE_LIST = list(transcription_lang[list(transcription_lang.keys())[0]].values())[0].keys() self._SELECTABLE_UI_LANGUAGE_LIST = ["en", "ja", "ko", "zh-Hant", "zh-Hans"] self._COMPUTE_MODE = "cuda" if torch.cuda.is_available() else "cpu" @@ -1203,6 +1221,7 @@ class Config: self._AUTH_KEYS = { "DeepL_API": None, "Plamo_API": None, + "Gemini_API": None, } self._USE_EXCLUDE_WORDS = True self._SELECTED_TRANSLATION_COMPUTE_DEVICE = copy.deepcopy(self.SELECTABLE_COMPUTE_DEVICE_LIST[0]) @@ -1210,6 +1229,7 @@ class Config: self._CTRANSLATE2_WEIGHT_TYPE = "m2m100_418M-ct2-int8" self._WHISPER_WEIGHT_TYPE = "base" self._PLAMO_MODEL = "plamo-2.0-prime" + self._GEMINI_MODEL = "gemini-2.5-flash-lite" self._AUTO_CLEAR_MESSAGE_BOX = True self._SEND_ONLY_TRANSLATED_MESSAGES = False self._OVERLAY_SMALL_LOG = False diff --git a/src-python/controller.py b/src-python/controller.py index bbc32e13..abb4605c 100644 --- a/src-python/controller.py +++ b/src-python/controller.py @@ -1515,6 +1515,90 @@ class Controller: self.updateTranslationEngineAndEngineList() return {"status":200, "result":config.AUTH_KEYS[translator_name]} + def getGeminiModelList(self, *args, **kwargs) -> dict: + return {"status":200, "result": config.SELECTABLE_GEMINI_MODEL_LIST} + + def setGeminiModel(self, data, *args, **kwargs) -> dict: + printLog("Set Gemini Model", data) + try: + data = str(data) + result = model.authenticationTranslatorGeminiAuthKey(auth_key=config.AUTH_KEYS["Gemini_API"], model_name=data) + if result is True: + config.GEMINI_MODEL = data + response = {"status":200, "result":config.GEMINI_MODEL} + else: + response = { + "status":400, + "result":{ + "message":"Gemini model is not valid", + "data": config.GEMINI_MODEL + } + } + except Exception as e: + errorLogging() + response = { + "status":400, + "result":{ + "message":f"Error {e}", + "data": config.GEMINI_MODEL + } + } + return response + + def getGeminiAuthKey(self, *args, **kwargs) -> dict: + return {"status":200, "result":config.AUTH_KEYS["Gemini_API"]} + + def setGeminiAuthKey(self, data, *args, **kwargs) -> dict: + printLog("Set Gemini Auth Key", data) + translator_name = "Gemini_API" + try: + data = str(data) + if len(data) >= 20: + result = model.authenticationTranslatorGeminiAuthKey(auth_key=data, model_name=config.GEMINI_MODEL) + if result is True: + key = data + auth_keys = config.AUTH_KEYS + auth_keys[translator_name] = key + config.AUTH_KEYS = auth_keys + config.SELECTABLE_TRANSLATION_ENGINE_STATUS[translator_name] = True + self.updateTranslationEngineAndEngineList() + response = {"status":200, "result":config.AUTH_KEYS[translator_name]} + else: + response = { + "status":400, + "result":{ + "message":"Authentication failure of gemini auth key", + "data": config.AUTH_KEYS[translator_name] + } + } + else: + response = { + "status":400, + "result":{ + "message":"Gemini auth key length is not correct", + "data": config.AUTH_KEYS[translator_name] + } + } + except Exception as e: + errorLogging() + response = { + "status":400, + "result":{ + "message":f"Error {e}", + "data": config.AUTH_KEYS[translator_name] + } + } + return response + + def delGeminiAuthKey(self, *args, **kwargs) -> dict: + translator_name = "Gemini_API" + auth_keys = config.AUTH_KEYS + auth_keys[translator_name] = None + config.AUTH_KEYS = auth_keys + config.SELECTABLE_TRANSLATION_ENGINE_STATUS[translator_name] = False + self.updateTranslationEngineAndEngineList() + return {"status":200, "result":config.AUTH_KEYS[translator_name]} + @staticmethod def getCtranslate2WeightType(*args, **kwargs) -> dict: return {"status":200, "result":config.CTRANSLATE2_WEIGHT_TYPE} diff --git a/src-python/mainloop.py b/src-python/mainloop.py index b44469f9..f6b52afa 100644 --- a/src-python/mainloop.py +++ b/src-python/mainloop.py @@ -174,6 +174,12 @@ mapping = { "/set/data/plamo_auth_key": {"status": False, "variable":controller.setPlamoAuthKey}, "/delete/data/plamo_auth_key": {"status": False, "variable":controller.delPlamoAuthKey}, + "/get/data/gemini_model_list": {"status": True, "variable":controller.getGeminiModelList}, + "/set/data/gemini_model": {"status": True, "variable":controller.setGeminiModel}, + "/get/data/gemini_auth_key": {"status": True, "variable":controller.getGeminiAuthKey}, + "/set/data/gemini_auth_key": {"status": True, "variable":controller.setGeminiAuthKey}, + "/delete/data/gemini_auth_key": {"status": True, "variable":controller.delGeminiAuthKey}, + "/get/data/convert_message_to_romaji": {"status": True, "variable":controller.getConvertMessageToRomaji}, "/set/enable/convert_message_to_romaji": {"status": True, "variable":controller.setEnableConvertMessageToRomaji}, "/set/disable/convert_message_to_romaji": {"status": True, "variable":controller.setDisableConvertMessageToRomaji}, diff --git a/src-python/model.py b/src-python/model.py index 9c2394a1..e99aeaa5 100644 --- a/src-python/model.py +++ b/src-python/model.py @@ -144,6 +144,10 @@ class Model: result = self.translator.authenticationPlamoAuthKey(auth_key, model=model) return result + def authenticationTranslatorGeminiAuthKey(self, auth_key: str, model: str) -> bool: + result = self.translator.authenticationGeminiAuthKey(auth_key, model=model) + return result + def startLogger(self): os_makedirs(config.PATH_LOGS, exist_ok=True) file_name = os_path.join(config.PATH_LOGS, f"{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.log") diff --git a/src-python/models/translation/translation_gemini.py b/src-python/models/translation/translation_gemini.py index 51f43933..225f495a 100644 --- a/src-python/models/translation/translation_gemini.py +++ b/src-python/models/translation/translation_gemini.py @@ -1,10 +1,14 @@ +import logging from langchain_google_genai import ChatGoogleGenerativeAI from langchain_core.messages import HumanMessage +logger = logging.getLogger("langchain_google_genai") +logger.setLevel(logging.ERROR) + _MODELS = [ "gemini-2.5-pro", "gemini-2.5-flash", - "gemini-2.5-flash-lite", + "gemini-2.5-flash-lite", # default "gemini-2.0-flash", "gemini-2.0-flash-lite", "gemini-1.5-pro", @@ -13,7 +17,7 @@ _MODELS = [ ] class GeminiClient: - def __init__(self, api_key: str = "", model: str = "gemini-2.5-flash"): + def __init__(self, api_key: str = "", model: str = "gemini-2.5-flash-lite"): self.api_key = api_key self.model = model self.prompt_template = """ @@ -93,7 +97,7 @@ if __name__ == "__main__": input_lang = "Japanese" output_lang = "English" - gemini_client = GeminiClient(api_key=AUTH_KEY, model="gemini-1.5-flash") + gemini_client = GeminiClient(api_key=AUTH_KEY, model="gemini-2.5-flash-lite") print("model list:", gemini_client.getListModels()) print("AuthKey:", gemini_client.getAuthKey()) @@ -110,41 +114,55 @@ if __name__ == "__main__": supported_languages = """ - English - Japanese - Korean - French - German - Spanish - Portuguese - Russian - Italian - Dutch - Polish - Turkish Arabic - Hindi - Thai - Vietnamese - Indonesian - Malay - Filipino - Swedish - Finnish - Danish - Norwegian - Romanian - Czech - Hungarian - Greek - Hebrew + Bengali + Bulgarian Simplified Chinese Traditional Chinese + Croatian + Czech + Danish + Dutch + English + Estonian + Finnish + French + German + Greek + Hebrew + Hindi + Hungarian + Indonesian + Italian + Japanese + Korean + Latvian + Lithuanian + Norwegian + Polish + Portuguese + Romanian + Russian + Serbian + Slovak + Slovenian + Spanish + Swahili + Swedish + Thai + Turkish + Ukrainian + Vietnamese """ for lang in supported_languages.split("\n"): if lang == "": continue print (f"Translating to {lang}:") - translated_text = gemini_client.translate(text, input_lang, lang) - print(f"Translated text: {translated_text}") + try: + translated_text = gemini_client.translate(text, input_lang, lang) + print(f"Translated text: {translated_text}") + except Exception as e: + print(f"Error translating to {lang} api limit") + print(f"Error reason: {e}") + break \ No newline at end of file diff --git a/src-python/models/translation/translation_languages.py b/src-python/models/translation/translation_languages.py index f3f334ae..de6ae5f8 100644 --- a/src-python/models/translation/translation_languages.py +++ b/src-python/models/translation/translation_languages.py @@ -641,4 +641,51 @@ dict_plamo_languages = { translation_lang["Plamo_API"] = { "source":dict_plamo_languages, "target":dict_plamo_languages, +} + +dict_gemini_languages = { + "Arabic": "Arabic", + "Bengali": "Bengali", + "Bulgarian": "Bulgarian", + "Simplified Chinese": "Simplified Chinese", + "Traditional Chinese": "Traditional Chinese", + "Croatian": "Croatian", + "Czech": "Czech", + "Danish": "Danish", + "Dutch": "Dutch", + "English": "English", + "Estonian": "Estonian", + "Finnish": "Finnish", + "French": "French", + "German": "German", + "Greek": "Greek", + "Hebrew": "Hebrew", + "Hindi": "Hindi", + "Hungarian": "Hungarian", + "Indonesian": "Indonesian", + "Italian": "Italian", + "Japanese": "Japanese", + "Korean": "Korean", + "Latvian": "Latvian", + "Lithuanian": "Lithuanian", + "Norwegian": "Norwegian", + "Polish": "Polish", + "Portuguese": "Portuguese", + "Romanian": "Romanian", + "Russian": "Russian", + "Serbian": "Serbian", + "Slovak": "Slovak", + "Slovenian": "Slovenian", + "Spanish": "Spanish", + "Swahili": "Swahili", + "Swedish": "Swedish", + "Thai": "Thai", + "Turkish": "Turkish", + "Ukrainian": "Ukrainian", + "Vietnamese": "Vietnamese", +} + +translation_lang["Gemini_API"] = { + "source":dict_gemini_languages, + "target":dict_gemini_languages, } \ No newline at end of file diff --git a/src-python/models/translation/translation_translator.py b/src-python/models/translation/translation_translator.py index e187d52a..93728570 100644 --- a/src-python/models/translation/translation_translator.py +++ b/src-python/models/translation/translation_translator.py @@ -10,6 +10,7 @@ try: from .translation_languages import translation_lang from .translation_utils import ctranslate2_weights from .translation_plamo import PlamoClient + from .translation_gemini import GeminiClient except Exception: import sys print(os_path.dirname(os_path.dirname(os_path.dirname(os_path.abspath(__file__))))) @@ -17,6 +18,7 @@ except Exception: from translation_languages import translation_lang from translation_utils import ctranslate2_weights from translation_plamo import PlamoClient + from translation_gemini import GeminiClient import ctranslate2 import transformers @@ -30,6 +32,7 @@ class Translator(): def __init__(self): self.deepl_client = None self.plamo_client = None + self.gemini_client = None self.ctranslate2_translator = None self.ctranslate2_tokenizer = None self.is_loaded_ctranslate2_model = False @@ -57,6 +60,17 @@ class Translator(): result = False return result + def authenticationGeminiAuthKey(self, auth_key: str, model: str) -> bool: + result = True + try: + self.gemini_client = GeminiClient(auth_key, model=model) + self.gemini_client.checkAuthKey() + except Exception: + errorLogging() + self.gemini_client = None + result = False + return result + def changeCTranslate2Model(self, path, model_type, device="cpu", device_index=0): self.is_loaded_ctranslate2_model = False directory_name = ctranslate2_weights[model_type]["directory_name"] @@ -158,6 +172,15 @@ class Translator(): input_lang=source_language, output_lang=target_language, ) + case "Gemini_API": + if self.gemini_client is None: + result = False + else: + result = self.gemini_client.translate( + message, + input_lang=source_language, + output_lang=target_language, + ) case "Google": if self.is_enable_translators is True: result = other_web_Translator(