Tio Boot DocsTio Boot Docs
Home
  • java-db
  • api-table
  • Enjoy
  • Tio Boot Admin
  • ai_agent
  • translator
  • knowlege_base
  • ai-search
  • 案例
Abount
  • Github
  • Gitee
Home
  • java-db
  • api-table
  • Enjoy
  • Tio Boot Admin
  • ai_agent
  • translator
  • knowlege_base
  • ai-search
  • 案例
Abount
  • Github
  • Gitee
  • 01_tio-boot 简介

    • tio-boot:新一代高性能 Java Web 开发框架
    • tio-boot 入门示例
    • Tio-Boot 配置 : 现代化的配置方案
    • tio-boot 整合 Logback
    • tio-boot 整合 hotswap-classloader 实现热加载
    • 自行编译 tio-boot
    • 最新版本
    • 开发规范
  • 02_部署

    • 使用 Maven Profile 实现分环境打包 tio-boot 项目
    • Maven 项目配置详解:依赖与 Profiles 配置
    • tio-boot 打包成 FastJar
    • 使用 GraalVM 构建 tio-boot Native 程序
    • 使用 Docker 部署 tio-boot
    • 部署到 Fly.io
    • 部署到 AWS Lambda
    • 到阿里云云函数
    • 使用 Deploy 工具部署
    • 胖包与瘦包的打包与部署
    • 使用 Jenkins 部署 Tio-Boot 项目
    • 使用 Nginx 反向代理 Tio-Boot
    • 使用 Supervisor 管理 Java 应用
  • 03_配置

    • 配置参数
    • 服务器监听器
    • 内置缓存系统 AbsCache
    • 使用 Redis 作为内部 Cache
    • 静态文件处理器
    • 基于域名的静态资源隔离
    • DecodeExceptionHandler
  • 04_原理

    • 生命周期
    • 请求处理流程
    • 重要的类
  • 05_json

    • Json
    • 接受 JSON 和响应 JSON
    • 响应实体类
  • 06_web

    • 概述
    • 文件上传
    • 接收请求参数
    • 接收日期参数
    • 接收数组参数
    • 返回字符串
    • 返回文本数据
    • 返回网页
    • 请求和响应字节
    • 文件下载
    • 返回视频文件并支持断点续传
    • http Session
    • Cookie
    • HttpRequest
    • HttpResponse
    • Resps
    • RespBodyVo
    • /zh/06_web/19.html
    • 全局异常处理器
    • 异步
    • 动态 返回 CSS 实现
    • 返回图片
    • Transfer-Encoding: chunked 实时音频播放
    • Server-Sent Events (SSE)
    • 接口访问统计
    • 接口请求和响应数据记录
    • 自定义 Handler 转发请求
    • 使用 HttpForwardHandler 转发所有请求
    • 跨域
    • 添加 Controller
    • 常用工具类
    • HTTP Basic 认证
    • WebJars
    • JProtobuf
  • 07_validate

    • 数据紧校验规范
    • 参数校验
  • 08_websocket

    • 使用 tio-boot 搭建 WebSocket 服务
    • WebSocket 聊天室项目示例
  • 09_java-db

    • java‑db
    • 操作数据库入门示例
    • SQL 模板
    • 数据源配置与使用
    • ActiveRecord
    • Model
    • 生成器与 Model
    • Db 工具类
    • 批量操作
    • 数据库事务处理
    • Cache 缓存
    • Dialect 多数据库支持
    • 表关联操作
    • 复合主键
    • Oracle 支持
    • Enjoy SQL 模板
    • Java-DB 整合 Enjoy 模板最佳实践
    • 多数据源支持
    • 独立使用 ActiveRecord
    • 调用存储过程
    • java-db 整合 Guava 的 Striped 锁优化
    • 生成 SQL
    • 通过实体类操作数据库
    • java-db 读写分离
    • Spring Boot 整合 Java-DB
    • like 查询
    • 常用操作示例
    • Druid 监控集成指南
    • SQL 统计
  • 10_api-table

    • ApiTable 概述
    • 使用 ApiTable 连接 SQLite
    • 使用 ApiTable 连接 Mysql
    • 使用 ApiTable 连接 Postgres
    • 使用 ApiTable 连接 TDEngine
    • 使用 api-table 连接 oracle
    • 使用 api-table 连接 mysql and tdengine 多数据源
    • EasyExcel 导出
    • EasyExcel 导入
    • TQL(Table SQL)前端输入规范
    • ApiTable 实现增删改查
    • 数组类型
    • 单独使用 ApiTable
  • 11_aop

    • JFinal-aop
    • Aop 工具类
    • 配置
    • 配置
    • 独立使用 JFinal Aop
    • @AImport
    • 原理解析
  • 12_cache

    • Caffine
    • Jedis-redis
    • hutool RedisDS
    • Redisson
    • Caffeine and redis
    • CacheUtils 工具类
    • 使用 CacheUtils 整合 caffeine 和 redis 实现的两级缓存
    • 使用 java-db 整合 ehcache
    • 使用 java-db 整合 redis
    • Java DB Redis 相关 Api
    • redis 使用示例
  • 13_认证和权限

    • hutool-JWT
    • FixedTokenInterceptor
    • 使用内置 TokenManager 实现登录
    • 用户系统
    • 重置密码
    • 匿名登录
    • Google 登录
    • 权限校验注解
    • Sa-Token
    • sa-token 登录注册
    • StpUtil.isLogin() 源码解析
    • 短信登录
    • 移动端微信登录实现指南
    • 移动端重置密码
  • 14_i18n

    • i18n
  • 15_enjoy

    • tio-boot 整合 Enjoy 模版引擎文档
    • 引擎配置
    • 表达式
    • 指令
    • 注释
    • 原样输出
    • Shared Method 扩展
    • Shared Object 扩展
    • Extension Method 扩展
    • Spring boot 整合
    • 独立使用 Enjoy
    • tio-boot enjoy 自定义指令 localeDate
    • PromptEngine
    • Enjoy 入门示例-擎渲染大模型请求体
    • Enjoy 使用示例
  • 16_定时任务

    • Quartz 定时任务集成指南
    • 分布式定时任务 xxl-jb
    • cron4j 使用指南
  • 17_tests

    • TioBootTest 类
  • 18_tio

    • TioBootServer
    • tio-core
    • 内置 TCP 处理器
    • 独立启动 UDPServer
    • 使用内置 UDPServer
    • t-io 消息处理流程
    • tio-运行原理详解
    • TioConfig
    • ChannelContext
    • Tio 工具类
    • 业务数据绑定
    • 业务数据解绑
    • 发送数据
    • 关闭连接
    • Packet
    • 监控: 心跳
    • 监控: 客户端的流量数据
    • 监控: 单条 TCP 连接的流量数据
    • 监控: 端口的流量数据
    • 单条通道统计: ChannelStat
    • 所有通道统计: GroupStat
    • 资源共享
    • 成员排序
    • ssl
    • DecodeRunnable
    • 使用 AsynchronousSocketChannel 响应数据
    • 拉黑 IP
    • 深入解析 Tio 源码:构建高性能 Java 网络应用
  • 19_aio

    • ByteBuffer
    • AIO HTTP 服务器
    • 自定义和线程池和池化 ByteBuffer
    • AioHttpServer 应用示例 IP 属地查询
    • 手写 AIO Http 服务器
  • 20_netty

    • Netty TCP Server
    • Netty Web Socket Server
    • 使用 protoc 生成 Java 包文件
    • Netty WebSocket Server 二进制数据传输
    • Netty 组件详解
  • 21_netty-boot

    • Netty-Boot
    • 原理解析
    • 整合 Hot Reload
    • 整合 数据库
    • 整合 Redis
    • 整合 Elasticsearch
    • 整合 Dubbo
    • Listener
    • 文件上传
    • 拦截器
    • Spring Boot 整合 Netty-Boot
    • SSL 配置指南
    • ChannelInitializer
    • Reserve
  • 22_MQ

    • Mica-mqtt
    • EMQX
    • Disruptor
  • 23_tio-utils

    • tio-utils
    • HttpUtils
    • Notification
    • 邮箱
    • JSON
    • 读取文件
    • Base64
    • 上传和下载
    • Http
    • Telegram
    • RsaUtils
    • EnvUtils 使用文档
    • 系统监控
    • 毫秒并发 ID (MCID) 生成方案
  • 24_tio-http-server

    • 使用 Tio-Http-Server 搭建简单的 HTTP 服务
    • tio-boot 添加 HttpRequestHandler
    • 在 Android 上使用 tio-boot 运行 HTTP 服务
    • tio-http-server-native
    • handler 常用操作
  • 25_tio-websocket

    • WebSocket 服务器
    • WebSocket Client
  • 26_tio-im

    • 通讯协议文档
    • ChatPacket.proto 文档
    • java protobuf
    • 数据表设计
    • 创建工程
    • 登录
    • 历史消息
    • 发消息
  • 27_mybatis

    • Tio-Boot 整合 MyBatis
    • 使用配置类方式整合 MyBatis
    • 整合数据源
    • 使用 mybatis-plus 整合 tdengine
    • 整合 mybatis-plus
  • 28_mongodb

    • tio-boot 使用 mongo-java-driver 操作 mongodb
  • 29_elastic-search

    • Elasticsearch
    • JavaDB 整合 ElasticSearch
    • Elastic 工具类使用指南
    • Elastic-search 注意事项
    • ES 课程示例文档
  • 30_magic-script

    • tio-boot 整合 magic-script
  • 31_groovy

    • tio-boot 整合 Groovy
  • 32_firebase

    • 整合 google firebase
    • Firebase Storage
    • Firebase Authentication
    • 使用 Firebase Admin SDK 进行匿名用户管理与自定义状态标记
    • 导出用户
    • 注册回调
    • 登录注册
  • 33_文件存储

    • 文件上传数据表
    • 本地存储
    • 使用 AWS S3 存储文件并整合到 Tio-Boot 项目中
    • 存储文件到 腾讯 COS
  • 34_spider

    • jsoup
    • 爬取 z-lib.io 数据
    • 整合 WebMagic
    • WebMagic 示例:爬取学校课程数据
    • Playwright
    • Flexmark (Markdown 处理器)
    • tio-boot 整合 Playwright
    • 缓存网页数据
  • 36_integration_thirty_party

    • tio-boot 整合 okhttp
    • 整合 GrpahQL
    • 集成 Mailjet
    • 整合 ip2region
    • 整合 GeoLite 离线库
    • 整合 Lark 机器人指南
    • 集成 Lark Mail 实现邮件发送
    • Thymeleaf
    • Swagger
    • Clerk 验证
  • 37_dubbo

    • 概述
    • dubbo 2.6.0
    • dubbo 2.6.0 调用过程
    • dubbo 3.2.0
  • 38_spring

    • Spring Boot Web 整合 Tio Boot
    • spring-boot-starter-webflux 整合 tio-boot
    • Tio Boot 整合 Spring Boot Starter
    • Tio Boot 整合 Spring Boot Starter Data Redis 指南
  • 39_spring-cloud

    • tio-boot spring-cloud
  • 40_mysql

    • 使用 Docker 运行 MySQL
    • /zh/42_mysql/02.html
  • 41_postgresql

    • PostgreSQL 安装
    • PostgreSQL 主键自增
    • PostgreSQL 日期类型
    • Postgresql 金融类型
    • PostgreSQL 数组类型
    • PostgreSQL 全文检索
    • PostgreSQL 查询优化
    • 获取字段类型
    • PostgreSQL 向量
    • PostgreSQL 优化向量查询
    • PostgreSQL 其他
  • 43_oceanbase

    • 快速体验 OceanBase 社区版
    • 快速上手 OceanBase 数据库单机部署与管理
    • 诊断集群性能
    • 优化 SQL 性能指南
    • /zh/43_oceanbase/05.html
  • 50_media

    • JAVE 提取视频中的声音
    • Jave 提取视频中的图片
    • /zh/50_media/03.html
  • 51_asr

    • Whisper-JNI
  • 54_native-media

    • java-native-media
    • JNI 入门示例
    • mp3 拆分
    • mp4 转 mp3
    • 使用 libmp3lame 实现高质量 MP3 编码
    • Linux 编译
    • macOS 编译
    • 从 JAR 包中加载本地库文件
    • 支持的音频和视频格式
    • 任意格式转为 mp3
    • 通用格式转换
    • 通用格式拆分
    • 视频合并
    • VideoToHLS
    • split_video_to_hls 支持其他语言
    • 持久化 HLS 会话
  • 55_telegram4j

    • 数据库设计
    • /zh/55_telegram4j/02.html
    • 基于 MTProto 协议开发 Telegram 翻译机器人
    • 过滤旧消息
    • 保存机器人消息
    • 定时推送
    • 增加命令菜单
    • 使用 telegram-Client
    • 使用自定义 StoreLayout
    • 延迟测试
    • Reactor 错误处理
    • Telegram4J 常见错误处理指南
  • 56_telegram-bots

    • TelegramBots 入门指南
    • 使用工具库 telegram-bot-base 开发翻译机器人
  • 60_LLM

    • 简介
    • AI 问答
    • /zh/60_LLM/03.html
    • /zh/60_LLM/04.html
    • 增强检索(RAG)
    • 结构化数据检索
    • 搜索+AI
    • 集成第三方 API
    • 后置处理
    • 推荐问题生成
    • 连接代码执行器
    • 避免 GPT 混乱
    • /zh/60_LLM/13.html
  • 61_ai_agent

    • 数据库设计
    • 示例问题管理
    • 会话管理
    • 历史记录
    • 对接 Perplexity API
    • 意图识别与生成提示词
    • 智能问答模块设计与实现
    • 文件上传与解析文档
    • 翻译
    • 名人搜索功能实现
    • Ai studio gemini youbue 问答使用说明
    • 自建 YouTube 字幕问答系统
    • 自建 获取 youtube 字幕服务
    • 通用搜索
    • /zh/61_ai_agent/15.html
    • 16
    • 17
    • 18
    • 在 tio-boot 应用中整合 ai-agent
    • 16
  • 62_translator

    • 简介
  • 63_knowlege_base

    • 数据库设计
    • 用户登录实现
    • 模型管理
    • 知识库管理
    • 文档拆分
    • 片段向量
    • 命中测试
    • 文档管理
    • 片段管理
    • 问题管理
    • 应用管理
    • 向量检索
    • 推理问答
    • 问答模块
    • 统计分析
    • 用户管理
    • api 管理
    • 存储文件到 S3
    • 文档解析优化
    • 片段汇总
    • 段落分块与检索
    • 多文档解析
    • 对话日志
    • 检索性能优化
    • Milvus
    • 文档解析方案和费用对比
    • 离线运行向量模型
  • 64_ai-search

    • ai-search 项目简介
    • ai-search 数据库文档
    • ai-search SearxNG 搜索引擎
    • ai-search Jina Reader API
    • ai-search Jina Search API
    • ai-search 搜索、重排与读取内容
    • ai-search PDF 文件处理
    • ai-search 推理问答
    • Google Custom Search JSON API
    • ai-search 意图识别
    • ai-search 问题重写
    • ai-search 系统 API 接口 WebSocket 版本
    • ai-search 搜索代码实现 WebSocket 版本
    • ai-search 生成建议问
    • ai-search 生成问题标题
    • ai-search 历史记录
    • Discover API
    • 翻译
    • Tavily Search API 文档
    • 对接 Tavily Search
    • 火山引擎 DeepSeek
    • 对接 火山引擎 DeepSeek
    • ai-search 搜索代码实现 SSE 版本
    • jar 包部署
    • Docker 部署
    • 爬取一个静态网站的所有数据
    • 网页数据预处理
    • 网页数据检索与问答流程整合
  • 65_java-linux

    • Java 执行 python 代码
    • 通过大模型执行 Python 代码
    • MCP 协议
    • Cline 提示词
    • Cline 提示词-中文版本
  • 66_manim

    • 简介
    • Manim 开发环境搭建
    • 生成场景提示词
    • 生成代码
    • 完整脚本示例
    • 语音合成系统
    • Fish.audio TTS 接口说明文档与 Java 客户端封装
    • 整合 fishaudio 到 java-uni-ai-server 项目
    • 执行 Python (Manim) 代码
    • 使用 SSE 流式传输生成进度的实现文档
    • 整合全流程完整文档
    • HLS 动态推流技术文档
    • manim 分场景生成代码
    • 分场景运行代码及流式播放支持
    • 分场景业务端完整实现流程
    • Maiim布局管理器
    • 仅仅生成场景代码
    • 使用 modal 运行 manim 代码
    • Python 使用 Modal GPU 加速渲染
    • Modal 平台 GPU 环境下运行 Manim
    • Modal Manim OpenGL 安装与使用
    • 优化 GPU 加速
    • 生成视频封面流程
    • Java 调用 manim 命令 执行代码 生成封面
    • Manim 图像生成服务客户端文档
    • manim render help
    • 显示 中文公式
    • manimgl
    • EGL
    • /zh/66_manim/30.html
    • /zh/66_manim/31.html
    • 成本核算
    • /zh/66_manim/33.html
  • 70_tio-boot-admin

    • 入门指南
    • 初始化数据
    • token 存储
    • 与前端集成
    • 文件上传
    • 网络请求
    • 图片管理
    • /zh/70_tio-boot-admin/08.html
    • Word 管理
    • PDF 管理
    • 文章管理
    • 富文本编辑器
  • 71_tio-boot

    • /zh/71_tio-boot/01.html
    • Swagger 整合到 Tio-Boot 中的指南
    • HTTP/1.1 Pipelining 性能测试报告
  • 80_性能测试

    • 压力测试 - tio-http-serer
    • 压力测试 - tio-boot
    • 压力测试 - tio-boot-native
    • 压力测试 - netty-boot
    • 性能测试对比
    • TechEmpower FrameworkBenchmarks
    • 压力测试 - tio-boot 12 C 32G
  • 99_案例

    • 封装 IP 查询服务
    • tio-boot 案例 - 全局异常捕获与企业微信群通知
    • tio-boot 案例 - 文件上传和下载
    • tio-boot 案例 - 整合 ant design pro 增删改查
    • tio-boot 案例 - 流失响应
    • tio-boot 案例 - 增强检索
    • tio-boot 案例 - 整合 function call
    • tio-boot 案例 - 定时任务 监控 PostgreSQL、Redis 和 Elasticsearch
    • Tio-Boot 案例:使用 SQLite 整合到登录注册系统
    • tio-boot 案例 - 执行 shell 命令

