【Python】如何给你的kook机器人添加上翻译功能
翻译功能实现
打开 code/endpoints/translate.py,这便是本仓库中翻译代码的实现。
其中第一部分有道翻译的代码来自Many-Translaters项目,该项目上一次维护是在4年前,且里面的部分代码已经无法使用。该代码属于一个白嫖产物,稳定性未知。
为了不让我的bot在有道翻译接口失效后直接没有了翻译功能,这里我使用了彩云小译来作“备胎”
你可以在彩云小译的官网上找到api文档,内部包含了一个Python代码示例,开箱即用!免费用户申请的
api-key
,每月有100w字符的免费额度,对于我们的bot算是够用了。
1.关于aiohttp和requests的优劣
在khl.py
一众大佬的建议下,我简单学习了aiohttp
的代码,并将彩云小译的requests
修改为了aiohttp
1 | #原有requests代码 |
这里简单说一下aiohttp
和requests
的区别
requests
途中,程序会挂起,bot将不会响应其他命令aiohttp
作为异步框架,bot在使用它的同时,可以同步处理其他命令
举个栗子:假设有用户每1分钟调用一次bot的翻译接口,彩云小译的服务器用了3秒钟(实际肯定没那么久)响应了我们的requests
。这3秒钟内,如果有其他用户调用了bot的另外一个指令,我们的bot就跟假死了一样,不会响应该用户的指令
这样看来,优势就很明显了:虽然在网络稳定的时候,requests
和aiohttp
不会形成鲜明的效率差距,但在KOOK或者彩云小译服务器拥堵期间,我们的bot也能做到不会因为requests
时间太长而影响用户的使用体验。
2.利用抛异常机制更改翻译引擎
看到main.py中的translate
部分,这里我import
了translate.py
中的相关函数,随后使用bot.command
来调用这两个函数。那么如何让bot在有道翻译接口寄了的时候,自动去找备胎彩云小译呢?
- 简单了解抛异常
在python中,基本的抛异常机制如下:
1 | try: |
上面这个代码就是一个简单的抛异常机制。编译器会先尝试运行try
后面的代码,如果该部分报错,则会转而执行except
后的代码。
转换倒我们这里的例子,我们只需要在try后面写入有道翻译的代码,在except后写入彩云小译的代码,编译器就能在有道的接口出错的时候,自动找备胎
1 | try: |
3.关于带空格英文句子传参问题
当我们翻译一个句子的时候,中文内容往往没有空格,但英文句子极其依赖于空格
进行单词的分割。
如果我们简单地使用str来接受传参,就会导致用户需要翻译的英文内容,只有第一个单词传了过来
1 | async def translate(msg: Message,txt:str): |
比如当用户打出:/TL I LOVE YOU
时,bot实际接收到的只有首单词I
,它会翻译该单词,可后面的LOVE YOU
直接被无情抛弃了!
这里我们就需要使用python中牛逼的不定传参*arg
了!
1 | async def translate(msg: Message,*arg): |
*arg
是python中支持的不定参数传参,即函数先前不知道用户会传入多少个参数。我们可以在传参完毕后,再对这些参数进行操作。
利用*arg
的特性,我们可以一次性把所有单词都接收过来,再在函数中将它们拼成一个完整的字符串,传入到translate
函数中。
1 | async def translate(msg: Message,*arg): |
这里的" ".jion(arg)
代表用空格来分隔每一个参数,这样才能拼出一个完整的英文句子!
好了,基本的单句翻译已经写好了,但我们还可以整点花活,让bot可以实时翻译某一个文字频道内的所有消息!
4.实时翻译(全局变量)
见main.py
中的ListTL
,这里我为实时翻译创建了一个全局数组,用来存放需要实时翻译的文字频道id。
注意:ListTL
作为全局变量,在函数中调用的时候,需要先用global ListTL
进行全局变量声明。否侧程序会在该函数中创建临时变量!
- 当用户需要实时翻译时,利用
/TLON
功能在他所在的文字频道开启该功能
bot可以在msg.ctx.channel.id
中获取到用户所在文字频道的id,并将其写入List中
- 使用
@bot.command(regex=r'(.+)')
正则表达式获取文字频道的所有内容,再通过判断该文字频道id是否存于List之中,来确认是否要进行实时翻译并返回结果
这种正则方法也是让bot监看文字频道的一个非常好的办法,比如发现关键词之后,自动发送对应消息提示。
- 当用户使用
/TLOFF
关闭实时翻译后,将对应位置的List置零,空出栏位
具体的代码实现可以查看main.py
中translate
相关部分的函数
5.处理met和rol消息
为了避免冲突,机器人不应该翻译 @xx用户
和@xx角色
的消息,在kook的后台,机器人会接收到 (met)user_id(met)/(rol)role_id(rol)
格式的文字;
用下面的代码处理,可以将这两个串替换成空串,不进行翻译
1 | # 单独处理met和rol消息,不翻译这部分内容 |
结语
使用实时翻译可以实现一些好玩的事情:比如把一句话来回翻译N遍进行“提纯”
(非常无聊了属于是)