# 制片: @- @Ready@(_EasyNMT 兼容@MS K4}翻译处

## 一. 导言导言 导言 导言 导言

快速执行快速API 复制 EasyNMT @( @httpsç://}github.com}/Ukplaba}MS K4Easy NMTMSKO5}这是一个极好但废弃的神经机械 -{-翻译计划>.但是I've添加了如此多好的功能,以提高可靠性并准备在生产系统中使用。 “.}思考快速翻译自我托管的...〞

自从这个博客“,” 启动以来,我一直非常热切地欢迎那些不读英文文章的人@-}(翻译)部落格文章 <.#是我知道了 @'\google 在浏览器中做这' (SQMK5etc...}但<'>不是点@MSKO8}我想知道如何建立这种类型的系统*.{哦 它给了我一些想法:如何在ASP\.NET中使用它来自动本地化文本 □(}包括动态的文字 ) 使用 signalR _&_Zirlanglok}一个实时更新系统。[继续收听 @! @](https://github.com/scottgal/mostlylucid.activetranslatetag)).

哦,I' 已在此提供演示@; https @://_nmtdemo}.}(大多是普通的) .net{/demo/}它<'}只是用一台旧笔记本电脑运行,没有 GPU ,但给了你这个想法 <(> 让我测试复仇性\).}

人类写垃圾文字的本质是超吵, 让机器能高效地处理#.}所以很多事情都在想着如何解决与 EasyNMT &(有关的问题。 `mostlylucid-nmt` 设计成一个战斗测试的“(well” 翻译这里成千上万个单词 “!) 有用系统用于任何译文“MS K2 一种 BappelFish API}.

它还拥有我从30年的 建筑生产服务器“&”系统中学到的所有知识。 “.”系统“MSK1 从“MS K2”代码中摘取,让客户退缩到“,”代码,返回关于翻译的元数据以帮助客户@,额外的终点以获得更多的数据和COURESE [演示页 ](#interactive-demo-page) 让我和你们一起发展 来玩个游戏

一一 [写入整个系统](https://www.mostlylucid.net/blog/category/EasyNMT) 要做到这一点 与一个惊人的工程 一个叫 EasiNMT.}HoweverMS K1}如果你刚刚检查了 您知道有'的回调 你有一个问题吗? ...?

@.}但是随着时间流逝, 裂缝开始显示#.是更好的时候了。

[与往常一样,GitHub全套免费使用等](https://github.com/scottgal/mostlylucid-nmt)

[![Dock 拆船码头](https://img.shields.io/docker/pulls/scottgal/mostlylucid-nmt)](https://hub.docker.com/r/scottgal/mostlylucid-nmt)
[![cpu( cu)](https://img.shields.io/docker/v/scottgal/mostlylucid-nmt/cpu?label=cpu)](https://hub.docker.com/r/scottgal/mostlylucid-nmt)
[![{\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}我](https://img.shields.io/docker/v/scottgal/mostlylucid-nmt/cpu-min?label=cpu-min)](https://hub.docker.com/r/scottgal/mostlylucid-nmt)
[![gpu](https://img.shields.io/docker/v/scottgal/mostlylucid-nmt/gpu?label=gpu)](https://hub.docker.com/r/scottgal/mostlylucid-nmt)
[![{\fn方正黑体简体\fs18\b1\bord1\shad1\3cH2F2F3F](https://img.shields.io/docker/v/scottgal/mostlylucid-nmt/gpu-min?label=gpu-min)](https://hub.docker.com/r/scottgal/mostlylucid-nmt)

## Demo...}请看稍后的演示文稿: !

[交互式演示页面](#interactive-demo-page) (at `http://<server>:<port>/demo` 或仅仅是根@) @%

<p>
<img src="/articleimages/translatedemof.png?format=webp&height=450" alt="Demo">
</p>
[TOC]

<!--category-- mostlylucid-nmt, EasyNMT,  Neural Machine Translation, Python, FastAPI, Docker, CUDA, PyTorch, Transformers, Helsinki-NLP,  API-->
<datetime class="hidden">2025-11-08T12:30</datetime>

## 什么' New?

在我们跳入快速启动前 @,这里 @ '}这是什么使得这个版本的游戏@-# changing_ :}

### 最新主要消息 @(@v3.1)}{-}情报: &}可见度

**新建于 v3.1:** 最新版本带来了对可靠性的大规模改进: ,性能可见度@,和智能模型选择_!

**1. 智能模型与可见性缓存** {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}看看到底发生了什么

- ✓ **Cache HIT 记录**: `Reusing loaded model for en->de (3/10 models in cache)`
- ✗ **缓存 MISS 记录**: `Need to load model for en->fr (3/10 models in cache)`
- **缓存状态跟踪**: 显示利用率百分率和已装入的模型
- **驱逐警告**当缓存满且模型被拆迁时, :清晰警示@ action
- **提高能力**@ : 默认缓存大小, 从 @ MPK3 折叠到 mostK1 模型@ MS K2
- **Per-模擬裝置紀錄**: 查看每个模型都使用哪个 GPU/CPU

**2. 增强下载进度** {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}不奇怪它是不是卡住了?

- **下载前的大小**@:_ 显示全部下载大小@(_ e_ .g.,}{"TOTL size:2.46GBQ")
- **文件计数**: 显示要下载的文件数量
- **设备显示**: 顯示目標裝置 @ MS K1GPU}/CPU)
- **进度栏**@:# 美丽的 tqdm 进度, 每个文件在 TTY@ ) @
- **完成横幅**@:# 当模型准备好时清晰的成功信息@ option
- **实例产出**:
  ```
  ====================================================================================================
    🚀 DOWNLOADING MODEL
    Model: facebook/mbart-large-50-many-to-many-mmt
    Family: mbart50
    Direction: en → bn
    Device: GPU (cuda:0)
    Total Size: 2.46 GB
    Files: 6 main files
  ====================================================================================================
  [Progress bars for each file...]
  ====================================================================================================
    ✅ MODEL READY
    Model: facebook/mbart-large-50-many-to-many-mmt
    Translation: en → bn is now available
  ====================================================================================================
  ```

**3. Data-Driven智能枢纽选择** @-# 不再有盲目的企图@: @

- **智能交叉逻辑**“:” 查找存在双轴腿的语言
- **避免失败尝试**: Won' t tryen NSK2es→bn 如果是→Bn 不存在的话
- **en→bn 示例**:
  ```
  [Pivot] Languages reachable from en: 85 languages
  [Pivot] Languages that can reach bn: 42 languages
  [Pivot] Found 38 possible pivot languages
  [Pivot] Selected pivot: en → hi → bn (both legs verified)
  ```
- **后退优先级**法语:→ 德语: → 中文: @→ 俄语
- **透明伐木**{\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}看看为什么每个支流都被选中或者跳过

**固定自动后退** {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}不再有双倍的

- **总是尝试后退**#即使爱人家庭"#是否应该#"}支持这对夫妻
- **每个家庭单次未遂**: 不再两次重试同一种模式
- **实例流动**:
  ```
  Request: en→bn with opus-mt
  Trying families: ['opus-mt', 'mbart50', 'm2m100']  ✓ All three!
  opus-mt: Failed (model doesn't exist)
  mbart50: Success! (auto-fallback worked)
  ```

**5.+GPU 清晰度** 总是知道你的模特儿在哪里

- 每个模式的负载显示@: @% `Loading mbart50 model on GPU (cuda:0)`
- 装载确认后@: @% `Model loaded on device: cuda:0`
- 成功的消息包括 @: `Successfully loaded... on GPU (cuda:0)`

**6.-Pivot 建材模型** “- 高效的支流再利用”“:”

- 双脚都分开缓冲 : `en->hi`, `hi->bn`
- 下次en →hi 或 hi→bn 需要\ MS K2 即时缓存按下@!
- 清除日志@: @ {} `[Pivot] Both legs loaded and cached. Ready to translate.`

**@7.Per-请求示范选择** “-”已经在演示中工作

- Dmo 下调允许选择 Opus@ - @ mt, @ mbart @ MS K2} 或 mQ2 @m @ MPK4}
- 后端属性 `model_family` 每个请求的参数
- 用于即时切换的由家族单独缓存模型

### 主要更新@( @v3.0)}

**@1. 强化演示页面** @-_producting@-}即时互动界面#:

- 用于隐性翻译经验的全视图版式 @ (100vw/100vh})
- 正确选择的下调@  @ no more clunchy inpport *% 1\ datalist @ MS K2*
- 现场家庭模式切换 @(Opus-MTMS K2mBART}50,M2M100)
- 基于选定模式的动态语言加载
- 大翻译的可滚动输出区域

**2. 性能@-}优化默认值** @- @ @ "# 尽快 @ @% 2_ 从盒子里出来@:#

- **GPU 图形**:FP16 启用了,BATCH}_SIZE=64,MAXMSKO5INFLIGNSK6(Apptimal 用于单一 GPUMS K8
- **CPU CPCPU**-=YTET -伊甸园字幕组=- 翻译:
- **快速关闭**第二次优雅的超时
- 集装箱在没有可怕的SIGKILL信息的情况下干净停车

**3.生产建设优化** 快速图像@: @

- 从生产结构中移除的测试依赖性 @ (@ pytest @ , @ pytesterk @ -cov})}
- 每个图像保存 #% ~200\MB
- CPU 图像@: @ @ ~8-10_ GB @ I( @ full_ ),} @ MPK4+GB @(MINQ)
- GPU 图像@: @ @ ~12-15_ GB @ I( @ full_ MS K3} @ MPK4+GB @ (MINQMK6#
- 全部使用 `requirements-prod.txt` 最低足足足

**4. 全面测试& 加载测试** -=YTET -伊甸园字幕组=- 翻译:

- **API实时测试套件** “(30+”测试“)”健康考核“MS K2”翻译“MSC3”检测“,”发现
- **k6 负载测试** 具有现实交通模式
- **cross - 平台验证脚本** @(_Powershell#+_Bash_)#
- 模型下载和主轴翻转后补测试
- 用于快速验证的自动烟雾测试

**5.部署文件** -=YTET -伊甸园字幕组=- 翻译:

- 4调制假想: Max TextputMS K2 低时空}, 高时速 , 内存□-受限制
- 使用 GPU @ / CPU 配置的 docker 拼写示例
- Kubernetes 使用PVC=,}资源限值表单数@,健康检查
- 零散集装箱实例
- 负载测试指导和监测建议
- 共同货币对吞吐交易解释

**三个模范家庭** @-# 选择适合你需要的最佳方法@: @

- **Opus - @MT**最佳质量的( 独立模型
- **百万亿巴塔**单一的2.4GB 型号 @,@2,450配对
- **MMMSKOM 100**单一的2.2GB 型号 @,@9,900配对

**7.Auto-Fallback** @ -_ 智能选择最佳的模型@:}

- 为质量设定主家族 @ (@ e @ I.} gQ} MS K2} Opus-}%MT 用于品质@ )} *
- 如果对配无可用, 自动尝试 mBART @ MSQK0 @% MM 2 @ M100}
- 在不牺牲质量的情况下实现最大覆盖率

**8. 模型发现** @- 动态查询可用模型@:

