翻訳バックエンドを拡張・リファクタリング:OpenAI/Plamo/Gemini クライアントを追加・改修し、プロンプトを YAML から読み込むように変更。各クライアントでモデル一覧取得・認証・クライアント更新機能を実装し、Translator/Model 層の対応メソッドを追加。Controller と mainloop にプラモ・ジェミニ・OpenAI の認証/モデル操作エンドポイントを追加・整備。config のモデル/API設定をプロパティ化して既定値を None に変更し、選択肢リストを初期化。translation_languages に OpenAI 用マッピングを追加。requirements ファイルの依存記述を調整。

This commit is contained in:
misyaguziya
2025-10-16 18:09:08 +09:00
parent f8466bd6e4
commit 526fd4d5aa
13 changed files with 842 additions and 337 deletions

View File

@@ -20,6 +20,8 @@ hf-xet==1.1.2
setuptools==80.8.0
langchain-openai==0.3.32
langchain-google-genai==2.1.10
google-genai==1.45.0
grpcio==1.67.1
SudachiPy==0.6.10
SudachiDict-core==20250825
SudachiDict-full==20250825

View File

@@ -21,6 +21,8 @@ hf-xet==1.1.2
setuptools==80.8.0
langchain-openai==0.3.32
langchain-google-genai==2.1.10
google-genai==1.45.0
grpcio==1.67.1
SudachiPy==0.6.10
SudachiDict-core==20250825
SudachiDict-full==20250825

View File

@@ -35,16 +35,6 @@ try:
except Exception: # pragma: no cover - optional runtime
whisper_models = {} # type: ignore
try:
from models.translation.translation_gemini import _MODELS as gemini_models
except Exception: # pragma: no cover - optional runtime
gemini_models = [] # type: ignore
try:
from models.translation.translation_plamo import _MODELS as plamo_models
except Exception: # pragma: no cover - optional runtime
plamo_models = [] # type: ignore
from utils import errorLogging, validateDictStructure, getComputeDeviceList
json_serializable_vars = {}
@@ -173,14 +163,6 @@ class Config:
def SELECTABLE_TRANSLATION_ENGINE_LIST(self):
return self._SELECTABLE_TRANSLATION_ENGINE_LIST
@property
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
@@ -329,6 +311,33 @@ class Config:
if isinstance(value, dict):
self._SELECTABLE_TRANSCRIPTION_ENGINE_STATUS = value
@property
def SELECTABLE_PLAMO_MODEL_LIST(self):
return self._SELECTABLE_PLAMO_MODEL_LIST
@SELECTABLE_PLAMO_MODEL_LIST.setter
def SELECTABLE_PLAMO_MODEL_LIST(self, value):
if isinstance(value, list):
self._SELECTABLE_PLAMO_MODEL_LIST = value
@property
def SELECTABLE_GEMINI_MODEL_LIST(self):
return self._SELECTABLE_GEMINI_MODEL_LIST
@SELECTABLE_GEMINI_MODEL_LIST.setter
def SELECTABLE_GEMINI_MODEL_LIST(self, value):
if isinstance(value, list):
self._SELECTABLE_GEMINI_MODEL_LIST = value
@property
def SELECTABLE_OPENAI_MODEL_LIST(self):
return self._SELECTABLE_OPENAI_MODEL_LIST
@SELECTABLE_OPENAI_MODEL_LIST.setter
def SELECTABLE_OPENAI_MODEL_LIST(self, value):
if isinstance(value, list):
self._SELECTABLE_OPENAI_MODEL_LIST = value
# Save Json Data
## Main Window
@property
@@ -936,6 +945,18 @@ class Config:
self._GEMINI_MODEL = value
self.saveConfig(inspect.currentframe().f_code.co_name, value)
@property
@json_serializable('OPENAI_MODEL')
def OPENAI_MODEL(self):
return self._OPENAI_MODEL
@OPENAI_MODEL.setter
def OPENAI_MODEL(self, value):
if isinstance(value, str):
if value in self.SELECTABLE_OPENAI_MODEL_LIST:
self._OPENAI_MODEL = value
self.saveConfig(inspect.currentframe().f_code.co_name, value)
@property
@json_serializable('AUTO_CLEAR_MESSAGE_BOX')
def AUTO_CLEAR_MESSAGE_BOX(self):
@@ -1160,8 +1181,9 @@ class Config:
self._SELECTABLE_TRANSCRIPTION_ENGINE_LIST = list(transcription_lang[first_key].values())[0].keys()
except Exception:
self._SELECTABLE_TRANSCRIPTION_ENGINE_LIST = []
self._SELECTABLE_PLAMO_MODEL_LIST = plamo_models
self._SELECTABLE_GEMINI_MODEL_LIST = gemini_models
self._SELECTABLE_PLAMO_MODEL_LIST = []
self._SELECTABLE_GEMINI_MODEL_LIST = []
self._SELECTABLE_OPENAI_MODEL_LIST = []
self._SELECTABLE_UI_LANGUAGE_LIST = ["en", "ja", "ko", "zh-Hant", "zh-Hans"]
self._COMPUTE_MODE = "cuda" if torch.cuda.is_available() else "cpu"
self._SELECTABLE_COMPUTE_DEVICE_LIST = getComputeDeviceList()
@@ -1313,13 +1335,15 @@ class Config:
"DeepL_API": None,
"Plamo_API": None,
"Gemini_API": None,
"OpenAI_API": None,
}
self._USE_EXCLUDE_WORDS = True
self._SELECTED_TRANSLATION_COMPUTE_DEVICE = copy.deepcopy(self.SELECTABLE_COMPUTE_DEVICE_LIST[0])
self._SELECTED_TRANSCRIPTION_COMPUTE_DEVICE = copy.deepcopy(self.SELECTABLE_COMPUTE_DEVICE_LIST[0])
self._CTRANSLATE2_WEIGHT_TYPE = "m2m100_418M-ct2-int8"
self._PLAMO_MODEL = "plamo-2.0-prime"
self._GEMINI_MODEL = "gemini-2.5-flash-lite"
self._PLAMO_MODEL = None
self._GEMINI_MODEL = None
self._OPENAI_MODEL = None
self._SELECTED_TRANSLATION_COMPUTE_TYPE = "auto"
self._WHISPER_WEIGHT_TYPE = "base"
self._SELECTED_TRANSCRIPTION_COMPUTE_TYPE = "auto"