基于 MTProto 协议开发 Telegram 翻译机器人

  • 简介
  • 准备工作
    • 删除 Webhook 地址
    • 申请 Telegram API ID 和 Hash
  • 项目配置
    • 添加依赖
  • 开发实现
    • TelegramTranslateBot
    • UserPredicate
    • TranslateFunction
    • 异步处理的优势
  • 常见问题
    • 问题一:event.getChat() 已经可以获取 Chat,为什么还需要使用 event.getMessage().getChat()?
    • 问题二:chat.sendMessage 为什么要放到 flatMap 中?
    • 问题 1 和问题 2 总结
  • 消息格式
    • 用户发送的消息
    • 机器人回复的消息
    • 对比与分析
  • 测试与运行
    • 示例
  • 总结

本文档旨在指导开发者使用 MTProto 协议开发一个具备翻译功能的 Telegram 机器人。通过配置 Telegram 应用、添加必要的依赖项,并结合提供的 Java 代码示例,您可以实现一个高效且功能丰富的翻译机器人。

简介

Telegram 机器人是一种基于 Telegram 平台的自动化程序,能够与用户进行互动,实现各种功能。本文将介绍如何使用 MTProto 协议 开发一个支持翻译功能的 Telegram 机器人。与 HTTP 协议相比,MTProto 提供了更高的性能和安全性,适用于需要处理大量并发请求的应用场景。

