2026-05-10 20:25:48 +08:00
2026-05-10 22:23:14 +08:00
2026-04-12 17:19:14 +08:00
2026-04-18 23:52:15 +08:00
2026-04-18 23:52:15 +08:00

食谱工具(recipe_tool)

一款面向幼儿园食堂的食谱处理工具集,目前包含两大功能:

  1. 食谱翻译工具 —— 基于 AI 的食谱文档翻译:解析 Word 文档、智能翻译菜名、批量导出双语对照 Word
  2. 135编辑器转换器 —— 将幼儿园周食谱 .docx 一键转换可直接粘贴进 135编辑器 / 微信公众号排版器的 HTML

功能特性

食谱翻译工具

  • Word 文档解析:解析 .docx 格式的食谱文档,提取菜品信息
  • AI 智能翻译:支持 OpenAI / 智谱 GLM 等大模型 API,批量翻译菜品名称
  • 翻译词库管理:管理常用词组翻译对照表,命中词库免调 API
  • 多格式导出:导出双语对照的 Word 文档
  • 导出设置:自定义未翻译文本颜色、页面方向、第二页表头等

135编辑器转换器(/editor135)

  • 一键转换:上传周食谱 .docx → 自动解析「星期 × 餐次(早餐/早点/午餐/体弱儿餐/午点)」中英菜名 → 填充进 135 模板生成 HTML
  • 三视图展示:左侧源代码(可复制/下载)与解析结果(按星期折叠面板),右侧 375px 移动端宽度实时预览(与公众号阅读宽度一致,内部滚动、吸顶)
  • 缺失星期自动删除:docx 里缺哪天(含周六/周日、间隔天)就整段移除该天内容,导出的 HTML 不包含;支持「周一/礼拜天」等别名归一化
  • 逐条回读校验:填充后重新解析输出 HTML,与原始数据逐条比对,mismatch 必须为空才可信
  • 样式零污染:填充只改文本节点,不改样式与结构;构建前后做样式/图片/section 数快照对比
  • 微信图片代理:预览时微信 CDN(mmbiz.qpic.cn)图片走本地代理转发,解决「此图片来自微信公众平台」防盗链占位图;复制/下载的 HTML 仍保持原始 URL,不影响公众号内使用
  • 智能容错:裸文本菜名自动套用模板样式块、条目数与模板不符时自动克隆补足/删除多余

技术栈

  • 框架:Next.js 16(App Router, Turbopack)
  • 语言:TypeScript(strict)
  • 运行时:Node.js ≥ 22(jsdom 30 依赖新 Node API)
  • 包管理:pnpm ≥ 11(配置全部位于 pnpm-workspace.yaml)
  • 样式:Tailwind CSS 4 + shadcn/ui + radix-ui
  • 文档解析:mammoth(docx → HTML)、cheerio、jsdom(模板填充)
  • 文档生成:docx
  • 数据库:MySQL 8.0(mysql2)
  • AI:OpenAI SDK / 智谱 GLM

项目结构

├── app/                        # Next.js App Router
│   ├── api/                    # API 路由
│   │   ├── ai/                 # AI 翻译接口
│   │   ├── config/             # 配置管理接口
│   │   ├── editor135/
│   │   │   ├── render/         # 135转换:解析docx并填充模板
│   │   │   └── img/            # 微信CDN图片代理(仅允许 *.qpic.cn)
│   │   ├── recipe/             # 食谱解析接口
│   │   ├── translate/          # 翻译接口
│   │   ├── update/             # 应用自更新(check/execute)
│   │   └── words/              # 词库管理接口
│   ├── editor135/              # 135转换器页面
│   ├── settings/               # 设置页面
│   │   ├── ai/                 # AI 配置
│   │   ├── export/             # 导出设置
│   │   ├── translation/        # 翻译词库
│   │   └── update/             # 应用更新
│   └── page.tsx                # 首页(功能导航)
├── components/                 # React 组件
├── lib/
│   ├── ai-translate.ts         # AI 翻译
│   ├── config.ts               # 配置管理
│   ├── database.ts             # 数据库连接
│   ├── editor135-core.ts       # 135转换核心库(解析/填充/缺失天删除/校验)
│   └── update.ts               # 自更新逻辑
├── public/
│   └── template135.html        # 135模板(运行时读取,替换此文件即可换模板)
├── scripts/
│   └── test-remove-days.ts     # 135转换核心库回归测试(6场景)
├── config.json                 # 配置文件(首次启动由环境变量初始化)
├── Dockerfile                  # Docker 构建(node:22-alpine 双阶段)
└── docker-compose.yml          # Docker 编排

快速开始

环境要求

  • Node.js 22+(jsdom 30 要求)
  • pnpm 11+(构建脚本批准配置在 pnpm-workspace.yaml)
  • MySQL 8.0(翻译功能需要)

本地开发

# 1. 安装依赖
pnpm install

# 2. 配置环境变量
#    参考下方「环境变量」表格创建 .env,或从已有部署复制

# 3. 启动开发服务器
pnpm dev

访问 http://localhost:3000 ,翻译工具在首页,135转换器在 /editor135 或首页右上角「135编辑器转换」入口。

生产构建

pnpm build
pnpm start

Docker 部署

# 1. 配置环境变量
cp .env.docker .env   # 或手动创建,见下方表格

# 2. 构建并启动
docker-compose up -d

