将Telegram全自动翻译更进一步

本文自以下文章深度魔改:

本文的改进点主要是:

  1. 使用deeplx翻译
  2. 并发翻译多个语言
  3. 可指令化配置
  4. 更好的消息过滤
  5. 持久化json配置

先贴代码(代码不好,老py勿笑 :grin:):

# -*- coding: utf-8 -*-

import asyncio
import json
import logging
import os
import time

import aiohttp
from telethon import events
from telethon.sync import TelegramClient

# 设置日志记录,便于调试和追踪程序运行情况。
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')


def load_config():
    # load config from json file, check if the file exists first
    if not os.path.exists('config.json'):
        logging.error('config.json not found, created an empty one')
        exit()

    with open('config.json', 'r') as f:
        config = json.load(f)

    return config


def save_config():
    cfg['target_config'] = target_config
    with open('config.json', 'w') as f:
        json.dump(cfg, f, indent=2)


cfg = load_config()
api_id = cfg['api_id']
api_hash = cfg['api_hash']
target_config = cfg['target_config'] if 'target_config' in cfg else {}

# 初始化Telegram客户端和OpenAI客户端。
client = TelegramClient('chat_translator', api_id, api_hash)


async def translate_single(text, source_lang, target_lang, session):
    if source_lang == target_lang:
        return target_lang, text

    url = "https://api.deeplx.org/translate"
    payload = {
        "text": text,
        "source_lang": source_lang,
        "target_lang": target_lang
    }

    start_time = time.time()
    async with session.post(url, json=payload) as response:
        logging.info(f"翻译从 {source_lang} 至 {target_lang} 耗时: {time.time() - start_time}")
        if response.status != 200:
            logging.error(f"翻译失败:{response.status}")
            raise Exception(f"翻译失败")

        result = await response.json()
        if result['code'] != 200:
            logging.error(f"翻译失败:{result}")
            raise Exception(f"翻译失败")

        return target_lang, result['data']


async def translate_text(text, source_lang, target_langs) -> {}:
    result = {}
    async with aiohttp.ClientSession() as session:
        tasks = [translate_single(text, source_lang, target_lang, session) for target_lang in target_langs]
        for lang, text in await asyncio.gather(*tasks):
            result[lang] = text

    return result


async def command_mode(event, target_key, text) -> bool:
    if text == '.tt-off':
        await event.delete()

        if target_key in target_config:
            del target_config[target_key]
            save_config()
            logging.info("已禁用: %s" % target_key)

        return False

    if text.startswith('.tt-on,'):
        await event.delete()

        _, source_lang, target_langs = text.split(',')
        target_config[target_key] = {
            'source_lang': source_lang,
            'target_langs': target_langs.split('|')
        }

        save_config()
        logging.info(f"设置成功: {target_config[target_key]}")

        return False

    return True


# 监听新消息事件,进行消息处理。
@client.on(events.NewMessage(outgoing=True))
async def handle_message(event):
    target_key = '%d.%d' % (event.chat_id, event.sender_id)
    try:
        message = event.message

        if not message.text:
            return

        message_content = message.text.strip()
        if not message_content:
            return

        if message_content.startswith('.tt-') and not await command_mode(event, target_key, message_content):
            return

        if target_key not in target_config:
            return

        logging.info(f"翻译消息: {message.text}")

        config = target_config[target_key]
        target_langs = config['target_langs']
        if not target_langs:
            return

        start_time = time.time()  # 记录开始时间
        translated_texts = await translate_text(message.text, config['source_lang'], target_langs)
        logging.info(f"翻译耗时: {time.time() - start_time}")

        modified_message = translated_texts[target_langs[0]]

        if len(target_langs) > 1:
            secondary_messages = []
            for lang in target_langs[1:]:
                secondary_messages.append(translated_texts[lang])

            modified_message += '\n```%s\n```' % '\n'.join(secondary_messages)

        await message.edit(modified_message)
    except Exception as e:
        # 记录处理消息时发生的异常。
        logging.error(f"Error handling message: {e}")


