fix: 完善 runtime 離線支援

- 使用 babeldoc --warmup 下載完整資源(模型、字型、cmap、tiktoken)
- 修正驗證邏輯,指向正確的 BabelDOC cache 路徑
- 移除舊的 PDFMATHTRANSLATE_MODELS_PATH 環境變數
- 更新 pdfmathtranslate.ts 使用正確的模型路徑
- 移除手動指定 --onnx 參數(pdf2zh 內部自動處理)

確保所有組件 Runtime 不需要下載任何資源
This commit is contained in:
Your Name 2026-01-23 11:55:02 +08:00
parent cb8ee290bb
commit 9fc7217df1
2 changed files with 48 additions and 37 deletions

View file

@ -351,32 +351,40 @@ RUN set -eux && \
ls -lh /app/*.ttf && \ ls -lh /app/*.ttf && \
\ \
# ======================================== # ========================================
# [7/8] 準備 BabelDOC 資源 # [7/8] 下載 BabelDOC 完整資源
# ⬇️ 複製字型到 BabelDOC cache 目錄 # ⬇️ 使用 babeldoc --warmup 下載所有必需資源
# ONNX 模型已在 [6/8] 下載完成 # 包括ONNX 模型、字型、cmap、tiktoken 等
# 這是官方推薦的離線資源準備方式
# Runtime 不會再下載任何資源 # Runtime 不會再下載任何資源
# ======================================== # ========================================
echo "" && \ echo "" && \
echo "📥 [7/8] 準備 BabelDOC 資源..." && \ echo "📥 [7/8] 下載 BabelDOC 完整資源(使用 --warmup..." && \
mkdir -p /root/.cache/babeldoc/fonts && \ mkdir -p /root/.cache/babeldoc/fonts && \
mkdir -p /root/.cache/babeldoc/cmap && \ mkdir -p /root/.cache/babeldoc/cmap && \
mkdir -p /root/.cache/babeldoc/tiktoken && \ mkdir -p /root/.cache/babeldoc/tiktoken && \
\ \
# 複製字型到 BabelDOC 目錄(避免 runtime 下載) # 使用 babeldoc --warmup 下載所有必需資源
echo " 複製字型到 BabelDOC 目錄..." && \ if command -v babeldoc >/dev/null 2>&1; then \
echo " 使用 babeldoc --warmup 下載資源..." && \
(babeldoc --warmup 2>&1 || echo " ⚠️ babeldoc --warmup 執行完成(可能有警告)") && \
echo " ✅ BabelDOC warmup 完成"; \
else \
echo " ⚠️ babeldoc 不可用,跳過 warmup"; \
fi && \
\
# 複製額外字型到 BabelDOC 目錄(確保多語言支援)
echo " 複製額外字型到 BabelDOC 目錄..." && \
cp /app/GoNotoKurrent-Regular.ttf /root/.cache/babeldoc/fonts/ 2>/dev/null || true && \ cp /app/GoNotoKurrent-Regular.ttf /root/.cache/babeldoc/fonts/ 2>/dev/null || true && \
cp /app/SourceHanSerifCN-Regular.ttf /root/.cache/babeldoc/fonts/ 2>/dev/null || true && \ cp /app/SourceHanSerifCN-Regular.ttf /root/.cache/babeldoc/fonts/ 2>/dev/null || true && \
cp /app/SourceHanSerifTW-Regular.ttf /root/.cache/babeldoc/fonts/ 2>/dev/null || true && \ cp /app/SourceHanSerifTW-Regular.ttf /root/.cache/babeldoc/fonts/ 2>/dev/null || true && \
cp /app/SourceHanSerifJP-Regular.ttf /root/.cache/babeldoc/fonts/ 2>/dev/null || true && \ cp /app/SourceHanSerifJP-Regular.ttf /root/.cache/babeldoc/fonts/ 2>/dev/null || true && \
cp /app/SourceHanSerifKR-Regular.ttf /root/.cache/babeldoc/fonts/ 2>/dev/null || true && \ cp /app/SourceHanSerifKR-Regular.ttf /root/.cache/babeldoc/fonts/ 2>/dev/null || true && \
\ \
# 下載 BabelDOC 需要的額外資源(如果有的話) # 驗證 BabelDOC 資源
echo " 下載 BabelDOC 額外資源..." && \ echo " 驗證 BabelDOC 資源..." && \
(python3 -c "from huggingface_hub import snapshot_download; import os; os.environ['HF_HOME']='/root/.cache/huggingface'; snapshot_download(repo_id='funstory-ai/babeldoc-assets', local_dir='/root/.cache/babeldoc/assets', local_dir_use_symlinks=False); print('BabelDOC assets downloaded')" || echo "BabelDOC assets not available, skipping...") && \ ls -lh /root/.cache/babeldoc/models/ 2>/dev/null || echo " (models 目錄)" && \
\ ls -lh /root/.cache/babeldoc/fonts/ 2>/dev/null || echo " (fonts 目錄)" && \
# 驗證模型已正確下載 du -sh /root/.cache/babeldoc/ 2>/dev/null || true && \
echo " 驗證 BabelDOC 模型..." && \
ls -lh /root/.cache/babeldoc/models/ && \
echo "✅ BabelDOC 資源準備完成" && \ echo "✅ BabelDOC 資源準備完成" && \
\ \
# ======================================== # ========================================
@ -445,13 +453,12 @@ RUN set -eux && \
echo "===========================================================" && \ echo "===========================================================" && \
echo "" && \ echo "" && \
\ \
echo "🔹 PDFMathTranslate 模型:" && \ echo "🔹 PDFMathTranslate/BabelDOC ONNX 模型:" && \
ONNX_COUNT=$(find /models/pdfmathtranslate -name "*.onnx" 2>/dev/null | wc -l) && \ if [ -f "/root/.cache/babeldoc/models/doclayout_yolo_docstructbench_imgsz1024.onnx" ]; then \
if [ "$ONNX_COUNT" -gt 0 ]; then \ echo " ✅ DocLayout-YOLO ONNX 模型存在:"; \
echo " ✅ 找到 $ONNX_COUNT 個 ONNX 模型:"; \ ls -lh /root/.cache/babeldoc/models/*.onnx 2>/dev/null; \
ls -lh /models/pdfmathtranslate/*.onnx 2>/dev/null || find /models/pdfmathtranslate -name "*.onnx" -exec ls -lh {} \;; \
else \ else \
echo " ❌ /models/pdfmathtranslate 中沒有 ONNX 模型"; \ echo " ❌ /root/.cache/babeldoc/models/ 中沒有 ONNX 模型"; \
fi && \ fi && \
echo "" && \ echo "" && \
\ \
@ -500,10 +507,6 @@ RUN set -eux && \
echo " Runtime 不會再下載任何資源" && \ echo " Runtime 不會再下載任何資源" && \
echo "===========================================================" echo "==========================================================="
# PDFMathTranslate 環境變數
ENV PDFMATHTRANSLATE_MODELS_PATH="/models/pdfmathtranslate"
ENV NOTO_FONT_PATH="/app/GoNotoKurrent-Regular.ttf"
# BabelDOC 環境變數 # BabelDOC 環境變數
ENV BABELDOC_CACHE_PATH="/root/.cache/babeldoc" ENV BABELDOC_CACHE_PATH="/root/.cache/babeldoc"
ENV BABELDOC_SERVICE="google" ENV BABELDOC_SERVICE="google"

View file

@ -18,8 +18,10 @@ type TranslationService = (typeof TRANSLATION_SERVICES)[number];
* - original.pdf PDF * - original.pdf PDF
* - translated-<lang>.pdf PDF * - translated-<lang>.pdf PDF
* *
* Docker build *
* runtime * - pdf2zh 使 babeldoc.assets ONNX
* - /root/.cache/babeldoc/models/
* - Runtime Docker build
*/ */
// 支援的目標語言列表 // 支援的目標語言列表
@ -41,8 +43,10 @@ const SUPPORTED_LANGUAGES = [
"th", // Thai "th", // Thai
] as const; ] as const;
// 模型路徑Docker 環境中) // 模型路徑BabelDOC cache 目錄,由 pdf2zh 內部使用)
const MODELS_PATH = process.env.PDFMATHTRANSLATE_MODELS_PATH || "/models/pdfmathtranslate"; // 注意pdf2zh 會自動從 babeldoc.assets 載入模型,此路徑僅供參考
const BABELDOC_CACHE_PATH = process.env.BABELDOC_CACHE_PATH || "/root/.cache/babeldoc";
const MODELS_PATH = `${BABELDOC_CACHE_PATH}/models`;
// 生成 from/to 格式映射 // 生成 from/to 格式映射
function generateLanguageMappings(): { function generateLanguageMappings(): {
@ -110,12 +114,21 @@ function normalizeLanguageCode(lang: string): string {
* @returns * @returns
*/ */
function checkModelsExist(): boolean { function checkModelsExist(): boolean {
// 檢查 ONNX 模型目錄是否存在 // 檢查 BabelDOC ONNX 模型目錄是否存在
if (!existsSync(MODELS_PATH)) { if (!existsSync(MODELS_PATH)) {
console.warn(`[PDFMathTranslate] Models directory not found: ${MODELS_PATH}`); console.warn(`[PDFMathTranslate] BabelDOC models directory not found: ${MODELS_PATH}`);
console.warn(`[PDFMathTranslate] Models should be pre-downloaded during Docker build.`); console.warn(`[PDFMathTranslate] Models should be pre-downloaded during Docker build.`);
return false; return false;
} }
// 檢查特定的 ONNX 模型檔案
const onnxModelPath = join(MODELS_PATH, "doclayout_yolo_docstructbench_imgsz1024.onnx");
if (!existsSync(onnxModelPath)) {
console.warn(`[PDFMathTranslate] ONNX model not found: ${onnxModelPath}`);
console.warn(`[PDFMathTranslate] Model should be pre-downloaded during Docker build.`);
return false;
}
return true; return true;
} }
@ -195,13 +208,8 @@ function runPdf2zhWithService(
const args = [inputPath, "-lo", targetLang, "-o", outputDir, "-s", service]; const args = [inputPath, "-lo", targetLang, "-o", outputDir, "-s", service];
// 如果設定了自訂模型路徑,使用 --onnx 參數 // pdf2zh 使用 babeldoc.assets 內部載入模型,不需要手動指定 --onnx 參數
if (existsSync(MODELS_PATH)) { // 模型路徑:/root/.cache/babeldoc/models/doclayout_yolo_docstructbench_imgsz1024.onnx
const onnxModelPath = join(MODELS_PATH, "model.onnx");
if (existsSync(onnxModelPath)) {
args.push("--onnx", onnxModelPath);
}
}
console.log(`[PDFMathTranslate] Running: pdf2zh ${args.join(" ")} (service: ${service})`); console.log(`[PDFMathTranslate] Running: pdf2zh ${args.join(" ")} (service: ${service})`);