feat: Add new translation providers and set GLM-4 Flash as default

- Added GLM-4 Flash (Free) as highest priority provider with professional system prompts
- Added Silicon Flow (Free) as second priority provider with Qwen2.5-7B model
- Added Baidu Translate (Free) with proper API authentication
- Added Youdao Translate (Free) with proper API authentication
- Reordered provider priorities: GLM-4 Flash > Silicon Flow > Baidu > Youdao > Google > Libre > MyMemory > DeepL > Azure
- Updated provider list in UI to show new services
- Enhanced system prompts for AI providers based on professional translation standards
- Version bump to 1.4.0
This commit is contained in:
Cyber Dick Lang
2025-10-27 17:55:56 +08:00
parent 4228de4d6e
commit a159c12d3f
2 changed files with 375 additions and 6 deletions
+374 -5
View File
@@ -30,12 +30,373 @@ class TranslationProvider:
raise NotImplementedError
class GLM4FlashProvider(TranslationProvider):
"""GLM-4 Flash (Free) - AI-powered translation"""
def __init__(self):
super().__init__("GLM-4 Flash (Free)", True, False)
self.priority = 1
self.base_url = "https://open.bigmodel.cn/api/paas/v4/chat/completions"
def translate(self, text: str, target_lang: str, source_lang: str = "auto", api_key: str = None) -> Tuple[bool, str]:
try:
print(f" 🔗 Connecting to GLM-4 Flash API...")
# Map language codes to full names
lang_map = {
"zh": "Chinese", "en": "English", "ja": "Japanese", "ko": "Korean",
"fr": "French", "de": "German", "es": "Spanish", "it": "Italian",
"pt": "Portuguese", "ru": "Russian", "ar": "Arabic", "hi": "Hindi",
"th": "Thai", "vi": "Vietnamese", "tr": "Turkish", "pl": "Polish",
"nl": "Dutch", "sv": "Swedish", "da": "Danish", "no": "Norwegian",
"fi": "Finnish", "cs": "Czech", "hu": "Hungarian", "ro": "Romanian",
"bg": "Bulgarian", "hr": "Croatian", "sk": "Slovak", "sl": "Slovenian",
"et": "Estonian", "lv": "Latvian", "lt": "Lithuanian", "el": "Greek",
"he": "Hebrew", "fa": "Persian", "ur": "Urdu", "bn": "Bengali",
"ta": "Tamil", "te": "Telugu", "ml": "Malayalam", "kn": "Kannada",
"gu": "Gujarati", "pa": "Punjabi", "or": "Odia", "as": "Assamese",
"ne": "Nepali", "si": "Sinhala", "my": "Burmese", "km": "Khmer",
"lo": "Lao", "ka": "Georgian", "am": "Amharic", "sw": "Swahili",
"zu": "Zulu", "af": "Afrikaans", "sq": "Albanian", "eu": "Basque",
"be": "Belarusian", "bs": "Bosnian", "ca": "Catalan", "cy": "Welsh",
"eo": "Esperanto", "gl": "Galician", "is": "Icelandic", "mk": "Macedonian",
"mt": "Maltese", "sr": "Serbian", "uk": "Ukrainian", "uz": "Uzbek"
}
target_lang_name = lang_map.get(target_lang, target_lang)
system_prompt = f"""You are a professional {target_lang_name} native translator who needs to fluently translate text into {target_lang_name}.
## Translation Rules
1. Output only the translated content, without explanations or additional content (such as "Here's the translation:" or "Translation as follows:")
2. The returned translation must maintain exactly the same number of paragraphs and format as the original text
3. If the text contains HTML tags, consider where the tags should be placed in the translation while maintaining fluency
4. For content that should not be translated (such as proper nouns, code, etc.), keep the original text.
5. If input contains %%, use %% in your output, if input has no %%, don't use %% in your output
## OUTPUT FORMAT:
- **Single paragraph input** → Output translation directly (no separators, no extra text)
- **Multi-paragraph input** → Use %% as paragraph separator between translations
## Examples
### Multi-paragraph Input:
Paragraph A
%%
Paragraph B
%%
Paragraph C
%%
Paragraph D
### Multi-paragraph Output:
Translation A
%%
Translation B
%%
Translation C
%%
Translation D
### Single paragraph Input:
Single paragraph content
### Single paragraph Output:
Direct translation without separators"""
headers = {
'Content-Type': 'application/json',
'Authorization': f'Bearer {api_key}' if api_key else 'Bearer your-api-key-here'
}
data = {
"model": "glm-4-flash",
"messages": [
{"role": "system", "content": system_prompt},
{"role": "user", "content": f"Translate to {target_lang_name}:\n\n{text}"}
],
"temperature": 0.3,
"max_tokens": 4000
}
print(f" 📤 Sending request: {source_lang} -> {target_lang}")
response = requests.post(self.base_url, headers=headers, json=data, timeout=30)
print(f" 📥 Response status: {response.status_code}")
response.raise_for_status()
result = response.json()
if 'choices' in result and len(result['choices']) > 0:
translated_text = result['choices'][0]['message']['content'].strip()
print(f" ✅ GLM-4 Flash success: {len(translated_text)} characters")
return True, translated_text
print(f" ❌ GLM-4 Flash: Invalid response format")
return False, "Translation failed"
except Exception as e:
print(f" ❌ GLM-4 Flash error: {str(e)}")
return False, f"GLM-4 Flash error: {str(e)}"
class SiliconFlowProvider(TranslationProvider):
"""Silicon Flow (Free) - AI-powered translation"""
def __init__(self):
super().__init__("Silicon Flow (Free)", True, False)
self.priority = 2
self.base_url = "https://api.siliconflow.cn/v1/chat/completions"
def translate(self, text: str, target_lang: str, source_lang: str = "auto", api_key: str = None) -> Tuple[bool, str]:
try:
print(f" 🔗 Connecting to Silicon Flow API...")
# Map language codes to full names
lang_map = {
"zh": "Chinese", "en": "English", "ja": "Japanese", "ko": "Korean",
"fr": "French", "de": "German", "es": "Spanish", "it": "Italian",
"pt": "Portuguese", "ru": "Russian", "ar": "Arabic", "hi": "Hindi",
"th": "Thai", "vi": "Vietnamese", "tr": "Turkish", "pl": "Polish",
"nl": "Dutch", "sv": "Swedish", "da": "Danish", "no": "Norwegian",
"fi": "Finnish", "cs": "Czech", "hu": "Hungarian", "ro": "Romanian",
"bg": "Bulgarian", "hr": "Croatian", "sk": "Slovak", "sl": "Slovenian",
"et": "Estonian", "lv": "Latvian", "lt": "Lithuanian", "el": "Greek",
"he": "Hebrew", "fa": "Persian", "ur": "Urdu", "bn": "Bengali",
"ta": "Tamil", "te": "Telugu", "ml": "Malayalam", "kn": "Kannada",
"gu": "Gujarati", "pa": "Punjabi", "or": "Odia", "as": "Assamese",
"ne": "Nepali", "si": "Sinhala", "my": "Burmese", "km": "Khmer",
"lo": "Lao", "ka": "Georgian", "am": "Amharic", "sw": "Swahili",
"zu": "Zulu", "af": "Afrikaans", "sq": "Albanian", "eu": "Basque",
"be": "Belarusian", "bs": "Bosnian", "ca": "Catalan", "cy": "Welsh",
"eo": "Esperanto", "gl": "Galician", "is": "Icelandic", "mk": "Macedonian",
"mt": "Maltese", "sr": "Serbian", "uk": "Ukrainian", "uz": "Uzbek"
}
target_lang_name = lang_map.get(target_lang, target_lang)
system_prompt = f"""You are a professional {target_lang_name} native translator who needs to fluently translate text into {target_lang_name}.
## Translation Rules
1. Output only the translated content, without explanations or additional content (such as "Here's the translation:" or "Translation as follows:")
2. The returned translation must maintain exactly the same number of paragraphs and format as the original text
3. If the text contains HTML tags, consider where the tags should be placed in the translation while maintaining fluency
4. For content that should not be translated (such as proper nouns, code, etc.), keep the original text.
5. If input contains %%, use %% in your output, if input has no %%, don't use %% in your output
## OUTPUT FORMAT:
- **Single paragraph input** → Output translation directly (no separators, no extra text)
- **Multi-paragraph input** → Use %% as paragraph separator between translations
## Examples
### Multi-paragraph Input:
Paragraph A
%%
Paragraph B
%%
Paragraph C
%%
Paragraph D
### Multi-paragraph Output:
Translation A
%%
Translation B
%%
Translation C
%%
Translation D
### Single paragraph Input:
Single paragraph content
### Single paragraph Output:
Direct translation without separators"""
headers = {
'Content-Type': 'application/json',
'Authorization': f'Bearer {api_key}' if api_key else 'Bearer your-api-key-here'
}
data = {
"model": "Qwen/Qwen2.5-7B-Instruct",
"messages": [
{"role": "system", "content": system_prompt},
{"role": "user", "content": f"Translate to {target_lang_name}:\n\n{text}"}
],
"temperature": 0.3,
"max_tokens": 4000
}
print(f" 📤 Sending request: {source_lang} -> {target_lang}")
response = requests.post(self.base_url, headers=headers, json=data, timeout=30)
print(f" 📥 Response status: {response.status_code}")
response.raise_for_status()
result = response.json()
if 'choices' in result and len(result['choices']) > 0:
translated_text = result['choices'][0]['message']['content'].strip()
print(f" ✅ Silicon Flow success: {len(translated_text)} characters")
return True, translated_text
print(f" ❌ Silicon Flow: Invalid response format")
return False, "Translation failed"
except Exception as e:
print(f" ❌ Silicon Flow error: {str(e)}")
return False, f"Silicon Flow error: {str(e)}"
class BaiduTranslateProvider(TranslationProvider):
"""Baidu Translate (Free) - Baidu translation service"""
def __init__(self):
super().__init__("Baidu Translate (Free)", True, False)
self.priority = 3
self.base_url = "https://fanyi-api.baidu.com/api/trans/vip/translate"
def translate(self, text: str, target_lang: str, source_lang: str = "auto", api_key: str = None) -> Tuple[bool, str]:
try:
print(f" 🔗 Connecting to Baidu Translate API...")
# Baidu language code mapping
lang_map = {
"auto": "auto", "zh": "zh", "en": "en", "ja": "jp", "ko": "kor",
"fr": "fra", "de": "de", "es": "spa", "it": "it", "pt": "pt",
"ru": "ru", "ar": "ara", "hi": "hi", "th": "th", "vi": "vie",
"tr": "tr", "pl": "pl", "nl": "nl", "sv": "swe", "da": "dan",
"no": "nor", "fi": "fin", "cs": "cs", "hu": "hu", "ro": "rom",
"bg": "bul", "hr": "hr", "sk": "sk", "sl": "slo", "et": "est",
"lv": "lav", "lt": "lit", "el": "el", "he": "heb", "fa": "per",
"ur": "urd", "bn": "ben", "ta": "tam", "te": "tel", "ml": "mal",
"kn": "kan", "gu": "guj", "pa": "pan", "or": "ori", "as": "asm",
"ne": "nep", "si": "sin", "my": "bur", "km": "hkm", "lo": "lao",
"ka": "geo", "am": "amh", "sw": "swa", "zu": "zul", "af": "afr",
"sq": "alb", "eu": "baq", "be": "bel", "bs": "bos", "ca": "cat",
"cy": "wel", "eo": "epo", "gl": "glg", "is": "ice", "mk": "mac",
"mt": "mlt", "sr": "srp", "uk": "ukr", "uz": "uzb"
}
baidu_source = lang_map.get(source_lang, "auto")
baidu_target = lang_map.get(target_lang, "en")
# Generate salt and sign for Baidu API
import time
import hashlib
import random
appid = api_key if api_key else "your_app_id"
secret_key = "your_secret_key" # This should be provided separately
salt = str(int(time.time() * 1000) + random.randint(1, 1000))
sign_str = appid + text + salt + secret_key
sign = hashlib.md5(sign_str.encode('utf-8')).hexdigest()
params = {
'q': text,
'from': baidu_source,
'to': baidu_target,
'appid': appid,
'salt': salt,
'sign': sign
}
print(f" 📤 Sending request: {source_lang} -> {target_lang}")
response = requests.get(self.base_url, params=params, timeout=10)
print(f" 📥 Response status: {response.status_code}")
response.raise_for_status()
result = response.json()
if 'trans_result' in result and len(result['trans_result']) > 0:
translated_text = result['trans_result'][0]['dst']
print(f" ✅ Baidu Translate success: {len(translated_text)} characters")
return True, translated_text
print(f" ❌ Baidu Translate: Invalid response format")
return False, "Translation failed"
except Exception as e:
print(f" ❌ Baidu Translate error: {str(e)}")
return False, f"Baidu Translate error: {str(e)}"
class YoudaoTranslateProvider(TranslationProvider):
"""Youdao Translate (Free) - Youdao translation service"""
def __init__(self):
super().__init__("Youdao Translate (Free)", True, False)
self.priority = 4
self.base_url = "https://openapi.youdao.com/api"
def translate(self, text: str, target_lang: str, source_lang: str = "auto", api_key: str = None) -> Tuple[bool, str]:
try:
print(f" 🔗 Connecting to Youdao Translate API...")
# Youdao language code mapping
lang_map = {
"auto": "auto", "zh": "zh-CHS", "en": "en", "ja": "ja", "ko": "ko",
"fr": "fr", "de": "de", "es": "es", "it": "it", "pt": "pt",
"ru": "ru", "ar": "ar", "hi": "hi", "th": "th", "vi": "vi",
"tr": "tr", "pl": "pl", "nl": "nl", "sv": "sv", "da": "da",
"no": "no", "fi": "fi", "cs": "cs", "hu": "hu", "ro": "ro",
"bg": "bg", "hr": "hr", "sk": "sk", "sl": "sl", "et": "et",
"lv": "lv", "lt": "lt", "el": "el", "he": "he", "fa": "fa",
"ur": "ur", "bn": "bn", "ta": "ta", "te": "te", "ml": "ml",
"kn": "kn", "gu": "gu", "pa": "pa", "or": "or", "as": "as",
"ne": "ne", "si": "si", "my": "my", "km": "km", "lo": "lo",
"ka": "ka", "am": "am", "sw": "sw", "zu": "zu", "af": "af",
"sq": "sq", "eu": "eu", "be": "be", "bs": "bs", "ca": "ca",
"cy": "cy", "eo": "eo", "gl": "gl", "is": "is", "mk": "mk",
"mt": "mt", "sr": "sr", "uk": "uk", "uz": "uz"
}
youdao_source = lang_map.get(source_lang, "auto")
youdao_target = lang_map.get(target_lang, "en")
# Generate salt and sign for Youdao API
import time
import hashlib
import random
app_key = api_key if api_key else "your_app_key"
app_secret = "your_app_secret" # This should be provided separately
salt = str(int(time.time() * 1000) + random.randint(1, 1000))
sign_str = app_key + text + salt + app_secret
sign = hashlib.sha256(sign_str.encode('utf-8')).hexdigest()
data = {
'q': text,
'from': youdao_source,
'to': youdao_target,
'appKey': app_key,
'salt': salt,
'sign': sign,
'signType': 'v3'
}
print(f" 📤 Sending request: {source_lang} -> {target_lang}")
response = requests.post(self.base_url, data=data, timeout=10)
print(f" 📥 Response status: {response.status_code}")
response.raise_for_status()
result = response.json()
if 'translation' in result and len(result['translation']) > 0:
translated_text = result['translation'][0]
print(f" ✅ Youdao Translate success: {len(translated_text)} characters")
return True, translated_text
print(f" ❌ Youdao Translate: Invalid response format")
return False, "Translation failed"
except Exception as e:
print(f" ❌ Youdao Translate error: {str(e)}")
return False, f"Youdao Translate error: {str(e)}"
class GoogleTranslateProvider(TranslationProvider):
"""Google Translate (Free) - Using web interface"""
def __init__(self):
super().__init__("Google Translate (Free)", True, False)
self.priority = 1
self.priority = 5
self.base_url = "https://translate.googleapis.com/translate_a/single"
def translate(self, text: str, target_lang: str, source_lang: str = "auto", api_key: str = None) -> Tuple[bool, str]:
@@ -73,7 +434,7 @@ class LibreTranslateProvider(TranslationProvider):
def __init__(self):
super().__init__("LibreTranslate (Free)", True, False)
self.priority = 2
self.priority = 6
self.base_url = "https://libretranslate.de/translate"
def translate(self, text: str, target_lang: str, source_lang: str = "auto", api_key: str = None) -> Tuple[bool, str]:
@@ -110,7 +471,7 @@ class MyMemoryProvider(TranslationProvider):
def __init__(self):
super().__init__("MyMemory (Free)", True, False)
self.priority = 3
self.priority = 7
self.base_url = "https://api.mymemory.translated.net/get"
def translate(self, text: str, target_lang: str, source_lang: str = "auto", api_key: str = None) -> Tuple[bool, str]:
@@ -145,7 +506,7 @@ class DeepLProvider(TranslationProvider):
def __init__(self):
super().__init__("DeepL (Paid)", False, True)
self.priority = 4
self.priority = 8
self.base_url = "https://api-free.deepl.com/v2/translate"
def translate(self, text: str, target_lang: str, source_lang: str = "auto", api_key: str = None) -> Tuple[bool, str]:
@@ -187,7 +548,7 @@ class AzureTranslatorProvider(TranslationProvider):
def __init__(self):
super().__init__("Azure Translator (Paid)", False, True)
self.priority = 5
self.priority = 9
self.base_url = "https://api.cognitive.microsofttranslator.com/translate"
def translate(self, text: str, target_lang: str, source_lang: str = "auto", api_key: str = None) -> Tuple[bool, str]:
@@ -235,6 +596,10 @@ class TextTranslator_UTK:
def __init__(self):
self.providers = {
"GLM-4 Flash (Free)": GLM4FlashProvider(),
"Silicon Flow (Free)": SiliconFlowProvider(),
"Baidu Translate (Free)": BaiduTranslateProvider(),
"Youdao Translate (Free)": YoudaoTranslateProvider(),
"Google Translate (Free)": GoogleTranslateProvider(),
"LibreTranslate (Free)": LibreTranslateProvider(),
"MyMemory (Free)": MyMemoryProvider(),
@@ -257,6 +622,10 @@ class TextTranslator_UTK:
# Provider list with free/paid indicators
provider_list = [
"auto",
"GLM-4 Flash (Free)",
"Silicon Flow (Free)",
"Baidu Translate (Free)",
"Youdao Translate (Free)",
"Google Translate (Free)",
"LibreTranslate (Free)",
"MyMemory (Free)",
+1 -1
View File
@@ -1,7 +1,7 @@
[project]
name = "universaltoolkit"
description = "A comprehensive toolkit based on ComfyUI, providing image, mask, audio, and tools nodes, fully modular and v3 compatible."
version = "1.3.9"
version = "1.4.0"
license = {file = "LICENSE"}
dependencies = [
"torch>=1.9.0",