tft-translator / app.py
waang's picture
Update app.py
e86d8b0 verified
import gradio as gr
import os
from openai import AzureOpenAI
import re
import json
import tempfile
from rapidfuzz import fuzz
from datetime import datetime
# 系统提示词
SYS_PROMPT_BASE = '''Please translate this content for Teamfight Tactics (云顶之弈) to Chinese.
Your task is to translate the content into Chinese, ensuring they reflect the original meaning as accurately as possible. The goal is to preserve the cultural context, nuances, and intent of the original content.
## Terminology Reference Table:
【模板类】
Circlet/Crest/Crown → <Trait 译>之环/之徽/之冕,例如Juggernaut Crown → 主宰之冕
Emblem → <Trait 译>纹章
Radiant → 光明版<ItemName 译>
Anvil → <ItemType 译>锻造器;例如Completed / Component / Artifact / Support Anvil → 成装/基础装备/神器装备/辅助装锻造器
roll / high-roll / low-roll → 刷新 / 运气好 / 运气差
re-roll → 赌狗or低费阵容,指持续刷新商店以获得高星级,该技术常用于低费阵容;例如:Ahri reroll → 赌阿狸, reroll comp → 低费阵容
stage X = X阶段,例如:stage 1 → 第一阶段; stage 3-4 → 3-4'''
def find_terminology(text, terminology):
"""查找文本中匹配的术语"""
matches = []
for term, translation in terminology.items():
if term.lower() in text.lower():
matches.append((term, translation))
if not matches:
words = re.findall(r'\b\w+\b', text.lower())
for word in words:
for term, translation in terminology.items():
# 添加高相似度的术语
if fuzz.ratio(term.lower(), word) > 85: # 85% 相似度阈值
matches.append((term, translation))
return matches
def load_terminology():
"""加载术语词典"""
en_to_zh = {}
# 加载通用术语
try:
with open("terminology.json", 'r', encoding='utf-8') as f:
en_to_zh = json.load(f)
except FileNotFoundError:
print("警告: terminology.json 文件未找到")
# 加载第15赛季数据
try:
with open("set15.json", 'r', encoding='utf-8') as f:
set_data = json.load(f)
for key, value in set_data.items():
en_to_zh[key] = value
except FileNotFoundError:
print("警告: set15.json 文件未找到")
return en_to_zh
def translate_text(input_text, progress=gr.Progress()):
"""主要翻译函数"""
if not input_text.strip():
return "请输入要翻译的文本", None
progress(0.1, desc="开始处理...")
sys_prompt = SYS_PROMPT_BASE
processed_text = input_text
progress(0.3, desc="加载术语词典...")
en_to_zh = load_terminology()
if en_to_zh:
progress(0.4, desc="查找匹配术语...")
matches = find_terminology(input_text, en_to_zh)
if matches:
unique_matches = {}
for term, translation in matches:
if term not in unique_matches:
unique_matches[term] = translation
for term, translation in unique_matches.items():
sys_prompt += f"- \"{term}\" → \"{translation['translation']}\" (context: {translation['context']})\n"
sys_prompt += "\n"
# GPT翻译处理
progress(0.6, desc="连接GPT服务...")
# 从环境变量读取API配置
api_key = os.getenv("AZURE_OPENAI_API_KEY")
api_endpoint = os.getenv("AZURE_OPENAI_ENDPOINT")
if not api_key or not api_endpoint:
return "❌ 错误: 未设置Azure OpenAI API密钥或端点。请联系管理员配置环境变量。", None
try:
client = AzureOpenAI(
api_version="2025-04-01-preview",
azure_endpoint=api_endpoint,
api_key=api_key,
max_retries=10,
)
progress(0.8, desc="正在翻译...")
messages = [
{"role": "system", "content": sys_prompt},
{"role": "user", "content": "待翻译内容:\n" + processed_text}
]
response = client.chat.completions.create(
model="o3",
messages=messages,
)
processed_text = response.choices[0].message.content.strip()
except Exception as e:
return f"❌ GPT翻译出错: {str(e)}", None
progress(1.0, desc="完成!")
# 生成下载文件
file_content = f"# TFT翻译结果\n\n## 原文\n{input_text}\n\n## 译文\n{processed_text}\n\n"
file_content += f"\n---\n生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
# 创建临时文件
temp_file = tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.md', encoding='utf-8')
temp_file.write(file_content)
temp_file.close()
result_text = processed_text
return result_text, temp_file.name
def create_interface():
"""创建Gradio界面"""
with gr.Blocks(title="TFT 文档翻译器", theme=gr.themes.Base()) as app:
gr.Markdown("""
# 🎯 TFT 文档翻译器
专为云顶之弈内容翻译设计,支持术语匹配和GPT翻译
⚡ **快速开始**: 选择示例或直接输入文本开始翻译
""")
with gr.Row():
with gr.Column(scale=2):
# 示例输入
example_inputs = [
["Ahri reroll comp is very strong this patch"],
["Top 4 with vertical Bastion build using Jinx carry"],
["Perfect items: Guinsoo, RFC, and IE for maximum DPS"],
["Level 8 rolldown for 4-cost units in late game"],
]
input_text = gr.Textbox(
label="📝 输入要翻译的文本",
placeholder="请输入要翻译的TFT相关内容...",
lines=10,
max_lines=25
)
translate_btn = gr.Button(
"🚀 开始翻译",
variant="primary",
size="lg"
)
gr.Markdown("## 💡 示例")
gr.Examples(
examples=example_inputs,
inputs=[input_text],
label="点击示例快速体验",
cache_examples=False
)
with gr.Column(scale=2):
output_text = gr.Textbox(
label="📄 翻译结果",
lines=10,
max_lines=25,
interactive=False
)
download_file = gr.File(
label="💾 下载翻译文件 (Markdown格式)",
interactive=False
)
# 绑定翻译功能
translate_btn.click(
fn=translate_text,
inputs=[input_text],
outputs=[output_text, download_file],
show_progress=True,
api_name="translate"
)
gr.Markdown("""
---
🔧 **开发** by @树懒醒醒
""")
return app
def get_auth_credentials():
"""获取认证凭据"""
# 从环境变量获取用户名和密码
username = os.getenv("GRADIO_USERNAME", "xx")
password = os.getenv("GRADIO_PASSWORD", "s15tft")
return (username, password)
if __name__ == "__main__":
app = create_interface()
# 获取认证凭据
auth_credentials = get_auth_credentials()
app.launch(
server_name="0.0.0.0",
server_port=7860,
share=False,
show_error=True,
auth=auth_credentials,
auth_message="🔐 请输入用户名和密码访问 TFT 翻译器",
ssr_mode=False, # 禁用SSR模式以避免国际化错误
favicon_path=None, # 避免favicon相关问题
)