- `/discover/opus-mt` 抱住脸的双胞胎
- `/discover/mbart50` -=YTET -伊甸园字幕组
- `/discover/m2m100` -=YTET -伊甸园字幕组=- 翻译:

**9. 最小图像** “- 小型 , 灵活部署”“: ”

- 没有预加载模型@ ( download on @ MS K1}( 点名) @ MPK2
- 立方公尺的持久性缓存
- 不重建的交换式家庭模式

**10. 单嵌入仓库** “- ”所有变量都放在一个地方“: ”

- `scottgal/mostlylucid-nmt:cpu` (或 `:latest`-=YTET -伊甸园字幕组=- 翻译:
- `scottgal/mostlylucid-nmt:cpu-min` - CPU 最小
- `scottgal/mostlylucid-nmt:gpu` -=YTET -伊甸园字幕组=- 翻译:
- `scottgal/mostlylucid-nmt:gpu-min` - GPU 最小

**11. 正确版本** @ - 所有图像都包含日期时间版本@:

- 命名标签 @ ( @ {}`latest`, `min`, `gpu`, `gpu-min`)總是指向最近的建築
- 无法变换的版本标签 @ ( @ e @ MPK1}\g., `20250108.143022`) 用于插针特定建筑
- 用于跟踪版本的完整 OCI 标签@,构建日期 @,和 git 承诺

**@12. 最新基础图像** 安全和性能改进

- **Python 3.12-slim** 对于 CPU 图像来说, @(}地址是 Python {3.11}\ 脆弱性=)
- **CUDA 12.6** GPU 图像的 Ubuntu {24.04} 和 NVIDIA stack_ )+NBUNT
- **与CUDA的火炬** -=YTET -伊甸园字幕组=- 翻译:
- 所有附属关系均更新为最新安全版本

***13.固定折旧警告** 未来- 校对:

- 使用高频 _HOME)
- 与变换器兼容v5

---


## 快速启动 @ (5 @ minutes@ MS K1 @

想要翻譯@?_这里 @'}這是最簡單的運作方式

### 可用的嵌入夹图像

所有变量都可以从 **1个存储库** 带有不同标签@: @%

|标记 @|完整图像名称@|大小 @MS K3描述 @|使用案例_|
|-----|-----------------|------|-------------|----------|
| `cpu` (或 `latest`) | `scottgal/mostlylucid-nmt:cpu` -=YTET -伊甸园字幕组=- 翻译:
| `cpu-min` | `scottgal/mostlylucid-nmt:cpu-min` |{~1.5}GB| CPU 最小,没有预加载的模型
| `gpu` | `scottgal/mostlylucid-nmt:gpu` -=YTET -伊甸园字幕组=- 翻译:
| `gpu-min` | `scottgal/mostlylucid-nmt:gpu-min` |{~4}GB|GPU 最小=,没有预加载的型号

**最小图像** 推荐给@: @%

- 生产部署量为=-}(缩放缓存)
- 使用 mBART50或 MQ2MMS K2 (sing 大型型号@)
- 使集装箱尺寸保持小
- 在不重建的情况下转换模范家庭的灵活性

### 简单开始@( @Opus @-}%MT CPU_)

**"M1." 拉并运行:**

```bash
docker run -d \
  --name mostlylucid-nmt \
  -p 8000:8000 \
  scottgal/mostlylucid-nmt
```

**翻譯一些文字 *:***

```bash
curl -X POST "http://localhost:8000/translate" \
  -H "Content-Type: application/json" \
  -d '{
    "text": ["Hello, how are you?"],
    "target_lang": "de"
  }'
```

**回应::**

```json
{
  "translated": ["Hallo, wie geht es Ihnen?"],
  "target_lang": "de",
  "source_lang": "en",
  "translation_time": 0.34
}
```

### GPU 加速的 @ (10 @ x ahead\ )}

需要 NVIDIA docker 运行时间@ : @

```bash
docker run -d \
  --name mostlylucid-nmt \
  --gpus all \
  -p 8000:8000 \
  -e EASYNMT_MODEL_ARGS='{"torch_dtype":"fp16"}' \
  scottgal/mostlylucid-nmt:gpu
```

### 使用持久性模式缓存

下载模型一次并保存在集装箱间重新启动@:

**Linux / Mac:**

```bash
docker run -d \
  --name mostlylucid-nmt \
  -p 8000:8000 \
  -v $HOME/model-cache:/models \
  -e MODEL_CACHE_DIR=/models \
  scottgal/mostlylucid-nmt:cpu-min
```

**視窗@( @ powershell_):**

```powershell
docker run -d `
  --name mostlylucid-nmt `
  -p 8000:8000 `
  -v ${HOME}/model-cache:/models `
  -e MODEL_CACHE_DIR=/models `
  scottgal/mostlylucid-nmt:cpu-min
```

**视窗 @ (CMD):**

```cmd
docker run -d ^
  --name mostlylucid-nmt ^
  -p 8000:8000 ^
  -v %USERPROFILE%/model-cache:/models ^
  -e MODEL_CACHE_DIR=/models ^
  scottgal/mostlylucid-nmt:cpu-min
```

模型在首次使用时自动下载并持续到您的本地目录@! @%

**健康检查+:**

```bash
curl http://localhost:8000/healthz
```

快速启动! 用于生产部署@,配置 @,和高级功能 @MS K5}继续阅读#.

## 互动演示页面

此服务包括全@ -_ 功能化的服务 **交互式演示页** 使无需写入任何编码即可测试翻译成为易事

```
http://localhost:8000/demo/
```

<p>
<img src="/articleimages/translatedemof.png?format=webp&height=800" alt="Demo">
</p>
### 感化特征

演示页提供完整的翻译测试环境,使用 @: @%

**1. 语言选择**

- 从现场服务下载自动- 流行语言
- Swap source\ /}目标语言,请单击
- 支持在服务中配置的所有100+}语言

**2. 智能文字跳动**

- 自动处理任意大小的大文本输入
- 保存文档结构
- 倒回到分开的句子上很长一段
- 显示多@ - chunk 翻译的进度 @ MS K1 translating broad 块 @ MPK2}
- 以适当的间距无缝重新组装块块

**3. 语言检测**

- 单击一点击检测源语言
- 自动弹出源语言下调
- 工作文本最多为 5000}字符

**4. 高级选项**

- **光束大小**: 控制翻译质量
  - 高值 *=}质量更好,但慢
  - 低值@ = 快速输送
- **句号拆分**: 切换自动句子分割
  - 启用了“% (” 默认@ MS K1 @ 将长文本拆分为句子, 以便提高质量
  - 将整个文本转换为用于短文本的块@(_faster @)}

**-=YTET -伊甸园字幕组**

- **翻译时间**@ :_ 显示实际服务器@ MS K1}side 翻译持续时间
- **字符数**: 键入时的活数
- **状况指标**@ : @ Idle @ → @ translating @ MPK2 @ Done@ /_ Error

**6.模范家庭发现**

- 探索每个模型家族的可用翻译配对@: @%
  - **Opus - @MT**“: 1200+语配对”
  - **百万亿巴塔**@: @ @ 50 @ 语言 @ I,} @ MPK3配对
  - **MMMSKOM 100**@: @ @ 100 @ 语言 @ I,} @ MPK3配对
- 在翻译前,请确切查看哪些语文配对可用

### 文本拼图如何工作

演示工具在客户端执行智能文字块“:”

```javascript
// Example: Translating a 5000-word article
Input: Long article with multiple paragraphs

Step 1: Split by paragraphs (preserves structure)
  → Paragraph 1 (800 chars)
  → Paragraph 2 (1200 chars)
  → Paragraph 3 (600 chars)
  ...

Step 2: Group into ~1000 character chunks
  → Chunk 1: Paragraphs 1-2
  → Chunk 2: Paragraph 3-4
  → Chunk 3: Paragraphs 5-6

Step 3: Translate each chunk sequentially
  → Shows progress: "Translating chunk 1/3..."
  → Shows progress: "Translating chunk 2/3..."
  → Shows progress: "Translating chunk 3/3..."

Step 4: Reassemble with paragraph breaks
  → Final output: Complete translated article with preserved formatting
```

### 为何使用 Demo?

**快速测试**

- 没有写入代码的测试翻译
- 校验语文配对可用性
- 比较翻译质量与不同光束大小的对比
- 测试边缘情况 @(emoji,符号@,特殊字符_)

**发展援助**

- 详细参见 API 请求/}回应格式
- 在融合之前对服务健康进行检查
- 具有不同文本大小的测试性操作
- 发现可用的模式家庭

**客户参考**

- 显示适当的 API 使用模式
- 演示错误处理@ (429, @ 语言检测@ MPK1
- 集块实施实例
- 真实的-世界重试逻辑

### 实例使用率

1. **简单翻译**:
   
   - 粘贴文本@: @ @% "_ 你好 @ MS K2} 你今天怎么样
   - 选择目标@: @% 德语
   - 点击“"”
   - -=YTET -伊甸园字幕组=- 翻译:

2. **长文件翻译**:
   
   - 粘贴整个博客文章 @QZ(5000+ words@)
   - 演示自动将它挤成可操作的碎片
   - 每个块翻译时显示进度
   - 返回完全翻译的文件

3. **语言检测**:
   
   - 以未知语言粘贴文本
   - 点击“"”检测语言@"
   - 演示识别语言并更新下调
   - 准备立即翻译

### 技术细节

演示页是:

- **自 己-足**: 包含嵌入 JavaScript 的单个 HTML 文件
- **零依赖性**: 不需要外部图书馆
- **移动友好**: 所有装置的响应性设计工程
- **现成生产**: 可以在您的应用程序中使用相同的块状逻辑

访问现场演示 `/demo/` 正在运行的示例中@! @%

## A. 容易NMT问题

现在这是'倾弃 [A. 易便网](https://github.com/UKPLab/EasyNMT) 造就了这栋建筑 [a 使用该项目的项目数](https://www.mostlylucid.net/blog/category/EasyNMT){\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}什么问题?

@.#科技在“...+”上有所进步, 也从未打算成为生产品@-#Squality system_.}(这里有些问题是):{

1. **它撞车 ...aLOT.** 它不是用来从经常出现的问题中恢复过来的 只是掉在了.
2. **有关其投入的.** 偶数可以混淆它@. @%
3. **它不是为任何负载设计的 .\ {}** 见上面“. ”从未被设计为“MSC1 ”
4. **并非旨在更新其模型。** 或为“( @easily@ )_ built ” 所建的“ MS K2 @ in models @ .}
5. **它的GPU CUDA东西是古老的** 速度比需要的#.还慢
6. **您可修复任何东西@ . @ title** Python 代码在回邮上,但再一次 *不算大*.
7. **没有后压或队列@ . @%** 发送太多请求, 它只会在@. @
8. **无可观测性.** 当事情出错时 你就会失明地飞翔

## 解答M: 多数是Lucid}-NMT

@So...#I决定建造一个新的、更好的 EasyNMT @,_现在 **多数情况下, - @nmt**@ . @ this is' @ title a professional job@ ; @ itMS K3} 這是一個完整的重寫, 產品用於意念 @ MPK4 @ here @ I' @ 是什么讓它更好? @ OMK6 @

### MOU - 模式家庭支持

MostLucid -NMT 现在支持 **三个翻译模范家庭**使你根据你的需要灵活变通

#### Opus - @MT @( @Hellinki-}NLP=)}{-}默认

- **覆盖范围*:** “1200+”翻译对“150+”语言
- **架构@: @%** 每个翻译方向的单独模型
- **质量:** 最高总体翻译质量
- **使用 Case:** 生产翻译,质量问题
- **型号大小@: @%** 300-500MB 每个方向
- **实例::** 德文和德语不同

#### 脸书=)

- **覆盖范围*:** 50 语言 @,}全部-#to@-}所有翻译
- **架构@: @%** 单一多种语文模式
- **质量:** 质量良好 @, 特别是主要语言
- **使用 Case:** Space - 限制部署或多种语言配对
- **型号大小@: @%** @~2.4_GB @ (#single 适用于所有@50}语言=)的模范
- **优势 :** 一个模式手持 2,450}翻译对

#### MM2M100 (纸本MS K3

- **覆盖范围*:** 100 语言 @,}全部-#to@-}所有翻译
- **架构@: @%** 单一多种语文模式
- **质量:** 高质量,语言覆盖面最广
- **使用 Case:** 最大语言覆盖率
- **型号大小@: @%** @~2.2_GB @ (#single 适用于所有@100}语言=)的模范
- **优势 :** 一个模式手持 9,900}翻译对

**易交换** M- 刚刚设置 `MODEL_FAMILY` 环境变量:

```bash
# Opus-MT (default, best quality)
MODEL_FAMILY=opus-mt

