弃用腾讯翻译API,使用免费的翻译API,并修改项目名
@@ -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)添加该节点,可以在 utils 中选择,也可以双击鼠标左键搜索 `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"/>
|
||||
获取翻译平台列表,同时会在终端上显示。
|
||||
|
||||
当然你也可以选择在   .node/tencent_translation.py   文件中,把输出语句前加 “#” 注释掉。
|
||||
<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)添加该节点到 ComfyUI
|
||||
|
||||
(6)如果你想修改翻译后的语言类型等功能,可在代码里修改。想要达到   WebUI   中可实时翻译或点击翻译的效果,该节点目前做不到,因为我不了解js脚本。
|
||||
|
||||
(7)代码里有注释,便于理解。
|
||||
|
||||
### 2、安装
|
||||
(1)获取 [腾讯翻译API](https://cloud.tencent.com/product/tmt) 密钥(API接口说明:[腾讯翻译API文档](https://cloud.tencent.com/document/api/551/15619))
|
||||
|
||||
在浏览器搜索 “腾讯机器翻译” 或点击 [腾讯翻译](https://cloud.tencent.com/product/tmt) 前往,
|
||||
|
||||
登录自己的账号后依次点击 头像 >> 访问管理 >> API密钥管理 >> 创建密钥 >> 复制密钥
|
||||
|
||||
<img src="images/image7.png" width="1024"/>
|
||||
|
||||
(2) 安装 腾讯翻译SDK (更多安装介绍:[腾讯翻译SDK文档](https://cloud.tencent.com/document/sdk/Python))。
|
||||
|
||||
请先确定你使用的 ComfyUI 的 Python 目录在哪里,在终端中切换到该目录下,输入以下命令:
|
||||
|
||||
```
|
||||
pip install --upgrade tencentcloud-sdk-python
|
||||
```
|
||||
或者使用国内镜像
|
||||
```
|
||||
pip install -i https://mirrors.tencent.com/pypi/simple/ --upgrade tencentcloud-sdk-python
|
||||
```
|
||||
|
||||
(勿将SDK添加错位置,否则无效)
|
||||
|
||||
(3)添加该节点到 ComfyUI
|
||||
|
||||
 1) 克隆本项目
|
||||
####  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
|
||||
```
|
||||
 2) 直接下载ZIP
|
||||
####  2) 方式二:直接下载ZIP
|
||||
|
||||
下载解压后放入`custom_nodes`内
|
||||
|
||||
### (2)配置环境
|
||||
|
||||
```
|
||||
cd ComfyUI_Text_Translation
|
||||
```
|
||||
|
||||
(4)配置密钥
|
||||
如果你下载的是 ComfyUI 的 便携版本,可直接执行下面代码,否则请将 `requirements.txt` 内的依赖安装到对应位置。
|
||||
```
|
||||
..\..\..\python_embeded\python.exe -s -m pip install -r requirements.txt
|
||||
```
|
||||
#### (3)更改 翻译平台、翻译语言
|
||||
截止 [Translators](https://github.com/UlionTse/translators) 版本:v5.9.1 支持如下翻译平台:
|
||||
|
||||
 1) 直接写在代码里,在   .custom_nodes/ComfyUI_Text_Translation_zh_CN/node/tencent_translation.py   文件里,
|
||||
找到`cred = credential.Credential("secretId", "secretKey")`这里填上你的密钥( "secretId" 和 "secretKey" )该方式有泄露密钥的风险,不推荐,但简单。
|
||||
```
|
||||
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)
|
||||
```
|
||||
直接写在代码里,在   .custom_nodes/ComfyUI_Text_Translation/nodes/text.py   文件的如下位置修改:
|
||||
<img src="images/Text_Translation_V2_s.png" width="1024"/>
|
||||
|
||||
<img src="images/image8.png" width="1024"/>
|
||||
#### (4)修改节点显示的语言
|
||||
直接写在代码里,在   .custom_nodes/ComfyUI_Text_Translation/nodes/text.py   文件的 开头和 结尾 位置修改:
|
||||
|
||||
 2) 放在环境变量里,添加`TENCENTCLOUD_SECRET_ID`和`TENCENTCLOUD_SECRET_KEY`,稍微多些步骤,但安全。(请在启动ComfyUI前设置好,若已启动
|
||||
需要重启 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,简化配置,使用 [Translators](https://github.com/UlionTse/translators) 提供的方式进行翻译,无需申请密钥了。
|
||||
|
||||
2、完全重写节点、新增或修改 “文本翻译”、“文本翻译 V2”、 “获取翻译平台列表”、“文本”、“文本开关”、“文本联接”节点。
|
||||
2、完全重写节点、新增或修改 “文本翻译”、“文本翻译 V2”、 “获取翻译平台列表”、“文本”、“文本开关”、“文本联接”节点。
|
||||
|
||||
#### 2023-08-27
|
||||
|
||||
 去除“翻译开关”的默认值,以便适配 [StableSwarmUI](https://github.com/Stability-AI/StableSwarmUI) ,不然该开关的值会由“可选择类型”变成“要输入类型的文字”。
|
||||
|
||||
2023-8-22
|
||||
#### 2023-08-22
|
||||
|
||||
 初始提交,节点采用了[腾讯翻译API](https://cloud.tencent.com/product/tmt)进行文本翻译。
|
||||
|
||||
|
||||
### 5、其他
|
||||
我对比了阿里、百度、有道、腾讯这些翻译API,其中腾讯每月免费可用的量是最大的,所以选择用它。
|
||||
|
||||
至于为什么没有选择免费的API,只是觉得这些API稳定性稍差,便没有考虑。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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"]
|
||||
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 8.2 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 205 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 201 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 31 KiB |
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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": "文本翻译",
|
||||
# }
|
||||
@@ -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",
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
translators
|
||||
@@ -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
|
||||
|
||||
@@ -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}")
|
||||
|
||||