使用 ChatGPT 翻译 FreeSWITCH 官方文档
- Published on
RTS 最近使用 ChatGPT 将 FreeSWITCH 官方文档翻译成了中文,而在翻译过程中也遇到不少问题和坑,这里就用本文记录下整个翻译过程。另外当前中文版 FreeSWITCH 文档已经上线了,欢迎大家阅读指正机翻的错误。
翻译工具的选型
在开始翻译工作之前,找了几种常用的翻译工具做了个简单对比,结果如下:
DeepL | ChatGPT | Azure 文本翻译 API | |
---|---|---|---|
正文翻译准确度 | 很好 | 一般 | 一般 |
markdown 格式保留 | 一般 | 很好 | 差 |
通过以上简单对比,最终确定用 ChatGPT 来做文档翻译,因为这样能节省大量解析文档的时间。而 DeepL 和 Azure 文本翻译 API 只适合纯文本的文档翻译,如果用他们来做需要不少的时间浪费在 markdown 文档解析上。
哪些基于 ChatGPT 翻译工具的轮子
在确定了翻译工具后,就基于整个工具在 Github 搜索,看能否找到现成的轮子直接拿来用。结果还真找到两个比较合适的轮子,如下:
开始先使用的是ChatGPT-for-Translation
,因为看介绍它会在翻译后单独存一份中英双语版本,不过当笔者使用次工具运行时发现OpenAI
接口是老版本的,新版本的调用方法已经改了,下文是最新的调用方法:
client = openai.OpenAI(api_key=key)
completion = client.chat.completions.create(
model=options.model,
messages=messages,
)
修复此问题后,程序可以正常跑了,期间抽检了几个介绍类的文档,也基本正常。但是历经十几个小时运行完毕后,抽查翻译后的文件发现有大量代码也被一起翻译了。比如下面这段原文:
<students>
<student>
<name>John</name>
<age>20</age>
<gender>Male</gender>
</student>
<student>
<name>Emily</name>
<age>18</age>
<gender>Female</gender>
</student>
<student>
<name>Michael</name>
<age>21</age>
<gender>Male</gender>
</student>
</students>
被翻译为:
<学生们>
<学生>
<名字>John</名字>
<年龄>20</年龄>
<性别>男</性别>
</学生>
<学生>
<名字>Emily</名字>
<年龄>18</年龄>
<性别>女</性别>
</学生>
<学生>
<名字>Michael</名字>
<年龄>21</年龄>
<性别>男</性别>
</学生>
</学生们>
同时还有部分Markdown
的段落标记##
被删除了,这时仔细看了该工具的源码才发现它是按行切片,然后交由 ChatGPT 进行翻译,因此即便使用下面的prompt
描述,也依然出现大量Markdown
格式被破坏,同时代码或配置部分被翻译的问题。
messages = [{
'role': 'system',
'content': 'You are a translator assistant.'
}, {
"role":
"user",
"content":
f"Translate the following text into {target_language}. You must maintain the original markdown format. Return only the translation and nothing else:\n{text}",
}]
后面又对比了Auto-i18n
的分段方式,发现它的分段处理逻辑要好点,是根据连续两个换行符进行切片,然后交给 ChatGPT 进行翻译。这样基本保留了原文的代码块,也不会造成代码部分被翻译的问题。
文档中的坑
<
与 <
的坑
解决文章分段切片问题后,重新将所有文档翻译一遍,然后在将文档渲染成 html 格式时,报错抛出大量语法错误,如下:
SyntaxError: /opt/jenkins/rts-docs/docs/FreeSWITCH-Explained/Auxiliary-Knowledge-and-Utilities/Multi-home-tutorial/index.mdx: Expected corresponding JSX closing tag for <gateway>. (453:192)
451 | <p>{`假设您已经设置了分机1013(物理电话的语音邮件会话),并留下了一个关于每个人都很忙,请留下您的回拨号码的消息,那么您就可以开始使用了(记得重新加载XML文件或者关闭/启动)。我的电话(诚然是一部旧的Grandstream GXP-2000)在我拨打并错误留言后就会出现红色闪烁的消息指示灯(我是1013) 。根据《仔细观察您的拨号计划》中的适当号码,您现在可以获取您的语音邮件并处理它。`}</p>
452 | <h3 {...{"id":"添加另一个did"}}>{`添加另一个DID`}</h3>
> 453 | <p>{`假设您希望为家庭或企业拥有多个直拨号码,我们在注册SIP提供商时看到了如何注册一个DID号码。如果您要拥有多个号码,您需要设置另一个与之前相同的`}<gateway>{`。然而,如果您想使用同一提供商,我们需要更改/ usr / local / freeswitch / conf / sip_profiles / external目录中的XML文件的语法。以下是例子:`}</p>
| ^
454 | <p>{`我的注册和使用一个DID的`}{`~`}{`/conf/sip`}{`_`}{`profiles/external/urban.xml文件:`}</p>
455 | <pre><code parentName="pre" {...{"className":"language-xml"}}>{`<include>
456 | <gateway name="xxx.xxx.xxx.xxx">
仔细对比原文发现造成问题的原因是正文内出现了<
,而原文将<
转义为了<
。这个也不算是 ChatGPT 的锅,原因是原来的 markdown 文件不规范。后面我们手工改了。
代码块被破坏的坑
原文有部分代码块由于内容过长,会出现超出被 ChatGPT 分为两个代码块的问题。同时分段的代码块,有些还会被 ChatGPT 根据上线文的理解,加上自己的一部分代码,翻译异常示例如下:
```xml
<extension name="local_extension">
<condition field="destination_number" expression="^\d+$">
<action application="transfer" data="user/${destination_number}@exch.cluecon.com"/>
</condition>
</extension>
```
要在Exchange服务器上启用统一消息服务器角色,请运行以下命令:
```powershell
Set-UMServer -Identity:'exch.cluecon.com' -DialPlans 4DigitDialPlan
```
要为特定用户(_Ext1000_)启用UM功能,请使用以下命令:
```powershell
Enable-UMMailbox -Identity:'CLUECON\EXT1000' -Pin '1234' -PinExpired $false -UMMailboxPolicy:'4DigitDialPlan Default Policy' -Extensions '1000'
```
可选:要在Exchange服务器上启用传真检测,请在具有统一消息服务器角色的Exchange 2007计算机的`\\Program Files\\Microsoft\\Exchange\\bin\\globcfg.xml`文件中将`EnableInbandFaxDetection`设置为True。
```xml
<extension name="本地分机">
<condition field="destination_number" expression="^(10[01][0-9])$">
<action application="set" data="dialed_ext=$1"/>
<action application="export" data="dialed_ext=$1"/>
</condition>
<condition field="destination_number" expression="^${caller_id_number}$">
<action application="answer"/>
<action application="sleep" data="1000"/>
<action application="export" data="sip_h_Diversion=${dialed_ext}"/>
<action application="bridge" data="{absolute_codec_string=PCMA}sofia/gateway/exch.cluecon.com/${dialed_ext}"/>
<anti-action application="bind_meta_app" data="1 b s execute_extension::dx XML features"/>
<anti-action application="bind_meta_app" data="2 b s record_session::$${base_dir}/recordings/${caller_id_number}.${strftime(%Y-%m-%d-%H-%M-%S)}.wav"/>
<anti-action application="bind_meta_app" data="3 b s execute_extension::cf XML features"/>
<anti-action application="set" data="transfer_ringback=${us-ring}"/>
<anti-action application="set" data="call_timeout=30"/>
<anti-action application="set" data="hangup_after_bridge=true"/>
<anti-action application="set" data="continue_on_fail=true"/>
<anti-action application="db" data="insert/call_return/${dialed_ext}/${caller_id_number}"/>
<anti-action application="db" data="insert/last_dial_ext/${dialed_ext}/${uuid}"/>
<anti-action application="bridge" data="user/${dialed_ext}@$${domain}"/>
<anti-action application="answer"/>
<anti-action application="sleep" data="1000"/>
<anti-action application="voicemail" data="default $${domain} ${dialed_ext}"/>
<anti-action application="export" data="sip_h_Diversion=${dialed_ext}"/>
<anti-action application="bridge" data="{absolute_codec_string=PCMA}sofia/gateway/exch.cluecon.com/${dialed_ext}"/>
</condition>
</extension>
```
上文中 Exchange 部分正文和PowerShell
命令部分都是 ChatGPT 自行添加的,这些在原文是没有的,下文是原文内容:
```xml
<extension name="Local_Extension">
<condition field="destination_number" expression="^(10[01][0-9])$">
<action application="set" data="dialed_ext=$1"/>
<action application="export" data="dialed_ext=$1"/>
</condition>
<condition field="destination_number" expression="^${caller_id_number}$">
<action application="answer"/>
<action application="sleep" data="1000"/>
<action application="export" data="sip_h_Diversion=${dialed_ext}"/>
<action application="bridge" data="{absolute_codec_string=PCMA}sofia/gateway/exch.cluecon.com/${dialed_ext}"/>
<anti-action application="bind_meta_app" data="1 b s execute_extension::dx XML features"/>
<anti-action application="bind_meta_app" data="2 b s record_session::$${base_dir}/recordings/${caller_id_number}.${strftime(%Y-%m-%d-%H-%M-%S)}.wav"/>
<anti-action application="bind_meta_app" data="3 b s execute_extension::cf XML features"/>
<anti-action application="set" data="transfer_ringback=${us-ring}"/>
<anti-action application="set" data="call_timeout=30"/>
<anti-action application="set" data="hangup_after_bridge=true"/>
<anti-action application="set" data="continue_on_fail=true"/>
<anti-action application="db" data="insert/call_return/${dialed_ext}/${caller_id_number}"/>
<anti-action application="db" data="insert/last_dial_ext/${dialed_ext}/${uuid}"/>
<anti-action application="bridge" data="user/${dialed_ext}@$${domain}"/>
<anti-action application="answer"/>
<anti-action application="sleep" data="1000"/>
<anti-action application="voicemail" data="default $${domain} ${dialed_ext}"/>
<anti-action application="export" data="sip_h_Diversion=${dialed_ext}"/>
<anti-action application="bridge" data="{absolute_codec_string=PCMA}sofia/gateway/exch.cluecon.com/${dialed_ext}"/>
</condition>
</extension>
```
而这个坑不太好处理,试着加过一些禁止自行解释的prompt
也没啥效果。如果读者你有好的解决办法,欢迎到 RTS 社区分享下。
总结
FreeSWITCH 是一个历史悠久的项目,其官方文档都是社区力量贡献的,格式审查也不严格,风格也不统一。尤其是多年以来,使用过很多不同的 Wiki 系统,在格式转换过程中也不免会出现一些问题。在转换到现行的 Markdown 格式之前,使用的是 Confluence Wiki 系统。
虽然 ChatGPT 翻译后的文档还是有不少缺点,但是依然能帮助开发人员节省大量文档翻译的时间。尤其是对比传统的翻译工具,能自动理解文件格式,在不需要对代码和注释做特殊处理的情况下,依然能很好的只翻译注释部分,同时不修改代码或配置内容。
如果要更好地处理文档,ChatGPT 的大上下文应该能解决一切问题,只是大上下文会比较贵。如果在上下文 Token 受限的情况下,使用 Markdown 语法解析工具(有很多工具都可以解析 Markdown 语法,如一些 Node.js 模块或 Pandoc 等),将代码块完整地切片,应该可以达到更好的效果。不过,我们并没有尝试这些方法,现在的解决方案勉强够用。
接下来,就手工修吧,欢迎大家多看看,多提 PR。Github 地址: https://github.com/rts-cn/docs 。