# mBART50 (50 languages, single model)
MODEL_FAMILY=mbart50

# M2M100 (100 languages, broadest coverage)
MODEL_FAMILY=m2m100
```

### 自动家庭后退模式 @ - @ NewQ!@

最强大的新特征之一是 **模式家庭之间的自动后退**这确保了最大程度的语文对口覆盖,同时优先考虑翻译质量 .

**如何运作?**

1. 您设置了初级 `MODEL_FAMILY` (E.G., `opus-mt` 最佳质量#)
2. 当您申请初级家庭没有的翻译配对时
3. 系统自动在后退顺序中尝试下一个家庭
4. 直至找到合适的模型

**实例假想**

```bash
# Set primary to Opus-MT (best quality)
MODEL_FAMILY=opus-mt
AUTO_MODEL_FALLBACK=1
MODEL_FALLBACK_ORDER=opus-mt,mbart50,m2m100

# Request Ukrainian → French
# 1. Try Opus-MT first (not available)
# 2. Automatically fall back to mBART50 (available!)
# 3. Translation succeeds with mBART50
```

**福利*:**

- **最大覆盖范围@: @** 支持“100+”语言, 不管理多种部署
- **质量优先级 @:** 每对夫妇总是使用最佳可用模式
- **零配置@: @%** 自动工作@,不需要人工干预
- **透明日志@: @%** 每次翻译都使用哪种模式式家庭式,请查看

**設定@: @% 1**

```bash
# Enable auto-fallback (default: enabled)
AUTO_MODEL_FALLBACK=1

# Set fallback priority (default: opus-mt → mbart50 → m2m100)
MODEL_FALLBACK_ORDER="opus-mt,mbart50,m2m100"

# Disable for strict single-family mode
AUTO_MODEL_FALLBACK=0
```

这个功能对生产环境来说是完美的, 在那里您需要最大覆盖率而不牺牲质量@! @ @

### 关键改进

1. **模范家庭支助** @(50語言@),或MZ2MQ}或MQ100 (100 語言_).
2. **模型发现终点** @- 动态查询每个家庭 Hugging Face 的可用模型@.
3. **强大的输入处理** -Emoji?数MS K2 符号? 把它带上\□.}现在的服务包括综合输入消毒和符号遮罩_.
4. **请求排队和后压** “- 内建 - 以血压为主 mSPORE}- 与智能重试一起排队 ”- 在估计后“.
5. **LRU 模型缓存** - 自动管理 VRAM, 当缓存满时驱逐旧型号@.
6. **CUDA现代支助** -使用PyTorrch与 CUDA12.6,支持 FPMS K2BH16 用于 @2x速度改进@.
7. **现成的可观测性** @-_健康检查,}准备就绪的探针 *,}缓存状态*,}结构式记录机
8. **优利关闭** 不再有孤儿要求或腐烂的状态
9. **EasyNMT- 兼容的API** @- Drop- 取代现有集成@.
10. **枢轴翻转后补** - 如果直接语言配对是 @'t可提供}%,自动通过英语 _或您所选的轴轴轴
11. **最小 docker 图像** - 新建 `-min` 用于较小部署量的 mapped 缓存@ .

## 为何NMT超过翻译LMLm@?

您可能想知道 GPT=-4,}Claude*,}或Llama 等LLMs能翻译@?"}大问题吗?

### 速度@ : @ *\ MS K1# x 快

**NMT *(* 大部分是纯净的 mostlylucid *MS K1}nmt\ ): ***

- CPU: ~0.3-1.0 秒/ 每句
- GPU (FP16): @ ~0.05-0.2秒/ 每句
- 批量处理@: @\ 50+}句号 @/秒加GPU

**LL: 女士**

- GPT-4: @ 3-10 秒/ 请求@(API lantency @+ generation_ MS K4
- Llama @3 @ @ 70_B:}(每句3秒) @(@local@)#
- Claude “3:”“2-8”秒,每个请求@($API lantency @)

**真实的示例@: @** 翻译@1000-_word博客 post @:}

- **多数情况下,-Nmt @(}GPU%)**几秒后
- **GPT-4 API**几秒后
- **本地 Llama @ 70_B**@: @ 2-5 @ 分钟 @

当您将数以百计的博客文章转换为 12+ 语言@,}速度差异是 MASSIVE @.

### 模型大小@: @ @ @ 500 @%MB vs @140_GB

**NMT 模型**

- Opus - @MT @(#每个方向@):} @300-500MB
- @(}所有的 50语言 @MS K3 2.4GB
- M2M 100} @ MS K2QA}所有的100 语言 @ I): 2.2GB
- **“100+”语言合计**

**LL: 女士**

- Llama 3 MS K1B: MSSK3GB
- Llama 3 MS K1B: MSSK3GB
- 混血儿 @8_x}7#B:}{~90_GB
- GPT-4: 无法自定义@-主机

**储存效果*:**

```bash
# NMT: Fits on a USB stick
du -sh model-cache/
2.5G    model-cache/

# LLM: Needs serious storage
du -sh llama-models/
140G    llama-models/
```

### 资源需求*: 笔记本与服务器农场

**NMT CPU 部署**

- 在: 2 CPU核心}MS K2 NSK3GB RAM上运行罚款
- Docker 图像@: @ @\ 1.5-2.5_%GB
- 引用@ : @ CPU 只 ,} 不需要 GPU
- 每月VPS的开销

**LLM 要求**

- Llama @3 70B: 需要@80GB}+VRAM=(A{100GPUMS K7
- 微小的 @7 @B-13_B模型@:}仍然在{16-32}GB RAM最小值
- API$@: @ @ @ $0.03-0.30} 每张#1000_ 标语 @ I(_ 增加快速=!){
- 严肃的 GPU 月份

**校对:Soup**

时间:|
|--------|------|------|
@| @ mostlucid@-_nmt @ (CPU})#|#$20/_一个月的VPS @MS K6}{2-3_小时{\|>
@ | @ mostlucid@ MS K1 @ nmt @ I(GPU @ MPK3} @ MOSK4 @ @ MCK5_ 月 GPU VPS @ MASPK6 @ @ *15-30# minutes @| @
|+GPT+-4+API#I|+ @$150-300+#|+8-15+@|_小时
-=YTET -伊甸园字幕组=- 翻译:
@| @当地Llama @MS K1_B @|# $1000+/月硬件@|}{20-40#小时♫|#

### 质量@:目的 @-#Bruilt vs General=-目标

**NMT 强势+:**

- 专门翻译培训
- 一致质量 * @(}%same involution {\fn方正黑体简体\fs18\b1\bord1\shad1\3cH2F2F3F}@=}相同输出 *)*
- 没有纯翻译的 "+Hallucations
- 处理技术内容@,代码 @,}格式化良好
- 不需要即时工程

**LLM挑战 :**

- @⚠_ 有时添加非原文的诠释
- 质量随语法的迅速变化而不同
- “⚠”可以是“"” 技术术语
- 需要仔细的快速工程
- @⚠ 无法预见有边缘病例

**实例假想**

```text
Input: "The API returns a 429 status code when rate limited."

NMT (Opus-MT): "Die API gibt einen 429-Statuscode zurück, wenn sie ratenbegrenzt ist."
(Accurate, preserves technical terms)

LLM (might do): "Die API sendet den Fehlercode 429, wenn zu viele Anfragen gestellt werden."
(Interprets rather than translates, adds context not in original)
```

### 何时使用

**使用 NMT @ ( @ mostlylucid+-@nmt)}当 < MSC3 > 时使用NMT@ MSk4}**

- 您需要在比例尺上快速翻译一致@ , @% @ action
- 预算事项 @(_self_-}接待或大容量@)
- 您正在翻译技术内容@,}代码=,}结构化数据
- 您需要确定性输出@ ( @same 输入 @ MS K1} 相同输出 @ OMK2 *
- 您想要运行 CPU 或普通硬件
- 您正在建造自动翻译管道

**使用 LLM 时间@ : @%**

- 您需要创造性的适应@ , @ 而非字面翻译
- 环境和文化细微差别比速度重要得多
- 您正在做低端的 @ - @ avolution@ MS K2} 1\ -off 翻译
- 您需要将“ +” 摘要翻译为“ I+” 。
- 您对可变成本和慢处理程序都满意

### 底线

用于 **自动博客翻译** “(my use case”“),NMT是明显赢家‘:’吗?”

- 将“100+”博客文章翻译为“12”语言,
- 运行于 @ $50/_ month VPS
- 所有员额的一贯质量
- 全部设置@: 1个嵌入器容器

使用LLMS尝试这个方法,每月需要数百美元的API收费或需要一个 GPU 服务器来自行操作@- @Host.}仅速度差异就使得NMT成为生产翻译管道的唯一实际选择

**{\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}TL** NMT 目的@- @% 为翻译而建的NMT@MS K1}运行在微小硬件 @,上,如果您需要快速\,}understandQ,}成本=-}有效翻译以Scale_,#NM Twin hands down+.}则速度比LMZMZ.快

## 建筑结构概览

```mermaid
flowchart LR
    A[HTTP Client] --> B[API Gateway]
    B --> C[Translation Endpoint]
    C --> D{Has Capacity?}
    D -->|Yes| E[Translation Service]
    D -->|No| F[Queue with 429]
    F --> E
    E --> G[Process Pipeline]
    G --> H[Get Model from Cache]
    H --> I[Translate]
    I --> J[Return Response]
    J --> A