View File

@@ -1605,36 +1605,6 @@ class Controller:
self.updateTranslationEngineAndEngineList()
return {"status":200, "result":config.AUTH_KEYS[translator_name]}
def getPlamoModelList(self, *args, **kwargs) -> dict:
return {"status":200, "result": config.SELECTABLE_PLAMO_MODEL_LIST}
def setPlamoModel(self, data, *args, **kwargs) -> dict:
printLog("Set Plamo Model", data)
try:
data = str(data)
result = model.authenticationTranslatorPlamoAuthKey(auth_key=config.AUTH_KEYS["Plamo_API"], model_name=data)
if result is True:
config.PLAMO_MODEL = data
response = {"status":200, "result":config.PLAMO_MODEL}
else:
response = {
"status":400,
"result":{
"message":"Plamo model is not valid",
"data": config.PLAMO_MODEL
}
}
except Exception as e:
errorLogging()
response = {
"status":400,
"result":{
"message":f"Error {e}",
"data": config.PLAMO_MODEL
}
}
return response
def getPlamoAuthKey(self, *args, **kwargs) -> dict:
return {"status":200, "result":config.AUTH_KEYS["Plamo_API"]}
@@ -1644,13 +1614,19 @@ class Controller:
try:
data = str(data)
if len(data) == 72:
result = model.authenticationTranslatorPlamoAuthKey(auth_key=data, model_name=config.PLAMO_MODEL)
result = model.authenticationTranslatorPlamoAuthKey(auth_key=data)
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
config.SELECTABLE_PLAMO_MODEL_LIST = model.getTranslatorPlamoModelList()
# ここにrunが必要
if config.PLAMO_MODEL not in config.SELECTABLE_PLAMO_MODEL_LIST:
config.PLAMO_MODEL = config.SELECTABLE_PLAMO_MODEL_LIST[0]
# ここにrunが必要
model.updateTranslatorPlamoClient()
self.updateTranslationEngineAndEngineList()
response = {"status":200, "result":config.AUTH_KEYS[translator_name]}
else:
@@ -1689,23 +1665,27 @@ 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 getPlamoModelList(self, *args, **kwargs) -> dict:
return {"status":200, "result": config.SELECTABLE_PLAMO_MODEL_LIST}
def setGeminiModel(self, data, *args, **kwargs) -> dict:
printLog("Set Gemini Model", data)
def getPlamoModel(self, *args, **kwargs) -> dict:
return {"status":200, "result":config.PLAMO_MODEL}
def setPlamoModel(self, data, *args, **kwargs) -> dict:
printLog("Set Plamo Model", data)
try:
data = str(data)
result = model.authenticationTranslatorGeminiAuthKey(auth_key=config.AUTH_KEYS["Gemini_API"], model_name=data)
result = model.setTranslatorPlamoModel(model=data)
if result is True:
config.GEMINI_MODEL = data
response = {"status":200, "result":config.GEMINI_MODEL}
config.PLAMO_MODEL = data
model.updateTranslatorPlamoClient()
response = {"status":200, "result":config.PLAMO_MODEL}
else:
response = {
"status":400,
"result":{
"message":"Gemini model is not valid",
"data": config.GEMINI_MODEL
"message":"Plamo model is not valid",
"data": config.PLAMO_MODEL
}
}
except Exception as e:
@@ -1714,7 +1694,7 @@ class Controller:
"status":400,
"result":{
"message":f"Error {e}",
"data": config.GEMINI_MODEL
"data": config.PLAMO_MODEL
}
}
return response
@@ -1728,13 +1708,19 @@ class Controller:
try:
data = str(data)
if len(data) >= 20:
result = model.authenticationTranslatorGeminiAuthKey(auth_key=data, model_name=config.GEMINI_MODEL)
result = model.authenticationTranslatorGeminiAuthKey(auth_key=data)
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
config.SELECTABLE_GEMINI_MODEL_LIST = model.getTranslatorGeminiModelList()
# ここにrunが必要
if config.GEMINI_MODEL not in config.SELECTABLE_GEMINI_MODEL_LIST:
config.GEMINI_MODEL = config.SELECTABLE_GEMINI_MODEL_LIST[0]
# ここにrunが必要
model.updateTranslatorGeminiClient()
self.updateTranslationEngineAndEngineList()
response = {"status":200, "result":config.AUTH_KEYS[translator_name]}
else:
@@ -1773,6 +1759,118 @@ 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 getGeminiModel(self, *args, **kwargs) -> dict:
return {"status":200, "result":config.GEMINI_MODEL}
def setGeminiModel(self, data, *args, **kwargs) -> dict:
printLog("Set Gemini Model", data)
try:
data = str(data)
result = model.setTranslatorGeminiModel(model=data)
if result is True:
config.GEMINI_MODEL = data
model.updateTranslatorGeminiClient()
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
@staticmethod
def getOpenAiAuthKey(*args, **kwargs) -> dict:
return {"status":200, "result":config.AUTH_KEYS["OpenAI_API"]}
def setOpenAiAuthKey(self, data, *args, **kwargs) -> dict:
printLog("Set OpenAI Auth Key", data)
translator_name = "OpenAI_API"
try:
data = str(data)
if len(data) >= 20:
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":"OpenAI 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 delOpenAiAuthKey(self, *args, **kwargs) -> dict:
translator_name = "OpenAI_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]}
def getOpenAiModelList(self, *args, **kwargs) -> dict:
return {"status":200, "result": config.SELECTABLE_OPENAI_MODEL_LIST}
def getOpenAiModel(self, *args, **kwargs) -> dict:
return {"status":200, "result":config.OPENAI_MODEL}
def setOpenAiModel(self, data, *args, **kwargs) -> dict:
printLog("Set OpenAI Model", data)
try:
data = str(data)
result = model.setTranslatorOpenAiModel(model=data)
if result is True:
config.OPENAI_MODEL = data
response = {"status":200, "result":config.OPENAI_MODEL}
else:
response = {
"status":400,
"result":{
"message":"OpenAI model is not valid",
"data": config.OPENAI_MODEL
}
}
except Exception as e:
errorLogging()
response = {
"status":400,
"result":{
"message":f"Error {e}",
"data": config.OPENAI_MODEL
}
}
return response
@staticmethod
def getCtranslate2WeightType(*args, **kwargs) -> dict:
return {"status":200, "result":config.CTRANSLATE2_WEIGHT_TYPE}
@@ -2651,9 +2749,14 @@ class Controller:
printLog("Start check Plamo API Key")
config.SELECTABLE_TRANSLATION_ENGINE_STATUS[engine] = False
if config.AUTH_KEYS[engine] is not None:
if model.authenticationTranslatorPlamoAuthKey(auth_key=config.AUTH_KEYS[engine], model=config.PLAMO_MODEL) is True:
if model.authenticationTranslatorPlamoAuthKey(auth_key=config.AUTH_KEYS[engine]) is True:
config.SELECTABLE_TRANSLATION_ENGINE_STATUS[engine] = True
printLog("Plamo API Key is valid")
config.SELECTABLE_PLAMO_MODEL_LIST = model.getTranslatorPlamoModelList()
if config.PLAMO_MODEL not in config.SELECTABLE_PLAMO_MODEL_LIST:
config.PLAMO_MODEL = config.SELECTABLE_PLAMO_MODEL_LIST[0]
model.setTranslatorPlamoModel(config.PLAMO_MODEL)
model.updateTranslatorPlamoClient()
else:
# error update Auth key
auth_keys = config.AUTH_KEYS
@@ -2664,15 +2767,38 @@ class Controller:
printLog("Start check Gemini API Key")
config.SELECTABLE_TRANSLATION_ENGINE_STATUS[engine] = False
if config.AUTH_KEYS[engine] is not None:
if model.authenticationTranslatorGeminiAuthKey(auth_key=config.AUTH_KEYS[engine], model=config.GEMINI_MODEL) is True:
if model.authenticationTranslatorGeminiAuthKey(auth_key=config.AUTH_KEYS[engine]) is True:
config.SELECTABLE_TRANSLATION_ENGINE_STATUS[engine] = True
printLog("Gemini API Key is valid")
config.SELECTABLE_GEMINI_MODEL_LIST = model.getTranslatorGeminiModelList()
if config.GEMINI_MODEL not in config.SELECTABLE_GEMINI_MODEL_LIST:
config.GEMINI_MODEL = config.SELECTABLE_GEMINI_MODEL_LIST[0]
model.setTranslatorGeminiModel(config.GEMINI_MODEL)
model.updateTranslatorGeminiClient()
else:
# error update Auth key
auth_keys = config.AUTH_KEYS
auth_keys[engine] = None
config.AUTH_KEYS = auth_keys
printLog("Gemini API Key is invalid")
case "OpenAI_API":
printLog("Start check OpenAI API Key")
config.SELECTABLE_TRANSLATION_ENGINE_STATUS[engine] = False
if config.AUTH_KEYS[engine] is not None:
if model.authenticationTranslatorOpenAIAuthKey(auth_key=config.AUTH_KEYS[engine]) is True:
config.SELECTABLE_TRANSLATION_ENGINE_STATUS[engine] = True
printLog("OpenAI API Key is valid")
config.SELECTABLE_OPENAI_MODEL_LIST = model.getTranslatorOpenAIModelList()
if config.OPENAI_MODEL not in config.SELECTABLE_OPENAI_MODEL_LIST:
config.OPENAI_MODEL = config.SELECTABLE_OPENAI_MODEL_LIST[0]
model.setTranslatorOpenAiModel(config.OPENAI_MODEL)
model.updateTranslatorOpenAIClient()
else:
# error update Auth key
auth_keys = config.AUTH_KEYS
auth_keys[engine] = None
config.AUTH_KEYS = auth_keys
printLog("OpenAI API Key is invalid")
case _:
if connected_network is True:
config.SELECTABLE_TRANSLATION_ENGINE_STATUS[engine] = True

