LunaTranslator 内置网络服务完全指南:HTTP API 与 WebSocket 的页面路由、接口协议与源码实现
【免费下载链接】LunaTranslator视觉小说翻译器 / Visual Novel Translator项目地址: https://gitcode.com/GitHub_Trending/lu/LunaTranslator
LunaTranslator 除了桌面 GUI 外,还内置了一套轻量级网络服务:它以本机 TCP 服务的形式提供 Web 控制页面(主界面同步、翻译历史、词典查询、翻译/OCR/TTS 演示页)和一套可直接调用的 HTTP/WebSocket API,方便外部程序、浏览器脚本乃至 Agent 把这款视觉小说翻译器当作一个可编程的"翻译/OCR/词典后端"来使用。读完本文,你将掌握全部页面路由与 API 端点的请求格式、返回结构、配置方法,以及这些能力在 tcpservice.py 与 servicecollection.py 中的底层实现原理。
一、服务概览:一个自带 Web 界面的本地 TCP 服务
该网络服务并不是独立进程,而是随 LunaTranslator 主程序运行的内嵌 TCP 服务。从源码结构看,它由三层组成:
- 传输层:tcpservice.py 中的
TCPService负责监听端口、解析 HTTP 请求头与 body、按路径分发到具体 Handler,同时内置了一个极简 WebSocket 服务端(WSHandler)。 - 路由层:servicecollection.py 中的
registerall(service)一次性注册了全部 20 个路由(8 个 Web 页面、8 个 HTTP API、4 个 WebSocket),见registerall函数末尾的注册清单。 - 应用层:各 Handler 直接复用
gobject.base中的翻译、词典、OCR、TTS、MeCab 解析等核心能力。
服务在 LunaTranslator.py 的serviceinit()中启动:
self.service.stop() if globalconfig.get("networktcpenable", False): try: self.service.init(globalconfig.get("networktcpport", 2333)) except OSError: gobject.base.portconflict.emit("端口冲突")两个关键结论:服务默认关闭(networktcpenable默认False),默认端口为 2333;如果端口被占用,界面会弹出"端口冲突"提示。TCP 层绑定的是0.0.0.0(见 tcpservice.py),即监听本机全部网卡地址。
1.1 请求分发与响应模型
TCPService.handle_client对每个连接做以下处理:
- 解析请求行与头部,得到
RequestInfo(含path与解析后的query字典); - 若路径命中
globalconfig["network_service_disabled_paths"](默认空列表,见 config.json),直接返回 404; - 根据请求头是否包含
Upgrade: websocket区分 WebSocket 握手与普通 HTTP 请求,再遍历已注册 Handler 匹配path; - 未命中任何路由则返回 404。
响应统一由ResponseInfo构造,它对不同 body 类型自动设置响应头(tcpservice.py):
| body 类型 | Content-Type | 说明 |
|---|---|---|
str | text/html; charset=utf-8 | 页面文本 |
dict/list/tuple | application/json; charset=utf-8 | JSON 响应 |
bytes | 需自行带ResponseWithHeader指定 | 二进制数据(如音频) |
FileResponse | 由 MIME 助手按扩展名推断 | 静态页面文件 |
RedirectResponse | Location头 + 302 | 重定向 |
GeneratorType | text/event-stream; charset=utf-8 | SSE 流式输出 |
另外所有响应都带Access-Control-Allow-Origin: *,因此浏览器跨域调用 API 时无需额外配置。
二、Web 页面路由:把翻译器的界面搬到浏览器
以下 8 个页面路由在文档 docs/ja/apiservice.md 中有详细说明,它们对应的实际页面文件位于 htmlcode/service 目录。
2.1/—— 导航页
返回 index.html,内含指向其余页面的链接,相当于服务主页(导航页)。
2.2/page/mainui—— 主界面文本同步
与主窗口TextBrowser显示的文本内容实时同步。实现上它返回的是渲染文本所用的同一套页面(TextBrowser.loadex_(),见 servicecollection.py),数据推送则依赖内部 WebSocket(见第五节)。在浏览器里打开该页面,看到的即是游戏内抽取文本的镜像视图,支持点击单词查词典。
2.3/page/transhist—— 翻译历史同步
与"翻译历史"窗口(wvtranshist)显示的文本内容实时同步,返回wvtranshist.loadex_()生成的页面(servicecollection.py)。
2.4/page/dictionary—— 单词搜索页
单词搜索页面。在/page/mainui中点击单词发起搜索时,本页面负责展示结果。它的特殊之处在于支持word查询参数:
- 不带参数:返回静态页面 dictionary.html;
- 带
word参数:由PageSearchWord处理,会先对单词做原型还原(WordSegResult.from_dict→word.prototype),若原型与原文不同,则 302 重定向到原型词的查询 URL(servicecollection.py),确保词典以词原型命中。
2.5/page/manyinone—— 三合一集成页
将上述主界面、翻译历史、词典三个页面集成到一个窗口的页面,对应 manyinone.html。其实现非常巧妙:用三个<object>内嵌/page/transhist、/page/dictionary、/page/mainui?__internal=1,并用 JavaScript 覆写 mainui iframe 的window.open:
<object data="/page/mainui?__internal=1" ... id="mainui"></object> <script> const iframe = document.getElementById('mainui') iframe.contentWindow.open=(url)=>{ document.getElementById('searchword').data=url } </script>效果正如文档所述:在主界面子区块点击单词搜索时不会打开新窗口,而是在当前页面的词典子区块内展示搜索结果。
2.6/page/translate、/page/ocr、/page/tts
分别是翻译接口、OCR 接口、TTS 接口的 Web 演示页,返回 translate.html、ocr.html、tts.html。它们通常在前端用 JavaScript 调用下面第三、四节对应的 HTTP API。
三、HTTP API:把翻译器变成可编程后端
3.1GET /api/translate—— 文本翻译
必填查询参数:text(待翻译文本)。
可选参数:id(翻译器 ID)。
- 指定
id时:使用该翻译器进行翻译; - 未指定
id时:走默认翻译流程,从可用翻译器中选择结果返回。
返回:application/json,包含翻译器 IDid、名称name、翻译结果result。
源码实现(servicecollection.py):APITranslate.parse通过gobject.base.textgetmethod(text, False, waitforresultcallback=..., waitforresultcallbackengine=tsid, waitforresultcallbackengine_force=True)触发完整翻译管线(含预处理、翻译、后处理),并以threading.Event同步等待结果。错误时返回{"error": ..., "id": ..., "name": ...},成功时返回:
{ "id": "翻译器ID", "name": "翻译器名称", "result": "翻译结果文本" }id与name的映射分别由dynamicapiname()与国际化表_TR解析。未指定id时,翻译器的选择顺序由配置项fix_translate_rank_rank(默认空列表,见 config.json)决定。
3.2GET /api/dictionary—— 词典查询
必填查询参数:word(要查询的单词)。
可选参数:id(词典 ID)。分两种行为:
- 指定
id:只查询该词典,返回单个 JSON 对象,含词典 IDid、词典名称name、HTML 内容result;查询失败时返回空对象{}。源码对应 servicecollection.py 的APISearchWord.parse分支。 - 未指定
id:并行查询全部已启用词典(gobject.base.cishus),返回SSE(text/event-stream)流,每个事件是一个 JSON 对象(词典 IDid、名称name、HTML 内容result)。这就是文档中"返回event/text-stream"的含义。
实现细节:iterhelper是一个生成器(servicecollection.py),对每个词典调用cishu.safesearch(...)异步搜索,用threading.Semaphore收集结果并逐个yield;ResponseInfo识别生成器类型后设置text/event-stream,并在 tcpservice.py 中以data: {json}\n\n的 SSE 帧格式逐条发送。
3.3GET /api/mecab—— MeCab 分词解析
必填查询参数:text。
返回text的 MeCab 解析结果(servicecollection.py):内部调用gobject.base.parsehira(text),把每个词的解析结果(原型、读音、词性等字段)以 JSON 数组形式返回,等价于界面上的日语假名/分词标注功能。
3.4GET /api/tts—— 语音合成
必填查询参数:text。
返回音频二进制数据(非 JSON)。源码(servicecollection.py)调用gobject.base.reader.ttscallback(text, callback)走当前 TTS 引擎,通过ResponseWithHeader携带音频的content-type(如audio/mpeg、audio/wav等 MIME,来自TTSResult.mime)与content-length返回;若合成出错,则返回{"error": ...}。
3.5POST /api/ocr—— 图片文字识别
与其它端点不同,本接口要求POST 方法,请求体为 JSON:{"image": "<base64 编码的图片数据>"}。源码(servicecollection.py)先base64.b64decode解码,再用QImage.loadFromData载入,最后调用ocr_run(qi)(见 myutils/ocrutil.py)执行当前 OCR 引擎,返回识别结果的 JSON(含文本、置信度与各识别块坐标等信息,具体结构取决于所用 OCR 引擎)。
3.6GET /api/list/dictionary与GET /api/list/translator—— 可用引擎清单
分别列出当前可用的词典与翻译器,返回元素为{"id": ..., "name": ...}的 JSON 数组(servicecollection.py):
/api/list/dictionary:遍历globalconfig["cishuvisrank"]中已实例化的词典(gobject.base.cishus),name由dynamiccishuname+_TR国际化得到;/api/list/translator:遍历globalconfig["fix_translate_rank_rank"]中已实例化的翻译器(gobject.base.translators)。
这两个接口可与/api/translate、/api/dictionary配合使用:先拉取清单获取id,再按id精确调用,形成"枚举引擎 → 定向调用"的完整工作流。
3.7GET /api/textinput—— 文本输入注入
必填查询参数:text。
把文本注入 LunaTranslator 的翻译管线(servicecollection.py),等价于从剪贴板或游戏文本源送入一段文本的效果,is_auto_run=False表示不触发自动执行,而是走普通流程。适用于把外部文本源(如其它工具抓取的文本)接入翻译器的场景。
四、WebSocket 服务:实时文本流输出
WebSocket 部分提供两个端点,用于把游戏文本持续实时推送给客户端,配合内置的 WebSocket 文本输出器使用:
| 端点 | 用途 |
|---|---|
/api/ws/text/origin | 持续输出抽取到的全部原文文本 |
/api/ws/text/trans | 持续输出全部翻译结果 |
它们由 textio/textoutput/websocket.py 驱动:Outputer.dispatch(text, isorigin)在收到文本时,根据isorigin区分原文/译文,遍历wsoutputsave列表中的连接,调用对应WSHandler.send_text(text)推送:
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, __)也就是说:任何连接到/api/ws/text/origin的客户端,都会持续收到一条条原文文本帧;连接到/api/ws/text/trans的客户端则收到翻译结果帧。该输出器可以在设置中作为"文本输出"方式启用(对应配置项textoutputer.websocket,见 config.json)。
4.1 内置 WebSocket 服务端实现
服务端握手与帧协议均在WSHandler(tcpservice.py)中自实现:
- 握手:校验
Upgrade: websocket头与Sec-WebSocket-Key,按 RFC 6455 用Sec-WebSocket-Key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"做 SHA-1 + Base64 得到Sec-WebSocket-Accept,返回 101 状态码; - 帧解析:支持 FIN/opcode 解析、掩码异或解码、扩展长度(126→2 字节、127→8 字节)、文本帧(opcode 0x1)、Ping(0x9)/Pong(0xA)、关闭帧(0x8);
- 发送:
send_text以文本帧发送 UTF-8 负载(服务端发送无需掩码)。
同一套 WSHandler 还支撑了 GUI 内部的实时同步通道(/__internalservice/mainuiws、/__internalservice/transhistws,用于主界面与翻译历史页面的 JS ↔ Python 双向通信),页面/page/mainui、/page/transhist的内容推送正是经由mainuiwsoutputsave、transhistwsoutputsave列表完成(见 servicecollection_1.py)。
五、配置与使用:开启服务、设置端口与常见场景
服务开关与端口在 GUI 的"文本输入"设置页中配置(gui/setting/textinput.py):
- 开启开关:对应配置
networktcpenable(默认False),开启/关闭都会触发serviceinit()立即重启服务; - 端口号:对应
networktcpport,取值范围 0~65535,默认 2333,修改后同样即时生效;端口冲突时界面提示"端口冲突"; - 打开按钮:直接调用系统默认浏览器打开
http://127.0.0.1:{port},即跳到导航页/。
5.1 快速上手示例
- 在设置页打开"网络服务"开关,保持默认端口 2333;
- 浏览器访问
http://127.0.0.1:2333/进入导航页,或在设置页点击"打开"按钮; - 打开
/page/mainui即可看到与主窗口同步的文本;点击单词可在/page/dictionary查词; - 直接用命令行或脚本调用 API:
# 翻译(未指定引擎) curl "http://127.0.0.1:2333/api/translate?text=こんにちは" # 指定翻译器 ID 翻译(先用 /api/list/translator 获取 id) curl "http://127.0.0.1:2333/api/translate?text=こんにちは&id=<翻译器ID>" # 查询全部词典(SSE 流) curl "http://127.0.0.1:2333/api/dictionary?word=猫" # 指定词典查询 curl "http://127.0.0.1:2333/api/dictionary?word=猫&id=<词典ID>" # MeCab 分词 curl "http://127.0.0.1:2333/api/mecab?text=すもももももものうち" # TTS 合成(保存音频) curl -o out.mp3 "http://127.0.0.1:2333/api/tts?text=こんにちは" # OCR:POST 提交 base64 图片 curl -X POST "http://127.0.0.1:2333/api/ocr" \ -H "Content-Type: application/json" \ -d '{"image": "<base64图片数据>"}'5.2 实时文本流(WebSocket)示例
// 接收翻译结果流 const ws = new WebSocket("ws://127.0.0.1:2333/api/ws/text/trans"); ws.onmessage = (e) => console.log("译文:", e.data); // 接收原文流 const ws2 = new WebSocket("ws://127.0.0.1:2333/api/ws/text/origin"); ws2.onmessage = (e) => console.log("原文:", e.data);5.3 场景与限制说明
- 本地自动化:可作为本地翻译/词典/OCR/TTS 的 RPC 后端,供浏览器插件、脚本或其它程序调用,且所有响应带
Access-Control-Allow-Origin: *,浏览器跨域调用无障碍; - 安全边界:服务绑定
0.0.0.0且默认无鉴权,在局域网中任何可访问该端口的主机都能调用 API。如果只是本机使用,建议不要对外暴露端口,或通过系统防火墙限制访问; - 可用性依赖:
/api/translate、/api/dictionary、/api/tts、/api/ocr均依赖当前已启用且配置正确的对应引擎,实际可用的引擎 ID 以两个 list 接口返回为准; - 关闭指定路由:可通过配置项
network_service_disabled_paths禁用任意路径(命中即返回 404),默认值为空列表。
六、小结
LunaTranslator 的内置网络服务是一套"麻雀虽小、五脏俱全"的自研轻量后端:8 个 Web 页面路由让你在浏览器中复用主界面、翻译历史、词典、翻译/OCR/TTS 演示能力;8 个 HTTP API 覆盖翻译、词典(含 SSE 流式多词典查询)、MeCab 分词、TTS 音频、OCR 识别、引擎清单与文本注入;2 个 WebSocket 端点则提供原文/译文实时流输出,配合文本输出器可支撑外部实时消费场景。结合 servicecollection.py、tcpservice.py 与 htmlcode/service 目录下的页面源码,你既可以按本文的接口协议直接集成,也可以参照其 Handler 写法理解路由注册、SSE 流式响应与 WebSocket 帧协议等实现细节。
【免费下载链接】LunaTranslator视觉小说翻译器 / Visual Novel Translator项目地址: https://gitcode.com/GitHub_Trending/lu/LunaTranslator
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考