```

请求流直截了当 *:*

1. **客户客户** 向API网关发送翻译请求@( @Gunicorn @+_Uvicolor workers @MS K2}发送译文
2. **API 网关** 翻译路线
3. **能力检查**: 系统检查是否有能力处理请求
   - **是 是** 请求立即到翻译处
   - **否 无** → 请求排队@,客户端接收 HTTP @429與 `Retry-After` 头标题
4. **笔译翻译处** 通过编审中程序处理请求 :
   - 投入消毒和判刑分拆
   - 掩码符号 @(emojis,特殊字符@)
   - 使用缓存模型翻译
   - 卸载符号和后缀@-}处理
5. **模型缓存模式** 提供翻译模型@: @
   - 缓存击中 @ → @ 快速响应
   - 从 Hugging Face 中装入缓存錯取@ → @ 1 。
   - 全部缓存@→Auto @-}(旧型号) *,清除 CUDA 记忆
6. **回应答复回应回应回应回复** 返回客户端

**密钥设计@: @%** 后压机制@(queue @+}HTTP {429) 当服务队列请求被淹没时, 反压力机制“ MSK 0queu ”\ MSk1 HTTP & MS K2 防止在装入中发生撞车事件 *. 服务队落队请求, 而不是让客户通过智能时间重试 `Retry-After` 信头@. @%

## 它如何运作 :深下潜

### 流动请求

当翻译请求在 @ ,} 这里 @ MPK1} 会发生什么 @ OMK2

```mermaid
sequenceDiagram
    participant Client
    participant API
    participant Queue
    participant Translator
    participant Cache
    participant Model

    Client->>API: POST /translate
    API->>Queue: Acquire slot

    alt Queue has space
        Queue-->>API: Slot acquired
        API->>Translator: Process translation
        Translator->>Translator: Sanitize input
        Translator->>Translator: Split sentences
        Translator->>Translator: Chunk text
        Translator->>Translator: Mask symbols
        Translator->>Cache: Get model (en→de)

        alt Cache hit
            Cache-->>Translator: Return cached model
        else Cache miss
            Cache->>Model: Load from Hugging Face
            Model-->>Cache: Pipeline loaded
            Cache->>Cache: Evict old if at capacity
            Cache-->>Translator: Return model
        end

        Translator->>Model: Translate batches
        Model-->>Translator: Translations
        Translator->>Translator: Unmask symbols
        Translator->>Translator: Post-process
        Translator-->>API: Translations
        API->>Queue: Release slot
        API-->>Client: 200 OK + translations
    else Queue full
        Queue-->>API: Overflow error
        API-->>Client: 429 Too Many Requests\nRetry-After: X seconds
    end
```

### 输入处理管道

该服务使用复杂的多-阶段管道处理乱七八糟的混杂真实@-world text @:

```mermaid
graph LR
    A[Raw Input] --> B{Sanitize?}
    B -->|Yes| C[Check Noise]
    B -->|No| D[Split Sentences]
    C -->|Is Noise| Z[Return Placeholder]
    C -->|Valid| D

    D --> E[Enforce Max Length]
    E --> F[Chunk for Batching]
    F --> G{Symbol Masking?}

    G -->|Yes| H[Mask Digits/Punct/Emoji]
    G -->|No| I[Translate]
    H --> I

    I --> J{Direct Model?}
    J -->|Available| K[Direct Translation]
    J -->|Not Available| L{Pivot Fallback?}

    L -->|Yes| M[src→en→tgt]
    L -->|No| Z
    K --> N[Unmask Symbols]
    M --> N

    N --> O[Remove Symbol Loops]
    O --> P[Join Chunks]
    P --> Q[Final Translation]

```

### 节约投入

最大的改进之一是强势的输入处理@. @ Here'_Qs what happens @:}这里发生的事情:

**噪声检测@: @%**

- 条形控制字符 @(}除{\_T,MS K3_N,}{\{R})}外
- 检查最小字符数@ ( @ default=:}\ MS K2
- 计算阿尔法数字比 *( default :}% 必须是 @ MS K2\ {
- 拒绝纯emoji ,纯标点@,或纯白空格

**遮罩:**
为什么面具符号@?翻译模型 被用文字训练? ,}不是moji或特殊符号吗?

1. 将所有位数@ , @ punctuation @ MS K1和emoji 提取为毗连运行
2. 替换为寄件符@: @% `⟪MSK0⟫`, `⟪MSK1⟫`# ,#等等 @.#
3. 翻译蒙面文字
4. 将原始符号恢复到位置

实例::

```
Input:  "Hello 👋 world! Price: $99.99"
Masked: "Hello ⟪MSK0⟫ world⟪MSK1⟫ Price⟪MSK2⟫ ⟪MSK3⟫"
                 (👋)        (!)      (:)    ($99.99)
```

**后 post\ - processing: _**
翻译@,}我们删除了源代码中的重复符号 @'}{:}

```
Source: "Hello world"
Bad translation: "Hola mundo!!!!!!!"
Cleaned: "Hola mundo"  # Removes the !!!! loop
```

### 句子拆分@ & @ chucking

长篇文字被智慧分割@: @%

```mermaid
graph TD
    A[Long Text] --> B[Split on . ! ? …]
    B --> C{Sentence > 500 chars?}
    C -->|Yes| D[Split on word boundaries]
    C -->|No| E[Keep sentence]
    D --> E

    E --> F[Group into chunks ≤900 chars]
    F --> G[Translate each chunk]
    G --> H[Join with space]

```

这确保了#:

- 模型不会因为大量投入而窒息
- 我们可以高效地分批
- 在合理边界内维护环境

### 模型 Caching {&} 存储管理

LRU 缓存关于 GPU 内存的智能@ : @

```mermaid
stateDiagram-v2
    [*] --> CheckCache
    CheckCache --> CacheHit: Model exists
    CheckCache --> CacheMiss: Model not loaded

    CacheHit --> MoveToEnd: Update LRU order
    MoveToEnd --> ReturnModel

    CacheMiss --> CheckCapacity
    CheckCapacity --> LoadModel: Space available
    CheckCapacity --> EvictOldest: Cache full

    EvictOldest --> MoveToCPU: Free VRAM
    MoveToCPU --> ClearCUDA: torch.cuda.empty_cache()
    ClearCUDA --> LoadModel

    LoadModel --> AddToCache
    AddToCache --> ReturnModel
    ReturnModel --> [*]
```

**为什么这重要?**

- GPU 内存值非常宝贵
- 翻译模型各为 @300-500MB
- 加载模型速度缓慢 @ (1-3 @ seconds@ MS K1 @
- 我们把最新模特儿的热量保持高温
- 旧型号自动驱逐

### 正在排队 @ & 后压

服务队列请求@:

```python
# Semaphore limits concurrent translations
MAX_INFLIGHT = 1  # On GPU, 1 at a time for efficiency
MAX_QUEUE_SIZE = 1000  # Up to 1000 waiting

# When full:
# - Returns 429 Too Many Requests
# - Includes Retry-After header
# - Estimates wait time based on average duration
```

重试估计值为智能@: @

```
avg_duration = 2.5 seconds (tracked with EMA)
waiters = 100
slots = 1
estimated_wait = (100 / 1) * 2.5 = 250 seconds
clamped = min(250, 120) = 120 seconds
Retry-After: 120
```

### Pivit 翻转回缩

并非所有语言配对都有直接模型,

```mermaid
graph LR
    A[Ukrainian Text] --> B{Direct uk→fr?}
    B -->|Exists| C[Translate Directly]
    B -->|Missing| D[Pivot via English]

    D --> E[uk→en]
    E --> F[en→fr]
    F --> G[French Result]
    C --> G

```

这增加了双延时, 但确保覆盖所有支持的语种: . @%

## 代码深潜水@ : @ 冷静特性解释

Let' @%s 探索代码库中最有趣的部分@ !}这些是真正的生产模式 让服务变得稳健而高效 每个片段都包含适合非@ I-Python开发商的解释 *.}

### 1.智能 LRU 用 GPU 内存管理缓存

最酷的功能之一是智能模型缓存, 它知道如何处理 GPU 内存@:

```python
# src/core/cache.py
from collections import OrderedDict
import torch

class LRUPipelineCache:
    """LRU cache that automatically cleans up GPU memory when evicting models."""

    def __init__(self, capacity: int):
        self.cache = OrderedDict()  # Maintains insertion order
        self.capacity = capacity

    def get(self, key: str):
        """Get model from cache, moves it to end (most recently used)."""
        if key not in self.cache:
            return None
        self.cache.move_to_end(key)  # Mark as recently used
        return self.cache[key]

    def put(self, key: str, value):
        """Add model to cache, evicting oldest if at capacity."""
        if key in self.cache:
            self.cache.move_to_end(key)
        else:
            self.cache[key] = value

        # If cache is full, evict the oldest model
        if len(self.cache) > self.capacity:
            oldest_key, oldest_pipeline = self.cache.popitem(last=False)

            # MAGIC: Move evicted model to CPU to free GPU memory
            try:
                oldest_pipeline.model.to("cpu")
                if torch.cuda.is_available():
                    torch.cuda.empty_cache()  # Tell GPU to release memory
                logger.info(f"Evicted {oldest_key}, freed GPU memory")
            except Exception as e:
                logger.warning(f"Failed to clean GPU memory: {e}")
```

**这里发生什么了?**

- `OrderedDict`: 就像普通的字典@,, 但记得添加了顺序项目
- **LRU @( @Lestern 最近使用@)#**: 缓存满时@, 踢出在最长时间内没有使用过的模型Name
- **GPU 清理**: 在驱逐模型时 我们明确将其移到 CPU 内存, 并告诉 GPU 释放资源
- **为什么重要**没有此选项, :GPU的内存将填充并崩溃。

### 2. 自动模拟家庭后退

这个聪明的功能会自动尝试多个 AI 模式提供者, 如果第一个选择“ ' @ t” 有您需要的语言配对@ MS K1 {}

```python
# src/services/model_manager.py
def get_pipeline(self, src: str, tgt: str):
    """Try to get translation model, with automatic fallback to other providers."""

    # Determine which model families support this language pair
    families_to_try = []

    if config.AUTO_MODEL_FALLBACK:
        # Try families in priority order: opus-mt → mbart50 → m2m100
        for family in config.MODEL_FALLBACK_ORDER.split(","):
            if self._is_pair_supported(src, tgt, family.strip()):
                families_to_try.append(family.strip())

    # Try each family until one succeeds
    last_error = None
    for family in families_to_try:
        try:
            model_name, src_lang, tgt_lang, _ = self._get_model_name_and_langs(src, tgt, family)

            if family != config.MODEL_FAMILY:
                logger.info(f"Using fallback '{family}' for {src}->{tgt}")

            # Load the model from HuggingFace
            pipeline = transformers.pipeline(
                "translation",
                model=model_name,
                device=device_manager.device_index,
                src_lang=src_lang,
                tgt_lang=tgt_lang
            )

            self.cache.put(f"{src}->{tgt}", pipeline)
            return pipeline

        except Exception as e:
            last_error = e
            logger.warning(f"Family '{family}' failed for {src}->{tgt}: {e}")
            continue  # Try next family

    # All families failed
    raise ModelLoadError(f"{src}->{tgt}", last_error)