准备工作

在开始开发 Telegram 机器人之前,需要完成一些前期准备工作,包括删除现有的 Webhook 地址和申请 Telegram API ID 及 Hash。

删除 Webhook 地址

如果您之前为机器人配置了 Webhook 地址,需要先将其删除,以便切换到 MTProto 协议进行开发。您可以通过以下步骤删除 Webhook:

  1. 打开 Telegram 应用,找到您的机器人。
  2. 发送 /deletewebhook 命令给 BotFather。
  3. BotFather 将确认删除 Webhook,并通知您操作结果。

申请 Telegram API ID 和 Hash

为了使用 MTProto 协议开发 Telegram 机器人,您需要申请 Telegram API ID 和 Hash。请按照以下步骤操作:

  1. 访问 Telegram API 网站。
  2. 使用您的 Telegram 账户登录。
  3. 填写应用名称、简短描述和您的应用平台等信息。
  4. 提交申请后,您将获得 api_id 和 api_hash,请妥善保存。

项目配置

添加依赖

为了开发 Telegram 机器人,您需要在项目中添加必要的依赖项。以下是使用 Maven 管理依赖的示例配置:

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                             http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.litongjava.gpt</groupId>
  <artifactId>translator</artifactId>
  <version>1.0.0</version>

  <properties>
    <!-- 项目属性 -->
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>17</java.version>
    <maven.compiler.source>${java.version}</maven.compiler.source>
    <maven.compiler.target>${java.version}</maven.compiler.target>
  </properties>

  <dependencies>
    <!-- Telegram4J 核心库 -->
    <dependency>
      <groupId>com.telegram4j</groupId>
      <artifactId>telegram4j-core</artifactId>
      <version>0.1.0-SNAPSHOT</version>
    </dependency>
    <!-- Jackson Core 库,用于 JSON 处理 -->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.15.2</version>
    </dependency>
    <!-- Reactor Core 库,用于响应式编程 -->
    <dependency>
      <groupId>io.projectreactor</groupId>
      <artifactId>reactor-core</artifactId>
      <version>3.5.0</version>
    </dependency>
  </dependencies>

  <repositories>
    <repository>
      <id>s01.oss.sonatype.org-snapshot</id>
      <url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>
      <snapshots>
        <enabled>true</enabled>
      </snapshots>
    </repository>
  </repositories>
