翻訳バックエンドを拡張・リファクタリング:OpenAI/Plamo/Gemini クライアントを追加・改修し、プロンプトを YAML から読み込むように変更。各クライアントでモデル一覧取得・認証・クライアント更新機能を実装し、Translator/Model 層の対応メソッドを追加。Controller と mainloop にプラモ・ジェミニ・OpenAI の認証/モデル操作エンドポイントを追加・整備。config のモデル/API設定をプロパティ化して既定値を None に変更し、選択肢リストを初期化。translation_languages に OpenAI 用マッピングを追加。requirements ファイルの依存記述を調整。
This commit is contained in:
@@ -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
|
||||
|
||||
49
src-python/models/translation/prompt/translation_openai.yml
Normal file
49
src-python/models/translation/prompt/translation_openai.yml
Normal 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
|
||||
@@ -1,148 +1,138 @@
|
||||
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
|
||||
|
||||
def _load_prompt_config(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)
|
||||
|
||||
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
|
||||
def __init__(self, root_path: str = None):
|
||||
self.api_key = None
|
||||
self.model = None
|
||||
|
||||
# プロンプト設定をYAMLファイルから読み込む
|
||||
prompt_config = self._load_prompt_config(root_path)
|
||||
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:
|
||||
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 setModel(self, model: str) -> bool:
|
||||
if model in self.getModelList():
|
||||
self.model = model
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def updateClient(self) -> None:
|
||||
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
|
||||
|
||||
def getAuthKey(self) -> str:
|
||||
"""現在のAuthKeyを取得する"""
|
||||
return self.api_key
|
||||
|
||||
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:
|
||||
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
|
||||
)
|
||||
system_prompt = self.prompt_template.format(
|
||||
supported_languages=self.supported_languages,
|
||||
input_lang=input_lang,
|
||||
output_lang=output_lang
|
||||
)
|
||||
|
||||
output = self.gemini_llm.invoke([HumanMessage(content=messages)])
|
||||
return output.content
|
||||
messages = [
|
||||
{"role": "system", "content": system_prompt},
|
||||
{"role": "user", "content": text}
|
||||
]
|
||||
|
||||
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
|
||||
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"))
|
||||
@@ -663,4 +663,50 @@ dict_gemini_languages = {
|
||||
"Vietnamese": "Vietnamese",
|
||||
}
|
||||
|
||||
translation_lang["Gemini_API"] = {"source":dict_gemini_languages, "target":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}
|
||||
148
src-python/models/translation/translation_openai.py
Normal file
148
src-python/models/translation/translation_openai.py
Normal 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"))
|
||||
@@ -1,147 +1,126 @@
|
||||
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"
|
||||
|
||||
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
|
||||
|
||||
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 = []
|
||||
|
||||
for model in res.data:
|
||||
allowed_models.append(model.id)
|
||||
|
||||
allowed_models.sort()
|
||||
return allowed_models
|
||||
|
||||
def _load_prompt_config(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)
|
||||
|
||||
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 __init__(self, root_path: str = None):
|
||||
self.api_key = None
|
||||
self.base_url = BASE_URL
|
||||
self.model = None
|
||||
|
||||
# プロンプト設定をYAMLファイルから読み込む
|
||||
prompt_config = self._load_prompt_config(root_path)
|
||||
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:
|
||||
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 setModel(self, model: str) -> bool:
|
||||
if model in self.getModelList():
|
||||
self.model = model
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
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),
|
||||
)
|
||||
|
||||
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
|
||||
|
||||
def getAuthKey(self) -> str:
|
||||
"""現在のAuthKeyを取得する"""
|
||||
return self.api_key
|
||||
|
||||
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:
|
||||
return False
|
||||
|
||||
try:
|
||||
self.model = model
|
||||
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:
|
||||
print(f"Error setting model: {e}")
|
||||
return 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": self.prompt_template.format(
|
||||
supported_languages=self.supported_languages,
|
||||
input_lang=input_lang,
|
||||
output_lang=output_lang
|
||||
),
|
||||
},
|
||||
{"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"))
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user