```

**这里发生什么了?**

- **后退链**: 如果 Opus@- @MT does @'}有烏克蘭─→}法國─MS K4 自动嘗試 mBART}50, 然后MZK6M100
- **无人工干预**@:用户只是要求翻译,
- **错误处理**“:”如果所有家庭都失败了,“, ” 我们以最后的失败原因抛出一个明显的错误。
- **智能缓存**: 成功模式使用语言配对密钥缓存

### @ 3._ 请求用后压队列 @ I(}HTTP *429)

production - 等級排队,防止在重载下发生服务器碰撞@:

```python
# src/services/queue_manager.py
import asyncio
from contextlib import asynccontextmanager

class QueueManager:
    """Manages request queuing and backpressure."""

    def __init__(self, max_inflight: int, max_queue: int):
        self.semaphore = asyncio.Semaphore(max_inflight)  # Limit concurrent translations
        self.max_queue_size = max_queue
        self.waiting_count = 0
        self.inflight_count = 0
        self.avg_duration_sec = 5.0  # Exponential moving average

    @asynccontextmanager
    async def acquire_slot(self):
        """Try to get a translation slot, track metrics, handle queueing."""

        # Check if queue is too full
        if self.waiting_count >= self.max_queue_size:
            # Calculate how long client should wait before retrying
            retry_after = self._estimate_retry_after()
            raise QueueOverflowError(self.waiting_count, retry_after)

        self.waiting_count += 1
        try:
            # Wait for available slot (this is the queue!)
            await self.semaphore.acquire()
            self.waiting_count -= 1
            self.inflight_count += 1

            start_time = time.time()
            yield  # Let the translation happen

            # Update average duration for retry-after estimates
            duration = time.time() - start_time
            alpha = config.RETRY_AFTER_ALPHA  # Smoothing factor (0.2)
            self.avg_duration_sec = alpha * duration + (1 - alpha) * self.avg_duration_sec

        finally:
            self.inflight_count -= 1
            self.semaphore.release()

    def _estimate_retry_after(self) -> int:
        """Smart calculation: how many waiting / how many slots * avg time per request."""
        if self.inflight_count == 0:
            return config.RETRY_AFTER_MIN_SEC

        # If 10 people waiting and 2 slots available, and each takes 5 seconds:
        # retry_after = (10 / 2) * 5 = 25 seconds
        retry_sec = (self.waiting_count / self.semaphore._value) * self.avg_duration_sec

        # Clamp between min and max
        return max(
            config.RETRY_AFTER_MIN_SEC,
            min(int(retry_sec), config.RETRY_AFTER_MAX_SEC)
        )
```

**这里发生什么了?**

- **塞马磷**就像俱乐部的保镖 只能让N的人一起进来 `max_inflight`)
- **背景主管人** (`@asynccontextmanager`): 自动跟踪度量和清理
- **智能重试@ - @ _% after**:@ tells clients @ "}根据队列深度和平均请求时间,回到 @ MS K2_ second_ scops @ MPK3
- **指数移动平均数**: 平滑出请求期间的峰值
- **为什么重要**@ : @ @ 在重负下=% 1} 返回 HTTP@ MS K2, 而不是无限制的崩溃或排队

### 4. 符号面具魔法

保留特殊字符@( @emojis,}符号 @)}翻译模式可能会破坏=:}

```python
# src/utils/symbol_masking.py
import re

def mask_symbols(text: str) -> tuple[str, dict[str, str]]:
    """Replace special symbols with placeholders before translation."""

    originals = {}
    masked_text = text
    placeholder_counter = 0

    # Pattern: Match emojis, symbols, special punctuation
    # \U0001F300-\U0001F9FF = emoji range
    # [\u2600-\u26FF\u2700-\u27BF] = misc symbols
    symbol_pattern = re.compile(
        r'[\U0001F300-\U0001F9FF\u2600-\u26FF\u2700-\u27BF'
        r'\u00A9\u00AE\u2122\u2139\u3030\u303D\u3297\u3299]+'
    )

    for match in symbol_pattern.finditer(text):
        symbol = match.group()
        placeholder = f"__SYMBOL_{placeholder_counter}__"
        originals[placeholder] = symbol
        masked_text = masked_text.replace(symbol, placeholder, 1)
        placeholder_counter += 1

    return masked_text, originals

def unmask_symbols(text: str, originals: dict[str, str]) -> str:
    """Restore original symbols after translation."""
    for placeholder, original in originals.items():
        text = text.replace(placeholder, original)
    return text
```

**实例用法@: @**

```python
# Before translation:
text = "Hello! 👋 Check out this cool feature 🚀"

# Mask symbols:
masked, originals = mask_symbols(text)
# masked = "Hello! __SYMBOL_0__ Check out this cool feature __SYMBOL_1__"
# originals = {"__SYMBOL_0__": "👋", "__SYMBOL_1__": "🚀"}

# Translate the masked text:
translated = translate(masked, "de")  # → "Hallo! __SYMBOL_0__ Schau dir diese coole Funktion an __SYMBOL_1__"

# Unmask symbols:
final = unmask_symbols(translated, originals)
# final = "Hallo! 👋 Schau dir diese coole Funktion an 🚀"
```

**这里发生什么了?**

- **Regex 模式图样**: 匹配emoji和特殊符号 Unicode 范围
- **占位符系统**-=YTET -伊甸园字幕组=- 翻译: `👋` 与 `__SYMBOL_0__` 临时暂时
- **为什么重要**翻译模式有时会腐蚀或移除emojis @-#这样就能保存它们完美=!}

### 5. 智能文本播放

将长文本折断为符合模式限制的块,同时保留句号边框@:

```python
# src/utils/text_processing.py
def chunk_sentences(sentences: list[str], max_chars: int = 900) -> list[list[str]]:
    """Group sentences into chunks that fit within model's max input length."""

    chunks = []
    current_chunk = []
    current_length = 0

    for sentence in sentences:
        sentence_len = len(sentence)

        # If this sentence alone is too long, it goes in its own chunk
        if sentence_len > max_chars:
            if current_chunk:
                chunks.append(current_chunk)
                current_chunk = []
                current_length = 0
            chunks.append([sentence])
            continue

        # If adding this sentence exceeds limit, start new chunk
        if current_length + sentence_len + 1 > max_chars:
            chunks.append(current_chunk)
            current_chunk = [sentence]
            current_length = sentence_len
        else:
            current_chunk.append(sentence)
            current_length += sentence_len + 1  # +1 for space

    # Don't forget the last chunk!
    if current_chunk:
        chunks.append(current_chunk)

    return chunks

def split_sentences(text: str, max_sentence_chars: int = 500) -> list[str]:
    """Split text into sentences, enforcing max length."""

    # Split on common sentence terminators
    sentences = re.split(r'([.!?…]+\s+)', text)

    result = []
    for sentence in sentences:
        if not sentence or sentence.isspace():
            continue

        # If sentence is too long, split on word boundaries
        if len(sentence) > max_sentence_chars:
            words = sentence.split()
            current = []
            current_len = 0

            for word in words:
                if current_len + len(word) + 1 > max_sentence_chars:
                    result.append(' '.join(current))
                    current = [word]
                    current_len = len(word)
                else:
                    current.append(word)
                    current_len += len(word) + 1

            if current:
                result.append(' '.join(current))
        else:
            result.append(sentence.strip())

    return result
```

**这里发生什么了?**

- **分句判刑**:使用正gex来分割 `.!?…` 保存标点
- **贪婪区块**: 将尽可能多的句子包装到每个块中,但不超过限制值
- **字词边界分割**: 单句太长 MS K1 在空格上拆分而不是切除中间-word
- **为什么重要**:翻译模式有输入限制@(}(通常为 @512-1024matters).) 这确保了我们不会超越它们 同时保持上下文完整\.

### 6.Async 使用缓存的模型发现

从 Hugging Face @: 动态发现可用的翻译模型

```python
# src/services/model_discovery.py
import httpx
from datetime import datetime, timedelta

class ModelDiscoveryService:
    """Discovers available translation models with 1-hour cache."""

    def __init__(self):
        self._cache = {}  # Cache results to avoid hammering HuggingFace API
        self._cache_ttl = timedelta(hours=1)
        self._hf_api_base = "https://huggingface.co/api/models"

    async def discover_opus_mt_pairs(self, force_refresh: bool = False):
        """Query HuggingFace for all Helsinki-NLP Opus-MT models."""

        cache_key = "opus-mt"

        # Check cache first
        if not force_refresh and cache_key in self._cache:
            cached_data, cached_time = self._cache[cache_key]
            if datetime.now() - cached_time < self._cache_ttl:
                return cached_data  # Cache hit!

        # Cache miss - query HuggingFace API
        async with httpx.AsyncClient() as client:
            response = await client.get(
                self._hf_api_base,
                params={
                    "author": "Helsinki-NLP",
                    "search": "opus-mt",
                    "limit": 1000
                },
                timeout=30.0
            )
            models = response.json()

        # Extract language pairs from model names
        # Example: "Helsinki-NLP/opus-mt-en-de" → ("en", "de")
        pairs = []
        for model in models:
            model_id = model.get("modelId", "")
            if model_id.startswith("Helsinki-NLP/opus-mt-"):
                # Extract the language codes after "opus-mt-"
                lang_part = model_id.replace("Helsinki-NLP/opus-mt-", "")
                if "-" in lang_part:
                    src, tgt = lang_part.split("-", 1)
                    pairs.append({"source": src, "target": tgt})

        # Cache the results
        self._cache[cache_key] = (pairs, datetime.now())

        return pairs
```

**这里发生什么了?**

- **Async HTTP 客户端** (`httpx`): 解除 HTTP 的阻塞请求
- **TimeQM-基缓存**: 商店在 @1小时的检测结果,以避免限制利率
- **模型名称解析**:摘录 `en` 和 `de` 从 `Helsinki-NLP/opus-mt-en-de`
- **为什么重要**: 抱抱脸有 @1200+ Opus-MT 型號@. 查詢它們都需要 &~10秒Q.Caching讓它立即MS K6

### @ 7._ 设备自动@ MS K1_ 检测

如果可用的话自动检测和使用 GPU @ : @ {}

```python
# src/core/device.py
import torch

class DeviceManager:
    """Smart device selection with GPU auto-detection."""

    def __init__(self):
        self.use_gpu = self._should_use_gpu()
        self.device_index = self._resolve_device()
        self.device_str = "cpu" if self.device_index < 0 else f"cuda:{self.device_index}"

        # Auto-configure parallel translation slots based on device
        if self.device_index >= 0:
            # GPU: Run translations serially to avoid VRAM fragmentation
            self.max_inflight = 1
        else:
            # CPU: Can handle multiple translations in parallel
            self.max_inflight = config.MAX_WORKERS_BACKEND

        self._log_device_info()

    def _should_use_gpu(self) -> bool:
        """Check if GPU should be used."""
        if config.USE_GPU.lower() == "false":
            return False
        if config.USE_GPU.lower() == "true":
            return torch.cuda.is_available()
        # "auto" mode: use GPU if available
        return torch.cuda.is_available()

    def _resolve_device(self) -> int:
        """Returns device index: -1 for CPU, 0+ for CUDA."""
        if not self.use_gpu:
            return -1

        # Check if specific CUDA device requested
        if config.DEVICE and config.DEVICE.startswith("cuda:"):
            device_num = int(config.DEVICE.split(":")[1])
            return device_num

        return 0  # Use first GPU

    def _log_device_info(self):
        """Log device information at startup."""
        if self.device_index >= 0:
            gpu_name = torch.cuda.get_device_name(self.device_index)
            vram_gb = torch.cuda.get_device_properties(self.device_index).total_memory / 1e9
            logger.info(f"Using GPU: {gpu_name} ({vram_gb:.1f}GB VRAM)")
            logger.info(f"Max inflight translations: {self.max_inflight} (GPU mode)")
        else:
            cpu_count = os.cpu_count()
            logger.info(f"Using CPU ({cpu_count} cores)")
            logger.info(f"Max inflight translations: {self.max_inflight} (CPU mode)")