# 启动客户端并保持运行。
try:
    client.start()
    client.run_until_disconnected()
finally:
    # 断开客户端连接。
    client.disconnect()

配置文件config.json:

{
  "api_id": 1234,
  "api_hash": "abcdef123aaaaaaaaaaaaaa"
}

使用前可能需要安装依赖:

pip install aiohttp telethon

如果你本机还缺其他依赖,自行安装即可。

使用方法:

  1. 在config.json中配置真实的api_idapi_hash,申请自https://my.telegram.org/apps
  2. 执行脚本,登录你的账号。
  3. 使用对应账号在对应聊天群里设置启用/禁用。

指令:

.tt-off 群内直接输入,禁用本账号/频道号该聊天/群的翻译功能。

.tt-on,zh,zh|en|ru 设置并开启本账号/频道号该聊天/群的翻译功能。参数依次是:源语言,目标语言列表。

目标语言列表将按顺序显示,第一个语言作为主要语言。
如果在目标语言列表中不包含原语言,则相当于上版本的不保留原内容。
目标语言列表使用|隔开。

以上配置会实时写进配置文件,后续重启脚本都会加载。

该服务跑在国外服务器上效果会更佳!

附:deepl的源语言和目标语言列表

源语言

  • AR - Arabic
  • BG - Bulgarian
  • CS - Czech
  • DA - Danish
  • DE - German
  • EL - Greek
  • EN - English
  • ES - Spanish
  • ET - Estonian
  • FI - Finnish
  • FR - French
  • HU - Hungarian
  • ID - Indonesian
  • IT - Italian
  • JA - Japanese
  • KO - Korean
  • LT - Lithuanian
  • LV - Latvian
  • NB - Norwegian (Bokmål)
  • NL - Dutch
  • PL - Polish
  • PT - Portuguese (all Portuguese varieties mixed)
  • RO - Romanian
  • RU - Russian
  • SK - Slovak
  • SL - Slovenian
  • SV - Swedish
  • TR - Turkish
  • UK - Ukrainian
  • ZH - Chinese

目标语言:

  • AR - Arabic
  • BG - Bulgarian
  • CS - Czech
  • DA - Danish
  • DE - German
  • EL - Greek
  • EN - English (unspecified variant for backward compatibility; please select EN-GB or EN-US instead)
  • EN-GB - English (British)
  • EN-US - English (American)
  • ES - Spanish
  • ET - Estonian
  • FI - Finnish
  • FR - French
  • HU - Hungarian
  • ID - Indonesian
  • IT - Italian
  • JA - Japanese
  • KO - Korean
  • LT - Lithuanian
  • LV - Latvian
  • NB - Norwegian (Bokmål)
  • NL - Dutch
  • PL - Polish
  • PT - Portuguese (unspecified variant for backward compatibility; please select PT-BR or PT-PT instead)
  • PT-BR - Portuguese (Brazilian)
  • PT-PT - Portuguese (all Portuguese varieties excluding Brazilian Portuguese)
  • RO - Romanian
  • RU - Russian
  • SK - Slovak
  • SL - Slovenian
  • SV - Swedish
  • TR - Turkish
  • UK - Ukrainian
  • ZH - Chinese (simplified)
113 Likes

沙发

5 Likes

雅!

5 Likes

我来用用这个成品

6 Likes

大佬牛逼

6 Likes

沙发

6 Likes

体验高端服务

6 Likes

来了

6 Likes

:kissing_heart:

5 Likes

好久没整活了,虽然这个活我不敢用

6 Likes

牛逼

6 Likes

反手一个收藏

6 Likes

不错,始皇算是把deepl玩透了

6 Likes

优雅

6 Likes

哈哈哈哈 我要用 居然升级了

4 Likes

赞赞赞

4 Likes

赏!

4 Likes

蹲一个封号评测

再等一个翻译过多,开5秒盾限流 :rofl:

27 Likes

@neo L站 i18n 不更进一步说不过去 :clown_face:

5 Likes

为什么不用PHP写

PHP是最好的语言

2 Likes