View File

@@ -175,17 +175,26 @@ mapping = {
"/delete/data/deepl_auth_key": {"status": False, "variable":controller.delDeeplAuthKey},
"/get/data/plamo_model_list": {"status": False, "variable":controller.getPlamoModelList},
"/get/data/plamo_model": {"status": False, "variable":controller.getPlamoModel},
"/set/data/plamo_model": {"status": False, "variable":controller.setPlamoModel},
"/get/data/plamo_auth_key": {"status": False, "variable":controller.getPlamoAuthKey},
"/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},
"/get/data/gemini_model": {"status": True, "variable":controller.getGeminiModel},
"/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/openai_model_list": {"status": True, "variable":controller.getOpenAiModelList},
"/get/data/openai_model": {"status": True, "variable":controller.getOpenAiModel},
"/set/data/openai_model": {"status": True, "variable":controller.setOpenAiModel},
"/get/data/openai_auth_key": {"status": True, "variable":controller.getOpenAiAuthKey},
"/set/data/openai_auth_key": {"status": True, "variable":controller.setOpenAiAuthKey},
"/delete/data/openai_auth_key": {"status": True, "variable":controller.delOpenAiAuthKey},
"/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},

View File

@@ -198,14 +198,57 @@ class Model:
result = self.translator.authenticationDeepLAuthKey(auth_key)
return result
def authenticationTranslatorPlamoAuthKey(self, auth_key: str, model: str) -> bool:
result = self.translator.authenticationPlamoAuthKey(auth_key, model=model, root_path=config.PATH_LOCAL)
def authenticationTranslatorPlamoAuthKey(self, auth_key: str) -> bool:
result = self.translator.authenticationPlamoAuthKey(auth_key, root_path=config.PATH_LOCAL)
return result
def authenticationTranslatorGeminiAuthKey(self, auth_key: str, model: str) -> bool:
result = self.translator.authenticationGeminiAuthKey(auth_key, model=model, root_path=config.PATH_LOCAL)
def getTranslatorPlamoModelList(self) -> list[str]:
self.ensure_initialized()
return self.translator.getPlamoModelList()
def setTranslatorPlamoModel(self, model: str) -> bool:
self.ensure_initialized()
result = self.translator.setPlamoModel(model=model)
return result
def updateTranslatorPlamoClient(self) -> None:
self.ensure_initialized()
self.translator.updatePlamoClient()
def authenticationTranslatorGeminiAuthKey(self, auth_key: str) -> bool:
result = self.translator.authenticationGeminiAuthKey(auth_key, root_path=config.PATH_LOCAL)
return result
def getTranslatorGeminiModelList(self) -> list[str]:
self.ensure_initialized()
return self.translator.getGeminiModelList()
def setTranslatorGeminiModel(self, model: str) -> bool:
self.ensure_initialized()
result = self.translator.setGeminiModel(model=model)
return result
def updateTranslatorGeminiClient(self) -> None:
self.ensure_initialized()
self.translator.updateGeminiClient()
def authenticationTranslatorOpenAIAuthKey(self, auth_key: str, base_url: Optional[str] = None) -> bool:
result = self.translator.authenticationOpenAIAuthKey(auth_key, base_url=base_url, root_path=config.PATH_LOCAL)
return result
def getTranslatorOpenAIModelList(self) -> list[str]:
self.ensure_initialized()
return self.translator.getOpenAIModelList()
def setTranslatorOpenAiModel(self, model: str) -> bool:
self.ensure_initialized()
result = self.translator.setOpenAIModel(model=model)
return result
def updateTranslatorOpenAIClient(self) -> None:
self.ensure_initialized()
self.translator.updateOpenAIClient()
def startLogger(self):
self.ensure_initialized()
os_makedirs(config.PATH_LOGS, exist_ok=True)

View File

@@ -1,7 +1,10 @@
system_prompt: |
Please translate the following text from {input_lang} to {output_lang}.
Only provide the translated text as the output.
{text}
You are a helpful translation assistant.
Supported languages:
{supported_languages}
Translate the user provided text from {input_lang} to {output_lang}.
Return ONLY the translated text. Do not add quotes or extra commentary.
supported_languages: |
Arabic

View File

@@ -0,0 +1,49 @@
system_prompt: |
You are a helpful translation assistant.
Supported languages:
{supported_languages}
Translate the user provided text from {input_lang} to {output_lang}.
Return ONLY the translated text. Do not add quotes or extra commentary.
supported_languages: |
Arabic
Bengali
Bulgarian
Catalan
Chinese Simplified
Chinese Traditional
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

View File

@@ -1,39 +1,48 @@
import logging
from google import genai
from langchain_google_genai import ChatGoogleGenerativeAI
from langchain_core.messages import HumanMessage
import yaml
from os import path as os_path
logger = logging.getLogger("langchain_google_genai")
logger.setLevel(logging.ERROR)
_MODELS = [
"gemini-2.5-pro",
"gemini-2.5-flash",
"gemini-2.5-flash-lite", # default
"gemini-2.0-flash",
"gemini-2.0-flash-lite",
"gemini-1.5-pro",
"gemini-1.5-flash-8b"
"gemini-1.5-flash",
def _authentication_check(api_key: str) -> bool:
"""Check if the provided API key is valid by attempting to list models.
"""
try:
client = genai.Client(api_key=api_key)
client.models.list()
return True
except Exception:
return False
def _get_available_text_models(api_key: str) -> list[str]:
"""Extract only Gemini models suitable for translation and chat applications
"""
client = genai.Client(api_key=api_key)
res = client.models.list()
allowed_models = []
# 除外対象のキーワード
exclude_keywords = [
"audio",
"image",
"veo",
"tts",
"robotics",
"computer-use"
]
for model in res:
model_id = model.name
if ("gemini" in model_id.lower() or "gemma" in model_id.lower()) and "generateContent" in model.supported_actions:
if any(x in model_id for x in exclude_keywords):
continue
allowed_models.append(model_id.replace("models/", ""))
allowed_models.sort()
return allowed_models
class GeminiClient:
def __init__(self, api_key: str = "", model: str = "gemini-2.5-flash-lite", root_path: str = None):
self.api_key = api_key
self.model = model
# プロンプト設定をYAMLファイルから読み込む
prompt_config = self._load_prompt_config(root_path)
self.supported_languages = prompt_config["supported_languages"]
self.prompt_template = prompt_config["system_prompt"]
self.gemini_llm = ChatGoogleGenerativeAI(
model=self.model,
api_key=self.api_key,
)
def _load_prompt_config(self, root_path: str = None) -> dict:
def _load_prompt_config(root_path: str = None) -> dict:
"""プロンプト設定をYAMLファイルから読み込む"""
prompt_filename = "translation_gemini.yml"
@@ -52,97 +61,78 @@ class GeminiClient:
with open(prompt_path, "r", encoding="utf-8") as f:
return yaml.safe_load(f)
def getListModels(self) -> list[str]:
return _MODELS
class GeminiClient:
def __init__(self, root_path: str = None):
self.api_key = None
self.model = None
# プロンプト設定をYAMLファイルから読み込む
prompt_config = _load_prompt_config(root_path)
self.supported_languages = prompt_config["supported_languages"]
self.prompt_template = prompt_config["system_prompt"]
self.gemini_llm = None
def getModelList(self) -> list[str]:
return _get_available_text_models(self.api_key)
def getAuthKey(self) -> str:
"""現在のAuthKeyを取得する"""
return self.api_key
def setAuthKey(self, api_key: str) -> bool:
result = _authentication_check(api_key)
if result:
self.api_key = api_key
return result
def getModel(self) -> str:
"""現在のモデルを取得する"""
return self.model
def setAuthKey(self, api_key: str) -> bool:
"""AuthKeyを設定し、成功したかどうかを返す"""
try:
self.api_key = api_key
self.gemini_llm = ChatGoogleGenerativeAI(
model=self.model,
api_key=self.api_key,
)
return True
except Exception as e:
print(f"Error setting AuthKey: {e}")
return False
def setModel(self, model: str) -> bool:
"""モデルを設定し、成功したかどうかを返す"""
try:
if model in _MODELS:
if model in self.getModelList():
self.model = model
self.gemini_llm = ChatGoogleGenerativeAI(
model=self.model,
api_key=self.api_key,
)
return True
else:
print(f"Model {model} is not supported.")
return False
except Exception as e:
print(f"Error setting model: {e}")
return False
def translate(self, text: str, input_lang: str, output_lang: str) -> str:
messages = self.prompt_template.format(
input_lang=input_lang,
output_lang=output_lang,
text=text
def updateClient(self) -> None:
self.gemini_llm = ChatGoogleGenerativeAI(
model=self.model,
api_key=self.api_key,
)
output = self.gemini_llm.invoke([HumanMessage(content=messages)])
return output.content
def translate(self, text: str, input_lang: str, output_lang: str) -> str:
system_prompt = self.prompt_template.format(
supported_languages=self.supported_languages,
input_lang=input_lang,
output_lang=output_lang
)
def checkAuthKey(self) -> bool:
try:
self.setModel(self.model)
self.translate("Hello World", input_lang="English", output_lang="Japanese")
return True
except Exception:
return False
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": text}
]
resp = self.gemini_llm.invoke(messages)
content = ""
if isinstance(resp.content, str):
content = resp.content
elif isinstance(resp.content, list):
for part in resp.content:
if isinstance(part, str):
content += part
elif isinstance(part, dict) and "content" in part and isinstance(part["content"], str):
content += part["content"]
return content.strip()
if __name__ == "__main__":
AUTH_KEY = "AUTH_KEY"
text = """
毎朝コーヒーを入れるのがささやかな楽しみになってる
"""
input_lang = "Japanese"
output_lang = "English"
gemini_client = GeminiClient(api_key=AUTH_KEY, model="gemini-2.5-flash-lite")
print("model list:", gemini_client.getListModels())
print("AuthKey:", gemini_client.getAuthKey())
# print("Model:", gemini_client.getModel())
# print(f"set model: {gemini_client.setModel('gemini-2.5-flash')}")
# print(f"set AuthKey: {gemini_client.setAuthKey(AUTH_KEY)}")
# print(f"check AuthKey: {gemini_client.checkAuthKey()}")
# try:
# translated_text = gemini_client.translate(text, input_lang, output_lang)
# print(translated_text)
# except Exception:
# print("Invalid API key. Please check your credentials.")
# 外部ファイルから読み込んだサポート言語を使用
for lang in gemini_client.supported_languages.split("\n"):
if lang == "":
continue
print (f"Translating to {lang}:")
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
client = GeminiClient()
client.setAuthKey(AUTH_KEY)
models = client.getModelList()
if models:
print("Available models:", models)
model = input("Select a model: ")
client.setModel(model)
client.updateClient()
print(client.translate("こんにちは世界", "Japanese", "English"))

View File

@@ -664,3 +664,49 @@ dict_gemini_languages = {
}
translation_lang["Gemini_API"] = {"source":dict_gemini_languages, "target":dict_gemini_languages}
# OpenAI API (Chat Completions) - Gemini とほぼ同等の自然言語名を使用
dict_openai_languages = {
"Arabic": "Arabic",
"Bengali": "Bengali",
"Bulgarian": "Bulgarian",
"Catalan": "Catalan",
"Chinese Simplified": "Simplified Chinese",
"Chinese Traditional": "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["OpenAI_API"] = {"source": dict_openai_languages, "target": dict_openai_languages}

View File

@@ -0,0 +1,148 @@
from openai import OpenAI
from langchain_openai import ChatOpenAI
from pydantic import SecretStr
import yaml
from os import path as os_path
def _authentication_check(api_key: str, base_url: str | None = None) -> bool:
"""Check if the provided API key is valid by attempting to list models.
"""
try:
client = OpenAI(api_key=api_key, base_url=base_url)
client.models.list()
return True
except Exception:
return False
def _get_available_text_models(api_key: str, base_url: str | None = None) -> list[str]:
"""Extract only GPT models suitable for translation and chat applications (plus those with fine-tuning)
"""
client = OpenAI(api_key=api_key, base_url=base_url)
res = client.models.list()
allowed_models = []
for model in res.data:
model_id = model.id
root = getattr(model, "root", "")
# 除外対象のキーワード
exclude_keywords = [
"whisper", # 音声認識
"embedding", # 埋め込み
"image", # 画像生成
"tts", # 音声合成
"audio", # 音声系transcribe, diarize含む
"search", # 検索補助モデル
"transcribe", # 音声→文字起こし
"diarize", # 話者分離
"vision" # 画像入力系旧gpt-4-visionなど
]
# 除外キーワードが含まれているモデルをスキップ
if any(kw in model_id for kw in exclude_keywords):
continue
# GPTモデルまたはFine-tune GPTモデルのみ対象
if model_id.startswith("gpt-"):
allowed_models.append(model_id)
elif model_id.startswith("ft:") and root.startswith("gpt-"):
allowed_models.append(model_id)
allowed_models.sort()
return allowed_models
def _load_prompt_config(root_path: str = None) -> dict:
prompt_filename = "translation_openai.yml"
# PyInstaller 展開後
if root_path and os_path.exists(os_path.join(root_path, "_internal", "prompt", prompt_filename)):
prompt_path = os_path.join(root_path, "_internal", "prompt", prompt_filename)
# src-python 直下実行
elif os_path.exists(os_path.join(os_path.dirname(__file__), "models", "translation", "prompt", prompt_filename)):
prompt_path = os_path.join(os_path.dirname(__file__), "models", "translation", "prompt", prompt_filename)
# translation フォルダ直下実行
elif os_path.exists(os_path.join(os_path.dirname(__file__), "prompt", prompt_filename)):
prompt_path = os_path.join(os_path.dirname(__file__), "prompt", prompt_filename)
else:
raise FileNotFoundError(f"Prompt file not found: {prompt_filename}")
with open(prompt_path, "r", encoding="utf-8") as f:
return yaml.safe_load(f)
class OpenAIClient:
"""OpenAI Translation simple wrapper.
prompt/translation_openai.yml から system_prompt / supported_languages を読み込む。
"""
def __init__(self, base_url: str | None = None, root_path: str = None):
self.api_key = None
self.model = None
self.base_url = base_url # None の場合は公式エンドポイント
prompt_config = _load_prompt_config(root_path)
self.supported_languages = prompt_config["supported_languages"]
self.prompt_template = prompt_config["system_prompt"]
self.openai_llm = None
def getModelList(self) -> list[str]:
return _get_available_text_models(self.api_key, self.base_url) if self.api_key else []
def getAuthKey(self) -> str:
return self.api_key
def setAuthKey(self, api_key: str) -> bool:
result = _authentication_check(api_key, self.base_url)
if result:
self.api_key = api_key
return result
def getModel(self) -> str:
return self.model
def setModel(self, model: str) -> bool:
if model in self.getModelList():
self.model = model
return True
else:
return False
def updateClient(self) -> None:
self.openai_llm = ChatOpenAI(
base_url=self.base_url,
model=self.model,
api_key=SecretStr(self.api_key),
streaming=False,
)
def translate(self, text: str, input_lang: str, output_lang: str) -> str:
system_prompt = self.prompt_template.format(
supported_languages=self.supported_languages,
input_lang=input_lang,
output_lang=output_lang,
)
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": text},
]
resp = self.openai_llm.invoke(messages)
content = ""
if isinstance(resp.content, str):
content = resp.content
elif isinstance(resp.content, list):
for part in resp.content:
if isinstance(part, str):
content += part
elif isinstance(part, dict) and "content" in part and isinstance(part["content"], str):
content += part["content"]
return content.strip()
if __name__ == "__main__":
AUTH_KEY = "OPENAI_API_KEY"
client = OpenAIClient()
client.setAuthKey(AUTH_KEY)
models = client.getModelList()
if models:
print("Available models:", models)
model = input("Select a model: ")
client.setModel(model)
client.updateClient()
print(client.translate("こんにちは世界", "Japanese", "English"))

View File

@@ -1,31 +1,35 @@
from openai import OpenAI
from langchain_openai import ChatOpenAI
from pydantic import SecretStr
import yaml
from os import path as os_path
_MODELS = [
"plamo-2.0-prime"
]
BASE_URL = "https://api.platform.preferredai.jp/v1"
class PlamoClient:
def __init__(self, api_key: str = "", model: str = "plamo-2.0-prime", root_path: str = None):
self.api_key = api_key
self.base_url = "https://api.platform.preferredai.jp/v1"
self.model = model
def _authentication_check(api_key: str) -> bool:
"""Check if the provided API key is valid by attempting to list models.
"""
try:
client = OpenAI(api_key=api_key, base_url=BASE_URL)
client.models.list()
return True
except Exception:
return False
# プロンプト設定をYAMLファイルから読み込む
prompt_config = self._load_prompt_config(root_path)
self.supported_languages = prompt_config["supported_languages"]
self.prompt_template = prompt_config["system_prompt"]
def _get_available_text_models(api_key: str) -> list[str]:
"""Extract all available models from the PLAMO API
"""
client = OpenAI(api_key=api_key, base_url=BASE_URL)
res = client.models.list()
allowed_models = []
self.plamo_llm = ChatOpenAI(
base_url=self.base_url,
model=self.model,
streaming=True,
api_key=SecretStr(self.api_key),
)
for model in res.data:
allowed_models.append(model.id)
def _load_prompt_config(self, root_path: str = None) -> dict:
allowed_models.sort()
return allowed_models
def _load_prompt_config(root_path: str = None) -> dict:
"""プロンプト設定をYAMLファイルから読み込む"""
prompt_filename = "translation_plamo.yml"
@@ -44,104 +48,79 @@ class PlamoClient:
with open(prompt_path, "r", encoding="utf-8") as f:
return yaml.safe_load(f)
def getListModels(self) -> list[str]:
return _MODELS
class PlamoClient:
def __init__(self, root_path: str = None):
self.api_key = None
self.base_url = BASE_URL
self.model = None
prompt_config = _load_prompt_config(root_path)
self.supported_languages = prompt_config["supported_languages"]
self.prompt_template = prompt_config["system_prompt"]
self.plamo_llm = None
def getModelList(self) -> list[str]:
return _get_available_text_models(self.api_key) if self.api_key else []
def getAuthKey(self) -> str:
"""現在のAuthKeyを取得する"""
return self.api_key
def setAuthKey(self, api_key: str) -> bool:
result = _authentication_check(api_key)
if result:
self.api_key = api_key
return result
def getModel(self) -> str:
"""現在のモデルを取得する"""
return self.model
def setAuthKey(self, api_key: str) -> bool:
"""AuthKeyを設定し、成功したかどうかを返す"""
try:
self.api_key = api_key
self.plamo_llm = ChatOpenAI(
base_url=self.base_url,
model=self.model,
streaming=True,
api_key=SecretStr(self.api_key),
)
return True
except Exception as e:
return False
def setModel(self, model: str) -> bool:
"""モデルを設定し、成功したかどうかを返す"""
if model not in _MODELS:
if model in self.getModelList():
self.model = model
return True
else:
return False
try:
self.model = model
def updateClient(self) -> None:
self.plamo_llm = ChatOpenAI(
base_url=self.base_url,
model=self.model,
streaming=True,
streaming=False,
api_key=SecretStr(self.api_key),
)
return True
except Exception as e:
print(f"Error setting model: {e}")
return False
def translate(self, text: str, input_lang: str, output_lang: str) -> str:
messages = [
{
"role": "system",
"content": self.prompt_template.format(
system_prompt = self.prompt_template.format(
supported_languages=self.supported_languages,
input_lang=input_lang,
output_lang=output_lang
),
},
)
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": text},
]
output = ""
for chunk in self.plamo_llm.stream(messages):
if isinstance(chunk.content, str):
output += chunk.content
elif isinstance(chunk.content, list):
for item in chunk.content:
if isinstance(item, str):
output += item
elif isinstance(item, dict):
if "content" in item and isinstance(item["content"], str):
output += item["content"]
return output[:-1]
def checkAuthKey(self) -> bool:
try:
self.setModel(self.model)
self.translate("Hello World", input_lang="English", output_lang="Japanese")
return True
except Exception as e:
print(f"Error checking AuthKey: {e}")
return False
resp = self.plamo_llm.invoke(messages)
content = ""
if isinstance(resp.content, str):
content = resp.content
elif isinstance(resp.content, list):
for part in resp.content:
if isinstance(part, str):
content += part
elif isinstance(part, dict) and "content" in part and isinstance(part["content"], str):
content += part["content"]
return content.strip()
if __name__ == "__main__":
AUTH_KEY = "AUTH_KEY"
text = """
毎朝コーヒーを入れるのがささやかな楽しみになってる
"""
input_lang = "Japanese"
output_lang = "English"
plamo_client = PlamoClient(api_key=AUTH_KEY)
print("model list:", plamo_client.getListModels())
print("AuthKey:", plamo_client.getAuthKey())
print("Model:", plamo_client.getModel())
print(f"set model: {plamo_client.setModel('plamo-2.0-prime')}")
print(f"set AuthKey: {plamo_client.setAuthKey(AUTH_KEY)}")
print(f"check AuthKey: {plamo_client.checkAuthKey()}")
try:
translated_text = plamo_client.translate(text, input_lang, output_lang)
print(translated_text)
except Exception:
print("Invalid API key. Please check your credentials.")
AUTH_KEY = "PLAMO_API_KEY"
client = PlamoClient()
client.setAuthKey(AUTH_KEY)
models = client.getModelList()
if models:
print("Available models:", models)
model = input("Select a model: ")
client.setModel(model)
client.updateClient()
print(client.translate("こんにちは世界", "Japanese", "English"))

View File

@@ -12,6 +12,7 @@ try:
from .translation_utils import ctranslate2_weights
from .translation_plamo import PlamoClient
from .translation_gemini import GeminiClient
from .translation_openai import OpenAIClient
except Exception:
import sys
print(os_path.dirname(os_path.dirname(os_path.dirname(os_path.abspath(__file__)))))
@@ -20,6 +21,7 @@ except Exception:
from translation_utils import ctranslate2_weights
from translation_plamo import PlamoClient
from translation_gemini import GeminiClient
from translation_openai import OpenAIClient
import ctranslate2
import transformers
@@ -44,6 +46,7 @@ class Translator:
self.deepl_client: Optional[DeepLClient] = None
self.plamo_client: Optional[PlamoClient] = None
self.gemini_client: Optional[GeminiClient] = None
self.openai_client: Optional[OpenAIClient] = None
self.ctranslate2_translator: Any = None
self.ctranslate2_tokenizer: Any = None
self.is_loaded_ctranslate2_model: bool = False
@@ -66,35 +69,107 @@ class Translator:
result = False
return result
def authenticationPlamoAuthKey(self, auth_key: str, model: str, root_path: str = None) -> bool:
def authenticationPlamoAuthKey(self, auth_key: str, root_path: str = None) -> bool:
"""Authenticate Plamo API with the provided key.
Returns True on success, False on failure.
"""
result = True
try:
self.plamo_client = PlamoClient(auth_key, model=model, root_path=root_path)
self.plamo_client.checkAuthKey()
except Exception:
errorLogging()
self.plamo_client = PlamoClient(root_path=root_path)
if self.plamo_client.setAuthKey(auth_key):
return True
else:
self.plamo_client = None
result = False
return result
return False
def authenticationGeminiAuthKey(self, auth_key: str, model: str, root_path: str = None) -> bool:
def getPlamoModelList(self) -> list[str]:
"""Get available Plamo models.
Returns a list of model names, or an empty list on failure.
"""
if self.plamo_client is None:
return []
return self.plamo_client.getModelList()
def setPlamoModel(self, model: str) -> bool:
"""Change the Plamo model used for translation.
Returns True on success, False on failure.
"""
if self.plamo_client is None:
return False
return self.plamo_client.setModel(model)
def updatePlamoClient(self) -> None:
"""Update the Plamo client (fetch available models)."""
self.plamo_client.updateClient()
def authenticationGeminiAuthKey(self, auth_key: str, root_path: str = None) -> bool:
"""Authenticate Gemini API with the provided key.
Returns True on success, False on failure.
"""
result = True
try:
self.gemini_client = GeminiClient(auth_key, model=model, root_path=root_path)
self.gemini_client.checkAuthKey()
except Exception:
errorLogging()
self.gemini_client = None
result = False
return result
self.gemini_client = GeminiClient(root_path=root_path)
if self.gemini_client.setAuthKey(auth_key):
return True
else:
return False
def getGeminiModelList(self) -> list[str]:
"""Get available Gemini models.
Returns a list of model names, or an empty list on failure.
"""
if self.gemini_client is None:
return []
return self.gemini_client.getModelList()
def setGeminiModel(self, model: str) -> bool:
"""Change the Gemini model used for translation.
Returns True on success, False on failure.
"""
if self.gemini_client is None:
return False
return self.gemini_client.setModel(model)
def updateGeminiClient(self) -> None:
"""Update the Gemini client (fetch available models)."""
self.gemini_client.updateClient()
def authenticationOpenAIAuthKey(self, auth_key: str, base_url: str | None = None, root_path: str = None) -> bool:
"""Authenticate OpenAI (Chat Completions) API with the provided key.
base_url を指定することで互換エンドポイント (例: Azure OpenAI 互換, Proxy) にも対応可能。
Returns True on success, False on failure.
"""
self.openai_client = OpenAIClient(base_url=base_url, root_path=root_path)
if self.openai_client.setAuthKey(auth_key):
return True
else:
self.openai_client = None
return False
def getOpenAIModelList(self) -> list[str]:
"""Get available OpenAI models.
Returns a list of model names, or an empty list on failure.
"""
if self.openai_client is None:
return []
return self.openai_client.getModelList()
def setOpenAIModel(self, model: str) -> bool:
"""Change the OpenAI model used for translation.
Returns True on success, False on failure.
"""
if self.openai_client is None:
return False
return self.openai_client.setModel(model)
def updateOpenAIClient(self) -> None:
"""Update the OpenAI client (fetch available models)."""
self.openai_client.updateClient()
def changeCTranslate2Model(self, path: str, model_type: str, device: str = "cpu", device_index: int = 0, compute_type: str = "auto") -> None:
"""Load a CTranslate2 model from weights.
@@ -236,6 +311,15 @@ class Translator:
input_lang=source_language,
output_lang=target_language,
)
case "OpenAI_API":
if self.openai_client is None:
result = False
else:
result = self.openai_client.translate(
message,
input_lang=source_language,
output_lang=target_language,
)
case "Google":
if self.is_enable_translators is True and other_web_Translator is not None:
result = other_web_Translator(