README_zh-CN.md

April 30, 2026 · View on GitHub

EPUB Translator

ci pip install epub-translator pypi epub-translator python versions license

Open in OOMOL Studio

English | 中文

想读一本外文书,却担心失去原文的语境?EPUB Translator 可以将任何 EPUB 转换成双语版本,AI 翻译与原文并列展示。

无论你是在学习新语言、进行学术研究,还是纯粹享受外国文学,你都能在一本书中同时获得两种版本——保留所有格式、图片和结构。

翻译效果

在线版本

如果你希望在不进行本地安装的情况下体验 EPUB Translator,可以试试 Inkora - EPUB Translator,这是一个基于相同双语 EPUB 翻译流程构建的正式在线应用。你可以直接上传 EPUB 文件,在浏览器中体验主要功能。

EPUB Translator 在线版本

安装

pip install epub-translator

系统要求: Python 3.11、3.12 或 3.13

快速开始

使用 OOMOL Studio (推荐)

最简单的使用方式是通过 OOMOL Studio 的可视化界面:

观看教程

使用 Python API

from epub_translator import LLM, translate, language, SubmitKind

# 使用 API 凭证初始化 LLM
llm = LLM(
    key="your-api-key",
    url="https://api.openai.com/v1",
    model="gpt-4",
    token_encoding="o200k_base",
)

# 使用语言常量翻译 EPUB 文件
translate(
    source_path="source.epub",
    target_path="translated.epub",
    target_language=language.CHINESE,
    submit=SubmitKind.APPEND_BLOCK,
    llm=llm,
)

带进度追踪

from tqdm import tqdm

with tqdm(total=100, desc="翻译中", unit="%") as pbar:
    last_progress = 0.0

    def on_progress(progress: float):
        nonlocal last_progress
        increment = (progress - last_progress) * 100
        pbar.update(increment)
        last_progress = progress

    translate(
        source_path="source.epub",
        target_path="translated.epub",
        target_language="Chinese",
        submit=SubmitKind.APPEND_BLOCK,
        llm=llm,
        on_progress=on_progress,
    )

API 参考

LLM

初始化翻译所需的 LLM 客户端:

LLM(
    key: str,                          # API 密钥
    url: str,                          # API 端点 URL
    model: str,                        # 模型名称 (例如 "gpt-4")
    token_encoding: str,               # Token 编码方式 (例如 "o200k_base")
    cache_path: PathLike | None = None,           # 缓存目录路径
    timeout: float | None = None,                  # 请求超时时间(秒)
    top_p: float | tuple[float, float] | None = None,
    temperature: float | tuple[float, float] | None = None,
    retry_times: int = 5,                         # 失败重试次数
    retry_interval_seconds: float = 6.0,          # 重试间隔(秒)
    log_dir_path: PathLike | None = None,         # 日志目录路径
)

translate 函数

翻译 EPUB 文件:

translate(
    source_path: PathLike | str,       # 源 EPUB 文件路径
    target_path: PathLike | str,       # 输出 EPUB 文件路径
    target_language: str,              # 目标语言 (例如 "Chinese", "English")
    submit: SubmitKind,                # 如何插入译文 (REPLACE, APPEND_TEXT, 或 APPEND_BLOCK)
    user_prompt: str | None = None,    # 自定义翻译指令
    max_retries: int = 5,              # 翻译失败的最大重试次数
    max_group_tokens: int = 2600,      # 每个翻译组的最大 token 数
    concurrency: int = 1,              # 并发翻译任务数 (默认: 1)
    llm: LLM | None = None,            # 用于翻译和填充的单个 LLM 实例
    translation_llm: LLM | None = None,  # 翻译专用 LLM 实例(优先于 llm)
    fill_llm: LLM | None = None,       # XML 填充专用 LLM 实例(优先于 llm)
    on_progress: Callable[[float], None] | None = None,  # 进度回调函数 (0.0-1.0)
    on_fill_failed: Callable[[FillFailedEvent], None] | None = None,  # 错误回调函数
)

注意: 必须提供 llm 或同时提供 translation_llmfill_llm。使用独立的 LLM 可以针对不同任务进行优化。

提交模式

submit 参数控制译文如何插入到文档中。使用 SubmitKind 枚举类型指定插入模式:

from epub_translator import SubmitKind

# 三种可用模式:
# - SubmitKind.REPLACE: 用译文替换原文(单语输出)
# - SubmitKind.APPEND_TEXT: 将译文作为内联文本附加(双语输出)
# - SubmitKind.APPEND_BLOCK: 将译文作为块级元素附加(双语输出,推荐)

模式对比:

  • SubmitKind.REPLACE: 用译文替换原文,创建单语翻译版本。适用于只需要目标语言版本的场景。

  • SubmitKind.APPEND_TEXT: 将译文作为内联文本紧接在原文后附加。两种语言出现在同一段落中,形成连续的阅读流。

  • SubmitKind.APPEND_BLOCK (推荐): 将译文作为独立的块级元素(段落)附加在原文后。这在两种语言之间创建清晰的视觉分隔,最适合双语对照阅读。

