收起左侧

LibreTranslate翻译(CUDA加速版/纯CPU版)+沉浸式翻译+Lucky反代 本地翻译部署笔记

0
回复
498
查看
[ 复制链接 ]

7

主题

13

回帖

0

牛值

江湖小虾

一、核心实现原理 & 整体架构

1.1 整体调用链路

沉浸式翻译插件(浏览器) → Lucky反代(HTTPS+密码+路径分流) → 中转服务(格式适配/秘钥转发/语言清洗) → LibreTranslate(CUDA GPU翻译核心) → 原路返回翻译结果

1.2 各组件核心作用

  1. LibreTranslate:latest-cuda:核心翻译服务,启用NVIDIA GPU硬件加速,加载指定语言模型,提供原生翻译API,开启密钥认证防无授权调用,性能拉满;
  2. Python中转服务(translate_proxy.py):本次部署的「核心适配层」,解决沉浸式翻译插件和LibreTranslate的格式不兼容+传参问题,核心能力:
    • 解析沉浸式插件的text_list数组请求格式,转为LibreTranslate支持的q文本格式;
    • 自动清洗插件的zh-CN/en-US带后缀语言码,转为zh/en纯语言码,避免400报错;
    • 自动读取URL中的?token=秘钥参数,转发给LibreTranslate做认证;
    • 文本自动截断至5000字符,适配Libre的字符限制,避免超限400报错;
    • 全网跨域放行,解决浏览器插件跨域调用限制;
  3. Lucky反代:本次部署的「关键优化层」,核心价值是同域名+同端口+不同路径,指向不同后端服务,同时提供:
    • HTTP转HTTPS加密访问,避免浏览器不安全提示;
    • 可以自行给Web管理界面设置访问密码,彻底杜绝他人滥用;
    • 路径分流:一个域名端口搞定「Web管理+翻译API」两个服务,无需记多个地址;
  4. 沉浸式翻译插件:浏览器端翻译载体,支持网页划词/整页翻译,缺点是原生不支持自定义传参,需要中转服务适配。

二、以下示例中,服务/端口/地址对照表

服务功能 端口号 访问/转发地址 用途说明
LibreTranslate主服务 50116 http://172.17.0.1:50116 核心翻译服务+Web管理界面,加载语言模型、密钥管理
Python中转服务 50106 http://172.17.0.1:50106 仅对接反代,做插件格式适配/密钥转发/语言码清洗,不直接访问
Lucky反代对外访问 5151 https://fanyi.xxxx.com:5151 对外唯一访问地址,同域名同端口,不同路径分流2个后端服务

三、部署文件结构

libretranslate/
**── docker-compose.yml  # 双服务核心配置文件,完整复制
**── translate_proxy.py  # 中转适配脚本,完整复制
# 以下文件夹启动后自动生成,无需手动创建
**── db/       # 存放API密钥数据库,持久化保存密钥
**── data/     # 存放翻译语言模型,重启不重复下载

四、完整核心配置文件

4.1 docker-compose.yml GPU加速完整版