</project>

依赖说明:

  • telegram4j-core:Telegram4J 的核心库,用于与 Telegram API 进行交互。
  • jackson-core:用于处理 JSON 数据。
  • reactor-core:Reactor 项目的核心库,提供响应式编程支持。

确保您的项目使用 Java 17 及以上版本,以兼容 Telegram4J 和其他依赖库。

开发实现

本文档提供了三个关键的 Java 类,用于实现 Telegram 机器人的配置、消息过滤和翻译功能。

TelegramTranslateBot

TelegramTranslateBot 类负责初始化 Telegram 客户端,配置事件监听器,并管理客户端的生命周期。

package com.litongjava.gpt.translator.config;

import java.time.Duration;

import com.litongjava.annotation.AConfiguration;
import com.litongjava.annotation.Initialization;
import com.litongjava.gpt.translator.predicate.UserPredicate;
import com.litongjava.gpt.translator.tgfunc.TranslateFunction;
import com.litongjava.tio.boot.server.TioBootServer;
import com.litongjava.tio.utils.environment.EnvUtils;

import lombok.extern.slf4j.Slf4j;
import reactor.util.retry.Retry;
import telegram4j.core.MTProtoTelegramClient;
import telegram4j.core.event.domain.message.SendMessageEvent;
import telegram4j.mtproto.RpcException;