# Global singleton instance
device_manager = DeviceManager()
```

**这里发生什么了?**

- **GPU 检测**: 使用 PyTorch 检查 CUDA是否可用
- **Auto - 配置**:集 `max_inflight=1` 在 GPU (aaeve VRAM 碎裂@) vs `max_inflight=4` 在 CPU @ ( @ 最大化平行@ ) @
- **选择设备**: 可以锁定特定 GPU 與 `DEVICE=cuda:1`
- **伐木**: 显示 GPU 名称和启动时用于调试的 VRAM
- **单吨模式**: 在整个应用程序中共享一个实例

### 8. 重试的指数移动平均值-

在根据实际请求持续时间进行估算后, 平滑重试@ - @

```python
# Snippet from QueueManager showing EMA calculation
def update_avg_duration(self, new_duration: float):
    """Update average duration using exponential moving average."""

    # EMA formula: new_avg = α × new_value + (1 - α) × old_avg
    # α = smoothing factor (0.0 to 1.0)
    #   - Higher α = more weight to recent values (faster adaptation)
    #   - Lower α = more weight to historical values (more stable)

    alpha = 0.2  # 20% weight to new value, 80% to historical

    self.avg_duration_sec = (
        alpha * new_duration +
        (1 - alpha) * self.avg_duration_sec
    )
```

**实例::**

```python
# Initial average: 5.0 seconds
# New request takes: 10.0 seconds

# EMA calculation:
new_avg = 0.2 * 10.0 + 0.8 * 5.0
        = 2.0 + 4.0
        = 6.0 seconds

# Next request takes: 3.0 seconds
new_avg = 0.2 * 3.0 + 0.8 * 6.0
        = 0.6 + 4.8
        = 5.4 seconds
```

**这里发生什么了?**

- **EMA = ( 外向移动平均 = )**: 就像一个更重视最近值的加权平均值
- **平滑因子 @ ()#**:控制我们适应变化的速度
- **为何不简单平均@? @**: EMA 快速适应变化,同时过滤溢出
- **为什么重要***:* 让客户现实 `Retry-After` 适应当前系统负荷的时间

---


**这些代码模式显示了生产过程 -Great Python做法**

- **资源管理 资源管理**: 明确 GPU 内存清理
- **优减降解**Q: 模式提供者之间的自动后退
- **后压处理**@ : @ Quue 而不是撞车 。
- **数据完整性**: 徽章遮罩保护特殊字符
- **性能优化**@ : 智能抓取Q, 填片@, 和平行处理
- **可观察性**:详细伐木和指标跟踪

每个功能都解决一个真正的生产问题, 从而导致撞车失事:=,}错误@, 或用户经验差没有这些#!

## 配置指南

此服务通过环境变量高度可配置@. @ Here'}完整的指南_:}*

### 选择设备

```bash
# Prefer GPU if available (default)
USE_GPU=auto

# Force GPU
USE_GPU=true

# Force CPU
USE_GPU=false

# Explicit device override
DEVICE=cuda:0
DEVICE=cpu
```

### 模型配置

```bash
# Model family selection (NEW in v2.0!)
MODEL_FAMILY=opus-mt   # Best quality (default)
MODEL_FAMILY=mbart50   # 50 languages, single model
MODEL_FAMILY=m2m100    # 100 languages, maximum coverage

# Auto-fallback between model families (NEW in v2.0!)
AUTO_MODEL_FALLBACK=1  # Enabled by default
MODEL_FALLBACK_ORDER="opus-mt,mbart50,m2m100"  # Priority order

# Volume-mapped model cache (NEW in v2.0!)
MODEL_CACHE_DIR=/models  # Persistent cache directory

# Model arguments passed to transformers.pipeline
EASYNMT_MODEL_ARGS='{"torch_dtype":"fp16"}'
EASYNMT_MODEL_ARGS='{"torch_dtype":"bf16","cache_dir":"/models"}'

# Preload models at startup (reduces first-request latency)
PRELOAD_MODELS="en->de,de->en,fr->en"

# LRU cache capacity
MAX_CACHED_MODELS=6
```

**新解析的配置@ : @ {}**

- **蒙德罗 _ 家庭**: 选择以哪一种家庭为主模式
  
  - `opus-mt`最佳质量=,}1200+}对子=MS K3}不同的模型
  - `mbart50`@:}好的品质 ~, ~ 50 语言 _, 单一的 2.4GB模式
  - `m2m100`@:}好的品质 ~, ~ 100 语言 _, 单一的 2.2GB模式

- **(奥托·莫诺·蒙德罗 万斯卡1 佛罗伦萨)**@ :_ 自动尝试其他家庭, 如果对无法使用的话 。
  
  - `1` @ (_ 默认@ MS K1} 启用了 @ - 最大覆盖范围
  - `0`: 残疾 @- 严格单人@-家庭模式

- **摩德罗・墨斯卡・福勒贝克・莫斯克1・奥多尔***:* 优先后退顺序
  
  - 默认@: @ {} `"opus-mt,mbart50,m2m100"` -=YTET 翻译:
  - 替代性: `"m2m100,mbart50,opus-mt"` “(”首先覆盖“)”

- **蒙德罗・_卡切・门斯克1德尔**: 通过 docker 批量进行持久性模型存储
  
  - 设定为 `/models` 和地图卷@: `-v ./model-cache:/models`
  - 集装箱重新启动模式始终存在
  - 多个容器间共享缓存

**命令@ _ @ dtype options @ MS K1 @**

- `fp16` GPU=,}*一半的内存 *, 微不足道的质量损失
- `bf16` (bfloat16):}比 fp16,更好的数字稳定性需要现代 GPU
- `fp32` {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}最慢但最准确

### 翻译设置

```bash
# Batch size for translation (higher = faster but more VRAM)
EASYNMT_BATCH_SIZE=16  # CPU: 8-16, GPU: 32-64

# Maximum text length per item
EASYNMT_MAX_TEXT_LEN=1000

# Maximum beam size (higher = better quality but slower)
EASYNMT_MAX_BEAM_SIZE=5

# Worker thread pools
MAX_WORKERS_BACKEND=1    # Translation workers
MAX_WORKERS_FRONTEND=2   # Language detection workers
```

### 正在排队 @ &+# 性能

```bash
# Enable request queueing (highly recommended)
ENABLE_QUEUE=1

# Max concurrent translations
# Auto: 1 on GPU, MAX_WORKERS_BACKEND on CPU
MAX_INFLIGHT_TRANSLATIONS=1

# Max queued requests before 429
MAX_QUEUE_SIZE=1000

# Per-request timeout (0 = disabled)
TRANSLATE_TIMEOUT_SEC=180

# Retry-After estimation
RETRY_AFTER_MIN_SEC=1      # Floor
RETRY_AFTER_MAX_SEC=120    # Ceiling
RETRY_AFTER_ALPHA=0.2      # EMA smoothing factor
```

### 节约投入

```bash
# Enable input filtering
INPUT_SANITIZE=1

# Minimum alphanumeric ratio (0.2 = 20%)
INPUT_MIN_ALNUM_RATIO=0.2

# Minimum character count
INPUT_MIN_CHARS=1

# Language code for undetermined/noise
UNDETERMINED_LANG_CODE=und
```

### 判决处理

```bash
# Default sentence splitting behavior
PERFORM_SENTENCE_SPLITTING_DEFAULT=1

# Max chars per sentence before word-boundary split
MAX_SENTENCE_CHARS=500

# Max chars per chunk for batching
MAX_CHUNK_CHARS=900

# Sentence joiner
JOIN_SENTENCES_WITH=" "
```

### 符号掩码

```bash
# Enable symbol masking
SYMBOL_MASKING=1

# What to mask
MASK_DIGITS=1    # Mask 0-9
MASK_PUNCT=1     # Mask .,!? etc.
MASK_EMOJI=1     # Mask 😀🎉 etc.
```

### 反应行为

```bash
# Align response array length to input
ALIGN_RESPONSES=1

# Placeholder for failed items (when aligned)
SANITIZE_PLACEHOLDER=""

# Response format
EASYNMT_RESPONSE_MODE=strings    # ["translation1", "translation2"]
EASYNMT_RESPONSE_MODE=objects    # [{"text":"translation1"}, ...]
```

### 中枢后退

```bash
# Enable two-hop translation via pivot
PIVOT_FALLBACK=1

# Pivot language (usually English)
PIVOT_LANG=en
```

### 伐木

```bash
# Log level
LOG_LEVEL=INFO

# Per-request logging (verbose)
REQUEST_LOG=1

# Format
LOG_FORMAT=plain    # Human-readable
LOG_FORMAT=json     # Structured JSON

# File logging with rotation
LOG_TO_FILE=1
LOG_FILE_PATH=/var/log/marian-translator/app.log
LOG_FILE_MAX_BYTES=10485760    # 10MB
LOG_FILE_BACKUP_COUNT=5

# Include raw text in logs (privacy risk!)
LOG_INCLUDE_TEXT=0
```

### 维护维修保养

```bash
# Periodically clear CUDA cache (seconds, 0=disabled)
CUDA_CACHE_CLEAR_INTERVAL_SEC=0
```

### 多克多克1号炮兵

```bash
# Worker count (use 1 for single GPU)
WEB_CONCURRENCY=1

# Request timeout
TIMEOUT=60

# Graceful shutdown timeout
GRACEFUL_TIMEOUT=20

# Keep-alive timeout
KEEP_ALIVE=5
```

## 使用率示例

### 基本笔译

```bash
# GET request
curl "http://localhost:8000/translate?target_lang=de&text=Hello%20world&source_lang=en"

# Response
{
  "translations": ["Hallo Welt"]
}
```

### 批量翻译@(_推荐})

```bash
# POST request
curl -X POST http://localhost:8000/translate \
  -H 'Content-Type: application/json' \
  -d '{
    "text": [
      "Hello world",
      "This is a test",
      "Machine translation is amazing"
    ],
    "target_lang": "de",
    "source_lang": "en",
    "beam_size": 1,
    "perform_sentence_splitting": true
  }'

# Response
{
  "target_lang": "de",
  "source_lang": "en",
  "translated": [
    "Hallo Welt",
    "Das ist ein Test",
    "Maschinenübersetzung ist erstaunlich"
  ],
  "translation_time": 0.342
}
```

### 自动语言探测

```bash
# Omit source_lang for auto-detection
curl -X POST http://localhost:8000/translate \
  -H 'Content-Type: application/json' \
  -d '{
    "text": ["Bonjour le monde"],
    "target_lang": "en"
  }'