services:
  libretranslate:
    image: libretranslate/libretranslate:latest-cuda
    container_name: libretranslate-cuda  
    runtime: nvidia # 启用NVIDIA GPU运行时
    environment:
      - LT_CORS_ALLOWED_ORIGINS=*
      - NVIDIA_VISIBLE_DEVICES=all 
      - LT_LOAD_ONLY=en,zh # 只加载英中模型,显存占用极低,启动超快
      - LT_API_KEYS_DB_PATH=/app/db/api_keys.db
      - LT_API_KEYS=False # 是否开启TOKEN令牌校验,当前关闭
      - LT_REQ_LIMIT=500  # 单IP请求限流:500次/分钟
      - LT_UPDATE_MODELS=True # 是否自动更新语言模型
      - LT_MAX_TEXT_LENGTH=5000 # 翻译文本最大长度限制
      - LT_DISABLE_FILTERS=True # 是否关闭文本过滤机制:开启(true),纯数字/短文本/特殊符号也能正常返回,不返回空值
      - LT_GPU_MEMORY_LIMIT=1024 # GPU显存限制1G,英中双模型足够用,防溢出
      - LT_WORKERS=1 # 单进程运行,GPU无冲突,极致稳定
      - LT_DEBUG=False # 关闭调试模式,减少日志冗余
    # 数据卷挂载:持久化模型/数据库文件,重启容器不丢失模型,无需重新下载
    volumes:
      - ./db:/app/db:rw
      - ./data:/root/.local:rw
    ports:
      - "50116:5000"
    restart: always
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities: [gpu]

  # ========== 中转服务:沉浸式翻译插件适配代理 ==========
  lt-proxy:
    image: python:3.11-slim  # Python运行环境镜像
    container_name: libretranslate-proxy
    working_dir: /app
    environment:
      - PYTHONUNBUFFERED=1     # 开启Python日志实时输出,方便排查问题
    volumes:
      - ./translate_proxy.py:/app/translate_proxy.py:rw
    ports:
      - "50106:5000"
    restart: always
    # 依赖关系:先启动LibreTranslate,再启动中转服务,防止连接失败
    depends_on:
      - libretranslate
    command: >
      bash -c "pip install --no-cache-dir -i https://pypi.tuna.tsinghua.edu.cn/simple flask requests flask-cors && python translate_proxy.py"

4.2 translate_proxy.py

新建一个文本文件(注意使用Unix格式的UTF-8编码),粘贴以下代码,修改文件名和扩展名即可

# -*- coding: utf-8 -*-
import requests
from flask import Flask, request, jsonify
from flask_cors import CORS

# ===================== 全局核心配置=====================
LIBRE_URL = "http://172.17.0.1:50116/translate" # 172.17.0.1 为飞牛docker内部网络IP可以不改,端口需要改为 libretranslate 容器的对外映射端口
PROXY_PORT = 5000
MAX_TEXT_LENGTH = 5000                          # 文本长度上限
TOKEN_CHECK = False                             # True=强制验token  False=忽略所有token检查

app = Flask(__name__)
CORS(app, resources=r'/*')  # 全网跨域放行,浏览器插件必开

# 语言码清洗适配【仅英中专用】,精简高效
def clean_lang_code(lang):
    if not lang:
        return "auto"
    lang = lang.strip().lower()
    if lang in ["zh-cn", "zh-tw", "zh"]:
        return "zh"
    elif lang == "en":
        return "en"
    else:
        return "auto"

# 核心翻译接口
@app.route('/translate', methods=['POST'])
def translate_proxy():
    # 从请求参数中获取前端传入的token
    client_api_key = request.args.get("token", "")
    api_key_param = ""

    # ===== TOKEN核心校验逻辑 =====
    if TOKEN_CHECK:
        if not client_api_key:  # 空token直接拦截拒绝,返回401未授权+提示语
            return jsonify({"translations": [{"text": "请配置正确的API Token"}],"detected_source_lang": "auto"}), 401
        api_key_param = client_api_key  # 有token则赋值,传给后端做二次校验
    else:
        api_key_param = ""  # 关闭校验时,不传token给后端

    # 获取插件请求数据
    req_data = request.get_json()
    if not req_data:
        return jsonify({"translations": [{"text": ""}], "detected_source_lang": "auto"}), 200

    # 解析参数+清洗语言码
    text_list = req_data.get("text_list", [])
    source_lang = clean_lang_code(req_data.get("source_lang", "auto"))
    target_lang = clean_lang_code(req_data.get("target_lang", "zh"))
    detected_source_lang = source_lang
    translations = []

    # 批量循环处理所有文本,解决部分内容不翻译问题
    for single_text in text_list:
        if not isinstance(single_text, str):
            translations.append({"text": ""})
            continue
        final_text = single_text.strip()[:MAX_TEXT_LENGTH]
        if not final_text:
            translations.append({"text": single_text})
            continue

        # 构造请求体
        libre_req_data = {
            "q": final_text,
            "source": source_lang,
            "target": target_lang,
            "format": "text",
            "api_key": api_key_param  # 传给Libre做后端二次校验的核心参数
        }

        # 请求翻译+异常处理
        try:
            headers = {"Content-Type": "application/json; charset=utf-8"}
            libre_response = requests.post(LIBRE_URL,json=libre_req_data,headers=headers,timeout=20,verify=False)
            libre_response.raise_for_status()
            libre_result = libre_response.json()
            trans_text = libre_result.get("translatedText", single_text)
            if detected_source_lang == "auto" and "detectedLanguage" in libre_result:
                detected_source_lang = libre_result["detectedLanguage"]["language"]
            translations.append({"text": trans_text})
        except Exception as e:
            # TOKEN校验开启时,异常返回【Token无效】提示+401;关闭时返回原文+200
            if TOKEN_CHECK:
                return jsonify({"translations": [{"text": "Token Error"}], "detected_source_lang": source_lang}), 401
            else:
                translations.append({"text": single_text})

    # 返回插件标准格式
    return jsonify({
        "translations": translations,
        "detected_source_lang": detected_source_lang
    })

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=PROXY_PORT, debug=False)