@Slf4j
@AConfiguration
public class TelegramTranslateBot {

  @Initialization
  public void config() {
    // 从环境变量获取 Telegram API 配置信息
    int apiId = EnvUtils.getInt("telegram.api.id");
    String apiHash = EnvUtils.getStr("telegram.api.hash");
    String botAuthToken = EnvUtils.getStr("telegram.bot.auth.token");

    // 创建并连接 MTProto Telegram 客户端
    MTProtoTelegramClient client = MTProtoTelegramClient.create(apiId, apiHash, botAuthToken).connect().block();
    if (client == null) {
      log.error("Failed to connect to Telegram MTProto client.");
      return;
    }

    // 配置事件监听器:接收 SendMessageEvent,过滤用户消息,并应用翻译功能
    client.on(SendMessageEvent.class)
        //
        .filter(new UserPredicate()::test).flatMap(new TranslateFunction()::apply)
        //
        .delayElements(Duration.ofSeconds(1)) // 每秒最多发送一条消息
        //
        .doOnError(e -> log.error("处理消息时发生错误", e))
        //
        .retryWhen(Retry.backoff(5, Duration.ofSeconds(1)).filter(e -> e instanceof RpcException))
        //
        .subscribe();

    // 防止主线程阻塞,监控客户端断开连接
    //    TioThreadUtils.submit(() -> {
    //      client.onDisconnect().block();
    //      log.info("Telegram client disconnected.");
    //    });

    // 在服务器关闭时,断开 Telegram 客户端连接
    HookCan.me().addDestroyMethod(client::disconnect);

    log.info("Telegram MTProto client configured and connected.");
  }
}

代码解析:

  1. 初始化配置:

    • 从环境变量中获取 api_id、api_hash 和 bot_auth_token。
    • 创建并连接 MTProto Telegram 客户端。
  2. 事件监听与处理:

    • 监听 SendMessageEvent 事件。
    • 使用 UserPredicate 过滤非用户发送的消息,确保机器人只处理来自真实用户的消息。
    • 使用 TranslateFunction 对消息进行翻译处理,并发送回复。
  3. 客户端生命周期管理:

    • 使用 TioThreadUtils 提交一个任务,监控客户端的断开连接事件。
    • 在服务器关闭时,确保客户端正常断开连接,释放资源。

UserPredicate

UserPredicate 类用于过滤消息事件,确保机器人只处理来自真实用户的消息,避免处理自己或其他机器人的消息。

package com.litongjava.gpt.translator.predicate;

import java.util.Optional;
import java.util.function.Predicate;

import lombok.extern.slf4j.Slf4j;
import telegram4j.core.event.domain.message.SendMessageEvent;
import telegram4j.core.object.MentionablePeer;
import telegram4j.core.object.chat.Chat;

@Slf4j
public class UserPredicate implements Predicate<SendMessageEvent> {
  @Override
  public boolean test(SendMessageEvent event) {
    log.info("接收到事件: {}", event);
    Optional<MentionablePeer> optional = event.getAuthor();
    Optional<Chat> chat = event.getChat();
    // 防止机器人处理自己发送的消息
    // 如果消息的发送者信息不存在,说明可能是机器人自身发送的消息,忽略
    if (optional.isEmpty()) {
      log.info("消息发送者信息缺失,可能是机器人自身发送的消息。");
      return false;
    }
    if (chat.isEmpty()) {
      log.info("消息聊天信息缺失,可能是机器人自身发送的消息。");
      return false;
    }
    return true;
  }
}

TranslateFunction

TranslateFunction 类负责处理过滤后的消息,执行翻译操作,并将翻译结果发送回用户。

package com.litongjava.gpt.translator.tgfunc;

import org.reactivestreams.Publisher;

import com.litongjava.gpt.translator.services.TranslatorService;
import com.litongjava.gpt.translator.vo.TranslatorTextVo;
import com.litongjava.jfinal.aop.Aop;

import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Mono;
import telegram4j.core.event.domain.message.SendMessageEvent;
import telegram4j.core.object.Message;
import telegram4j.core.object.chat.Chat;
import telegram4j.core.spec.SendMessageSpec;

@Slf4j
public class TranslateFunction {

  /**
   * 处理 SendMessageEvent,执行翻译并发送回复
   *
   * @param event 发送消息事件
   * @return 翻译后的消息 Publisher
   */
  public Publisher<? extends Message> apply(SendMessageEvent event) {
    // 获取 Chat 对象,如果不存在则从消息中获取
    Mono<Chat> chatMono = Mono.justOrEmpty(event.getChat()).switchIfEmpty(event.getMessage().getChat());

    // 处理 Chat 和消息发送
    return chatMono.flatMap(chat -> processAndSendMessage(chat, event.getMessage()));
  }

  /**
   * 处理消息内容,执行翻译并发送回复
   *
   * @param chat    聊天对象
   * @param message 原始消息对象
   * @return 翻译后的消息 Publisher
   */
  private Mono<Message> processAndSendMessage(Chat chat, Message message) {
    String text = message.getContent();

    // 根据文本内容设置源语言和目标语言
    String srcLang = containsChinese(text) ? "Chinese" : "English";
    String destLang = containsChinese(text) ? "English" : "Chinese";

    // 创建翻译请求对象
    TranslatorTextVo translatorTextVo = new TranslatorTextVo();
    translatorTextVo.setSrcText(text);
    translatorTextVo.setSrcLang(srcLang);
    translatorTextVo.setDestLang(destLang);

    String chatId = chat.getId().toString();
    String responseText;
    try {
      // 调用翻译服务
      responseText = Aop.get(TranslatorService.class).translate(chatId, translatorTextVo);
    } catch (Exception e) {
      log.error("翻译服务调用异常", e);
      responseText = "翻译服务出现问题,请稍后再试。";
    }

    // 构建发送消息规范
    SendMessageSpec messageSpec = SendMessageSpec.of(responseText);

    // 发送翻译结果回 Telegram
    Mono<Message> sendMessage = chat.sendMessage(messageSpec);
    return sendMessage;
  }

