LMStudio と Ollama の翻訳バックエンドを追加・統合。
- config: SELECTABLE_/SELECTED_ の LMStudio/Ollama 項目と LMSTUDIO_URL を追加。 - Controller: LMStudio/Ollama の認証チェック、URL取得/設定、モデル一覧取得/設定のエンドポイントを実装。 - Model/Translator: LMStudio/Ollama 用の認証・モデル一覧・モデル設定・クライアント更新メソッドを追加し、翻訳処理の選択肢に対応。 - translation_* クライアント: 各クライアントでのプロンプト読み込み処理を共通化し、translation_utils.loadPromptConfig を利用するようにリファクタ。 - translation_languages: LMStudio/Ollama 用の言語マッピングを追加。
This commit is contained in:
@@ -338,6 +338,24 @@ class Config:
|
|||||||
if isinstance(value, list):
|
if isinstance(value, list):
|
||||||
self._SELECTABLE_OPENAI_MODEL_LIST = value
|
self._SELECTABLE_OPENAI_MODEL_LIST = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def SELECTABLE_LMSTUDIO_MODEL_LIST(self):
|
||||||
|
return self._SELECTABLE_LMSTUDIO_MODEL_LIST
|
||||||
|
|
||||||
|
@SELECTABLE_LMSTUDIO_MODEL_LIST.setter
|
||||||
|
def SELECTABLE_LMSTUDIO_MODEL_LIST(self, value):
|
||||||
|
if isinstance(value, list):
|
||||||
|
self._SELECTABLE_LMSTUDIO_MODEL_LIST = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def SELECTABLE_OLLAMA_MODEL_LIST(self):
|
||||||
|
return self._SELECTABLE_OLLAMA_MODEL_LIST
|
||||||
|
|
||||||
|
@SELECTABLE_OLLAMA_MODEL_LIST.setter
|
||||||
|
def SELECTABLE_OLLAMA_MODEL_LIST(self, value):
|
||||||
|
if isinstance(value, list):
|
||||||
|
self._SELECTABLE_OLLAMA_MODEL_LIST = value
|
||||||
|
|
||||||
# Save Json Data
|
# Save Json Data
|
||||||
## Main Window
|
## Main Window
|
||||||
@property
|
@property
|
||||||
@@ -957,6 +975,41 @@ class Config:
|
|||||||
self._SELECTED_OPENAI_MODEL = value
|
self._SELECTED_OPENAI_MODEL = value
|
||||||
self.saveConfig(inspect.currentframe().f_code.co_name, value)
|
self.saveConfig(inspect.currentframe().f_code.co_name, value)
|
||||||
|
|
||||||
|
@property
|
||||||
|
@json_serializable('LMSTUDIO_URL')
|
||||||
|
def LMSTUDIO_URL(self):
|
||||||
|
return self._LMSTUDIO_URL
|
||||||
|
|
||||||
|
@LMSTUDIO_URL.setter
|
||||||
|
def LMSTUDIO_URL(self, value):
|
||||||
|
if isinstance(value, str):
|
||||||
|
self._LMSTUDIO_URL = value
|
||||||
|
self.saveConfig(inspect.currentframe().f_code.co_name, value)
|
||||||
|
|
||||||
|
@property
|
||||||
|
@json_serializable('SELECTED_LMSTUDIO_MODEL')
|
||||||
|
def SELECTED_LMSTUDIO_MODEL(self):
|
||||||
|
return self._SELECTED_LMSTUDIO_MODEL
|
||||||
|
|
||||||
|
@SELECTED_LMSTUDIO_MODEL.setter
|
||||||
|
def SELECTED_LMSTUDIO_MODEL(self, value):
|
||||||
|
if isinstance(value, str):
|
||||||
|
if value in self.SELECTABLE_LMSTUDIO_MODEL_LIST:
|
||||||
|
self._SELECTED_LMSTUDIO_MODEL = value
|
||||||
|
self.saveConfig(inspect.currentframe().f_code.co_name, value)
|
||||||
|
|
||||||
|
@property
|
||||||
|
@json_serializable('SELECTED_OLLAMA_MODEL')
|
||||||
|
def SELECTED_OLLAMA_MODEL(self):
|
||||||
|
return self._SELECTED_OLLAMA_MODEL
|
||||||
|
|
||||||
|
@SELECTED_OLLAMA_MODEL.setter
|
||||||
|
def SELECTED_OLLAMA_MODEL(self, value):
|
||||||
|
if isinstance(value, str):
|
||||||
|
if value in self.SELECTABLE_OLLAMA_MODEL_LIST:
|
||||||
|
self._SELECTED_OLLAMA_MODEL = value
|
||||||
|
self.saveConfig(inspect.currentframe().f_code.co_name, value)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@json_serializable('AUTO_CLEAR_MESSAGE_BOX')
|
@json_serializable('AUTO_CLEAR_MESSAGE_BOX')
|
||||||
def AUTO_CLEAR_MESSAGE_BOX(self):
|
def AUTO_CLEAR_MESSAGE_BOX(self):
|
||||||
@@ -1234,6 +1287,8 @@ class Config:
|
|||||||
self._SELECTABLE_PLAMO_MODEL_LIST = []
|
self._SELECTABLE_PLAMO_MODEL_LIST = []
|
||||||
self._SELECTABLE_GEMINI_MODEL_LIST = []
|
self._SELECTABLE_GEMINI_MODEL_LIST = []
|
||||||
self._SELECTABLE_OPENAI_MODEL_LIST = []
|
self._SELECTABLE_OPENAI_MODEL_LIST = []
|
||||||
|
self._SELECTABLE_LMSTUDIO_MODEL_LIST = []
|
||||||
|
self._SELECTABLE_OLLAMA_MODEL_LIST = []
|
||||||
|
|
||||||
# Save Json Data
|
# Save Json Data
|
||||||
## Main Window
|
## Main Window
|
||||||
@@ -1344,6 +1399,9 @@ class Config:
|
|||||||
self._SELECTED_PLAMO_MODEL = None
|
self._SELECTED_PLAMO_MODEL = None
|
||||||
self._SELECTED_GEMINI_MODEL = None
|
self._SELECTED_GEMINI_MODEL = None
|
||||||
self._SELECTED_OPENAI_MODEL = None
|
self._SELECTED_OPENAI_MODEL = None
|
||||||
|
self._LMSTUDIO_URL = "http://127.0.0.1:1234"
|
||||||
|
self._SELECTED_LMSTUDIO_MODEL = None
|
||||||
|
self._SELECTED_OLLAMA_MODEL = None
|
||||||
self._SELECTED_TRANSLATION_COMPUTE_TYPE = "auto"
|
self._SELECTED_TRANSLATION_COMPUTE_TYPE = "auto"
|
||||||
self._WHISPER_WEIGHT_TYPE = "base"
|
self._WHISPER_WEIGHT_TYPE = "base"
|
||||||
self._SELECTED_TRANSCRIPTION_COMPUTE_TYPE = "auto"
|
self._SELECTED_TRANSCRIPTION_COMPUTE_TYPE = "auto"
|
||||||
|
|||||||
@@ -1877,6 +1877,129 @@ class Controller:
|
|||||||
}
|
}
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
def getTranslatorLMStudioURL(self, *args, **kwargs) -> dict:
|
||||||
|
return {"status":200, "result":config.LMSTUDIO_URL}
|
||||||
|
|
||||||
|
def setTranslatorLMStudioURL(self, data, *args, **kwargs) -> dict:
|
||||||
|
printLog("Set Translator LMStudio URL", data)
|
||||||
|
try:
|
||||||
|
data = str(data)
|
||||||
|
result = model.authenticationTranslatorLMStudio(base_url=data)
|
||||||
|
if result is True:
|
||||||
|
config.LMSTUDIO_URL = data
|
||||||
|
response = {"status":200, "result":config.LMSTUDIO_URL}
|
||||||
|
else:
|
||||||
|
response = {
|
||||||
|
"status":400,
|
||||||
|
"result":{
|
||||||
|
"message":"LMStudio URL is not valid",
|
||||||
|
"data": config.LMSTUDIO_URL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
errorLogging()
|
||||||
|
response = {
|
||||||
|
"status":400,
|
||||||
|
"result":{
|
||||||
|
"message":f"Error {e}",
|
||||||
|
"data": config.LMSTUDIO_URL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return response
|
||||||
|
|
||||||
|
def getTranslatorLStudioModelList(self, *args, **kwargs) -> dict:
|
||||||
|
model_list = model.getTranslatorLMStudioModelList()
|
||||||
|
return {"status":200, "result": model_list}
|
||||||
|
|
||||||
|
def getTranslatorLMStudioModel(self, *args, **kwargs) -> dict:
|
||||||
|
return {"status":200, "result":config.SELECTED_LMSTUDIO_MODEL}
|
||||||
|
|
||||||
|
def setTranslatorLMStudioModel(self, data, *args, **kwargs) -> dict:
|
||||||
|
printLog("Set Translator LMStudio Model", data)
|
||||||
|
try:
|
||||||
|
data = str(data)
|
||||||
|
result = model.setTranslatorLMStudioModel(model=data)
|
||||||
|
if result is True:
|
||||||
|
config.SELECTED_LMSTUDIO_MODEL = data
|
||||||
|
response = {"status":200, "result":config.SELECTED_LMSTUDIO_MODEL}
|
||||||
|
else:
|
||||||
|
response = {
|
||||||
|
"status":400,
|
||||||
|
"result":{
|
||||||
|
"message":"LMStudio model is not valid",
|
||||||
|
"data": config.SELECTED_LMSTUDIO_MODEL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
errorLogging()
|
||||||
|
response = {
|
||||||
|
"status":400,
|
||||||
|
"result":{
|
||||||
|
"message":f"Error {e}",
|
||||||
|
"data": config.SELECTED_LMSTUDIO_MODEL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return response
|
||||||
|
|
||||||
|
def checkTranslatorLOllamaConnection(self, *args, **kwargs) -> dict:
|
||||||
|
printLog("Check Translator Lollama Connection")
|
||||||
|
try:
|
||||||
|
result = model.authenticationTranslatorOllama()
|
||||||
|
if result is True:
|
||||||
|
response = {"status":200, "result":True}
|
||||||
|
else:
|
||||||
|
response = {
|
||||||
|
"status":400,
|
||||||
|
"result":{
|
||||||
|
"message":"Cannot connect to Lollama server",
|
||||||
|
"data": False
|
||||||
|
}
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
errorLogging()
|
||||||
|
response = {
|
||||||
|
"status":400,
|
||||||
|
"result":{
|
||||||
|
"message":f"Error {e}",
|
||||||
|
"data": False
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return response
|
||||||
|
|
||||||
|
def getTranslatorLOllamaModelList(self, *args, **kwargs) -> dict:
|
||||||
|
model_list = model.getTranslatorOllamaModelList()
|
||||||
|
return {"status":200, "result": model_list}
|
||||||
|
|
||||||
|
def getTranslatorLOllamaModel(self, *args, **kwargs) -> dict:
|
||||||
|
return {"status":200, "result":config.SELECTED_OLLAMA_MODEL}
|
||||||
|
|
||||||
|
def setTranslatorLOllamaModel(self, data, *args, **kwargs) -> dict:
|
||||||
|
printLog("Set Translator Lollama Model", data)
|
||||||
|
try:
|
||||||
|
data = str(data)
|
||||||
|
result = model.setTranslatorOllamaModel(model=data)
|
||||||
|
if result is True:
|
||||||
|
config.SELECTED_OLLAMA_MODEL = data
|
||||||
|
response = {"status":200, "result":config.SELECTED_OLLAMA_MODEL}
|
||||||
|
else:
|
||||||
|
response = {
|
||||||
|
"status":400,
|
||||||
|
"result":{
|
||||||
|
"message":"Lollama model is not valid",
|
||||||
|
"data": config.SELECTED_OLLAMA_MODEL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
errorLogging()
|
||||||
|
response = {
|
||||||
|
"status":400,
|
||||||
|
"result":{
|
||||||
|
"message":f"Error {e}",
|
||||||
|
"data": config.SELECTED_OLLAMA_MODEL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return response
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def getCtranslate2WeightType(*args, **kwargs) -> dict:
|
def getCtranslate2WeightType(*args, **kwargs) -> dict:
|
||||||
return {"status":200, "result":config.CTRANSLATE2_WEIGHT_TYPE}
|
return {"status":200, "result":config.CTRANSLATE2_WEIGHT_TYPE}
|
||||||
@@ -2805,6 +2928,33 @@ class Controller:
|
|||||||
auth_keys[engine] = None
|
auth_keys[engine] = None
|
||||||
config.AUTH_KEYS = auth_keys
|
config.AUTH_KEYS = auth_keys
|
||||||
printLog("OpenAI API Key is invalid")
|
printLog("OpenAI API Key is invalid")
|
||||||
|
case "LMStudio":
|
||||||
|
printLog("Start check LMStudio API Key")
|
||||||
|
config.SELECTABLE_TRANSLATION_ENGINE_STATUS[engine] = False
|
||||||
|
if config.LMSTUDIO_URL is not None:
|
||||||
|
if model.authenticationTranslatorLMStudio(config.LMSTUDIO_URL) is True:
|
||||||
|
config.SELECTABLE_TRANSLATION_ENGINE_STATUS[engine] = True
|
||||||
|
printLog("LMStudio URL is valid")
|
||||||
|
config.SELECTABLE_LMSTUDIO_MODEL_LIST = model.getTranslatorLMStudioModelList()
|
||||||
|
if config.SELECTED_LMSTUDIO_MODEL not in config.SELECTABLE_LMSTUDIO_MODEL_LIST:
|
||||||
|
config.SELECTED_LMSTUDIO_MODEL = config.SELECTABLE_LMSTUDIO_MODEL_LIST[0]
|
||||||
|
model.setTranslatorLMStudioModel(config.SELECTED_LMSTUDIO_MODEL)
|
||||||
|
model.updateTranslatorLMStudioClient()
|
||||||
|
else:
|
||||||
|
printLog("LMStudio is not available")
|
||||||
|
case "Ollama":
|
||||||
|
printLog("Start check Ollama API Key")
|
||||||
|
config.SELECTABLE_TRANSLATION_ENGINE_STATUS[engine] = False
|
||||||
|
if model.authenticationTranslatorOllama() is True:
|
||||||
|
config.SELECTABLE_TRANSLATION_ENGINE_STATUS[engine] = True
|
||||||
|
printLog("Ollama is available")
|
||||||
|
config.SELECTABLE_OLLAMA_MODEL_LIST = model.getTranslatorOllamaModelList()
|
||||||
|
if config.SELECTED_OLLAMA_MODEL not in config.SELECTABLE_OLLAMA_MODEL_LIST:
|
||||||
|
config.SELECTED_OLLAMA_MODEL = config.SELECTABLE_OLLAMA_MODEL_LIST[0]
|
||||||
|
model.setTranslatorOllamaModel(config.SELECTED_OLLAMA_MODEL)
|
||||||
|
model.updateTranslatorOllamaClient()
|
||||||
|
else:
|
||||||
|
printLog("Ollama is not available")
|
||||||
case _:
|
case _:
|
||||||
if connected_network is True:
|
if connected_network is True:
|
||||||
config.SELECTABLE_TRANSLATION_ENGINE_STATUS[engine] = True
|
config.SELECTABLE_TRANSLATION_ENGINE_STATUS[engine] = True
|
||||||
|
|||||||
@@ -249,6 +249,38 @@ class Model:
|
|||||||
self.ensure_initialized()
|
self.ensure_initialized()
|
||||||
self.translator.updateOpenAIClient()
|
self.translator.updateOpenAIClient()
|
||||||
|
|
||||||
|
def authenticationTranslatorLMStudio(self, base_url: str) -> bool:
|
||||||
|
result = self.translator.setLMStudioClientURL(base_url=base_url, root_path=config.PATH_LOCAL)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def getTranslatorLMStudioModelList(self) -> list[str]:
|
||||||
|
self.ensure_initialized()
|
||||||
|
return self.translator.getLMStudioModelList()
|
||||||
|
|
||||||
|
def setTranslatorLMStudioModel(self, model: str) -> bool:
|
||||||
|
self.ensure_initialized()
|
||||||
|
return self.translator.setLMStudioModel(model=model)
|
||||||
|
|
||||||
|
def updateTranslatorLMStudioClient(self) -> None:
|
||||||
|
self.ensure_initialized()
|
||||||
|
self.translator.updateLMStudioClient()
|
||||||
|
|
||||||
|
def authenticationTranslatorOllama(self) -> bool:
|
||||||
|
result = self.translator.checkOllamaClient(root_path=config.PATH_LOCAL)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def getTranslatorOllamaModelList(self) -> list[str]:
|
||||||
|
self.ensure_initialized()
|
||||||
|
return self.translator.getOllamaModelList()
|
||||||
|
|
||||||
|
def setTranslatorOllamaModel(self, model: str) -> bool:
|
||||||
|
self.ensure_initialized()
|
||||||
|
return self.translator.setOllamaModel(model=model)
|
||||||
|
|
||||||
|
def updateTranslatorOllamaClient(self) -> None:
|
||||||
|
self.ensure_initialized()
|
||||||
|
self.translator.updateOllamaClient()
|
||||||
|
|
||||||
def startLogger(self):
|
def startLogger(self):
|
||||||
self.ensure_initialized()
|
self.ensure_initialized()
|
||||||
os_makedirs(config.PATH_LOGS, exist_ok=True)
|
os_makedirs(config.PATH_LOGS, exist_ok=True)
|
||||||
|
|||||||
@@ -1,8 +1,15 @@
|
|||||||
import logging
|
import logging
|
||||||
from google import genai
|
from google import genai
|
||||||
from langchain_google_genai import ChatGoogleGenerativeAI
|
from langchain_google_genai import ChatGoogleGenerativeAI
|
||||||
import yaml
|
|
||||||
from os import path as os_path
|
try:
|
||||||
|
from .translation_utils import loadPromptConfig
|
||||||
|
except Exception:
|
||||||
|
import sys
|
||||||
|
from os import path as os_path
|
||||||
|
print(os_path.dirname(os_path.dirname(os_path.dirname(os_path.abspath(__file__)))))
|
||||||
|
sys.path.append(os_path.dirname(os_path.dirname(os_path.dirname(os_path.abspath(__file__)))))
|
||||||
|
from translation_utils import loadPromptConfig
|
||||||
|
|
||||||
logger = logging.getLogger("langchain_google_genai")
|
logger = logging.getLogger("langchain_google_genai")
|
||||||
logger.setLevel(logging.ERROR)
|
logger.setLevel(logging.ERROR)
|
||||||
@@ -42,32 +49,13 @@ def _get_available_text_models(api_key: str) -> list[str]:
|
|||||||
allowed_models.sort()
|
allowed_models.sort()
|
||||||
return allowed_models
|
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:
|
class GeminiClient:
|
||||||
def __init__(self, root_path: str = None):
|
def __init__(self, root_path: str = None):
|
||||||
self.api_key = None
|
self.api_key = None
|
||||||
self.model = None
|
self.model = None
|
||||||
|
|
||||||
# プロンプト設定をYAMLファイルから読み込む
|
# プロンプト設定をYAMLファイルから読み込む
|
||||||
prompt_config = _load_prompt_config(root_path)
|
prompt_config = loadPromptConfig(root_path, "translation_gemini.yml")
|
||||||
self.supported_languages = prompt_config["supported_languages"]
|
self.supported_languages = prompt_config["supported_languages"]
|
||||||
self.prompt_template = prompt_config["system_prompt"]
|
self.prompt_template = prompt_config["system_prompt"]
|
||||||
|
|
||||||
|
|||||||
@@ -665,7 +665,6 @@ dict_gemini_languages = {
|
|||||||
|
|
||||||
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 = {
|
dict_openai_languages = {
|
||||||
"Arabic": "Arabic",
|
"Arabic": "Arabic",
|
||||||
"Bengali": "Bengali",
|
"Bengali": "Bengali",
|
||||||
@@ -710,3 +709,5 @@ dict_openai_languages = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
translation_lang["OpenAI_API"] = {"source": dict_openai_languages, "target": dict_openai_languages}
|
translation_lang["OpenAI_API"] = {"source": dict_openai_languages, "target": dict_openai_languages}
|
||||||
|
translation_lang["LMStudio"] = {"source": dict_openai_languages, "target": dict_openai_languages}
|
||||||
|
translation_lang["Ollama"] = {"source": dict_openai_languages, "target": dict_openai_languages}
|
||||||
@@ -1,8 +1,14 @@
|
|||||||
from openai import OpenAI
|
from openai import OpenAI
|
||||||
from langchain_openai import ChatOpenAI
|
from langchain_openai import ChatOpenAI
|
||||||
from pydantic import SecretStr
|
from pydantic import SecretStr
|
||||||
import yaml
|
|
||||||
from os import path as os_path
|
try:
|
||||||
|
from .translation_utils import loadPromptConfig
|
||||||
|
except Exception:
|
||||||
|
import sys
|
||||||
|
from os import path as os_path
|
||||||
|
sys.path.append(os_path.dirname(os_path.dirname(os_path.dirname(os_path.abspath(__file__)))))
|
||||||
|
from translation_utils import loadPromptConfig
|
||||||
|
|
||||||
def _authentication_check(api_key: str, base_url: str | None = None) -> bool:
|
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.
|
"""Check if the provided API key is valid by attempting to list models.
|
||||||
@@ -27,22 +33,6 @@ def _get_available_text_models(api_key: str, base_url: str | None = None) -> lis
|
|||||||
allowed_models.sort()
|
allowed_models.sort()
|
||||||
return allowed_models
|
return allowed_models
|
||||||
|
|
||||||
def _load_prompt_config(root_path: str = None) -> dict:
|
|
||||||
prompt_filename = "translation_lmstudio.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 LMStudioClient:
|
class LMStudioClient:
|
||||||
"""LM Studio Translation simple wrapper.
|
"""LM Studio Translation simple wrapper.
|
||||||
prompt/translation_lmstudio.yml から system_prompt / supported_languages を読み込む。
|
prompt/translation_lmstudio.yml から system_prompt / supported_languages を読み込む。
|
||||||
@@ -52,7 +42,7 @@ class LMStudioClient:
|
|||||||
self.model = None
|
self.model = None
|
||||||
self.base_url = base_url # None の場合は公式エンドポイント
|
self.base_url = base_url # None の場合は公式エンドポイント
|
||||||
|
|
||||||
prompt_config = _load_prompt_config(root_path)
|
prompt_config = loadPromptConfig(root_path, "translation_lmstudio.yml")
|
||||||
self.supported_languages = prompt_config["supported_languages"]
|
self.supported_languages = prompt_config["supported_languages"]
|
||||||
self.prompt_template = prompt_config["system_prompt"]
|
self.prompt_template = prompt_config["system_prompt"]
|
||||||
|
|
||||||
@@ -112,13 +102,11 @@ class LMStudioClient:
|
|||||||
return content.strip()
|
return content.strip()
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
AUTH_KEY = "lm-studio"
|
|
||||||
client = LMStudioClient(base_url="http://192.168.68.110:1234/v1")
|
client = LMStudioClient(base_url="http://192.168.68.110:1234/v1")
|
||||||
models = client.getModelList()
|
models = client.getModelList()
|
||||||
print(models)
|
if models:
|
||||||
# if models:
|
print("Available models:", models)
|
||||||
# print("Available models:", models)
|
model = input("Select a model: ")
|
||||||
# model = input("Select a model: ")
|
client.setModel(model)
|
||||||
client.setModel("google/gemma-3n-e4b")
|
client.updateClient()
|
||||||
client.updateClient()
|
print(client.translate("こんにちは世界", "Japanese", "English"))
|
||||||
print(client.translate("こんにちは世界", "Japanese", "English"))
|
|
||||||
@@ -1,8 +1,13 @@
|
|||||||
import requests
|
import requests
|
||||||
from langchain_ollama import ChatOllama
|
from langchain_ollama import ChatOllama
|
||||||
import yaml
|
|
||||||
from os import path as os_path
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
from .translation_utils import loadPromptConfig
|
||||||
|
except Exception:
|
||||||
|
import sys
|
||||||
|
from os import path as os_path
|
||||||
|
sys.path.append(os_path.dirname(os_path.dirname(os_path.dirname(os_path.abspath(__file__)))))
|
||||||
|
from translation_utils import loadPromptConfig
|
||||||
|
|
||||||
def _authentication_check(base_url: str | None = None) -> bool:
|
def _authentication_check(base_url: str | None = None) -> bool:
|
||||||
"""Check authentication for Ollama API.
|
"""Check authentication for Ollama API.
|
||||||
@@ -29,22 +34,6 @@ def _get_available_text_models(base_url: str | None = None) -> list[str]:
|
|||||||
allowed_models.sort()
|
allowed_models.sort()
|
||||||
return allowed_models
|
return allowed_models
|
||||||
|
|
||||||
def _load_prompt_config(root_path: str = None) -> dict:
|
|
||||||
prompt_filename = "translation_ollama.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 OllamaClient:
|
class OllamaClient:
|
||||||
"""Ollama Translation simple wrapper.
|
"""Ollama Translation simple wrapper.
|
||||||
prompt/translation_ollama.yml から system_prompt / supported_languages を読み込む。
|
prompt/translation_ollama.yml から system_prompt / supported_languages を読み込む。
|
||||||
@@ -53,14 +42,17 @@ class OllamaClient:
|
|||||||
self.model = None
|
self.model = None
|
||||||
self.base_url = "http://localhost:11434"
|
self.base_url = "http://localhost:11434"
|
||||||
|
|
||||||
prompt_config = _load_prompt_config(root_path)
|
prompt_config = loadPromptConfig(root_path)
|
||||||
self.supported_languages = prompt_config["supported_languages"]
|
self.supported_languages = prompt_config["supported_languages"]
|
||||||
self.prompt_template = prompt_config["system_prompt"]
|
self.prompt_template = prompt_config["system_prompt"]
|
||||||
|
|
||||||
self.openai_llm = None
|
self.openai_llm = None
|
||||||
|
|
||||||
|
def authenticationCheck(self) -> bool:
|
||||||
|
return _authentication_check(self.base_url)
|
||||||
|
|
||||||
def getModelList(self) -> list[str]:
|
def getModelList(self) -> list[str]:
|
||||||
if _authentication_check(self.base_url):
|
if self.authenticationCheck():
|
||||||
return _get_available_text_models(self.base_url)
|
return _get_available_text_models(self.base_url)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
@@ -111,5 +103,5 @@ if __name__ == "__main__":
|
|||||||
print("Available models:", models)
|
print("Available models:", models)
|
||||||
model = input("Select a model: ")
|
model = input("Select a model: ")
|
||||||
client.setModel(model)
|
client.setModel(model)
|
||||||
client.updateClient()
|
client.updateClient()
|
||||||
print(client.translate("こんにちは世界", "Japanese", "English"))
|
print(client.translate("こんにちは世界", "Japanese", "English"))
|
||||||
@@ -1,8 +1,14 @@
|
|||||||
from openai import OpenAI
|
from openai import OpenAI
|
||||||
from langchain_openai import ChatOpenAI
|
from langchain_openai import ChatOpenAI
|
||||||
from pydantic import SecretStr
|
from pydantic import SecretStr
|
||||||
import yaml
|
|
||||||
from os import path as os_path
|
try:
|
||||||
|
from .translation_utils import loadPromptConfig
|
||||||
|
except Exception:
|
||||||
|
import sys
|
||||||
|
from os import path as os_path
|
||||||
|
sys.path.append(os_path.dirname(os_path.dirname(os_path.dirname(os_path.abspath(__file__)))))
|
||||||
|
from translation_utils import loadPromptConfig
|
||||||
|
|
||||||
def _authentication_check(api_key: str, base_url: str | None = None) -> bool:
|
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.
|
"""Check if the provided API key is valid by attempting to list models.
|
||||||
@@ -51,22 +57,6 @@ def _get_available_text_models(api_key: str, base_url: str | None = None) -> lis
|
|||||||
allowed_models.sort()
|
allowed_models.sort()
|
||||||
return allowed_models
|
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:
|
class OpenAIClient:
|
||||||
"""OpenAI Translation simple wrapper.
|
"""OpenAI Translation simple wrapper.
|
||||||
prompt/translation_openai.yml から system_prompt / supported_languages を読み込む。
|
prompt/translation_openai.yml から system_prompt / supported_languages を読み込む。
|
||||||
@@ -76,7 +66,7 @@ class OpenAIClient:
|
|||||||
self.model = None
|
self.model = None
|
||||||
self.base_url = base_url # None の場合は公式エンドポイント
|
self.base_url = base_url # None の場合は公式エンドポイント
|
||||||
|
|
||||||
prompt_config = _load_prompt_config(root_path)
|
prompt_config = loadPromptConfig(root_path, "translation_openai.yml")
|
||||||
self.supported_languages = prompt_config["supported_languages"]
|
self.supported_languages = prompt_config["supported_languages"]
|
||||||
self.prompt_template = prompt_config["system_prompt"]
|
self.prompt_template = prompt_config["system_prompt"]
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
from openai import OpenAI
|
from openai import OpenAI
|
||||||
from langchain_openai import ChatOpenAI
|
from langchain_openai import ChatOpenAI
|
||||||
from pydantic import SecretStr
|
from pydantic import SecretStr
|
||||||
import yaml
|
|
||||||
from os import path as os_path
|
try:
|
||||||
|
from .translation_utils import loadPromptConfig
|
||||||
|
except Exception:
|
||||||
|
import sys
|
||||||
|
from os import path as os_path
|
||||||
|
sys.path.append(os_path.dirname(os_path.dirname(os_path.dirname(os_path.abspath(__file__)))))
|
||||||
|
from translation_utils import loadPromptConfig
|
||||||
|
|
||||||
BASE_URL = "https://api.platform.preferredai.jp/v1"
|
BASE_URL = "https://api.platform.preferredai.jp/v1"
|
||||||
|
|
||||||
@@ -29,32 +35,13 @@ def _get_available_text_models(api_key: str) -> list[str]:
|
|||||||
allowed_models.sort()
|
allowed_models.sort()
|
||||||
return allowed_models
|
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:
|
class PlamoClient:
|
||||||
def __init__(self, root_path: str = None):
|
def __init__(self, root_path: str = None):
|
||||||
self.api_key = None
|
self.api_key = None
|
||||||
self.base_url = BASE_URL
|
self.base_url = BASE_URL
|
||||||
self.model = None
|
self.model = None
|
||||||
|
|
||||||
prompt_config = _load_prompt_config(root_path)
|
prompt_config = loadPromptConfig(root_path, "translation_plamo.yml")
|
||||||
self.supported_languages = prompt_config["supported_languages"]
|
self.supported_languages = prompt_config["supported_languages"]
|
||||||
self.prompt_template = prompt_config["system_prompt"]
|
self.prompt_template = prompt_config["system_prompt"]
|
||||||
|
|
||||||
|
|||||||
@@ -13,15 +13,18 @@ try:
|
|||||||
from .translation_plamo import PlamoClient
|
from .translation_plamo import PlamoClient
|
||||||
from .translation_gemini import GeminiClient
|
from .translation_gemini import GeminiClient
|
||||||
from .translation_openai import OpenAIClient
|
from .translation_openai import OpenAIClient
|
||||||
|
from .translation_lmstudio import LMStudioClient
|
||||||
|
from .translation_ollama import OllamaClient
|
||||||
except Exception:
|
except Exception:
|
||||||
import sys
|
import sys
|
||||||
print(os_path.dirname(os_path.dirname(os_path.dirname(os_path.abspath(__file__)))))
|
|
||||||
sys.path.append(os_path.dirname(os_path.dirname(os_path.dirname(os_path.abspath(__file__)))))
|
sys.path.append(os_path.dirname(os_path.dirname(os_path.dirname(os_path.abspath(__file__)))))
|
||||||
from translation_languages import translation_lang
|
from translation_languages import translation_lang
|
||||||
from translation_utils import ctranslate2_weights
|
from translation_utils import ctranslate2_weights
|
||||||
from translation_plamo import PlamoClient
|
from translation_plamo import PlamoClient
|
||||||
from translation_gemini import GeminiClient
|
from translation_gemini import GeminiClient
|
||||||
from translation_openai import OpenAIClient
|
from translation_openai import OpenAIClient
|
||||||
|
from translation_lmstudio import LMStudioClient
|
||||||
|
from translation_ollama import OllamaClient
|
||||||
|
|
||||||
import ctranslate2
|
import ctranslate2
|
||||||
import transformers
|
import transformers
|
||||||
@@ -47,6 +50,8 @@ class Translator:
|
|||||||
self.plamo_client: Optional[PlamoClient] = None
|
self.plamo_client: Optional[PlamoClient] = None
|
||||||
self.gemini_client: Optional[GeminiClient] = None
|
self.gemini_client: Optional[GeminiClient] = None
|
||||||
self.openai_client: Optional[OpenAIClient] = None
|
self.openai_client: Optional[OpenAIClient] = None
|
||||||
|
self.lmstudio_client: LMStudioClient[LMStudioClient] = None
|
||||||
|
self.ollama_client: OllamaClient[OllamaClient] = None
|
||||||
self.ctranslate2_translator: Any = None
|
self.ctranslate2_translator: Any = None
|
||||||
self.ctranslate2_tokenizer: Any = None
|
self.ctranslate2_tokenizer: Any = None
|
||||||
self.is_loaded_ctranslate2_model: bool = False
|
self.is_loaded_ctranslate2_model: bool = False
|
||||||
@@ -171,6 +176,67 @@ class Translator:
|
|||||||
"""Update the OpenAI client (fetch available models)."""
|
"""Update the OpenAI client (fetch available models)."""
|
||||||
self.openai_client.updateClient()
|
self.openai_client.updateClient()
|
||||||
|
|
||||||
|
def setLMStudioClientURL(self, base_url: str | None = None, root_path: str = None) -> bool:
|
||||||
|
"""Authenticate LM Studio with the provided base URL.
|
||||||
|
|
||||||
|
Returns True on success, False on failure.
|
||||||
|
"""
|
||||||
|
self.lmstudio_client = LMStudioClient(base_url=base_url, root_path=root_path)
|
||||||
|
result = self.lmstudio_client.setBaseURL(base_url)
|
||||||
|
if result is False:
|
||||||
|
self.lmstudio_client = None
|
||||||
|
return result
|
||||||
|
|
||||||
|
def getLMStudioModelList(self) -> list[str]:
|
||||||
|
"""Get available LM Studio models.
|
||||||
|
|
||||||
|
Returns a list of model names, or an empty list on failure.
|
||||||
|
"""
|
||||||
|
if self.lmstudio_client is None:
|
||||||
|
return []
|
||||||
|
return self.lmstudio_client.getModelList()
|
||||||
|
|
||||||
|
def setLMStudioModel(self, model: str) -> bool:
|
||||||
|
"""Change the LM Studio model used for translation.
|
||||||
|
"""
|
||||||
|
if self.lmstudio_client is None:
|
||||||
|
return False
|
||||||
|
return self.lmstudio_client.setModel(model)
|
||||||
|
|
||||||
|
def updateLMStudioClient(self) -> None:
|
||||||
|
"""Update the LM Studio client (fetch available models)."""
|
||||||
|
self.lmstudio_client.updateClient()
|
||||||
|
|
||||||
|
def checkOllamaClient(self, root_path: str = None) -> bool:
|
||||||
|
"""Check if Ollama client is available.
|
||||||
|
|
||||||
|
Returns True if Ollama is reachable, False otherwise.
|
||||||
|
"""
|
||||||
|
self.ollama_client = OllamaClient(root_path=root_path)
|
||||||
|
return self.ollama_client.authenticationCheck()
|
||||||
|
|
||||||
|
def getOllamaModelList(self, root_path: str = None) -> bool:
|
||||||
|
"""Initialize Ollama client and fetch available models.
|
||||||
|
|
||||||
|
Returns True on success, False on failure.
|
||||||
|
"""
|
||||||
|
if self.ollama_client is None:
|
||||||
|
return []
|
||||||
|
return self.ollama_client.getModelList()
|
||||||
|
|
||||||
|
def setOllamaModel(self, model: str) -> bool:
|
||||||
|
"""Change the Ollama model used for translation.
|
||||||
|
|
||||||
|
Returns True on success, False on failure.
|
||||||
|
"""
|
||||||
|
if self.ollama_client is None:
|
||||||
|
return False
|
||||||
|
return self.ollama_client.setModel(model)
|
||||||
|
|
||||||
|
def updateOllamaClient(self) -> None:
|
||||||
|
"""Update the Ollama client (fetch available models)."""
|
||||||
|
self.ollama_client.updateClient()
|
||||||
|
|
||||||
def changeCTranslate2Model(self, path: str, model_type: str, device: str = "cpu", device_index: int = 0, compute_type: str = "auto") -> None:
|
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.
|
"""Load a CTranslate2 model from weights.
|
||||||
|
|
||||||
@@ -320,6 +386,24 @@ class Translator:
|
|||||||
input_lang=source_language,
|
input_lang=source_language,
|
||||||
output_lang=target_language,
|
output_lang=target_language,
|
||||||
)
|
)
|
||||||
|
case "LMStudio":
|
||||||
|
if self.lmstudio_client is None:
|
||||||
|
result = False
|
||||||
|
else:
|
||||||
|
result = self.lmstudio_client.translate(
|
||||||
|
message,
|
||||||
|
input_lang=source_language,
|
||||||
|
output_lang=target_language,
|
||||||
|
)
|
||||||
|
case "Ollama":
|
||||||
|
if self.ollama_client is None:
|
||||||
|
result = False
|
||||||
|
else:
|
||||||
|
result = self.ollama_client.translate(
|
||||||
|
message,
|
||||||
|
input_lang=source_language,
|
||||||
|
output_lang=target_language,
|
||||||
|
)
|
||||||
case "Google":
|
case "Google":
|
||||||
if self.is_enable_translators is True and other_web_Translator is not None:
|
if self.is_enable_translators is True and other_web_Translator is not None:
|
||||||
result = other_web_Translator(
|
result = other_web_Translator(
|
||||||
|
|||||||
@@ -2,11 +2,10 @@ from os import path as os_path
|
|||||||
from os import makedirs as os_makedirs
|
from os import makedirs as os_makedirs
|
||||||
from requests import get as requests_get
|
from requests import get as requests_get
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
import hashlib
|
|
||||||
import transformers
|
import transformers
|
||||||
import ctranslate2
|
import ctranslate2
|
||||||
from huggingface_hub import hf_hub_url, list_repo_files
|
from huggingface_hub import hf_hub_url, list_repo_files
|
||||||
from requests import get as requests_get
|
import yaml
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from utils import errorLogging, getBestComputeType
|
from utils import errorLogging, getBestComputeType
|
||||||
@@ -102,6 +101,21 @@ def downloadCTranslate2Tokenizer(path: str, weight_type: str = "m2m100_418M-ct2-
|
|||||||
tokenizer_path = os_path.join("./weights", "ctranslate2", directory_name, "tokenizer")
|
tokenizer_path = os_path.join("./weights", "ctranslate2", directory_name, "tokenizer")
|
||||||
transformers.AutoTokenizer.from_pretrained(tokenizer, cache_dir=tokenizer_path)
|
transformers.AutoTokenizer.from_pretrained(tokenizer, cache_dir=tokenizer_path)
|
||||||
|
|
||||||
|
def loadPromptConfig(root_path: str | None = None, prompt_filename: str | None = None) -> dict:
|
||||||
|
# PyInstaller 展開後
|
||||||
|
if root_path and prompt_filename 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 prompt_filename and 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 prompt_filename and 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)
|
||||||
|
|
||||||
# テスト用コード(直接実行時のみ)
|
# テスト用コード(直接実行時のみ)
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
def progress_callback(percent):
|
def progress_callback(percent):
|
||||||
|
|||||||
Reference in New Issue
Block a user