# 3. 查看日志
docker-compose logs -f app

配置说明

配置文件

所有配置存储在 config.json 中,可通过设置页面修改(首次启动由环境变量初始化,之后以 config.json 为准):

配置项 说明
db 数据库连接配置(host / port / user / password / database)
ai AI 翻译 API 配置(apiKey / baseUrl / model)
export 导出文档格式配置(untranslatedColor / orientation / secondPageHeader)

环境变量

变量名 说明 默认值
DB_HOST 数据库地址 127.0.0.1
DB_PORT 数据库端口 3306
DB_USER 数据库用户名 root
DB_PASSWORD 数据库密码 -
DB_NAME 数据库名 recipe_tools
AI_API_KEY AI API Key -
AI_BASE_URL API 地址 https://api.openai.com/v1
AI_MODEL 模型名称 gpt-3.5-turbo
EXPORT_UNTRANSLATED_COLOR 未翻译文本颜色 #FF0000
EXPORT_ORIENTATION 页面方向 landscape
ONEDEV_ACCESS_TOKEN 自更新拉取镜像的令牌 -
REGISTRY_IMAGE 更新镜像仓库地址 -

API 接口

翻译工具

接口 方法 说明
/api/config GET/POST 获取/保存配置
/api/recipe POST 解析食谱文档
/api/translate POST 批量翻译
/api/ai/translate GET 单词翻译测试
/api/words GET/POST 词库列表/添加
/api/words/[id] PATCH/DELETE 编辑/删除词条

135编辑器转换器

接口 方法 说明
/api/editor135/render POST 上传 .docx(multipart file 字段),返回 { fileName, summary, recipe, html, report }
/api/editor135/img GET 微信图片代理:?u=<URL编码的图片地址>,仅允许 *.qpic.cn 域名

render 返回的 report 结构:

{
  "filled": [       // 每个餐次的填充明细
    { "day": "星期一", "meal": "早餐", "replaced": 4, "added": 0, "removed": 0, "oldCount": 4, "newCount": 4 }
  ],
  "warnings": [],              // 非致命提示(如模板中无该餐次)
  "repaired": [],              // 裸文本菜名自动套样式的修复记录
  "mismatch": [],              // 回读校验差异,正常必须为空数组
  "removedDays": ["星期五"],   // docx 缺失、已从输出整段删除的星期
  "verification": {            // 构建前后快照对比
    "stylesAdded": 0, "stylesRemoved": 0,   // 样式变化数,正常为 0
    "imgsUnchanged": true,                  // 图片是否未被改动
    "sections": "570 -> 570", "elements": "1502 -> 1242"
  }
}

135编辑器转换器工作原理

  1. 解析:mammoth 将 docx 转为 HTML,逐叶子节点扫描,识别星期标题(支持 周一/礼拜一 等别名归一化)、餐次标题、中文菜名与紧跟的英文菜名,按「星期 → 餐次 → 条目」收集
  2. 删除缺失天:对比 docx 与模板中出现的星期,缺失的天用「逐节点精确区间删除」从模板 DOM 移除(从该天标题节点删到下一现存天标题之前;最后一天以「三审三校/温馨提示」为尾界)——算法处理了相邻天共用容器、深层嵌套等结构,不会误删保留天
  3. 填充:就地替换文本节点(文本未变不触碰),条目数不符时以模板最后一条为锚点克隆补足或从后往前删除多余
  4. 校验:重新收集输出 DOM 与原始数据逐条比对(mismatch),并对比构建前后的样式/图片/元素快照(verification)
  5. 输出:序列化 HTML 返回,可直接粘贴进 135编辑器 / 公众号后台

更换模板

替换 public/template135.html 即可。模板需包含:星期标题(星期一~星期日文本)、餐次标题(早餐/早点/午餐/体弱儿餐/午点)、以及至少一组「中文菜名块 + 紧邻的英文菜名块」作为克隆锚点。

运行测试

# Node 22+ 直接跑 TS(无需编译)
node --experimental-strip-types scripts/test-remove-days.ts

测试覆盖 6 个场景:间隔天(一/三/五)、含周末、仅周末、中间连续缺、条数增删路径、完整周回归。

Docker 构建注意事项

  • 基础镜像为 node:22-alpine(jsdom 30 需 Node ≥ 22,builder 与 runner 两个 stage 都要用 22)
  • pnpm 11 的构建脚本批准配置在 pnpm-workspace.yaml 的 allowBuilds,该文件必须在 pnpm install 之前 COPY 进镜像
  • pnpm-workspace.yaml 中已放行 msw / sharp / unrs-resolver 的构建脚本(pnpm 11 在 CI 下未批准会直接报 ERR_PNPM_IGNORED_BUILDS)

自更新机制

部署后可通过设置页「应用更新」拉取镜像仓库新版本:/api/update/check 检查、/api/update/execute 执行 docker pull 并重启容器(需要挂载 docker.sock 及 REGISTRY_IMAGE / ONEDEV_ACCESS_TOKEN 配置)。

License

MIT

S
Description
食谱翻译工具 | 一款基于 AI 的食谱文档翻译工具,支持解析 Word 文档、智能翻译、批量导出。
Readme 396 KiB
Languages
HTML 53.6%
TypeScript 44.3%
CSS 1%
Shell 0.5%
Dockerfile 0.4%
Other 0.2%