  /**
   * 判断文本中是否包含中文字符
   *
   * @param text 输入的文本
   * @return 如果包含中文字符则返回 true,否则返回 false
   */
  private boolean containsChinese(String text) {
    if (text == null || text.isEmpty()) {
      return false;
    }
    // 使用正则表达式检查是否包含中文字符
    return text.matches(".*[\\u4e00-\\u9fa5]+.*");
  }
}

异步处理的优势

在开发 Telegram 翻译机器人时,采用异步处理机制具有显著的优势,特别是在处理大量并发请求和提高应用性能方面。以下是异步处理的主要优势及其在本项目中的应用。

异步处理的优势

  1. 提高并发性和吞吐量: 异步处理允许程序在等待某些操作(如 I/O 操作、网络请求)完成时,继续执行其他任务。这种非阻塞的执行方式显著提高了应用的并发处理能力和整体吞吐量。

  2. 提升响应速度: 通过异步处理,机器人可以同时处理多个用户的请求,而不会因为单个请求的延迟而影响整体响应速度。这对于需要实时响应的聊天机器人尤为重要。

  3. 资源利用率更高: 异步模型避免了线程在等待期间的空闲状态,从而更高效地利用系统资源,减少不必要的线程切换和上下文切换开销。

  4. 增强系统的可扩展性: 异步架构使系统更容易扩展,能够处理更大规模的用户请求,而无需线性增加资源。

Mono 与 flatMap 的异步处理

在本项目中,使用了 Reactor 提供的 Mono 类来实现异步处理。Mono 是 Reactor 中的一个关键类型,代表一个异步计算过程,最终可能会产生一个结果或一个错误。

flatMap 的作用:

flatMap 方法用于将一个 Mono 的结果转换为另一个 Mono,并将其展开。这在需要进行一系列异步操作时尤为有用,因为它允许您在前一个异步操作完成后,基于其结果执行下一个异步操作。

在本项目中的应用:

  1. 事件处理链: 在 TelegramTranslateBot 类中,事件监听器通过以下链式调用进行配置:

    client.on(SendMessageEvent.class)
          .filter(new UserPredicate()::test)
          .flatMap(new TranslateFunction()::apply)
          .subscribe();
    

    这里,client.on(SendMessageEvent.class) 返回一个 Flux<SendMessageEvent>,表示接收到的消息事件流。通过 filter 方法筛选出符合条件的事件后,flatMap 将每个事件传递给 TranslateFunction 的 apply 方法进行处理。

  2. 翻译操作的异步执行: 在 TranslateFunction 类中,apply 方法返回一个 Publisher<? extends Message>,具体来说,是一个 Mono<Message>。通过 flatMap,每个消息事件被异步处理,执行翻译并发送回复。

    public Publisher<? extends Message> apply(SendMessageEvent event) {
      Mono<Chat> chatMono = Mono.justOrEmpty(event.getChat()).switchIfEmpty(event.getMessage().getChat());
      return chatMono.flatMap(chat -> processAndSendMessage(chat, event.getMessage()));
    }
    

    processAndSendMessage 方法内部,同样采用 Mono 来处理翻译服务的调用和消息发送:

    private Mono<Message> processAndSendMessage(Chat chat, Message message) {
      // ... 省略部分代码 ...
    
      Mono<Message> sendMessage = chat.sendMessage(messageSpec);
      return sendMessage;
    }
    

通过 flatMap 的使用,整个消息处理流程实现了非阻塞、异步的执行。这意味着机器人能够同时处理多个翻译请求,而不会因某个请求的延迟而阻塞其他请求的处理。这不仅提升了机器人的响应速度,还提高了系统的整体性能和稳定性。

常见问题


问题一:event.getChat() 已经可以获取 Chat,为什么还需要使用 event.getMessage().getChat()?

在代码中,我们看到以下行:

Mono<Chat> chatMono = Mono.justOrEmpty(event.getChat())
                          .switchIfEmpty(event.getMessage().getChat());

解释:

  1. event.getChat() 可能为空:

    虽然 event.getChat() 通常可以直接获取到消息所在的 Chat 对象,但在某些情况下,它可能返回空值(null 或 Optional.empty())。这是因为 SendMessageEvent 中的 getChat() 方法并不总是保证有值,具体取决于事件的来源和 Telegram 的数据结构。

    在 Telegram4J 的事件模型中,SendMessageEvent 可能来自不同的上下文,有时 Chat 信息可能不可用或未初始化。例如,对于某些类型的消息(如来自频道或匿名群组的消息),event.getChat() 可能无法直接获取到 Chat 对象。

  2. 使用 event.getMessage().getChat() 作为备用:

    为了确保我们始终能够获取到 Chat 对象,代码中使用了 switchIfEmpty 方法:

    Mono.justOrEmpty(event.getChat())
        .switchIfEmpty(event.getMessage().getChat());
    
    • Mono.justOrEmpty(event.getChat()): 尝试从事件中直接获取 Chat 对象。
    • switchIfEmpty(...): 如果上一步返回了空(即 event.getChat() 为空),则调用 event.getMessage().getChat() 尝试从消息对象中获取 Chat。

    这样做的目的是增加获取 Chat 对象的可靠性,确保无论 event.getChat() 是否为空,我们都有机会从 event.getMessage().getChat() 中获取到 Chat。

    event.getMessage().getChat()的返回类型是 "Mono Chat",因为这方法会执行网络请求获取 chat 信息

总结:

  • 可靠性和健壮性: 使用这种方式可以提高代码的健壮性,防止因 Chat 对象为空而导致的空指针异常(NullPointerException)。
  • 兼容性: 由于 Telegram 的消息事件可能来自不同的上下文,确保在各种情况下都能正确获取 Chat 对象是良好实践。

问题二:chat.sendMessage 为什么要放到 flatMap 中?

在代码中,processAndSendMessage 方法中有以下部分:

