LunaTranslator 内置网络服务完全指南:Web 页面、HTTP/WebSocket API 与源码级解析
LunaTranslator 内置网络服务完全指南:Web 页面、HTTP/WebSocket API 与源码级解析
LunaTranslator 作为一款视觉小说翻译器,内置了一套完整的本地网络服务:开启后即可通过浏览器访问与主程序实时同步的 Web 界面,并通过 HTTP 与 WebSocket 接口调用翻译、词典、Mecab 分词、OCR、TTS 等核心能力。本文以官方文档 docs/cht/apiservice.md 为骨架,结合 servicecollection.py、tcpservice.py 等源码,完整讲解每一个页面与接口的用途、请求格式、响应结构,以及背后的实现原理,帮助你将其接入自己的工具链。
一、服务概览:如何开启与访问
网络服务默认是关闭的,需要手动开启。在 LunaTranslator 的设置界面(对应源码 textinput.py)中有两个关键配置项:
| 配置项 | 默认值 | 说明 |
|---|---|---|
networktcpenable |
false |
网络服务总开关,开启后立即启动 TCP 服务 |
networktcpport |
2333 |
监听端口,取值范围 0–65535,修改后即时生效 |
设置界面还附带一个"打开"按钮,点击后调用 os.startfile 直接以默认浏览器打开 http://127.0.0.1:{端口号}。也就是说,开启后默认访问地址即为:
http://127.0.0.1:2333
服务的启动逻辑在 LunaTranslator.py 的 serviceinit() 中:
@threader
def serviceinit(self):
gobject.base.portconflict.emit("")
self.service.stop()
if globalconfig.get("networktcpenable", False):
try:
self.service.init(globalconfig.get("networktcpport", 2333))
except OSError:
gobject.base.portconflict.emit("端口冲突")
值得注意的几点:
- 服务在独立线程中启动,不会阻塞主程序 UI;
- 每次开启前会先
stop()旧服务,因此修改端口号后无需重启程序,设置界面回调serviceinit()即会以新端口重新监听; - 如果端口已被占用,
socket.bind抛出OSError,界面上会显示"端口冲突"提示。
从源码看,TCPService.init() 使用 socket.bind(("0.0.0.0", port))(见 tcpservice.py),意味着监听所有网卡地址,局域网内的其他设备也可以通过 http://<主机IP>:2333 访问;如果你只希望本机访问,请在防火墙或代理层面自行限制。服务注册的全部处理器由 registerall() 一次性挂载(见 servicecollection.py)。
二、Web 页面:浏览器里的 LunaTranslator
Web 页面与桌面端共享同一套渲染逻辑——主界面、历史记录页面的 HTML 模板复用自 gui 模块(TextBrowser.loadex_()、wvtranshist.loadex_(),对应 htmlcode/uiwebview 下的 mainui.html、transhist.html),因此浏览器中看到的内容与主窗口高度一致。
导航页 /
导航页,列出全部页面入口。其 HTML 实现位于 htmlcode/service/index.html,实际内容即一组指向各页面的链接:
<a href="/page/mainui">/page/mainui</a>
<a href="/page/transhist">/page/transhist</a>
<a href="/page/dictionary">/page/dictionary</a>
<a href="/page/manyinone">/page/manyinone</a>
<a href="/page/translate">/page/translate</a>
<a href="/page/ocr">/page/ocr</a>
<a href="/page/tts">/page/tts</a>
对应的处理器是 servicecollection.py 中的 PageIndex。
主界面 /page/mainui
与主窗口显示的文字内容同步。包括原文、翻译结果,甚至支持在页面上点击单词查词——此时会唤出 /page/dictionary 页面。
底层机制:页面通过 WebSocket 与程序保持实时同步。处理器 PageMainui 返回 TextBrowser.loadex_() 的 HTML,而页面内的连接对应内部 WebSocket 端点 /__internalservice/mainuiws(servicecollection.py),它把每个活跃连接登记进 mainuiwsoutputsave 列表,主窗口文本刷新时通过 WSForEach 批量推送;页面还能回传事件(calllunaclickedword 等)触发主程序的点击查词回调。
历史记录 /page/transhist
与历史文本窗口显示的内容同步,同样支持页面内交互(展开/收起原文、切换翻译名称等),对应内部端点 /__internalservice/transhistws(servicecollection.py)。
查词页面 /page/dictionary
查询单词的页面。在 /page/mainui 中点击单词时即会唤出此页。处理器 PageSearchWord(servicecollection.py)有一个实用细节:支持 URL 参数 word,若该词存在"原型"(prototype,例如动词活用还原为原形),会自动 302 重定向到原型词条。
整合页面 /page/manyinone
将 /page/mainui、/page/transhist、/page/dictionary 三个页面整合为一个页面(manyinone.html)。在该页面内的主界面子区域点击单词查词时,不会新开查词窗口,而是在当前窗口的词典子区域就地显示结果,适合单窗口集中操作。
翻译界面 /page/translate
独立的翻译输入界面,对应 translate.html。适合临时手动翻译一段文本。
OCR 界面 /page/ocr
OCR 识别界面,对应 ocr.html,页面中上传/粘贴图片后调用后端 OCR 引擎返回识别文本。
TTS 界面 /page/tts
TTS 语音合成界面,对应 tts.html,输入文本即可合成为语音并播放。
三、HTTP API:程序化调用核心能力
所有 API 均支持跨域(响应头固定携带 Access-Control-Allow-Origin: *,见 tcpservice.py),因此可以直接从前端页面或 Node/Python 脚本跨域调用。
3.1 翻译 /api/translate
- 必填查询参数:
text - 可选查询参数:
id(翻译器的 ID) - 返回:
application/json
当指定 id 时强制使用该翻译器;不指定时,自动选择"最快的翻译接口"(即当前配置排序下可用的第一个)。
请求示例:
GET /api/translate?text=こんにちは&id=google
成功响应(字段含义:id 翻译器 ID、name 翻译器名称、result 翻译结果):
{
"id": "google",
"name": "Google 翻译",
"result": "你好"
}
失败时返回错误信息:
{
"error": "翻译失败的具体原因",
"id": "google",
"name": "Google 翻译"
}
实现位于 servicecollection.py:请求被转交给 gobject.base.textgetmethod(),waitforresultcallbackengine 指定翻译器、waitforresultcallbackengine_force=True 表示强制使用指定引擎,通过 threading.Event 同步等待翻译完成后返回结果。
3.2 词典查询 /api/dictionary
- 必填查询参数:
word - 可选查询参数:
id(词典的 ID)
指定 id 时:仅查询该词典,返回 application/json,包含词典 ID id、名称 name、HTML 内容 result;查询失败则返回空对象 {}:
{
"id": "jisho",
"name": "Jisho",
"result": "<div>…查词结果 HTML…</div>"
}
不指定 id 时:并行查询所有已启用词典,响应为 text/event-stream(SSE),每个 Event 是一个 JSON 对象,结构与上述相同。实现见 APISearchWord:无 id 时遍历 gobject.base.cishus,用 threading.Semaphore 并发收集各词典结果并以生成器(Generator)形式逐条产出,响应体被自动识别为 SSE 流(见下文"底层实现")。
3.3 Mecab 分词 /api/mecab
- 必填查询参数:
text - 返回:Mecab 对
text的解析结果(JSON 数组)
用于日文分词/形态分析,底层调用 gobject.base.parsehira(text)(servicecollection.py)。该功能依赖项目中 Mecab 模块(myutils/mecab.py)及对应的原生解析组件。
3.4 TTS 合成 /api/tts
- 必填查询参数:
text - 返回:音频二进制数据(HTTP 响应)
实现(servicecollection.py)调用 gobject.base.reader.ttscallback() 异步合成语音,通过 threading.Event 等待合成完成后,以 ResponseWithHeader 返回原始音频数据,响应头中的 Content-Type 为当前 TTS 引擎的 MIME 类型(如 audio/mpeg),并附带 Content-Length;若合成失败则返回 JSON 错误对象。
3.5 OCR 识别 /api/ocr
- 方法:
POST - 请求体:JSON,含
image字段,值为 Base64 编码的图片(注意源码中并不包含data:image/...前缀,需要自行保证是纯 Base64 数据) - 返回:OCR 识别结果 JSON
实现(servicecollection.py):base64.b64decode 解码后经 QImage.loadFromData 还原为图像,交给 ocr_run()(见 myutils/ocrutil.py)走完整的 OCR 引擎链路,返回结果对象的 json 序列化。
请求示例:
POST /api/ocr
Content-Type: application/json
{"image": "<base64编码的图片数据>"}
3.6 列出可用词典 /api/list/dictionary
返回当前可用的词典列表(JSON 数组),每项包含 id 与 name。实现遍历 globalconfig<a href="https://link.gitcode.com/i/95be484c4250a0deedba9845accab0e2" target="_blank">"cishuvisrank"] 并过滤未实例化的词典([servicecollection.py),其结果可直接用于 /api/dictionary 的 id 参数。
3.7 列出可用翻译器 /api/list/translator
返回当前可用的翻译器列表(JSON 数组),每项包含 id 与 name。实现遍历 globalconfig<a href="https://link.gitcode.com/i/1693fd6d1a24b0f232e1431186b72750" target="_blank">"fix_translate_rank_rank"](翻译器排序配置)并过滤未实例化的引擎([servicecollection.py),其结果可直接用于 /api/translate 的 id 参数。
3.8 文本输入 /api/textinput
- 必填查询参数:
text - 无返回内容
将文本送入 LunaTranslator 的文本处理管线(等价于手动输入文本触发翻译流程),实现调用 gobject.base.textgetmethod(text, is_auto_run=False)(servicecollection.py)。典型用途:把外部复制的文本注入翻译器统一处理。
四、WebSocket 服务:实时文本流
WebSocket 端点用于持续推送实时提取的文本,适合对接需要逐句获取原文/译文的第三方工具(例如弹幕、字幕、聊天机器人)。
/api/ws/text/origin
持续输出所有提取到的原文文本。当客户端连接后,连接对象被加入 wsoutputsave 列表(servicecollection.py),此后每次游戏/OCR 提取到新的原文句子,都会向该连接推送文本帧。
/api/ws/text/trans
持续输出所有翻译结果,机制同上(servicecollection.py)。
这两个端点的推送到派发逻辑在 textio/textoutput/websocket.py:
def dispatch(self, text: str, isorigin: bool):
def __(handle):
if isorigin and isinstance(handle, TextOutputOrigin):
handle.send_text(text)
elif (not isorigin) and isinstance(handle, TextOutputTrans):
handle.send_text(text)
WSForEach(wsoutputsave, __)
要点:
- 它们本质上是 LunaTranslator 的一种"文本输出器"(
Outputer),在设置中启用对应的 WebSocket 输出后,原文与译文才会被推送到所有在线客户端; WSForEach(servicecollection_1.py)在线程中遍历所有连接逐个发送;若某个客户端断开(抛出OSError),会自动将其从列表移除,不会影响其他连接;- 消息格式为 WebSocket 文本帧,每帧一条完整句子。
五、底层实现:自研的轻量 HTTP + WebSocket 服务端
整个网络服务不依赖 Flask/Django 等框架,而是基于 Python 标准库 socket 手写的 TCP 服务(tcpservice.py),理解它有助于排查自定义调用中的异常。
5.1 请求路由与分发
TCPService 维护一个 handlers 列表;每个处理器是一个类,通过类属性 path 声明路径(HTTP 处理器还可通过 method 限定请求方法,如 /api/ocr 限定 POST)。连接建立后:
RequestInfo.readfrom()解析请求行、请求头和可选请求体,path/query由urlsplit+parse_qsl拆分(tcpservice.py);- 依据请求头中是否有
Upgrade: websocket区分 WebSocket 与普通 HTTP 请求,再遍历handlers按路径精确匹配; - 匹配成功则实例化处理器执行
parse(),失败返回 404。
5.2 丰富的响应类型
ResponseInfo 会根据 parse() 的返回值类型自动选择序列化方式(tcpservice.py):
| 返回类型 | 响应表现 |
|---|---|
str |
Content-Type: text/html; charset=utf-8 |
dict / list / tuple |
Content-Type: application/json; charset=utf-8(ensure_ascii=False) |
FileResponse |
以 1024 字节分块流式发送文件,MIME 类型由 query_mime 推断 |
GeneratorType(生成器) |
Content-Type: text/event-stream(SSE),每项以 data: ...\n\n 逐条发送——这正是 /api/dictionary 全词典查询的实现基础 |
RedirectResponse |
302 重定向(用于查词原型跳转) |
ResponseWithHeader |
自定义响应头(用于 /api/tts 的音频 MIME 与长度) |
5.3 WebSocket 握手与帧协议
WSHandler 实现了 RFC 6455 的核心握手:用 Sec-WebSocket-Key 拼接固定魔数 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 后做 SHA-1 + Base64,得到 Sec-WebSocket-Accept 返回 101 状态码(tcpservice.py)。
随后按帧协议收发:解析 FIN/opcode/mask/扩展长度(126→2 字节、127→8 字节),处理文本帧(opcode 0x1)、关闭帧(0x8)、Ping/Pong 帧(0x9/0xA),服务器发送帧不带掩码(tcpservice.py)。这意味着标准 WebSocket 客户端(浏览器 WebSocket、Python websocket-client 等)均可直接连接。
六、配置项与注意事项
network_service_disabled_paths
默认配置(defaultconfig/config.json)中为 <a href="https://link.gitcode.com/i/e03fae14e560b7a40ae6a6cf9b27c29b" target="_blank">]。TCPService 在路由前会检查请求路径是否命中该列表,命中则直接返回 404([tcpservice.py)。如需对外暴露服务又不想开放某些敏感接口(例如 OCR 或文本输入),可在此列表中加入对应路径(如 "/api/textinput")。
安全与使用提示
- 服务监听
0.0.0.0,且所有接口无鉴权,请勿在不可信网络中开启,或将端口暴露到公网; /api/ocr的image字段是纯 Base64 字符串,不含data:image/...;base64,前缀;- 修改端口或开关后即时生效,无需重启程序;端口被占用时会收到"端口冲突"提示;
- WebSocket 文本推送依赖在输出设置中启用对应的 WebSocket 输出器,否则即使建立了连接也不会收到数据。
七、典型应用场景小结
| 需求 | 推荐接口 |
|---|---|
| 网页端远程查看/控制主界面文本 | /page/mainui、/page/manyinone |
| 自己的程序里翻译文本 | /api/translate |
| 集成词典查询(含多词典并行) | /api/dictionary |
| 日文分词/形态分析 | /api/mecab |
| 语音合成 | /api/tts |
| 图片文字识别 | /api/ocr(POST + Base64) |
| 实时逐句获取原文/译文 | WebSocket /api/ws/text/origin、/api/ws/text/trans |
| 动态发现可用引擎 | /api/list/dictionary、/api/list/translator |
LunaTranslator 的这套内置网络服务把翻译器最核心的文本处理能力(翻译、查词、分词、OCR、TTS)完整暴露为标准的 HTTP/WebSocket/SSE 接口,且页面与桌面端共享同一渲染与同步链路。无论是想用手机/浏览器做第二屏幕,还是将翻译能力接入自己的脚本与自动化流程,都可以直接基于本指南的接口约定快速落地。