Files
akmon/trans_LLM/quick_translate.py
2026-01-20 08:04:15 +08:00

205 lines
7.0 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
快速翻译脚本
用于快速翻译 ak_contents 表内容
"""
import asyncio
import aiohttp
import json
import logging
# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s')
logger = logging.getLogger(__name__)
# ========== 配置区域 - 请修改以下参数 ==========
SUPABASE_URL = "YOUR_SUPABASE_URL" # 例如: https://abcdefgh.supabase.co
SUPABASE_KEY = "YOUR_SUPABASE_KEY" # 您的 Supabase anon key
RAGEFLOW_API_KEY = "YOUR_RAGEFLOW_KEY" # 您的 RageFlow API key
# 翻译设置
TARGET_LANGUAGES = ["en", "ja"] # 目标语言
CONTENT_LIMIT = 5 # 每次翻译的内容数量
MODEL = "gpt-4" # 使用的模型
# ===============================================
class QuickTranslator:
def __init__(self):
self.session = None
async def __aenter__(self):
self.session = aiohttp.ClientSession()
return self
async def __aexit__(self, exc_type, exc_val, exc_tb):
if self.session:
await self.session.close()
async def get_contents(self):
"""获取待翻译内容"""
headers = {
"apikey": SUPABASE_KEY,
"Authorization": f"Bearer {SUPABASE_KEY}",
}
url = f"{SUPABASE_URL}/rest/v1/ak_contents?select=id,title,content&limit={CONTENT_LIMIT}&order=created_at.desc"
async with self.session.get(url, headers=headers) as response:
if response.status == 200:
return await response.json()
else:
logger.error(f"获取内容失败: {response.status}")
return []
async def translate_text(self, text, target_lang):
"""翻译文本"""
if not text.strip():
return ""
lang_map = {"en": "English", "ja": "Japanese", "fr": "French"}
target_name = lang_map.get(target_lang, target_lang)
prompt = f"Please translate the following Chinese text to {target_name}:\n\n{text}\n\nTranslation:"
payload = {
"model": MODEL,
"messages": [
{"role": "user", "content": prompt}
],
"temperature": 0.3,
"max_tokens": 2048
}
headers = {
"Authorization": f"Bearer {RAGEFLOW_API_KEY}",
"Content-Type": "application/json"
}
try:
async with self.session.post(
"https://api.rageflow.ai/v1/chat/completions",
json=payload,
headers=headers
) as response:
if response.status == 200:
data = await response.json()
return data["choices"][0]["message"]["content"].strip()
else:
logger.error(f"翻译失败: {response.status}")
return ""
except Exception as e:
logger.error(f"翻译异常: {e}")
return ""
async def save_translation(self, content_id, language, title, content):
"""保存翻译结果"""
headers = {
"apikey": SUPABASE_KEY,
"Authorization": f"Bearer {SUPABASE_KEY}",
"Content-Type": "application/json"
}
data = {
"content_id": content_id,
"language": language,
"title": title,
"content": content,
"translation_source": "rageflow_auto"
}
# 先检查是否已存在
check_url = f"{SUPABASE_URL}/rest/v1/ak_content_translations?content_id=eq.{content_id}&language=eq.{language}&select=id"
async with self.session.get(check_url, headers=headers) as response:
if response.status == 200:
existing = await response.json()
if existing:
logger.info(f"翻译已存在,跳过: {content_id} -> {language}")
return True
# 插入新翻译
async with self.session.post(
f"{SUPABASE_URL}/rest/v1/ak_content_translations",
json=data,
headers=headers
) as response:
success = response.status in [200, 201]
if success:
logger.info(f"翻译保存成功: {content_id} -> {language}")
else:
logger.error(f"保存失败: {response.status}")
return success
async def run_translation(self):
"""执行翻译"""
logger.info("开始获取内容...")
contents = await self.get_contents()
if not contents:
logger.warning("没有找到内容")
return
logger.info(f"找到 {len(contents)} 条内容,开始翻译...")
total_success = 0
total_failed = 0
for content in contents:
content_id = content["id"]
title = content.get("title", "")
content_text = content.get("content", "")
logger.info(f"翻译内容: {title[:30]}...")
for target_lang in TARGET_LANGUAGES:
try:
# 翻译标题和内容
translated_title = await self.translate_text(title, target_lang)
await asyncio.sleep(1) # 避免API限制
translated_content = await self.translate_text(content_text, target_lang)
await asyncio.sleep(1)
if translated_title and translated_content:
# 保存翻译
success = await self.save_translation(
content_id, target_lang, translated_title, translated_content
)
if success:
total_success += 1
else:
total_failed += 1
else:
logger.error(f"翻译失败: {content_id} -> {target_lang}")
total_failed += 1
except Exception as e:
logger.error(f"处理异常: {content_id} -> {target_lang}: {e}")
total_failed += 1
logger.info(f"翻译完成!成功: {total_success}, 失败: {total_failed}")
async def main():
"""主函数"""
print("=" * 50)
print("🌍 简化版自动翻译服务")
print("=" * 50)
print(f"📝 目标语言: {', '.join(TARGET_LANGUAGES)}")
print(f"📊 内容限制: {CONTENT_LIMIT}")
print(f"🤖 使用模型: {MODEL}")
print("=" * 50)
# 检查配置
if "YOUR_" in SUPABASE_URL or "YOUR_" in SUPABASE_KEY or "YOUR_" in RAGEFLOW_API_KEY:
print("❌ 请先在脚本顶部配置正确的 API 参数!")
return
async with QuickTranslator() as translator:
await translator.run_translation()
print("✅ 翻译任务完成!")
if __name__ == "__main__":
asyncio.run(main())