return chatMono.flatMap(chat -> processAndSendMessage(chat, event.getMessage()));

并且在 processAndSendMessage 方法中:

Mono<Message> sendMessage = chat.sendMessage(messageSpec);
return sendMessage;

解释:

  1. Reactive Streams 与异步操作:

    在响应式编程(Reactive Programming)中,Mono 和 Flux 用于表示异步的数据流。Mono<T> 表示一个包含单个元素的异步数据流,而 Flux<T> 表示包含多个元素的异步数据流。

  2. flatMap 的作用:

    • 异步序列的转换: flatMap 方法用于将一个元素转换为另一个包含异步结果的 Mono 或 Flux,然后将这些异步序列扁平化,生成一个新的 Mono 或 Flux。
    • 链式异步操作: 当你有一个依赖于前一个异步操作结果的后续异步操作时,使用 flatMap 可以将它们串联起来,确保前一个操作完成后再执行下一个操作。
  3. 为什么不能用 map:

    • 如果使用 map,返回的类型将是 Mono<Mono<Message>>,这是一个嵌套的 Mono,不符合我们的需求。
    • flatMap 会自动帮我们解除一层嵌套,将 Mono<Mono<Message>> 扁平化为 Mono<Message>。
  4. 在本例中的应用:

    • 获取 Chat 对象后发送消息: 我们需要先获取到 Chat 对象,然后才能调用 chat.sendMessage(messageSpec) 方法发送消息。
    • chat.sendMessage(messageSpec) 返回 Mono<Message>: 发送消息本身是一个异步操作,返回一个 Mono<Message>,表示消息发送完成后返回的消息对象。
    • 使用 flatMap 链接操作: 通过 chatMono.flatMap(...),我们可以在获取到 Chat 对象后,继续执行发送消息的异步操作,并将最终结果作为一个 Mono<Message> 返回。

代码执行流程:

  1. chatMono: 一个异步的 Mono Chat,表示获取 Chat 对象的过程。
  2. flatMap: 在 Chat 对象获取成功后,执行 processAndSendMessage 方法。
  3. processAndSendMessage 方法:
    • 处理消息内容,执行翻译逻辑。
    • 调用 chat.sendMessage(messageSpec) 发送翻译后的消息,返回 Mono<Message>。

示意图:

Mono<Chat> --flatMap--> Mono<Message>

为什么需要这样做:

  • 保持异步执行: 因为上面的获取的是 Mono Chat,确保所有操作都是非阻塞和异步的,充分利用响应式编程的优势,提高性能和资源利用率。
  • 正确处理依赖关系: 由于发送消息需要依赖于前一步获取的 Chat 对象,使用 flatMap 可以确保在 Chat 对象可用后再执行发送消息的操作。
  • 避免嵌套和回调地狱: 使用 flatMap 可以保持代码的简洁和可读性,避免嵌套过深的回调。

示例:

假设不用 flatMap,而是直接写:

Mono<Mono<Message>> messageMono = chatMono.map(chat -> chat.sendMessage(messageSpec));

这将导致 messageMono 的类型是 Mono<Mono<Message>>,这并不是我们想要的,因为我们需要的是 Mono<Message>。


问题 1 和问题 2 总结

  • 关于 event.getChat() 和 event.getMessage().getChat():

    • 为了提高代码的健壮性和可靠性,我们在尝试获取 Chat 对象时,先尝试使用 event.getChat(),如果获取失败(为空),再使用 event.getMessage().getChat() 作为备用。
    • 这是为了确保在各种可能的事件上下文中,都能正确获取到 Chat 对象,防止因空值导致的异常。
  • 关于在 flatMap 中使用 chat.sendMessage:

    • flatMap 用于将依赖于前一个异步结果的后续异步操作串联起来,确保前一个操作完成后再执行下一个操作。
    • 在本例中,我们需要在获取到 Chat 对象后,才能发送消息,而发送消息本身是一个异步操作,返回 Mono<Message>。
    • 使用 flatMap 可以将整个操作链保持为异步和非阻塞的,同时避免嵌套的 Mono,保持代码简洁和可读性。

消息格式

在开发和调试过程中,了解消息的结构有助于更好地处理和解析消息内容。以下是用户发送的消息和机器人回复的消息的格式化 JSON 示例。

用户发送的消息

格式化后的 JSON:

{
  "timestamp": "2024-12-02T21:27:46.776",
  "thread": "t4j-events-2",
  "level": "INFO",
  "logger": "c.l.g.t.p.UserPredicate.test",
  "message": {
    "type": "SendMessageEvent",
    "message": {
      "data": {
        "variant": "Variant2",
        "content": {
          "type": "BaseMessage",
          "id": 1247,
          "flags": 0,
          "fromId": null,
          "peerId": {
            "type": "PeerUser",
            "userId": "user_id"
          },
          "fwdFrom": null,
          "viaBotId": null,
          "replyTo": null,
          "date": 1733210883,
          "message": "Function",
          "media": null,
          "replyMarkup": null,
          "entities": null,
          "views": null,
          "forwards": null,
          "replies": null,
          "editDate": null,
          "postAuthor": null,
          "groupedId": null,
          "reactions": null,
          "restrictionReason": null,
          "ttlPeriod": null
        }
      }
    },
    "chat": {
      "type": "PrivateChat",
      "user": {
        "minData": {
          "type": "BaseUser",
          "id": "user_id",
          "accessHash": -6745242867060598026,
          "firstName": "user_name",
          "lastName": null,
          "username": "user_name",
          "phone": null,
          "photo": {
            "type": "BaseUserProfilePhoto",
            "flags": 0,
            "photoId": 5129962608709971087,
            "strippedThumb": null,
            "dcId": 1
          },
          "status": {
            "type": "UserStatusRecently"
          },
          "botInfoVersion": null,
          "restrictionReason": null,
          "botInlinePlaceholder": null,
          "langCode": "zh-hans",
          "emojiStatus": null,
          "usernames": null,
          "storiesMaxId": null
        },
        "fullData": null
      },
      "selfUser": {
        "minData": {
          "type": "BaseUser",
          "id": "user_id",
          "accessHash": -4262855346709871929,
          "firstName": "my-translator",
          "lastName": null,
          "username": "litongjava_bot",
          "phone": null,
          "photo": null,
          "status": null,
          "botInfoVersion": 1,
          "restrictionReason": null,
          "botInlinePlaceholder": null,
          "langCode": null,
          "emojiStatus": null,
          "usernames": null,
          "storiesMaxId": null
        },
        "fullData": null
      }
    },
    "author": {
      "minData": {
        "type": "BaseUser",
        "id": "user_id",
        "accessHash": -6745242867060598026,
        "firstName": "",
        "lastName": null,
        "username": "user_name",
        "phone": null,
        "photo": {
          "type": "BaseUserProfilePhoto",
          "flags": 0,
          "photoId": 5129962608709971087,
          "strippedThumb": null,
          "dcId": 1
        },
        "status": {
          "type": "UserStatusRecently"
        },
        "botInfoVersion": null,
        "restrictionReason": null,
        "botInlinePlaceholder": null,
        "langCode": "zh-hans",
        "emojiStatus": null,
        "usernames": null,
        "storiesMaxId": null
      },
      "fullData": null
    }
  },
  "additionalInfo": "Sql: select \"dst_text\" from \"max_kb_sentence_tanslate_cache\" where \"md5\" = ?"
}