示例:

# 创建双语书籍(推荐)
translate(
    source_path="source.epub",
    target_path="translated.epub",
    target_language=language.CHINESE,
    submit=SubmitKind.APPEND_BLOCK,
    llm=llm,
)

# 创建单语翻译
translate(
    source_path="source.epub",
    target_path="translated.epub",
    target_language=language.CHINESE,
    submit=SubmitKind.REPLACE,
    llm=llm,
)

语言常量

EPUB Translator 提供了预定义的语言常量供用户使用,您可以使用这些常量而不是直接编写语言名称字符串:

from epub_translator import language

# 使用示例:
translate(
    source_path="source.epub",
    target_path="translated.epub",
    target_language=language.CHINESE,
    submit=SubmitKind.APPEND_BLOCK,
    llm=llm,
)

# 您也可以使用自定义的语言字符串:
translate(
    source_path="source.epub",
    target_path="translated.epub",
    target_language="Icelandic",  # 对于不在常量列表中的语言
    submit=SubmitKind.APPEND_BLOCK,
    llm=llm,
)

使用 on_fill_failed 处理错误

使用 on_fill_failed 回调监控翻译错误。系统会自动重试失败的翻译,最多重试 max_retries 次(默认:5 次)。大多数错误会在重试过程中恢复,不会影响最终输出。

from epub_translator import FillFailedEvent

def handle_fill_error(event: FillFailedEvent):
    # 只记录会影响最终 EPUB 的关键错误
    if event.over_maximum_retries:
        print(f"关键错误(已尝试 {event.retried_count} 次):")
        print(f"  {event.error_message}")
        print("  此错误将出现在最终的 EPUB 文件中!")

translate(
    source_path="source.epub",
    target_path="translated.epub",
    target_language=language.CHINESE,
    submit=SubmitKind.APPEND_BLOCK,
    llm=llm,
    on_fill_failed=handle_fill_error,
)

理解错误严重程度:

FillFailedEvent 包含:

  • error_message: str - 错误描述
  • retried_count: int - 当前重试次数(1 到 max_retries)
  • over_maximum_retries: bool - 错误是否为关键错误

错误分类:

  • 可恢复错误over_maximum_retries=False):重试过程中发生的错误。系统会继续重试并可能自动解决这些问题。大多数情况下可以安全忽略。

  • 关键错误over_maximum_retries=True):所有重试尝试后仍然存在的错误。这些错误会出现在最终的 EPUB 文件中,需要进行调查。

进阶用法:

在翻译调试期间进行详细日志记录:

def handle_fill_error(event: FillFailedEvent):
    if event.over_maximum_retries:
        # 关键错误:影响最终输出
        print(f"❌ 关键错误: {event.error_message}")
    else:
        # 信息提示:系统正在重试
        print(f"⚠️  第 {event.retried_count} 次重试: {event.error_message}")

双 LLM 架构

使用不同优化参数的独立 LLM 实例分别处理翻译和 XML 结构填充:

# 创建两个具有不同温度参数的 LLM 实例
translation_llm = LLM(
    key="your-api-key",
    url="https://api.openai.com/v1",
    model="gpt-4",
    token_encoding="o200k_base",
    temperature=0.8,  # 较高温度用于创造性翻译
)

fill_llm = LLM(
    key="your-api-key",
    url="https://api.openai.com/v1",
    model="gpt-4",
    token_encoding="o200k_base",
    temperature=0.3,  # 较低温度用于结构保持
)

translate(
    source_path="source.epub",
    target_path="translated.epub",
    target_language=language.CHINESE,
    submit=SubmitKind.APPEND_BLOCK,
    translation_llm=translation_llm,
    fill_llm=fill_llm,
)

配置示例

OpenAI

llm = LLM(
    key="sk-...",
    url="https://api.openai.com/v1",
    model="gpt-4",
    token_encoding="o200k_base",
)

Azure OpenAI

llm = LLM(
    key="your-azure-key",
    url="https://your-resource.openai.azure.com/openai/deployments/your-deployment",
    model="gpt-4",
    token_encoding="o200k_base",
)

其他兼容 OpenAI 的服务

任何提供 OpenAI 兼容 API 的服务都可以使用:

llm = LLM(
    key="your-api-key",
    url="https://your-service.com/v1",
    model="your-model",
    token_encoding="o200k_base",  # 匹配您模型的编码方式
)

高级功能

自定义翻译提示词

提供特定的翻译指令:

translate(
    source_path="source.epub",
    target_path="translated.epub",
    target_language="Chinese",
    submit=SubmitKind.APPEND_BLOCK,
    llm=llm,
    user_prompt="使用正式语言并保留专业术语",
)

