翻訳APIの認証ロジックを改善し、YAMLファイルからプロンプト設定を読み込む機能を追加。新しいフォントファイルを追加し、データパスを更新。

This commit is contained in:
misyaguziya
2025-10-15 18:50:26 +09:00
parent 7d0f63c118
commit f8466bd6e4
15 changed files with 206 additions and 148 deletions

View File

@@ -5,7 +5,14 @@ a = Analysis(
['src-python\\mainloop.py'],
pathex=[],
binaries=[],
datas=[('./fonts', 'fonts/'), ('.venv/Lib/site-packages/zeroconf', 'zeroconf/'), ('.venv/Lib/site-packages/openvr', 'openvr/'), ('.venv/Lib/site-packages/faster_whisper', 'faster_whisper/'), ('.venv/Lib/site-packages/hf_xet', 'hf_xet/')],
datas=[
('./src-python/models/overlay/fonts', 'fonts/'),
('./src-python/models/translation/prompt', 'prompt/'),
('.venv/Lib/site-packages/zeroconf', 'zeroconf/'),
('.venv/Lib/site-packages/openvr', 'openvr/'),
('.venv/Lib/site-packages/faster_whisper', 'faster_whisper/'),
('.venv/Lib/site-packages/hf_xet', 'hf_xet/')
],
hiddenimports=[],
hookspath=[],
hooksconfig={},

View File

@@ -5,7 +5,14 @@ a = Analysis(
['src-python\\mainloop.py'],
pathex=[],
binaries=[],
datas=[('./fonts', 'fonts/'), ('.venv_cuda/Lib/site-packages/zeroconf', 'zeroconf/'), ('.venv_cuda/Lib/site-packages/openvr', 'openvr/'), ('.venv_cuda/Lib/site-packages/faster_whisper', 'faster_whisper/'), ('.venv/Lib/site-packages/hf_xet', 'hf_xet/')],
datas=[
('./src-python/models/overlay/fonts', 'fonts/'),
('./src-python/models/translation/prompt', 'prompt/'),
('.venv_cuda/Lib/site-packages/zeroconf', 'zeroconf/'),
('.venv_cuda/Lib/site-packages/openvr', 'openvr/'),
('.venv_cuda/Lib/site-packages/faster_whisper', 'faster_whisper/'),
('.venv/Lib/site-packages/hf_xet', 'hf_xet/')
],
hiddenimports=[],
hookspath=[],
hooksconfig={},

View File

@@ -2640,22 +2640,39 @@ class Controller:
if config.AUTH_KEYS[engine] is not None:
if model.authenticationTranslatorDeepLAuthKey(auth_key=config.AUTH_KEYS[engine]) is True:
config.SELECTABLE_TRANSLATION_ENGINE_STATUS[engine] = True
printLog("DeepL API Key is valid")
else:
# error update Auth key
auth_keys = config.AUTH_KEYS
auth_keys[engine] = None
config.AUTH_KEYS = auth_keys
printLog("DeepL API Key is invalid")
case "Plamo_API":
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:
config.SELECTABLE_TRANSLATION_ENGINE_STATUS[engine] = True
printLog("Plamo API Key is valid")
else:
# error update Auth key
auth_keys = config.AUTH_KEYS
auth_keys[engine] = None
config.AUTH_KEYS = auth_keys
printLog("Plamo API Key is invalid")
case "Gemini_API":
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:
config.SELECTABLE_TRANSLATION_ENGINE_STATUS[engine] = True
printLog("Gemini API Key is valid")
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 _:
if connected_network is True:
config.SELECTABLE_TRANSLATION_ENGINE_STATUS[engine] = True

View File

@@ -199,11 +199,11 @@ class Model:
return result
def authenticationTranslatorPlamoAuthKey(self, auth_key: str, model: str) -> bool:
result = self.translator.authenticationPlamoAuthKey(auth_key, model=model)
result = self.translator.authenticationPlamoAuthKey(auth_key, model=model, root_path=config.PATH_LOCAL)
return result
def authenticationTranslatorGeminiAuthKey(self, auth_key: str, model: str) -> bool:
result = self.translator.authenticationGeminiAuthKey(auth_key, model=model)
result = self.translator.authenticationGeminiAuthKey(auth_key, model=model, root_path=config.PATH_LOCAL)
return result
def startLogger(self):

View File

@@ -26,10 +26,17 @@ class OverlayImage:
defaults to repository `fonts` directory.
"""
self.message_log: List[dict] = []
if root_path is None:
self.root_path = os_path.join(os_path.dirname(__file__), "..", "..", "..", "fonts")
else:
# PyInstallerでビルドされた場合のパス
if root_path and os_path.exists(os_path.join(root_path, "_internal", "fonts")):
self.root_path = os_path.join(root_path, "_internal", "fonts")
# src-pythonフォルダから直接実行している場合のパス
elif os_path.exists(os_path.join(os_path.dirname(__file__), "models", "overlay", "fonts")):
self.root_path = os_path.join(os_path.dirname(__file__), "models", "overlay", "fonts")
# overlayフォルダから直接実行している場合のパス
elif os_path.exists(os_path.join(os_path.dirname(__file__), "fonts")):
self.root_path = os_path.join(os_path.dirname(__file__), "fonts")
else:
raise FileNotFoundError("Font directory not found.")
@staticmethod
def concatenateImagesVertically(img1: Image, img2: Image, margin: int = 0) -> Image:
@@ -69,20 +76,8 @@ class OverlayImage:
img = Image.new("RGBA", (base_width, base_height), (0, 0, 0, 0))
draw = ImageDraw.Draw(img)
try:
font_path = os_path.join(self.root_path, font_family)
font = ImageFont.truetype(font_path, font_size)
except Exception:
# overlayフォルダから操作している場合
if os_path.exists(os_path.join(os_path.dirname(__file__), "..", "..", "..", "fonts", font_family)):
font_path = os_path.join(os_path.dirname(__file__), "..", "..", "..", "fonts", font_family)
font = ImageFont.truetype(font_path, font_size)
elif os_path.exists(os_path.join(os_path.dirname(__file__), "fonts", font_family)):
# src-pythonフォルダから操作している場合
font_path = os_path.join(os_path.dirname(__file__), "fonts", font_family)
font = ImageFont.truetype(font_path, font_size)
else:
raise FileNotFoundError(f"Font file not found: {font_family}")
text_width = draw.textlength(text, font)
character_width = text_width // len(text)
@@ -180,18 +175,8 @@ class OverlayImage:
img = Image.new("RGBA", (0, 0), (0, 0, 0, 0))
draw = ImageDraw.Draw(img)
try:
font_path = os_path.join(self.root_path, font_family)
font = ImageFont.truetype(font_path, font_size)
except Exception:
if os_path.exists(os_path.join(os_path.dirname(__file__), "..", "..", "..", "fonts", font_family)):
font_path = os_path.join(os_path.dirname(__file__), "..", "..", "..", "fonts", font_family)
font = ImageFont.truetype(font_path, font_size)
elif os_path.exists(os_path.join(os_path.dirname(__file__), "fonts", font_family)):
font_path = os_path.join(os_path.dirname(__file__), "fonts", font_family)
font = ImageFont.truetype(font_path, font_size)
else:
raise FileNotFoundError(f"Font file not found: {font_family}")
# 改行を含んだtextの最大の文字数を計算する
text_width = max(draw.textlength(line, font) for line in text.split("\n"))
@@ -221,20 +206,8 @@ class OverlayImage:
img = Image.new("RGBA", (0, 0), (0, 0, 0, 0))
draw = ImageDraw.Draw(img)
try:
font_path = os_path.join(self.root_path, self.LANGUAGES["Default"])
font = ImageFont.truetype(font_path, font_size)
except Exception:
# overlayフォルダから操作している場合
if os_path.exists(os_path.join(os_path.dirname(__file__), "..", "..", "..", "fonts", self.LANGUAGES["Default"])):
font_path = os_path.join(os_path.dirname(__file__), "..", "..", "..", "fonts", self.LANGUAGES["Default"])
font = ImageFont.truetype(font_path, font_size)
elif os_path.exists(os_path.join(os_path.dirname(__file__), "fonts", self.LANGUAGES["Default"])):
# src-pythonフォルダから操作している場合
font_path = os_path.join(os_path.dirname(__file__), "fonts", self.LANGUAGES["Default"])
font = ImageFont.truetype(font_path, font_size)
else:
raise FileNotFoundError(f"Font file not found: {self.LANGUAGES['Default']}")
text_height = font_size + ui_padding
text_width = draw.textlength(date_time, font)

View File

@@ -0,0 +1,45 @@
system_prompt: |
Please translate the following text from {input_lang} to {output_lang}.
Only provide the translated text as the output.
{text}
supported_languages: |
Arabic
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

View File

@@ -0,0 +1,39 @@
system_prompt: |
You are a translation assistant that uses the `plamo-translate` tool.
Translate the following text.Supported languages include:
{supported_languages}
Translate the following text from {input_lang} to {output_lang}.
output only the translated text without any additional commentary.
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
Simplified Chinese
Traditional Chinese

View File

@@ -1,6 +1,8 @@
import logging
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)
@@ -17,19 +19,39 @@ _MODELS = [
]
class GeminiClient:
def __init__(self, api_key: str = "", model: str = "gemini-2.5-flash-lite"):
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
self.prompt_template = """
Please translate the following text from {input_lang} to {output_lang}.
Only provide the translated text as the output.
{text}
"""
# プロンプト設定を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:
"""プロンプト設定をYAMLファイルから読み込む"""
prompt_filename = "translation_gemini.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)
def getListModels(self) -> list[str]:
return _MODELS
@@ -112,50 +134,8 @@ if __name__ == "__main__":
# except Exception:
# print("Invalid API key. Please check your credentials.")
supported_languages = """
Arabic
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"):
# 外部ファイルから読み込んだサポート言語を使用
for lang in gemini_client.supported_languages.split("\n"):
if lang == "":
continue
print (f"Translating to {lang}:")

View File

@@ -615,8 +615,8 @@ dict_plamo_languages = {
"Hungarian": "Hungarian",
"Greek": "Greek",
"Hebrew": "Hebrew",
"Simplified Chinese":"Simplified Chinese",
"Traditional Chinese":"Traditional Chinese"
"Chinese Simplified":"Simplified Chinese",
"Chinese Traditional":"Traditional Chinese"
}
translation_lang["Plamo_API"] = {"source":dict_plamo_languages, "target":dict_plamo_languages}
@@ -625,8 +625,8 @@ dict_gemini_languages = {
"Arabic": "Arabic",
"Bengali": "Bengali",
"Bulgarian": "Bulgarian",
"Simplified Chinese": "Simplified Chinese",
"Traditional Chinese": "Traditional Chinese",
"Chinese Simplified": "Simplified Chinese",
"Chinese Traditional": "Traditional Chinese",
"Croatian": "Croatian",
"Czech": "Czech",
"Danish": "Danish",

View File

@@ -1,53 +1,23 @@
from langchain_openai import ChatOpenAI
from pydantic import SecretStr
import yaml
from os import path as os_path
_MODELS = [
"plamo-2.0-prime"
]
class PlamoClient:
def __init__(self, api_key: str = "", model: str = "plamo-2.0-prime"):
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
self.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
Simplified Chinese
Traditional Chinese
"""
self.prompt_template = f"""
You are a translation assistant that uses the `plamo-translate` tool.
Translate the following text.Supported languages include:{self.supported_languages}
Translate the following text from {{input_lang}} to {{output_lang}}.
output only the translated text without any additional commentary.
"""
# プロンプト設定をYAMLファイルから読み込む
prompt_config = self._load_prompt_config(root_path)
self.supported_languages = prompt_config["supported_languages"]
self.prompt_template = prompt_config["system_prompt"]
self.plamo_llm = ChatOpenAI(
base_url=self.base_url,
model=self.model,
@@ -55,6 +25,25 @@ class PlamoClient:
api_key=SecretStr(self.api_key),
)
def _load_prompt_config(self, root_path: str = None) -> dict:
"""プロンプト設定をYAMLファイルから読み込む"""
prompt_filename = "translation_plamo.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)
def getListModels(self) -> list[str]:
return _MODELS
@@ -78,13 +67,11 @@ class PlamoClient:
)
return True
except Exception as e:
print(f"Error setting AuthKey: {e}")
return False
def setModel(self, model: str) -> bool:
"""モデルを設定し、成功したかどうかを返す"""
if model not in _MODELS:
print(f"Model {model} is not in the supported model list.")
return False
try:
@@ -105,7 +92,9 @@ class PlamoClient:
{
"role": "system",
"content": self.prompt_template.format(
input_lang=input_lang, output_lang=output_lang
supported_languages=self.supported_languages,
input_lang=input_lang,
output_lang=output_lang
),
},
{"role": "user", "content": text},
@@ -130,7 +119,8 @@ class PlamoClient:
self.setModel(self.model)
self.translate("Hello World", input_lang="English", output_lang="Japanese")
return True
except Exception:
except Exception as e:
print(f"Error checking AuthKey: {e}")
return False
if __name__ == "__main__":

View File

@@ -66,14 +66,14 @@ class Translator:
result = False
return result
def authenticationPlamoAuthKey(self, auth_key: str, model: str) -> bool:
def authenticationPlamoAuthKey(self, auth_key: str, model: 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)
self.plamo_client = PlamoClient(auth_key, model=model, root_path=root_path)
self.plamo_client.checkAuthKey()
except Exception:
errorLogging()
@@ -81,14 +81,14 @@ class Translator:
result = False
return result
def authenticationGeminiAuthKey(self, auth_key: str, model: str) -> bool:
def authenticationGeminiAuthKey(self, auth_key: str, model: 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)
self.gemini_client = GeminiClient(auth_key, model=model, root_path=root_path)
self.gemini_client.checkAuthKey()
except Exception:
errorLogging()