弃用腾讯翻译API,使用免费的翻译API,并修改项目名

This commit is contained in:
TFL-TFL
2024-05-19 12:47:19 +08:00
parent 5b00f8f758
commit 9311a34277
31 changed files with 512 additions and 193 deletions
+101 -81
View File
@@ -1,137 +1,157 @@
# 文本翻译
该自定义节点扩展 适用于 [ComfyUI](https://github.com/comfyanonymous/ComfyUI)。
可以自动识别输入的语言类型,并将其翻译成英语。
现版本无需申请翻译API,直接使用即可。
现已添加的翻译平台:阿里巴巴(Alibaba)、必应(Bing)、谷歌(Google)。
## 效果如下
<img src="images/image1.png" />
现已添加的翻译语言:中文(zh)、英文(en)。
### 在 [StableSwarmUI](https://github.com/Stability-AI/StableSwarmUI) 中使用 ComfyUI 作为后端的效果如下:
更多翻译平台请见 [Translators](https://github.com/UlionTse/translators)。其他的 翻译平台、翻译语言 等 需要自行添加,下文会给出其操作方法。
<img src="images/image11.png" />
## 注意:
1、更新前 需要将2024年05月19日前使用的老项目删除,当前项目与老项目完全不兼容。
## 说明
- 该节点采用了[腾讯翻译API](https://cloud.tencent.com/product/tmt)进行文本翻译。
- 可能会许多人需要使用这种类型的节点,但我目前尚未找到相关的开放资源,所以把这个分享给大家。
- 鉴于当前为个人使用的节点,暂时仅支持一个翻译API。如果将来有更多用户使用,可以考虑添加更多API支持。
- 因为日常并不经常使用Python,且刚刚接触了这个语言和ComfyUI自定义节点,所以可能存在一些未知的BUG。但目前为止,自己使用过程中尚未遇到过BUG。
- 随着使用这个节点,我将会对它进行修改、新增以及完善。
- 如果这对你有所帮助,可以给一个小星星呀~
2、该项目之前的项目名为 `ComfyUI_Text_Translation_zh_CN` 现修改为 `ComfyUI_Text_Translation`。
## 开始正文
### 1、节点介绍
(1)节点有两个文本输入和一个翻译启用开关
## 1、节点如下:
### 文本翻译
<img src="images/Text_Translation.png" width="512" />
<img src="images/image2.png" width="512"/>
默认使用必应翻译平台,自动识别语言翻译成英文。
翻译开关:开启(enabled);关闭(disabled)
### 文本翻译 V2
<img src="images/Text_Translation_V2.png" width="1024" />
(2)开启翻译后,如果在 “需翻译文本” 位置输入的内容不含有汉字,则不会调用 翻译API(避免浪费资源)。
默认隐藏多余选项,点击 `Show / Hide button` 显示或隐藏更多选项。
(3)如果想不显示“不需要翻译文本”的输入框,在该节点上点击鼠标右键,把将 text_normal 转换成输入模式即可,并不会影响功能。
### 文本联接
<img src="images/Text_Concatenate.png" width="200" />
`text_trans 为需要翻译的文本` `text_normal 为无需翻译的文本`
<img src="images/Text_Concatenate2.png" width="700" />
<img src="images/image3.png" width="512"/> <img src="images/image4.png" width="512"/>
自动根据连接的数量增加/减少 输入端,将输入端的值拼接成一个字符串。
### 文本
<img src="images/Text.png" width="512" />
(4)添加该节点,可以在 &nbsp; utils &nbsp;中选择,也可以双击鼠标左键搜索 `TencentTextTranslation`。
文本输入框。
<img src="images/image10.png" width="512"/>
### 文本开关
<img src="images/Text_Switch.png" width="256" />
文本开关,关闭则输出空字符串。
(5)如果想要查看翻译后的文本,你可以在打开ComfyUI时弹出来的终端上查看。
### 获取翻译平台列表
<img src="images/Get_Translator.png" width="256" />
<img src="images/image5.png" width="1024"/>
获取翻译平台列表,同时会在终端上显示。
当然你也可以选择在 &ensp; .node/tencent_translation.py &ensp; 文件中,把输出语句前加 “#” 注释掉。
<img src="images/Get_Translator_a.png" width="700" />
<img src="images/image6.png" width="1024"/>
想要在ComfyUI上显示输出文本可以使用,如 [ComfyUI-Custom-Scripts](https://github.com/pythongosssss/ComfyUI-Custom-Scripts) 中的 `ShowText` 或其他节点
(不显示它,用处不大。建议保留,可用于检查文本翻译是否正常。)
## 2、安装
如果在有这个输出语句的前提下,终端上没有显示,那么会是这个翻译API或代码有问题,可以向我反馈。当然请求翻译API时有问题也会在终端上显示。
### (1)添加该节点到&nbsp;ComfyUI
(6)如果你想修改翻译后的语言类型等功能,可在代码里修改。想要达到 &ensp; WebUI &ensp; 中可实时翻译或点击翻译的效果,该节点目前做不到,因为我不了解js脚本。
(7)代码里有注释,便于理解。
### 2、安装
(1)获取&nbsp;[腾讯翻译API](https://cloud.tencent.com/product/tmt)&nbsp;密钥(API接口说明:[腾讯翻译API文档](https://cloud.tencent.com/document/api/551/15619))
在浏览器搜索 &nbsp; “腾讯机器翻译” &nbsp; 或点击 &nbsp; [腾讯翻译](https://cloud.tencent.com/product/tmt) &nbsp; 前往,
登录自己的账号后依次点击 &nbsp;头像&nbsp; >>&nbsp;访问管理&nbsp; >>&nbsp;API密钥管理&nbsp;>>&nbsp;创建密钥&nbsp;>>&nbsp;复制密钥&nbsp;
<img src="images/image7.png" width="1024"/>
(2) 安装 &nbsp; 腾讯翻译SDK &nbsp;(更多安装介绍:[腾讯翻译SDK文档](https://cloud.tencent.com/document/sdk/Python))。
请先确定你使用的&nbsp;ComfyUI&nbsp;的&nbsp;Python&nbsp;目录在哪里,在终端中切换到该目录下,输入以下命令:
```
pip install --upgrade tencentcloud-sdk-python
```
或者使用国内镜像
```
pip install -i https://mirrors.tencent.com/pypi/simple/ --upgrade tencentcloud-sdk-python
```
(勿将SDK添加错位置,否则无效)
(3)添加该节点到&nbsp;ComfyUI
&ensp;1) 克隆本项目
#### &ensp;1) 方式一:克隆本项目
```
cd custom_nodes
```
```
git clone https://github.com/TFL-TFL/ComfyUI_Text_Translation_zh_CN.git
git clone https://github.com/TFL-TFL/ComfyUI_Text_Translation.git
```
&ensp;2) 直接下载ZIP
#### &ensp;2) 方式二:直接下载ZIP
下载解压后放入`custom_nodes`内
### (2)配置环境
```
cd ComfyUI_Text_Translation
```
(4)配置密钥
如果你下载的是&ensp;ComfyUI&ensp;的 便携版本,可直接执行下面代码,否则请将 `requirements.txt` 内的依赖安装到对应位置。
```
..\..\..\python_embeded\python.exe -s -m pip install -r requirements.txt
```
#### (3)更改 翻译平台、翻译语言
截止 [Translators](https://github.com/UlionTse/translators) 版本:v5.9.1 支持如下翻译平台:
&ensp;1) 直接写在代码里,在 &ensp; .custom_nodes/ComfyUI_Text_Translation_zh_CN/node/tencent_translation.py &ensp; 文件里,
找到`cred = credential.Credential("secretId", "secretKey")`这里填上你的密钥(&nbsp;"secretId" &nbsp;和&nbsp; "secretKey"&nbsp;)该方式有泄露密钥的风险,不推荐,但简单。
```
alibaba -- 阿里巴巴(Alibaba)
apertium -- Apertium
argos -- Argos
baidu -- 百度(Baidu)
bing -- 必应(Bing)
caiyun -- 彩云(Caiyun)
cloudTranslation -- 云翻译(CloudTranslation)
deepl -- DeepL
elia -- Elia
google -- 谷歌(Google)
hujiang -- 沪江(Hujiang)
iciba -- 金山词霸(ICIBA)
iflytek -- 讯飞(iFlytek)
iflyrec -- 讯飞语音识别(iFlyrec)
itranslate -- iTranslate
judic -- Judic
languageWire -- LanguageWire
lingvanex -- Lingvanex
niutrans -- 牛翻译(Niutrans)
mglip -- Mglip
mirai -- Mirai
modernMt -- ModernMT
myMemory -- MyMemory
papago -- Papago
qqFanyi -- QQ翻译(QQFanyi)
qqTranSmart -- QQ智能翻译(QQTranSmart)
reverso -- Reverso
sogou -- 搜狗(Sogou)
sysTran -- Systran
tilde -- Tilde
translateCom -- Translate.com
translateMe -- TranslateMe
utibet -- UTibet
volcEngine -- VolcEngine
yandex -- Yandex
yeekit -- Yeekit
youdao -- 有道(Youdao)
```
直接写在代码里,在 &ensp; .custom_nodes/ComfyUI_Text_Translation/nodes/text.py &ensp; 文件的如下位置修改:
<img src="images/Text_Translation_V2_s.png" width="1024"/>
<img src="images/image8.png" width="1024"/>
#### (4)修改节点显示的语言
直接写在代码里,在 &ensp; .custom_nodes/ComfyUI_Text_Translation/nodes/text.py &ensp; 文件的 开头和 结尾 位置修改:
&ensp;2) 放在环境变量里,添加`TENCENTCLOUD_SECRET_ID`和`TENCENTCLOUD_SECRET_KEY`,稍微多些步骤,但安全。(请在启动ComfyUI前设置好,若已启动
需要重启&nbsp;ComfyUI)
修改节点类别:
<img src="images/image9.png" width="1024"/>
<img src="images/Text_Translation_V2_a.png" width="500"/>
可在终端使用 `echo %环境变量名称%` 查看环境变量是否设置正确。
修改节点名称:
(5)重启ComfyUI
<img src="images/Text_Translation_V2_b.png" width="500"/>
#### (5)重启ComfyUI
所有的步骤都操作完啦,可以愉快的创作呦!
### 4、更新日志
2023-8-27
#### 2024-05-19
1、弃用腾讯翻译API,简化配置,使用&nbsp;[Translators](https://github.com/UlionTse/translators)&nbsp;提供的方式进行翻译,无需申请密钥了。
2、完全重写节点、新增或修改 “文本翻译”、“文本翻译 V2”、 “获取翻译平台列表”、“文本”、“文本开关”、“文本联接”节点。
2、完全重写节点、新增或修改 “文本翻译”、“文本翻译 V2”、 “获取翻译平台列表”、“文本”、“文本开关”、“文本联接”节点。
#### 2023-08-27
&emsp;去除“翻译开关”的默认值,以便适配&nbsp;[StableSwarmUI](https://github.com/Stability-AI/StableSwarmUI)&nbsp;,不然该开关的值会由“可选择类型”变成“要输入类型的文字”。
2023-8-22
#### 2023-08-22
&emsp;初始提交,节点采用了[腾讯翻译API](https://cloud.tencent.com/product/tmt)进行文本翻译。
### 5、其他
我对比了阿里、百度、有道、腾讯这些翻译API,其中腾讯每月免费可用的量是最大的,所以选择用它。
至于为什么没有选择免费的API,只是觉得这些API稳定性稍差,便没有考虑。
+14 -9
View File
@@ -1,14 +1,19 @@
from .node.tencent_translation import *
import os
import glob
import importlib
__version__ = "1.0.0"
node_list = [os.path.splitext(os.path.basename(f))[0] for f in glob.glob(os.path.join(os.path.dirname(__file__), "nodes", "*.py"))]
NODE_CLASS_MAPPINGS = {
"TencentTextTranslation": TencentTextTranslation,
}
NODE_CLASS_MAPPINGS = {}
NODE_DISPLAY_NAME_MAPPINGS = {}
NODE_DISPLAY_NAME_MAPPINGS = {
"TencentTextTranslation": "文本翻译",
}
for module_name in node_list:
if module_name != "__init__":
imported_module = importlib.import_module(".nodes.{}".format(module_name), __name__)
NODE_CLASS_MAPPINGS = {**NODE_CLASS_MAPPINGS, **imported_module.NODE_CLASS_MAPPINGS}
NODE_DISPLAY_NAME_MAPPINGS = {**NODE_DISPLAY_NAME_MAPPINGS, **imported_module.NODE_DISPLAY_NAME_MAPPINGS}
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS']
WEB_DIRECTORY = "./js"
__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS","WEB_DIRECTORY"]
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 201 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

+77
View File
@@ -0,0 +1,77 @@
import {app } from "../../scripts/app.js";
import { log, dynamic_connection, findWidgetByName, toggleWidget } from './ulits.js'
app.registerExtension({
name: "TextTranslation.text",
async beforeRegisterNodeDef(nodeType, nodeData, app) {
switch(nodeData.name){
case 'Text_Concatenate':
text_concatenate_widget(nodeType, nodeData, app);
break;
case 'Text_Translation_V2':
text_translation_v2_widget(nodeType, nodeData, app);
break;
}
},
});
function text_concatenate_widget(nodeType, nodeData, app) {
var input_name = "text";
const onNodeCreated = nodeType.prototype.onNodeCreated;
nodeType.prototype.onNodeCreated = function () {
const onc = onNodeCreated?.apply(this, arguments);
this.addInput(`${input_name}`, "STRING");
return onc;
};
const onConnectionsChange = nodeType.prototype.onConnectionsChange;
nodeType.prototype.onConnectionsChange = function (type, index, connected, link_info) {
if(!link_info)
return;
const occ = onConnectionsChange
? onConnectionsChange.apply(this, arguments)
: undefined
// log("输入类型:" +this.inputs[0].type);
dynamic_connection(this, index, connected, input_name, this.inputs[0].type );
return occ
}
}
function text_translation_v2_widget(nodeType, nodeData, app) {
const onNodeCreated = nodeType.prototype.onNodeCreated;
nodeType.prototype.onNodeCreated = function () {
const onc = onNodeCreated?.apply(this, arguments);
let node = this;
toggleWidget(node, findWidgetByName(node, 'translator'), false);
toggleWidget(node, findWidgetByName(node, 'source_language'), false);
toggleWidget(node, findWidgetByName(node, 'target_language'), false);
node.addWidget("button", "Show / Hide button", "button_show", function(value, widget, node){
let is_show = null
if(this.value === "button_show") {
is_show = true;
} else if (this.value === "button_hide") {
is_show = false;
}
toggleWidget(node, findWidgetByName(node, 'translator'), is_show)
toggleWidget(node, findWidgetByName(node, 'source_language'), is_show)
toggleWidget(node, findWidgetByName(node, 'target_language'), is_show)
this.value = is_show ? "button_hide" : "button_show";
app.graph.setDirtyCanvas(true);
});
return onc;
};
}
+82
View File
@@ -0,0 +1,82 @@
export const isPropertiesWidgetShow = (widget_name) => {
if(properties_widget[widget_name]){
return properties_widget[widget.name].value.includes('_hide');
}else{
return false;
}
};
let origProps = {};
export const findWidgetByName = (node, name) => node.widgets.find((w) => w.name === name);
export const doesInputWithNameExist = (node, name) => node.inputs ? node.inputs.some((input) => input.name === name) : false;
export function updateNodeHeight(node) {node.setSize([node.size[0], node.computeSize()[1]]);}
export function toggleWidget(node, widget, show = false, suffix = "") {
if (!widget || doesInputWithNameExist(node, widget.name)) return;
if (!origProps[widget.name]) {
origProps[widget.name] = { origType: widget.type, origComputeSize: widget.computeSize };
}
const origSize = node.size;
widget.type = show ? origProps[widget.name].origType : "easyHidden" + suffix;
widget.computeSize = show ? origProps[widget.name].origComputeSize : () => [0, -4];
widget.linkedWidgets?.forEach(w => toggleWidget(node, w, ":" + widget.name, show));
const height = show ? Math.max(node.computeSize()[1], origSize[1]) : node.size[1];
node.setSize([node.size[0], height]);
}
export const dynamic_connection = (
node,
index,
connected,
connectionPrefix = 'input_',
connectionType = 'PSDLAYER'
) => {
if (!connected && (node.inputs.length > 1)) {
const stackTrace = new Error().stack;
for (let i = 0; i < node.inputs.length -1; i++) {
if(!stackTrace.includes('LGraphNode.prototype.connect') &&
!stackTrace.includes('LGraphNode.connect') &&
!stackTrace.includes('loadGraphData') &&
!node.inputs[i].link) {
node.removeInput(i);
}
}
}
let last_slot = node.inputs[node.inputs.length - 1];
if (last_slot.link != undefined) {
node.addInput(`${connectionPrefix}`, connectionType);
}
if (connected && (node.inputs.length > 1)) {
const stackTrace = new Error().stack;
for (let i = 0; i < node.inputs.length -1; i++) {
if(!stackTrace.includes('LGraphNode.prototype.connect') &&
!stackTrace.includes('LGraphNode.connect') &&
!stackTrace.includes('loadGraphData') &&
!node.inputs[i].link) {
node.removeInput(i);
}
}
}
if ((node.inputs.length > 1)) {
for (let i = 0; i < node.inputs.length -1; i++) {
node.inputs[i].name = `${connectionPrefix}${i + 1}`
node.inputs[i].label = `${connectionPrefix}${i + 1}`
}
}
}
export const log = (...args) => {
console.debug(...args)
}
-103
View File
@@ -1,103 +0,0 @@
import json
import re
import os
from tencentcloud.common import credential
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
from tencentcloud.tmt.v20180321 import tmt_client, models
# 腾讯翻译安装 Python SDK https://cloud.tencent.com/document/sdk/Python
# pip install --upgrade tencentcloud-sdk-python
# 腾讯翻译文档 https://cloud.tencent.com/document/api/551/15619
# region 腾讯翻译全局对象 起始
httpProfile = HttpProfile()
httpProfile.endpoint = "tmt.tencentcloudapi.com"
clientProfile = ClientProfile()
clientProfile.httpProfile = httpProfile
# 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取
# 有两种方式设置密钥
# (1)硬编码密钥到代码中,这有可能随代码泄露而暴露,有安全隐患,不推荐 (简单)
# cred = credential.Credential("secretId", "secretKey")
# (2)密钥设置在环境变量中,推荐 (稍微多些步骤,请在开启ComfyUI前设置好,若已开启需要重启ComfyUI)
# 可在终端使用 echo %环境变量名称% 查看是否正确设置
cred = credential.Credential(
os.environ.get("TENCENTCLOUD_SECRET_ID"),
os.environ.get("TENCENTCLOUD_SECRET_KEY"))
# 操作的资源所属的地域 如、ap-beijing、ap-chengdu、ap-chongqing、ap-guangzhou、ap-shanghai
# 可以选择离自己近的地域,更多详情见 https://cloud.tencent.com/document/api/551/15615#.E5.9C.B0.E5.9F.9F.E5.88.97.E8.A1.A8
tmt_client_instance = tmt_client.TmtClient(cred, "ap-guangzhou", clientProfile)
# endregion
# 调用腾讯翻译API
def tencent_api(text_to_translate):
try:
req = models.TextTranslateRequest()
params = {
"SourceText": text_to_translate,
"Source": "auto", # 翻译前的语言类型,默认 自动(auto)
"Target": "en", # 翻译后的语言类型,默认 英语(en)
"ProjectId": 0,
}
req.from_json_string(json.dumps(params))
resp = tmt_client_instance.TextTranslate(req)
return resp.TargetText
except TencentCloudSDKException as err:
print("文本翻译错误:" + err)
return ""
# 判断是否包含中文
def contains_chinese(text):
pattern = re.compile(r'[\u4e00-\u9fa5]')
return bool(pattern.search(text))
class TencentTextTranslation:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"text_trans": ("STRING", {"multiline": True}),
"text_normal": ("STRING", {"multiline": True}),
"trans_switch": (["enabled", "disabled"],),
},
}
RETURN_TYPES = ("STRING",)
FUNCTION = "translation"
CATEGORY = "utils"
# trans_switch 翻译功能的开关,enabled 开启;disabled 关闭
def translation(self, text_trans, text_normal, trans_switch, ):
if text_trans == "undefined":
text_trans = ""
if text_normal == "undefined":
text_normal = ""
is_enabled = trans_switch == "enabled"
target_text = ""
if is_enabled and contains_chinese(text_trans):
target_text = tencent_api(text_trans)
# 在终端打印翻译后的内容,不需要可删除或注释
print("文本翻译结果: " + target_text)
else:
target_text = text_trans
output_text = ", ".join(filter(None, [target_text, text_normal]))
output_text = output_text.replace(',', ',').replace('。', ',').replace(" ", " ").replace(" ,", ",").replace(",,", ",")
# 在终端打印翻译后的内容,不需要可删除或注释
print("文本最终结果: " + output_text)
return (output_text,)
# NODE_CLASS_MAPPINGS = {
# "TencentTranslation": TencentTextTranslation,
# }
#
# NODE_DISPLAY_NAME_MAPPINGS = {
# "TencentTranslation": "文本翻译",
# }
+201
View File
@@ -0,0 +1,201 @@
from ..utils.translation import translators, get_translator
# 适应不同地区的人使用该节点,当前默认类别名为英文,按需自行更改
# Adapt to people from different regions using this node.
# The current default class alias is in English and can be changed as needed
# CATEGORY_NAME = "文本翻译"
CATEGORY_NAME = "Text Translation"
class Text:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"text": ("STRING", {"multiline": True}),
},
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("string",)
FUNCTION = "func"
#OUTPUT_NODE = False
CATEGORY = CATEGORY_NAME
def func(self, text):
return (text,)
class Text_Translation:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"trans_switch": ("BOOLEAN", {"default": True, "label_on": "on", "label_off": "off"}),
"trans_text": ("STRING", {"multiline": True}),
},
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("string",)
FUNCTION = "func"
#OUTPUT_NODE = False
CATEGORY = CATEGORY_NAME
def func(self, trans_switch, trans_text):
output_text = ""
if trans_switch:
output_text = translators(text = trans_text)
else:
output_text = trans_text
return (output_text,)
class Text_Translation_V2:
def __init__(self):
pass
# 截止 [Translators](https://github.com/UlionTse/translators) 版本:v5.9.1 支持如下翻译平台:
# alibaba, apertium, argos, baidu, bing, caiyun, cloudTranslation, deepl, elia,
# google, hujiang, iciba, iflytek, iflyrec, itranslate, judic, languageWire, lingvanex,
# niutrans, mglip, mirai, modernMt, myMemory, papago, qqFanyi, qqTranSmart, reverso,
# sogou, sysTran, tilde, translateCom, translateMe, utibet, volcEngine, yandex, yeekit, youdao
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"trans_switch": ("BOOLEAN", {"default": True, "label_on": "on", "label_off": "off"}),
"trans_text": ("STRING", {"multiline": True}),
"translator": (["alibaba", "bing", "google", ],), #直接再此添加 翻译平台
"source_language": (["auto", "zh", "en", ],), #直接再此添加 相应支持的源语言
"target_language": (["en", "zh", ],), #直接再此添加 相应支持的目标语言
},
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("string",)
FUNCTION = "func"
#OUTPUT_NODE = False
CATEGORY = CATEGORY_NAME
def func(self, trans_switch, trans_text, translator, source_language, target_language):
output_text = ""
if trans_switch:
output_text = translators(text = trans_text, translator = translator, source_language = source_language, target_language = target_language)
else:
output_text = trans_text
return (output_text,)
class Get_Translator:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": { },
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("string",)
FUNCTION = "func"
#OUTPUT_NODE = False
CATEGORY = CATEGORY_NAME
def func(self):
translator = get_translator()
return (translator,)
class Text_Switch:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"switch": ("BOOLEAN", {"default": True, "label_on": "on", "label_off": "off"}),
"text": ("STRING", {"forceInput": True})
},
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("string",)
FUNCTION = "func"
#OUTPUT_NODE = False
CATEGORY = CATEGORY_NAME
def func(self, switch, text):
output_text = ""
if switch:
output_text = text
return (output_text,)
class Text_Concatenate:
@classmethod
def INPUT_TYPES(s):
return {"required": {}}
RETURN_TYPES = ("STRING",)
FUNCTION = "func"
CATEGORY = CATEGORY_NAME
def func(self, **kwargs):
text = ""
for k, v in kwargs.items():
text = text + v
return (text, )
NODE_CLASS_MAPPINGS = {
"Text": Text,
"Text_Translation": Text_Translation,
"Text_Translation_V2": Text_Translation_V2,
"Text_Switch": Text_Switch,
"Text_Concatenate": Text_Concatenate,
"Get_Translator": Get_Translator,
}
# 适应不同地区的人使用该节点,当前默认节点名为英文,按需自行更改
# Adapt to people from different regions using this node.
# The current default node name is English and can be changed as needed
# NODE_DISPLAY_NAME_MAPPINGS = {
# "Text": "文本",
# "Text_Translation": "文本翻译",
# "Text_Translation_V2": "文本翻译V2",
# "Text_Switch": "文本开关",
# "Text_Concatenate": "文本联接",
# "Get_Translator": "获取翻译平台",
# }
NODE_DISPLAY_NAME_MAPPINGS = {
"Text": "Text",
"Text_Translation": "Text Translation",
"Text_Translation_V2": "Text Translation V2",
"Text_Switch": "Text Switch",
"Text_Concatenate": "Text Concatenate",
"Get_Translator": "Get Translator",
}
+1
View File
@@ -0,0 +1 @@
translators
+14
View File
@@ -0,0 +1,14 @@
# 判断是否包含中文
def has_chinese_character(string):
"""
判断字符串中是否包含中文字符
:param string: 待判断的字符串
:return: True如果字符串中至少包含一个中文字符,否则返回False
"""
for char in string:
if '\u4e00' <= char <= '\u9fff':
return True
return False
+22
View File
@@ -0,0 +1,22 @@
def translators(text : str , translator: str = "bing", source_language = "auto", target_language = "en", timeout: float = 10.0):
if not text:
return ""
try:
import translators
result = translators.translate_text(query_text = text, translator = translator,from_language = source_language, to_language= target_language, timeout= timeout)
return result
except Exception as e:
raise Exception(f"Error: Translation failed , Message : {e}")
def get_translator():
try:
import translators
translators_list = translators.translators_pool
result = '\n'.join(translators_list)
print(f"Text Translation translator: \n{result}")
return result
except Exception as e:
raise Exception(f"Error: Translation failed , Message : {e}")