首次启动libretranslate需要下载翻译模型,请耐心等待


五、Lucky反代配置(以应用中心里面的Lucky为例)

✅ 核心实现:一个域名+一个端口https://fanyi.xxxx.com:5151,通过不同路径,转发到2个不同的后端服务,这是最核心的配置,缺一不可
✅ 飞牛NAS Docker内网IP固定为 172.17.0.1,所有反代目标地址均填这个,如果不对,可以直接使用飞牛宿主机的局域网地址

规则1:【 翻译WebUI 】 → 指向 LibreTranslate主服务 (http://172.17.0.1:50116)

  1. Lucky → Web服务 → Web服务规则 → 监听端口 5151,启用TLS → 新建子规则(如果你已经配置过Lucky实现https访问,请忽略这条,从你原来的规则创建子规则即可)
  2. 前端地址:fanyi.xxxx.com、后端地址:http://172.17.0.1:50116
  3. ✅ 可选:开启【基本认证】,设置账号+密码
  4. 此时,浏览器通过 https://fanyi.xxxx.com:5151 这个地址,就能打开翻译的Web-UI

01.png

规则2: 【 翻译API中转 】 → 指向 中转服务 (http://172.17.0.1:50106)

  1. 同样新建一条子规则
  2. 前端地址:fanyi.xxxx.com/pyapi、后端地址:http://172.17.0.1:50106,其中/pyapi 这个路径可以自定义用其他的,沉浸式翻译插件跟着修改即可
  3. ✅ 必须:关闭【基本认证】→ 插件调用不能设置密码,直接放行
  4. 此时,沉浸式翻译插件的API URL https://fanyi.xxxx.com:5151/pyapi/translate?token=你的API密钥 这个地址,就能调用API翻译
  5. 上述配置文件中,默认是关闭 API Key ,也就是不进行token校验,使用https://fanyi.xxxx.com:5151/pyapi/translate也可调用API翻译

02.png

最终效果示例

03.jpg

💡 Tip

如果没有设置反代,沉浸式翻译插件直接填写 http://fanyi.xxxx.com:5151/translate?token=你的API密钥 即可,也就是直接指向中转容器的端口。


六、沉浸式翻译插件配置

前置必做步骤(不然找不到自定义服务)

插件图标 → 设置 → 左侧下滑找到【开发者设置】→ 开启【启用 Beta 测试特性】→ 保存并刷新插件页面

04.png

插件配置步骤

  1. 左侧 翻译服务 → 点击【添加自定义翻译服务】→ 选择【自定义API】

    05.png

  2. 名称随意(例如:本地Libre翻译)

  3. ✅API URL 填写格式:

    https://fanyi.xxxx.com:5151/pyapi/translate?token=你的API密钥
    或者
    https://fanyi.xxxx.com:5151/pyapi/translate     #无需密钥校验
    
  4. 插件的其余所有配置项保持默认即可,如果显卡性能优异,可以试着调高每秒最大请求数

    06.png

  5. 保存后,选中该自定义服务为默认翻译服务,完成配置

✅ 为什么是pyapi/translate?

反代规则2的前端地址加了/pyapi,中转服务的翻译接口本身是/translate,路径叠加后就是/pyapi/translate,少一个直接报404 Not Found,这是部署最大的坑,记住即可。


七、如果想使用API Key

把 Compose 里的 LT_API_KEYS 和 Python 文件里的TOKEN_CHECK 都设置为 True,重构Docker即可

需求场景 Compose(LT_API_KEYS) Python(TOKEN_CHECK) 效果
强制验token(防滥用) True True 仅正确token可访问
免验token(自用便捷) False False 空/错/正确token均可访问
关于LibreTranslate+Python中转 双开关组合解释
Compose
Python 访问效果 是否合理 核心逻辑
True True 空/错token拒绝,正确token通过 ✅ 合理 Python前置拦截+后端半校验,双重保障
True False 空/错/正确token均通过 ⚠️ 现象正常(非预期) Python无拦截,后端宽松接口对空/错token直接放行
False True 空/错token拒绝,正确token通过 ⚠️ 现象正常(非预期) Python前置绝对拦截,无视后端校验状态
False False 空/错/正确token均通过 ✅ 合理 Python无拦截+后端无校验,全程放行

八、创建LibreTranslate的API密钥

  1. 在飞牛的 Docker 管理器中,找到 libretranslate-cuda 容器,运行其终端,连接 /bin/bash

    07.png

    08.png

  2. 添加新密钥

    ltmanage keys add 3000 --char-limit 5000
    # 以上表示创建一个新的以每分钟3000个请求,最多单次请求5000个字符的新秘钥,也就是每分钟能翻译3000*5000字(如果你显卡够牛的话)
    
  3. 删除密钥
    ltmanage keys remove <api-key>
    
  4. 查看密钥
    ltmanage keys
    
  5. 自己用,只保留1个密钥,删除其他密钥即可


九、纯CPU 的Compose方案

如果你没有 Nvidia 显卡,compose可以使用这个纯CPU方案,translate_proxy.py 内容不变,其他设置也均一样

services:
  libretranslate:
    image: libretranslate/libretranslate:latest  # CPU核心修改:移除-cuda,纯CPU官方镜像
    container_name: libretranslate-cuda  
    environment:
      - LT_CORS_ALLOWED_ORIGINS=*
      - LT_LOAD_ONLY=en,zh # 只加载英中模型,显存/内存占用极低,启动超快
      - LT_API_KEYS_DB_PATH=/app/db/api_keys.db
      - LT_API_KEYS=False # 是否开启TOKEN令牌校验
      - LT_REQ_LIMIT=200  # 单IP请求限流:200次/分钟
      - LT_UPDATE_MODELS=True # 是否自动更新语言模型
      - LT_MAX_TEXT_LENGTH=5000 # 翻译文本最大长度限制
      - LT_DISABLE_FILTERS=True # 是否关闭文本过滤机制:开启(true),纯数字/短文本/特殊符号也能正常返回,不返回空值
      - LT_WORKERS=1 # 单进程运行,CPU无冲突,极致稳定
      - LT_DEBUG=False # 关闭调试模式,减少日志冗余
    # 数据卷挂载:持久化模型/数据库文件,重启容器不丢失模型,无需重新下载
    volumes:
      - ./db:/app/db:rw
      - ./data:/root/.local:rw
    ports:
      - "50116:5000"
    restart: always

  # ========== 中转服务:沉浸式翻译插件适配代理 ==========
  lt-proxy:
    image: python:3.11-slim  # Python运行环境镜像
    container_name: libretranslate-proxy
    working_dir: /app
    environment:
      - PYTHONUNBUFFERED=1     # 开启Python日志实时输出,方便排查问题
    volumes:
      - ./translate_proxy.py:/app/translate_proxy.py:rw
    ports:
      - "50106:5000"
    restart: always
    # 依赖关系:先启动LibreTranslate,再启动中转服务,防止连接失败
    depends_on:
      - libretranslate
    command: >
      bash -c "pip install --no-cache-dir -i https://pypi.tuna.tsinghua.edu.cn/simple flask requests flask-cors && python translate_proxy.py"
收藏
送赞
分享

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则