机器人回复的消息

格式化后的 JSON:

{
  "timestamp": "2024-12-02T21:27:46.936",
  "thread": "t4j-events-2",
  "level": "INFO",
  "logger": "c.l.g.t.p.UserPredicate.test",
  "message": {
    "type": "SendMessageEvent",
    "message": {
      "data": {
        "variant": "Variant2",
        "content": {
          "type": "BaseMessage",
          "id": 1248,
          "flags": 100000010,
          "fromId": {
            "type": "PeerUser",
            "userId": "user_id"
          },
          "peerId": {
            "type": "PeerUser",
            "userId": "user_id"
          },
          "fwdFrom": null,
          "viaBotId": null,
          "replyTo": null,
          "date": 1733210883,
          "message": "功能",
          "media": null,
          "replyMarkup": null,
          "entities": null,
          "views": null,
          "forwards": null,
          "replies": null,
          "editDate": null,
          "postAuthor": null,
          "groupedId": null,
          "reactions": null,
          "restrictionReason": null,
          "ttlPeriod": null
        }
      }
    },
    "chat": null,
    "author": null
  }
}

对比与分析

通过上述格式化后的 JSON,可以更清晰地对比用户发送的消息和机器人回复的消息:

  1. 发送者 (author) 区别:

    • 用户发送的消息:
      • author 字段包含用户的详细信息。
      • fromId 为 null,但通过 author 可以获取到发送者的用户 ID。
    • 机器人发送的消息:
      • author 字段为 null。
      • fromId 包含机器人的用户 ID ("user_id")。
  2. 聊天 (chat) 区别:

    • 用户发送的消息:
      • chat 字段包含 PrivateChat 对象,详细描述了聊天双方的信息。
    • 机器人发送的消息:
      • chat 字段为 null,这可能表示机器人发送的消息不关联特定的聊天上下文,或者在日志记录时未捕获到相关信息。
  3. 消息内容 (message) 区别:

    • 用户发送的消息:
      • 内容为 "Function"。
    • 机器人发送的消息:
      • 内容为 "功能"。
  4. 其他字段:

    • 用户发送的消息:
      • 包含更多关于用户的详细信息,如 firstName、username、photo 等。
    • 机器人发送的消息:
      • author 和 chat 字段为 null,只包含基本的消息信息。

测试与运行

完成上述配置和开发后,即可通过 Telegram 与机器人进行对话,测试翻译功能。以下是测试步骤:

  1. 启动服务器:

    • 确保您的服务器正在运行,并且 MTProto Telegram 客户端已成功连接。
    • 检查日志,确认客户端已连接且事件监听器已配置。
  2. 与机器人对话:

    • 在 Telegram 中找到您的机器人,发送需要翻译的文本。
    • 例如,发送 "你好,世界!" 或 "Good morning!"。
  3. 查看翻译结果:

    • 机器人将根据文本内容自动检测源语言,并返回翻译后的文本。

    • 例如:

      • 用户发送:你好,世界!

      • 机器人回复:Hello, World!

      • 用户发送:Good morning!

      • 机器人回复:早上好!

  4. 检查日志:

    • 查看服务器日志,确保消息处理流程正常,没有异常或错误。
    • 通过日志可以追踪消息的接收、翻译和回复过程。

示例

  • 用户发送:今天天气怎么样?

  • 机器人回复:How is the weather today?

  • 用户发送:What's the capital of France?

  • 机器人回复:法国的首都是哪里?

总结

本文档详细介绍了如何使用 MTProto 协议开发一个具备翻译功能的 Telegram 机器人。通过以下步骤,您可以快速搭建并测试自己的翻译机器人:

  1. 准备工作:删除现有 Webhook 地址,申请 Telegram API ID 和 Hash。
  2. 项目配置:添加必要的依赖项,确保项目使用 Java 17 及以上版本。
  3. 开发实现:编写配置类、消息过滤器和翻译功能模块,确保机器人能够正确处理和翻译消息。
  4. 异步处理:利用 Reactor 的 Mono 和 flatMap 实现异步处理,提高机器人的并发处理能力和响应速度。
  5. 测试与运行:启动服务器,与机器人对话,验证翻译功能的有效性。

通过采用异步处理机制,您的 Telegram 翻译机器人将具备更高的性能和可扩展性,能够高效应对大量并发请求,提供稳定可靠的服务体验。希望本文档能够帮助您顺利开发出功能强大的翻译机器人。

Edit this page
Last Updated:
Contributors: Tong Li
Prev
/zh/55_telegram4j/02.html
Next
过滤旧消息