# Response
{
  "target_lang": "en",
  "source_lang": "fr",  # Detected
  "translated": ["Hello world"],
  "translation_time": 0.156
}
```

### 仅识别语言

```bash
# GET
curl "http://localhost:8000/language_detection?text=Hola%20mundo"
# {"language": "es"}

# POST with batch
curl -X POST http://localhost:8000/language_detection \
  -H 'Content-Type: application/json' \
  -d '{"text": ["Hello", "Bonjour", "Hola"]}'
# {"languages": ["en", "fr", "es"]}
```

### 终点

```bash
# Health check
curl http://localhost:8000/healthz
# {"status": "ok"}

# Readiness
curl http://localhost:8000/readyz
# {
#   "status": "ready",
#   "device": "cuda:0",
#   "queue_enabled": true,
#   "max_inflight": 1
# }

# Cache status
curl http://localhost:8000/cache
# {
#   "capacity": 6,
#   "size": 3,
#   "keys": ["en->de", "de->en", "fr->en"],
#   "device": "cuda:0",
#   "inflight": 1,
#   "queue_enabled": true
# }

# Model info
curl http://localhost:8000/model_name | jq
```

### 处理后压

```bash
# When queue is full, you get 429
curl -X POST http://localhost:8000/translate \
  -H 'Content-Type: application/json' \
  -d '{"text": ["test"], "target_lang": "de"}'

# Response: 429 Too Many Requests
# Headers: Retry-After: 45
# Body:
{
  "message": "Too many requests; queue full",
  "retry_after_sec": 45
}

# Proper client behavior:
# 1. Read Retry-After header
# 2. Wait that long + jitter
# 3. Retry request
```

## 建筑和改造

所有嵌入图像现在都包含正确的版本和元数据, 用于跟踪@. @%

### 快速构建

以自动日期时间版本构建所有 & 4+% 变量@ :+%

**Windows :**

```powershell
.\build-all.ps1
```

**Linux / Mac:**

```bash
chmod +x build-all.sh
./build-all.sh
```

### 版本战略

每个建筑创造 **两个标记**:

1. **命名标签** (`latest`, `min`, `gpu`, `gpu-min`@) @ @ - @ 总是指出最近的一点
2. **版本标签** (E.G., `20250108.143022`无法改变的快照

例如 @:

```bash
# Always get the latest version
docker pull scottgal/mostlylucid-nmt:cpu
# Or use the :latest alias
docker pull scottgal/mostlylucid-nmt:latest

# Pin to a specific version for reproducibility
docker pull scottgal/mostlylucid-nmt:cpu-20250108.143022
docker pull scottgal/mostlylucid-nmt:cpu-min-20250108.143022
```

### OCIO 标签

每个图像包含元数据@: @%

- **版本版本**:构建时间戳 @(}YYYMDD.HHMSS})
- **建立日期**:QISO ISO *8601Q 时间戳
- **Git 承诺**短短的莎萨
- **变式**@ : @ cpu@ MSQ1 @ full , @ cupu MS K3},} gpu -_ pull,} 或gpuç-min

检查标签@: @%

```bash
docker inspect scottgal/mostlylucid-nmt:cpu | jq '.[0].Config.Labels'
```

详细建筑说明和 CICMSMK0}CD 整合 *,}请参见 [BUILD. md](https://github.com/scottgal/mostlylucid-nmt/blob/main/BUILD.md).

## 部署

### CPU 部署

```bash
# Using pre-built image from Docker Hub (recommended)
docker run -d \
  --name translator \
  -p 8000:8000 \
  -e ENABLE_QUEUE=1 \
  -e MAX_QUEUE_SIZE=500 \
  -e EASYNMT_BATCH_SIZE=16 \
  -e TIMEOUT=180 \
  -e LOG_LEVEL=INFO \
  -e REQUEST_LOG=0 \
  scottgal/mostlylucid-nmt

# Or build locally
docker build -t mostlylucid-nmt .
docker run -d --name translator -p 8000:8000 mostlylucid-nmt

# Check logs
docker logs -f translator
```

### GPU部署

```bash
# Using pre-built GPU image from Docker Hub (recommended)
docker run -d \
  --name translator-gpu \
  --gpus all \
  -p 8000:8000 \
  -e USE_GPU=true \
  -e DEVICE=cuda:0 \
  -e PRELOAD_MODELS="en->de,de->en,en->fr,fr->en,en->es,es->en" \
  -e EASYNMT_MODEL_ARGS='{"torch_dtype":"fp16"}' \
  -e EASYNMT_BATCH_SIZE=64 \
  -e MAX_CACHED_MODELS=8 \
  -e ENABLE_QUEUE=1 \
  -e MAX_QUEUE_SIZE=2000 \
  -e WEB_CONCURRENCY=1 \
  -e TIMEOUT=180 \
  -e GRACEFUL_TIMEOUT=30 \
  -e LOG_FORMAT=json \
  -e LOG_TO_FILE=1 \
  -v /var/log/translator:/var/log/marian-translator \
  scottgal/mostlylucid-nmt:gpu

# Or build locally
docker build -f Dockerfile.gpu -t mostlylucid-nmt:gpu .
docker run -d --name translator-gpu --gpus all -p 8000:8000 mostlylucid-nmt:gpu

# Monitor cache and performance
watch -n 5 "curl -s http://localhost:8000/cache | jq"
```

### docker 合成器

```yaml
version: '3.8'

services:
  translator:
    image: scottgal/mostlylucid-nmt:gpu  # Use pre-built image
    container_name: translator
    restart: unless-stopped

    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities: [gpu]

    ports:
      - "8000:8000"

    environment:
      USE_GPU: "true"
      DEVICE: "cuda:0"
      PRELOAD_MODELS: "en->de,de->en,en->fr,fr->en"
      EASYNMT_MODEL_ARGS: '{"torch_dtype":"fp16"}'
      EASYNMT_BATCH_SIZE: "64"
      MAX_CACHED_MODELS: "8"
      ENABLE_QUEUE: "1"
      MAX_QUEUE_SIZE: "2000"
      WEB_CONCURRENCY: "1"
      TIMEOUT: "180"
      LOG_FORMAT: "json"
      LOG_TO_FILE: "1"

    volumes:
      - translator-logs:/var/log/marian-translator
      - translator-cache:/root/.cache/huggingface

    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/healthz"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

volumes:
  translator-logs:
  translator-cache:
```

### 库贝涅特部署

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: translator
spec:
  replicas: 2  # Scale horizontally for CPU, use 1 per GPU
  selector:
    matchLabels:
      app: translator
  template:
    metadata:
      labels:
        app: translator
    spec:
      containers:
      - name: translator
        image: scottgal/mostlylucid-nmt:gpu
        ports:
        - containerPort: 8000
        env:
        - name: USE_GPU
          value: "true"
        - name: EASYNMT_MODEL_ARGS
          value: '{"torch_dtype":"fp16"}'
        - name: PRELOAD_MODELS
          value: "en->de,de->en"
        - name: ENABLE_QUEUE
          value: "1"
        - name: MAX_QUEUE_SIZE
          value: "2000"

        resources:
          requests:
            memory: "4Gi"
            cpu: "2"
            nvidia.com/gpu: 1
          limits:
            memory: "8Gi"
            cpu: "4"
            nvidia.com/gpu: 1

        livenessProbe:
          httpGet:
            path: /healthz
            port: 8000
          initialDelaySeconds: 30
          periodSeconds: 10

        readinessProbe:
          httpGet:
            path: /readyz
            port: 8000
          initialDelaySeconds: 20
          periodSeconds: 5

---
apiVersion: v1
kind: Service
metadata:
  name: translator
spec:
  selector:
    app: translator
  ports:
  - port: 80
    targetPort: 8000
  type: LoadBalancer
```

## 绩效优化

### GPU 优化检查列表

1. **使用 FP16 精密度**
   
   ```bash
   EASYNMT_MODEL_ARGS='{"torch_dtype":"fp16"}'
   ```
   
   - 2#x 更快的推断
   - VRAM使用量的一半
   - 翻译质量损失可忽略不计

2. **Tune 批量大小**
   
   ```bash
   # Start high, reduce if you get OOM
   EASYNMT_BATCH_SIZE=64  # Try 128 on large GPUs
   ```

3. **预装热模型**
   
   ```bash
   PRELOAD_MODELS="en->de,de->en,en->fr,fr->en,en->es,es->en"
   ```

4. **人均劳动力单位的单身工人数**
   
   ```bash
   WEB_CONCURRENCY=1
   MAX_INFLIGHT_TRANSLATIONS=1
   ```

5. **增加缓存大小**
   
   ```bash
   MAX_CACHED_MODELS=10  # Keep more models in VRAM
   ```

6. **吞吐量的低光束尺寸**
   
   ```bash
   # beam_size=1 is 3-5x faster than beam_size=5
   # Quality difference is often minimal
   curl -X POST ... -d '{"beam_size": 1, ...}'
   ```

### CPU 优化检查列表

1. **较低批次规模**
   
   ```bash
   EASYNMT_BATCH_SIZE=8
   ```

2. **增加平行主义**
   
   ```bash
   MAX_WORKERS_BACKEND=4
   MAX_INFLIGHT_TRANSLATIONS=4
   WEB_CONCURRENCY=2
   ```

3. **短文本分句停用**
   
   ```bash
   PERFORM_SENTENCE_SPLITTING_DEFAULT=0
   ```

### 客户最佳做法

1. **批次申请**
   
   ```javascript
   // Bad: 100 separate requests
   for (const text of texts) {
     await translate(text);
   }
   
   // Good: 1 batch request
   await translate(texts);
   ```

2. **尊重重试@ - @ after**
   
   ```javascript
   async function translateWithRetry(texts) {
     try {
       return await translate(texts);
     } catch (err) {
       if (err.status === 429) {
         const retryAfter = err.headers['retry-after'];
         const jitter = Math.random() * 5;
         await sleep((retryAfter + jitter) * 1000);
         return translateWithRetry(texts);
       }
       throw err;
     }
   }
   ```

3. **使用连接共用电联**
   
   ```javascript
   // Reuse HTTP connections
   const agent = new https.Agent({ keepAlive: true });
   ```

4. **按语配对分组**
   
   ```javascript
   // Bad: mixed language pairs in one request
   translate([
     { text: "Hello", sourceLang: "en", targetLang: "de" },
     { text: "Bonjour", sourceLang: "fr", targetLang: "de" }
   ]);
   
   // Good: group by language pair
   translateBatch(enToDe, "en", "de");
   translateBatch(frToDe, "fr", "de");
   ```

## 监测:观察

### 要跟踪的密钥矩阵