缓存用于进度恢复

启用缓存以在翻译失败后恢复进度:

llm = LLM(
    key="your-api-key",
    url="https://api.openai.com/v1",
    model="gpt-4",
    token_encoding="o200k_base",
    cache_path="./translation_cache",  # 翻译结果缓存在此
)

并发翻译

通过并发处理多个文本段落来加速翻译。使用 concurrency 参数控制并行运行的翻译任务数量:

translate(
    source_path="source.epub",
    target_path="translated.epub",
    target_language="Chinese",
    submit=SubmitKind.APPEND_BLOCK,
    llm=llm,
    concurrency=4,  # 同时处理 4 个段落
)

性能建议:

  • 建议从 concurrency=4 开始,根据 API 速率限制和系统资源进行调整
  • 更高的并发值可以显著减少大型书籍的翻译时间
  • 无论并发设置如何,翻译顺序都会被保留
  • 注意监控 API 提供商的速率限制,避免触发限流

线程安全:

当使用 concurrency > 1 时,请确保任何自定义回调函数(on_progresson_fill_failed)是线程安全的。内置回调函数默认是线程安全的。

Token 使用量监控

在翻译过程中跟踪 token 消耗,以监控 API 成本和用量:

from epub_translator import LLM, translate, language, SubmitKind

llm = LLM(
    key="your-api-key",
    url="https://api.openai.com/v1",
    model="gpt-4",
    token_encoding="o200k_base",
)

translate(
    source_path="source.epub",
    target_path="translated.epub",
    target_language=language.CHINESE,
    submit=SubmitKind.APPEND_BLOCK,
    llm=llm,
)

# 翻译后访问 token 统计信息
print(f"总 token 数: {llm.total_tokens}")
print(f"输入 token 数: {llm.input_tokens}")
print(f"输入缓存 token 数: {llm.input_cache_tokens}")
print(f"输出 token 数: {llm.output_tokens}")

可用的统计数据:

  • total_tokens - 使用的 token 总数(输入 + 输出)
  • input_tokens - 提示词/输入的 token 数量
  • input_cache_tokens - 缓存的输入 token 数量(使用 prompt caching 时)
  • output_tokens - 生成/完成的 token 数量

实时监控:

您也可以在翻译过程中实时监控 token 使用量:

from tqdm import tqdm
import time

with tqdm(total=100, desc="翻译中", unit="%") as pbar:
    last_progress = 0.0
    start_time = time.time()

    def on_progress(progress: float):
        nonlocal last_progress
        increment = (progress - last_progress) * 100
        pbar.update(increment)
        last_progress = progress

        # 在进度条中更新 token 统计
        pbar.set_postfix({
            'tokens': llm.total_tokens,
            'cost_est': f'${llm.total_tokens * 0.00001:.4f}'  # 根据您的定价估算成本
        })

    translate(
        source_path="source.epub",
        target_path="translated.epub",
        target_language=language.CHINESE,
        submit=SubmitKind.APPEND_BLOCK,
        llm=llm,
        on_progress=on_progress,
    )

    elapsed = time.time() - start_time
    print(f"\n翻译完成,耗时 {elapsed:.1f} 秒")
    print(f"使用的 token 总数: {llm.total_tokens:,}")
    print(f"平均 tokens/秒: {llm.total_tokens/elapsed:.1f}")

双 LLM Token 追踪:

当使用独立的 LLM 进行翻译和填充时,每个 LLM 都会跟踪自己的统计信息:

translation_llm = LLM(key="...", url="...", model="gpt-4", token_encoding="o200k_base")
fill_llm = LLM(key="...", url="...", model="gpt-4", token_encoding="o200k_base")

translate(
    source_path="source.epub",
    target_path="translated.epub",
    target_language=language.CHINESE,
    submit=SubmitKind.APPEND_BLOCK,
    translation_llm=translation_llm,
    fill_llm=fill_llm,
)

print(f"翻译 tokens: {translation_llm.total_tokens}")
print(f"填充 tokens: {fill_llm.total_tokens}")
print(f"总计: {translation_llm.total_tokens + fill_llm.total_tokens}")

注意: Token 统计数据是累积的,包含 LLM 实例发出的所有 API 调用。计数只会增加,并且在使用并发翻译时是线程安全的。

相关项目

  • PDF Craft:如果你的源文件是扫描版或图片型 PDF,可以先用 PDF Craft 转成 EPUB,再接入 EPUB Translator 做翻译。完整流程可参考这个演示视频
  • SpineDigest:如果你不只是想翻译,还想进一步获得整本书的结构化提炼,SpineDigest 可以基于 EPUB 生成摘要、章节拓扑和知识图谱。

贡献

欢迎贡献! 请随时提交 Pull Request。

许可证

本项目采用 MIT 许可证 - 详见 LICENSE 文件

支持