1. **翻译量** (请求 */*sec*)*
2. **平均间平均** {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}
3. **队列深度** (=当前等待数=)}
4. **缓存误快率** 请求中的(% 点击缓存@)
5. **错误率** (5#xx回复 *)}
6. **GPU 利用率** *如果适用的话* *(}*)
7. **内存使用** 用于 GPU 的(VRAM 用于 CPU @) 的 ,RAM

### Prometheus示例

如果您整合了 Prometheus @ ( @ not build@ MS K1_in @ I,}, 但很容易添加@ MPK3 @

```python
translation_requests_total{lang_pair="en->de",status="success"} 1523
translation_requests_total{lang_pair="en->de",status="error"} 7
translation_duration_seconds{lang_pair="en->de",quantile="0.5"} 0.342
translation_duration_seconds{lang_pair="en->de",quantile="0.95"} 1.234
translation_queue_depth 23
translation_cache_size 6
translation_cache_hits_total 8234
translation_cache_misses_total 142
```

### 结构日志示例

```bash
# Enable JSON logging
LOG_FORMAT=json REQUEST_LOG=1

# Output example
{
  "ts": "2025-01-08T15:30:45+0000",
  "level": "INFO",
  "name": "app",
  "message": "translate_post done items=5 dt=0.342s",
  "req_id": "a3d2f5b1-c4e6-4f7a-9d8c-1e2f3a4b5c6d",
  "endpoint": "/translate",
  "src": "en",
  "tgt": "de",
  "items": 5,
  "duration_ms": 342
}
```

您可以通过此管道连接到 Elasticsearch@ , @ Cloud Watch_ , @ 或任何对数聚合器@ MPK2+%

## 比较@: EasyNMT 相对于多数Lucid}-NMD

“|” 特写“|” “EasyNMT @|” 多数是LUCID}- NMT@|
|---------|---------|-----------------|
| **稳定** | 崩溃频繁 @| producting @MS K2ready}, 优雅的错误处理@|
| **输入处理** “|”在moji @/_symbols 上失灵,
| **后压** “|None,OOMs 下载”“|Semaphore @+列队列,在@|后重试‘-#
| **可观察性** |+|+Health=/+Wiredy @/+Cache终点点@,+Assetical log 结构化的日志 @MS K5_
| **GPU 支持** -=YTET -伊甸园字幕组=- 翻译:
| **示范管理管理** | 手动, 无缓存 *| LRU 缓存和自动-evction *|
| **句号处理** “|”基本分解“|”智能填充“MS K2”批发“MSC3”
| **轴心翻译** @| @ no {|} 没有通过英语的自动后退@| @
| **优雅的关闭** @| @ no |_Yes#,}加上超时@|
| **配置配置** |有限公司@| @40+ envv vars 用于精细的-调制_|
| **APPI 兼容性** |+EasyNMT 端点 @|_Q#100%}兼容的@++ 扩展 *|*
| **守则质量** |}未保存的 MS K1 单曲 *| modular @, 打字的, 测试的 *|

## 排除故障

### @429_% 太多请求

**原因:** 队列为全@. @

**解答@: @**

- 增加 `MAX_QUEUE_SIZE`
- 添加更多复制@ ( @ orizontal 缩放 @ MS K1 @ {
- 增加 `MAX_INFLIGHT_TRANSLATIONS` (,如果你有客厅
- 客户减少批量数量

### 503服务无可用

**原因:** 正在排队已禁用且所有空位都在忙 @. @%

**解答@: @**

- 启用队列@ : @ { `ENABLE_QUEUE=1`
- 增加飞行限制,如果有资源

### 在 GPU 上 OOM @ ( @ 内存@ MSKO1 @ gPU

**原因:** 批量大小太高或模型太多缓存@. @%

**解答@: @**

- 减少 `EASYNMT_BATCH_SIZE`
- 减少 `MAX_CACHED_MODELS`
- 启用 FP 16: `EASYNMT_MODEL_ARGS='{"torch_dtype":"fp16"}'`
- 确保确保: `WEB_CONCURRENCY=1` 和 `MAX_INFLIGHT_TRANSLATIONS=1`

### 慢速第一请求

**原因:** 未预装入的模型@ . @%

**解答@: @**

```bash
PRELOAD_MODELS="en->de,de->en"
```

### 失踪语言对等

**原因:** `Helsinki-NLP/opus-mt-{src}-{tgt}` Hugging face 上不存在'Q@. @%

**解答@: @**

- 启用轴向后退@ : @ {} `PIVOT_FALLBACK=1` @(_routes 通过英语#)}
- 检查支持的配对@: @% `curl http://localhost:8000/lang_pairs`

### 翻译中的人工制品符号

**原因:** 徽章遮罩可能太凶猛了

**解答@: @**

- 禁用特定遮罩@: @% 1 `MASK_EMOJI=0` 或 `MASK_PUNCT=0`
- 或者完全禁用@ : @ {} `SYMBOL_MASKING=0`

## 与 ASP+.NET 整合

如何更新您的 CQ# 客户端@: @%

```csharp
public class MostlyLucidNmtClient
{
    private readonly HttpClient _httpClient;
    private readonly string _baseUrl;

    public MostlyLucidNmtClient(HttpClient httpClient, string baseUrl)
    {
        _httpClient = httpClient;
        _baseUrl = baseUrl;
    }

    public async Task<TranslationResponse> TranslateAsync(
        List<string> texts,
        string targetLang,
        string sourceLang = "",
        int beamSize = 1,
        bool performSentenceSplitting = true,
        CancellationToken cancellationToken = default)
    {
        var request = new TranslationRequest
        {
            Text = texts,
            TargetLang = targetLang,
            SourceLang = sourceLang,
            BeamSize = beamSize,
            PerformSentenceSplitting = performSentenceSplitting
        };

        var response = await _httpClient.PostAsJsonAsync(
            $"{_baseUrl}/translate",
            request,
            cancellationToken);

        if (response.StatusCode == System.Net.HttpStatusCode.TooManyRequests)
        {
            // Read Retry-After header
            var retryAfter = response.Headers.RetryAfter?.Delta?.TotalSeconds ?? 30;
            var jitter = Random.Shared.Next(0, 5);
            await Task.Delay(TimeSpan.FromSeconds(retryAfter + jitter), cancellationToken);

            // Retry
            return await TranslateAsync(texts, targetLang, sourceLang, beamSize,
                performSentenceSplitting, cancellationToken);
        }

        response.EnsureSuccessStatusCode();
        return await response.Content.ReadFromJsonAsync<TranslationResponse>(cancellationToken);
    }
}

public class TranslationRequest
{
    [JsonPropertyName("text")]
    public List<string> Text { get; set; }

    [JsonPropertyName("target_lang")]
    public string TargetLang { get; set; }

    [JsonPropertyName("source_lang")]
    public string SourceLang { get; set; }

    [JsonPropertyName("beam_size")]
    public int BeamSize { get; set; }

    [JsonPropertyName("perform_sentence_splitting")]
    public bool PerformSentenceSplitting { get; set; }
}

public class TranslationResponse
{
    [JsonPropertyName("target_lang")]
    public string TargetLang { get; set; }

    [JsonPropertyName("source_lang")]
    public string SourceLang { get; set; }

    [JsonPropertyName("translated")]
    public List<string> Translated { get; set; }

    [JsonPropertyName("translation_time")]
    public double TranslationTime { get; set; }
}
```

在您的 DI 容器中注册@: @%

```csharp
services.AddHttpClient<MostlyLucidNmtClient>(client =>
{
    client.BaseAddress = new Uri("http://translator:8000");
    client.Timeout = TimeSpan.FromMinutes(3);
});
```

## 结论结论

多数Lucid-NMT是简单NMD概念的完整改写,其生产可靠性在意@. **版本@2.0 @% 将其带到下一个级别** 模范家庭支持与智慧后退.

### 是什么使得V2.0}特别

**最大语言覆盖率**

- 支持所有三个模范家庭使用“100+”语言
- 自动- 后退确保您从不打@"}语言配对不支持 @"
- 单一部署手柄 @9,900+翻译对

**第一种方法**

- 优先为每对夫妇确定最佳现有模式
- Opus - @MT @(}最佳品质 @)}→ mBART50}@→ MZ2MQ100}后退顺序
- 透明记录显示使用哪种模式

**灵活部署**

- 带有 4}{} 变量的单嵌入仓库
- 用于空间的最小图像@ - 限制环境
- 用于模型持久性的立方缓存
- 不重建的交换式家庭模式

**-=YTET -伊甸园字幕组=- 翻译:**

- 真实的 messy real @-world involvement {(}%2}符号@, 边框病例_)
- 生产负载 @(Qqueueing@,}后压 @MS K2}优雅的降解 *)*
- GPU 效率 @(FP}16,} LRU 缓存 *, VRAM 管理=)
- 操作可见度( 健康检查 ,
- 开发者经验 @ (100%_ EasyNMT API 兼容@ MS K1} 全面的 docs=)

### 世界使用量

翻译数千篇博客文章, **100+ 语言** CCU 和 GPU ,QQ 处理 pipky 流量的优雅@,QQ, 为典型博客内容提供sub*-第二译文 @.}

### 密钥外出

- **最大覆盖范围@: @** 100+語言@, @9,900+配對},自動回復
- **质量第一:** 具有透明度的选择
- **坚韧度:** 处理错误处理% , @ 优雅关闭
- **智能资源@: @** LRU 抓取@, @ 后压 @ , @ VRAM 自动@ MS K2_ action
- **观察性:** 健康检查@,缓存状态 @,示范发现_,结构化日志
- **性能=:** FP+16,批量@, 预加载 @, 多MS K3家庭支持
- **开发者友好型@: @%** EasyNMT-}匹配的 API},}宽广配置 *,}明显错误
- **简单部署@: @%** 单嵌入容器@ , @ 没有复杂设置

### 快速启动提醒

```bash
# Maximum coverage with auto-fallback (recommended!)
docker run -d -p 8000:8000 \
  -v ./model-cache:/models \
  -e MODEL_CACHE_DIR=/models \
  -e AUTO_MODEL_FALLBACK=1 \
  -e MODEL_FALLBACK_ORDER="opus-mt,mbart50,m2m100" \
  scottgal/mostlylucid-nmt:cpu-min

# GPU with best quality
docker run -d --gpus all -p 8000:8000 \
  -e USE_GPU=true \
  -e MODEL_FAMILY=opus-mt \
  -e EASYNMT_MODEL_ARGS='{"torch_dtype":"fp16"}' \
  scottgal/mostlylucid-nmt:gpu

# Test it
curl -X POST http://localhost:8000/translate \
  -H 'Content-Type: application/json' \
  -d '{"text": ["Hello world"], "target_lang": "de"}'
```

### 什么是' 下一步 @?

整个服务是一个单一的 Docker 容器@. @ no complicate settleption\ ,}除了 Hugging Face 模型下载之外没有外部依赖性=%.

**使用最佳的模型翻译@! @**

翻译愉快 @!

---


## 继续阅读

- [Helinki -NLP Opus-MT 模型](https://huggingface.co/Helsinki-NLP)
- [Huggg 面变换器文档](https://huggingface.co/docs/transformers)
- [FastAPI 文件](https://fastapi.tiangolo.com/)
- [PyTollch CUDA 优化](https://pytorch.org/docs/stable/notes/cuda.html)

## 源代码

完整源代码可用于 [欢迎捐款 !

## 标签标记

`Translation` `NMT` `Neural Machine Translation` `Python` `FastAPI` `Docker` `CUDA` `PyTorch` `Transformers` `Helsinki-NLP` `Production` `Microservices` `API`