@thor123141245r/ai-translate 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agentdocs/code-changes/2026-01-22/AI/347/277/273/350/257/221/345/231/250TS/345/256/236/347/216/260-/345/256/236/347/216/260.md +22 -0
- package/.agentdocs/code-changes/2026-01-23/CLI/345/210/206/345/217/221-npx/345/256/236/347/216/260.md +18 -0
- package/.agentdocs/code-changes/2026-01-23/sora-watermask-remover-/345/233/275/351/231/205/345/214/226/347/277/273/350/257/221-/345/256/236/347/216/260.md +37 -0
- package/.agentdocs/code-changes/2026-01-23//351/205/215/347/275/256/350/257/273/345/217/226-/347/216/257/345/242/203/345/217/230/351/207/217/344/274/230/345/205/210-/345/256/236/347/216/260.md +22 -0
- package/.agentdocs/plans/2026-01-22/AI/347/277/273/350/257/221/345/231/250TS/345/256/236/347/216/260-/344/274/230/345/214/226/346/226/271/346/241/210.md +67 -0
- package/.agentdocs/plans/2026-01-23/CLI/345/210/206/345/217/221-npx/346/226/271/346/241/210.md +60 -0
- package/.agentdocs/plans/2026-01-23/sora-watermask-remover-/345/233/275/351/231/205/345/214/226/347/277/273/350/257/221-/344/274/230/345/214/226/346/226/271/346/241/210.md +51 -0
- package/.agentdocs/plans/2026-01-23//351/205/215/347/275/256/350/257/273/345/217/226-/347/216/257/345/242/203/345/217/230/351/207/217/344/274/230/345/205/210-/344/274/230/345/214/226/346/226/271/346/241/210.md +80 -0
- package/README.md +120 -0
- package/SKILL.md +103 -0
- package/dist/asyncTransform.d.ts +7 -0
- package/dist/asyncTransform.d.ts.map +1 -0
- package/dist/asyncTransform.js +23 -0
- package/dist/asyncTransform.js.map +1 -0
- package/dist/bin/ai-translate.d.ts +3 -0
- package/dist/bin/ai-translate.d.ts.map +1 -0
- package/dist/bin/ai-translate.js +4 -0
- package/dist/bin/ai-translate.js.map +1 -0
- package/dist/cli.d.ts +7 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +259 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +3 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +3 -0
- package/dist/logger.js.map +1 -0
- package/dist/model.d.ts +29 -0
- package/dist/model.d.ts.map +1 -0
- package/dist/model.js +103 -0
- package/dist/model.js.map +1 -0
- package/dist/prompt.d.ts +12 -0
- package/dist/prompt.d.ts.map +1 -0
- package/dist/prompt.js +51 -0
- package/dist/prompt.js.map +1 -0
- package/dist/split.d.ts +27 -0
- package/dist/split.d.ts.map +1 -0
- package/dist/split.js +87 -0
- package/dist/split.js.map +1 -0
- package/dist/utils.d.ts +7 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +14 -0
- package/dist/utils.js.map +1 -0
- package/package.json +42 -0
- package/src/asyncTransform.ts +31 -0
- package/src/bin/ai-translate.ts +5 -0
- package/src/cli.ts +313 -0
- package/src/index.ts +9 -0
- package/src/logger.ts +3 -0
- package/src/model.ts +139 -0
- package/src/prompt.ts +71 -0
- package/src/split.ts +111 -0
- package/src/utils.ts +15 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
作者:Codex|创建时间:2026-01-22 23:35
|
|
2
|
+
|
|
3
|
+
# 变更概述
|
|
4
|
+
基于方案实现 TypeScript 版本的 AI 翻译器:按官方库结构复刻核心流程,补齐模块分层、CLI 入口、配置与日志策略,并提供最小验证脚本与中文说明。
|
|
5
|
+
|
|
6
|
+
# 变更清单
|
|
7
|
+
- [x] 引入并对齐 ai-translate 的核心 API 与流程
|
|
8
|
+
- [x] 新增 TypeScript 目录结构与模块实现
|
|
9
|
+
- [x] 新增 CLI 或脚本入口
|
|
10
|
+
- [x] 配置与日志策略落地
|
|
11
|
+
- [x] 中文使用文档更新
|
|
12
|
+
- [x] 最小测试或验证脚本补齐
|
|
13
|
+
|
|
14
|
+
# 关键设计对齐
|
|
15
|
+
- 模块分层:配置解析层、翻译执行层、文件读写层、日志层
|
|
16
|
+
- 复用优先:最大限度遵循官方库结构与命名
|
|
17
|
+
- 日志策略:开发环境整对象打印,生产环境精简敏感信息
|
|
18
|
+
|
|
19
|
+
# 待确认事项状态
|
|
20
|
+
- 是否要求完全对齐官方库的所有导出与命令参数:未确认
|
|
21
|
+
- 是否需要发布为独立 npm 包:未确认
|
|
22
|
+
- 是否要兼容现有 Python 脚本的输入格式:未确认
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
作者:Codex|创建时间:2026-01-23 04:18
|
|
2
|
+
|
|
3
|
+
# 变更概述
|
|
4
|
+
为 CLI 增加可通过 npx/pnpx 直接执行的分发配置,更新包名与发布设置,并补充中文使用说明。
|
|
5
|
+
|
|
6
|
+
# 变更清单
|
|
7
|
+
- [x] package.json 发布与 bin 配置调整
|
|
8
|
+
- [x] README 增加 npx/pnpx 使用说明
|
|
9
|
+
- [x] 本地构建与验证
|
|
10
|
+
|
|
11
|
+
# 关键设计对齐
|
|
12
|
+
- bin 入口保持 ai-translate
|
|
13
|
+
- npm 包名为 @thor123141245r/ai-translate
|
|
14
|
+
- 发布为 public
|
|
15
|
+
|
|
16
|
+
# 待确认事项状态
|
|
17
|
+
- 采用哪个 npm 包名:@thor123141245r/ai-translate(已确认)
|
|
18
|
+
- 是否允许发布到 npm:允许,public(已确认)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
作者: Codex | 创建时间: 2026-01-23 21:35
|
|
2
|
+
|
|
3
|
+
# sora-watermask-remover 国际化翻译实现
|
|
4
|
+
|
|
5
|
+
## 变更概述
|
|
6
|
+
- 使用脚本 `sentence_json_translator.py` 基于 `en.json` 翻译并覆盖目录内全部语言文件
|
|
7
|
+
- 保持受保护关键词 `sora watermask remover` 原样
|
|
8
|
+
- 保留专有名词与产品名:Sora、Sora2 Cloud、OpenAI Pro、HD、15s
|
|
9
|
+
|
|
10
|
+
## 执行方式
|
|
11
|
+
- 脚本位置:`/Users/thor/.codex/skills/i18n-copywriter/scripts/sentence_json_translator.py`
|
|
12
|
+
- 目标目录:`/Users/thor/Github/sora2.cloud-main/src/i18n/pages/sora-watermask-remover`
|
|
13
|
+
- 运行参数要点:
|
|
14
|
+
- `--overwrite` 全量覆盖
|
|
15
|
+
- `--protected-terms "sora watermask remover,Sora,Sora2 Cloud,OpenAI Pro,HD,15s"`
|
|
16
|
+
- 由于接口偶发 SSL 握手失败,启用 `CONTENT_LOCALIZE_INSECURE=1` 并提高重试次数
|
|
17
|
+
|
|
18
|
+
## 涉及文件
|
|
19
|
+
- `/Users/thor/Github/sora2.cloud-main/src/i18n/pages/sora-watermask-remover/ar.json`
|
|
20
|
+
- `/Users/thor/Github/sora2.cloud-main/src/i18n/pages/sora-watermask-remover/de.json`
|
|
21
|
+
- `/Users/thor/Github/sora2.cloud-main/src/i18n/pages/sora-watermask-remover/es.json`
|
|
22
|
+
- `/Users/thor/Github/sora2.cloud-main/src/i18n/pages/sora-watermask-remover/fr.json`
|
|
23
|
+
- `/Users/thor/Github/sora2.cloud-main/src/i18n/pages/sora-watermask-remover/he.json`
|
|
24
|
+
- `/Users/thor/Github/sora2.cloud-main/src/i18n/pages/sora-watermask-remover/hi.json`
|
|
25
|
+
- `/Users/thor/Github/sora2.cloud-main/src/i18n/pages/sora-watermask-remover/id.json`
|
|
26
|
+
- `/Users/thor/Github/sora2.cloud-main/src/i18n/pages/sora-watermask-remover/ja.json`
|
|
27
|
+
- `/Users/thor/Github/sora2.cloud-main/src/i18n/pages/sora-watermask-remover/km.json`
|
|
28
|
+
- `/Users/thor/Github/sora2.cloud-main/src/i18n/pages/sora-watermask-remover/ru.json`
|
|
29
|
+
- `/Users/thor/Github/sora2.cloud-main/src/i18n/pages/sora-watermask-remover/th.json`
|
|
30
|
+
- `/Users/thor/Github/sora2.cloud-main/src/i18n/pages/sora-watermask-remover/zh.json`
|
|
31
|
+
|
|
32
|
+
## 验证
|
|
33
|
+
- JSON 解析检查通过
|
|
34
|
+
- key 集合与 `en.json` 完全一致
|
|
35
|
+
|
|
36
|
+
## 备注
|
|
37
|
+
- 本次翻译为脚本输出结果,如需人工润色可在此基础上微调
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
作者:Codex|创建时间:2026-01-23 21:06
|
|
2
|
+
|
|
3
|
+
# 实现说明
|
|
4
|
+
- 新增运行时配置解析 让 apiKey 与 baseUrl 优先取环境变量
|
|
5
|
+
- 调整模型工厂 避免空 apiKey 覆盖 SDK 默认环境变量读取
|
|
6
|
+
- README 增补环境变量优先级与变量名说明
|
|
7
|
+
|
|
8
|
+
# 变更清单
|
|
9
|
+
- src/cli.ts
|
|
10
|
+
- 新增 baseUrl schema
|
|
11
|
+
- 新增 resolveRuntimeConfig 处理环境变量优先级
|
|
12
|
+
- src/model.ts
|
|
13
|
+
- apiKey baseUrl 仅在有效值时注入
|
|
14
|
+
- openai deepseek 使用 configuration baseURL
|
|
15
|
+
- ollama 使用 baseUrl
|
|
16
|
+
- README.md
|
|
17
|
+
- 增加环境变量优先级与变量列表
|
|
18
|
+
|
|
19
|
+
# 自测要点
|
|
20
|
+
- 设置环境变量后 即使配置文件不同仍以环境变量为准
|
|
21
|
+
- 未设置环境变量时 使用配置文件
|
|
22
|
+
- 不设置 apiKey 时 SDK 自动读取自身环境变量
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
作者:Codex|创建时间:2026-01-22 23:30
|
|
2
|
+
|
|
3
|
+
# 背景
|
|
4
|
+
当前项目只有 Python 脚本实现。需要参考 `ai-translate` 的源码,在本仓库实现一套 TypeScript 版本,保证功能对齐与可复用。
|
|
5
|
+
|
|
6
|
+
# 目标
|
|
7
|
+
- 基于官方库源码,实现等价的 TypeScript 模块与对外 API
|
|
8
|
+
- 保持结构清晰可维护,避免超 500 行文件
|
|
9
|
+
- 形成可执行的本地脚本与最小测试覆盖
|
|
10
|
+
|
|
11
|
+
# 范围
|
|
12
|
+
- 新增 TypeScript 实现与必要的运行脚本
|
|
13
|
+
- 新增或更新配置与文档
|
|
14
|
+
- 不改动数据库迁移文件
|
|
15
|
+
|
|
16
|
+
# 方案概述
|
|
17
|
+
以“标准化与生态复用”为优先策略:先安装并审阅 `ai-translate` 源码,梳理其导出接口与核心流程,再在本仓库实现等价模块与 CLI 或脚本入口,确保行为与输入输出一致。
|
|
18
|
+
|
|
19
|
+
```mermaid
|
|
20
|
+
flowchart TD
|
|
21
|
+
A[安装依赖] --> B[读取源码]
|
|
22
|
+
B --> C[整理接口]
|
|
23
|
+
C --> D[设计模块]
|
|
24
|
+
D --> E[实现功能]
|
|
25
|
+
E --> F[编写测试]
|
|
26
|
+
F --> G[更新文档]
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
# 关键设计
|
|
30
|
+
- 模块分层:配置解析层、翻译执行层、文件读写层、日志层
|
|
31
|
+
- 复用策略:最大限度遵循官方库结构与命名,避免自研偏离
|
|
32
|
+
- 日志策略:开发环境整对象打印,生产环境精简敏感信息
|
|
33
|
+
|
|
34
|
+
```mermaid
|
|
35
|
+
flowchart LR
|
|
36
|
+
A[输入源文件] --> B[解析配置]
|
|
37
|
+
B --> C[调用翻译引擎]
|
|
38
|
+
C --> D[写入目标文件]
|
|
39
|
+
D --> E[输出结果]
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
# 实施步骤
|
|
43
|
+
1. 安装 `ai-translate` 并定位源码入口
|
|
44
|
+
2. 梳理导出 API 与关键执行流程
|
|
45
|
+
3. 设计 TypeScript 目录结构与模块边界
|
|
46
|
+
4. 实现核心功能并补齐类型定义
|
|
47
|
+
5. 编写最小可用测试或验证脚本
|
|
48
|
+
6. 补充中文说明文档与使用示例
|
|
49
|
+
|
|
50
|
+
# 验收标准
|
|
51
|
+
- 与官方库的核心功能等价,输入输出一致
|
|
52
|
+
- 新增 ts 文件均小于 500 行
|
|
53
|
+
- 可以通过脚本完成一次实际翻译流程
|
|
54
|
+
- 中文文档完整可读
|
|
55
|
+
|
|
56
|
+
# 需求清单
|
|
57
|
+
- [ ] 安装并分析 `ai-translate` 源码
|
|
58
|
+
- [ ] TypeScript 版本的核心翻译功能
|
|
59
|
+
- [ ] CLI 或脚本入口
|
|
60
|
+
- [ ] 配置与日志策略
|
|
61
|
+
- [ ] 中文使用文档
|
|
62
|
+
- [ ] 基础测试或验证脚本
|
|
63
|
+
|
|
64
|
+
# 待确认事项
|
|
65
|
+
- 是否要求完全对齐官方库的所有导出与命令参数 (需用户确认)
|
|
66
|
+
- 是否需要发布为独立 npm 包 (需用户确认)
|
|
67
|
+
- 是否要兼容现有 Python 脚本的输入格式 (需用户确认)
|
package/.agentdocs/plans/2026-01-23/CLI/345/210/206/345/217/221-npx/346/226/271/346/241/210.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
作者:Codex|创建时间:2026-01-23 04:10
|
|
2
|
+
|
|
3
|
+
# 背景
|
|
4
|
+
当前仓库已具备 `ai-translate` CLI,但还未完成可通过 `npx/pnpx` 直接执行的分发形态。
|
|
5
|
+
|
|
6
|
+
# 目标
|
|
7
|
+
- 让用户通过 `npx` 或 `pnpx` 直接执行 `ai-translate` CLI
|
|
8
|
+
- 保持单人团队可维护规模
|
|
9
|
+
- 维持现有接口与配置逻辑
|
|
10
|
+
|
|
11
|
+
# 范围
|
|
12
|
+
- package.json 配置与发布相关设置
|
|
13
|
+
- 文档更新
|
|
14
|
+
- 不涉及迁移文件
|
|
15
|
+
|
|
16
|
+
# 方案概述
|
|
17
|
+
1) 规范包名与 bin 输出,使 `npx <包名>` 直接可用
|
|
18
|
+
2) 调整发布配置,避免 private 阻断
|
|
19
|
+
3) 在 README 增加 `npx/pnpx` 使用说明
|
|
20
|
+
|
|
21
|
+
```mermaid
|
|
22
|
+
flowchart TD
|
|
23
|
+
A[确认包名] --> B[配置 bin]
|
|
24
|
+
B --> C[取消私有设置]
|
|
25
|
+
C --> D[更新文档]
|
|
26
|
+
D --> E[本地验证]
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
# 关键设计
|
|
30
|
+
- bin 入口保持 `ai-translate` 命令
|
|
31
|
+
- `npx` 触发时使用包名执行(需 npm 包名可用)
|
|
32
|
+
- `pnpx` 行为与 `npx` 一致
|
|
33
|
+
|
|
34
|
+
```mermaid
|
|
35
|
+
flowchart LR
|
|
36
|
+
A[用户执行 npx] --> B[下载包]
|
|
37
|
+
B --> C[执行 bin]
|
|
38
|
+
C --> D[调用 CLI]
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
# 实施步骤
|
|
42
|
+
1. 确认 npm 包名与发布范围
|
|
43
|
+
2. 调整 package.json: name、private、bin、exports
|
|
44
|
+
3. README 添加 npx 与 pnpx 的示例
|
|
45
|
+
4. 本地 build 与 npx 验证
|
|
46
|
+
|
|
47
|
+
# 验收标准
|
|
48
|
+
- `npx <包名>` 可直接执行
|
|
49
|
+
- `pnpx <包名>` 可直接执行
|
|
50
|
+
- README 有中文使用说明
|
|
51
|
+
|
|
52
|
+
# 需求清单
|
|
53
|
+
- [ ] 确认包名与是否发布
|
|
54
|
+
- [ ] 完成 package.json 配置
|
|
55
|
+
- [ ] README 更新
|
|
56
|
+
- [ ] 本地验证
|
|
57
|
+
|
|
58
|
+
# 待确认事项
|
|
59
|
+
- 采用哪个 npm 包名 (需用户确认)
|
|
60
|
+
- 是否允许发布到 npm(需用户确认)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
作者: Codex | 创建时间: 2026-01-23 21:15
|
|
2
|
+
|
|
3
|
+
# sora-watermask-remover 国际化翻译优化方案
|
|
4
|
+
|
|
5
|
+
## 背景与目标
|
|
6
|
+
当前目录 `/Users/thor/Github/sora2.cloud-main/src/i18n/pages/sora-watermask-remover` 下存在多语言 JSON。需要以 `en.json` 为单一事实来源,对所有语言文件进行完整本地化翻译与一致性校验,确保营销页面文案统一、可发布、且受保护关键词不被误译。
|
|
7
|
+
|
|
8
|
+
## 范围
|
|
9
|
+
- 仅处理该目录下 i18n JSON 文案内容
|
|
10
|
+
- 不改动业务逻辑与组件
|
|
11
|
+
- 不新增迁移文件
|
|
12
|
+
|
|
13
|
+
## 受保护关键词策略
|
|
14
|
+
- 从 `en.json` 与项目命名中抽取品牌与关键词
|
|
15
|
+
- 受保护关键词在任何语言中保持英文原样
|
|
16
|
+
|
|
17
|
+
## 方案概述
|
|
18
|
+
1. 读取 `en.json`,确认 key 结构与文案目标
|
|
19
|
+
2. 建立受保护关键词清单并确认
|
|
20
|
+
3. 对比所有语言文件,补齐缺失 key 并对齐结构
|
|
21
|
+
4. 逐语言翻译与本地化,避免硬翻译品牌与关键词
|
|
22
|
+
5. 运行 key 一致性检查与占位符检查
|
|
23
|
+
|
|
24
|
+
## 流程图
|
|
25
|
+
```mermaid
|
|
26
|
+
flowchart TD
|
|
27
|
+
A[读取英文文案] --> B[整理受保护关键词]
|
|
28
|
+
B --> C[对齐所有语言结构]
|
|
29
|
+
C --> D[逐语言本地化翻译]
|
|
30
|
+
D --> E[一致性与占位符检查]
|
|
31
|
+
E --> F[输出最终多语言文件]
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## 影响评估
|
|
35
|
+
- 仅修改 JSON 文案内容
|
|
36
|
+
- 不涉及代码逻辑与运行时行为
|
|
37
|
+
|
|
38
|
+
## 验证方案
|
|
39
|
+
- 运行 `scripts/check_i18n_keys.py` 校验 key 一致性
|
|
40
|
+
- 抽样核对受保护关键词与占位符
|
|
41
|
+
|
|
42
|
+
## 需求清单
|
|
43
|
+
- [ ] 完整翻译并本地化所有语言 JSON
|
|
44
|
+
- [ ] 受保护关键词保持英文原样
|
|
45
|
+
- [ ] 所有语言与 `en.json` key 完全一致
|
|
46
|
+
- [ ] 输出可直接发布的营销文案
|
|
47
|
+
|
|
48
|
+
## 待确认事项
|
|
49
|
+
- 目标语言清单是否为目录内全部语言文件(ar de es fr he hi id ja km ru th zh)(需用户确认)
|
|
50
|
+
- 受保护关键词清单与大小写规则(如 Sora 2 Sora2 Cloud OpenAI Pro HD 15s sora watermask remover)(需用户确认)
|
|
51
|
+
- 文案语气与风格偏好(理性简洁或强转化促销)(需用户确认)
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
作者:Codex|创建时间:2026-01-23 21:06
|
|
2
|
+
|
|
3
|
+
# 目标
|
|
4
|
+
- 让 apiKey 与 baseUrl 优先从环境变量读取
|
|
5
|
+
- 兼容已有配置文件与 CLI 写入配置
|
|
6
|
+
- 明确并文档化配置优先级与环境变量名称
|
|
7
|
+
|
|
8
|
+
# 方案概述
|
|
9
|
+
- 新增统一的配置解析流程
|
|
10
|
+
- 以 环境变量 为最高优先级 其次配置文件 最后默认值
|
|
11
|
+
- 仅在有值时向模型构造函数注入 apiKey 与 baseUrl 避免空值覆盖
|
|
12
|
+
|
|
13
|
+
```mermaid
|
|
14
|
+
flowchart TD
|
|
15
|
+
A[启动命令] --> B[读取环境变量]
|
|
16
|
+
B --> C[读取配置文件]
|
|
17
|
+
C --> D[合并配置]
|
|
18
|
+
D --> E[构建模型]
|
|
19
|
+
E --> F[执行翻译]
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
# 配置优先级
|
|
23
|
+
- 环境变量优先级高于配置文件
|
|
24
|
+
- 配置文件高于代码默认值
|
|
25
|
+
- 未设置的字段不写入模型参数
|
|
26
|
+
|
|
27
|
+
```mermaid
|
|
28
|
+
flowchart LR
|
|
29
|
+
A[环境变量有值] --> D[使用环境变量]
|
|
30
|
+
B[环境变量无值] --> C[读取配置]
|
|
31
|
+
C --> D
|
|
32
|
+
D --> E[合并默认值]
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
# 环境变量规划
|
|
36
|
+
- 通用变量
|
|
37
|
+
- AI_TRANSLATE_API_KEY
|
|
38
|
+
- AI_TRANSLATE_BASE_URL
|
|
39
|
+
- 兼容主流 SDK 变量
|
|
40
|
+
- OPENAI_API_KEY
|
|
41
|
+
- OPENAI_BASE_URL
|
|
42
|
+
- ANTHROPIC_API_KEY
|
|
43
|
+
- MISTRAL_API_KEY
|
|
44
|
+
- DEEPSEEK_API_KEY
|
|
45
|
+
- OLLAMA_BASE_URL
|
|
46
|
+
|
|
47
|
+
```mermaid
|
|
48
|
+
sequenceDiagram
|
|
49
|
+
participant CLI
|
|
50
|
+
participant 配置管理
|
|
51
|
+
participant 模型工厂
|
|
52
|
+
CLI->>配置管理: 读取环境变量
|
|
53
|
+
配置管理->>配置管理: 合并配置文件
|
|
54
|
+
配置管理->>模型工厂: 输出最终配置
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
# 影响范围
|
|
58
|
+
- src/cli.ts
|
|
59
|
+
- 新增 baseUrl schema
|
|
60
|
+
- 引入配置解析函数
|
|
61
|
+
- src/model.ts
|
|
62
|
+
- 去除空 apiKey 注入
|
|
63
|
+
- 按 provider 注入 baseUrl
|
|
64
|
+
- README.md
|
|
65
|
+
- 增补环境变量说明与优先级
|
|
66
|
+
|
|
67
|
+
# 实施步骤
|
|
68
|
+
1. 新增配置解析函数并接入 CLI
|
|
69
|
+
2. 调整模型工厂的 apiKey 与 baseUrl 注入策略
|
|
70
|
+
3. 更新 README 使用说明与示例
|
|
71
|
+
|
|
72
|
+
# 验收清单
|
|
73
|
+
- [ ] 设置环境变量后 即使配置文件不同仍以环境变量生效
|
|
74
|
+
- [ ] 未设置环境变量时 使用配置文件值
|
|
75
|
+
- [ ] 未配置 apiKey 时不再覆盖 SDK 默认取值逻辑
|
|
76
|
+
- [ ] README 清晰说明优先级与变量名称
|
|
77
|
+
|
|
78
|
+
# 待确认事项
|
|
79
|
+
- [ ] 是否接受新增 AI_TRANSLATE_API_KEY 与 AI_TRANSLATE_BASE_URL 作为通用环境变量 (需用户确认)
|
|
80
|
+
- [ ] 是否需要同时支持 provider 专属 baseUrl 变量 如 DEEPSEEK_BASE_URL (需用户确认)
|
package/README.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# i18n-copywriter 的 AI 翻译器 TS 实现
|
|
2
|
+
|
|
3
|
+
本仓库提供 `ai-translate` 的 TypeScript 等价实现,复用官方库的模块结构与接口,面向本地脚本与可复用模块两种用法。
|
|
4
|
+
|
|
5
|
+
## 功能概览
|
|
6
|
+
- CLI:`ai-translate` 命令行翻译
|
|
7
|
+
- 模块:`AiTranslateTransform`、`TextSplitterStream` 等可复用组件
|
|
8
|
+
- 配置:`.ai-translate.json` 本地或全局配置
|
|
9
|
+
- 最小验证脚本:本地可运行的快速自测
|
|
10
|
+
|
|
11
|
+
## 参数一览
|
|
12
|
+
|
|
13
|
+
### CLI 参数
|
|
14
|
+
| 参数 | 作用 | 备注 |
|
|
15
|
+
| --- | --- | --- |
|
|
16
|
+
| `-h`, `--help` | 输出帮助信息 | |
|
|
17
|
+
| `-v`, `--version` | 输出版本号 | |
|
|
18
|
+
| `-c`, `--config DIR` | 指定配置目录或配置文件路径 | 读取 `.ai-translate.json` |
|
|
19
|
+
| `-f`, `--from LANG` | 源语言 | 可用英文名或 BCP47 代码 |
|
|
20
|
+
| `-t`, `--to LANG` | 目标语言 | 可用英文名或 BCP47 代码 |
|
|
21
|
+
| `-i`, `--input FILE` | 输入文件路径 | |
|
|
22
|
+
| `-o`, `--output FILE` | 输出文件路径 | |
|
|
23
|
+
| `--format FORMAT` | 指定输入格式 | 支持 `cpp`、`go`、`java`、`js`、`php`、`proto`、`python`、`rst`、`ruby`、`rust`、`scala`、`swift`、`markdown`、`latex`、`html` |
|
|
24
|
+
| `set KEY VALUE` | 写入配置项 | `KEY` 见下表 |
|
|
25
|
+
|
|
26
|
+
### 配置参数
|
|
27
|
+
| 参数 | 作用 | 默认值 |
|
|
28
|
+
| --- | --- | --- |
|
|
29
|
+
| `provider` | 模型提供方 | `ollama` |
|
|
30
|
+
| `model` | 模型名称 | `qwen2.5:7b` |
|
|
31
|
+
| `apiKey` | 模型 API Key | 空 |
|
|
32
|
+
| `baseUrl` | 模型 Base URL | 空 |
|
|
33
|
+
| `temperature` | 模型温度 | `0.1` |
|
|
34
|
+
| `maxRetries` | 最大重试次数 | `10` |
|
|
35
|
+
| `chunkSize` | 文本分块大小 | `1000` |
|
|
36
|
+
|
|
37
|
+
## 安装依赖
|
|
38
|
+
```bash
|
|
39
|
+
npm install
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## 构建与运行
|
|
43
|
+
```bash
|
|
44
|
+
npm run build
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## npx / pnpx 使用
|
|
48
|
+
无需全局安装,直接运行:
|
|
49
|
+
```bash
|
|
50
|
+
npx @thor123141245r/ai-translate --help
|
|
51
|
+
pnpx @thor123141245r/ai-translate --help
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
示例:
|
|
55
|
+
```bash
|
|
56
|
+
npx @thor123141245r/ai-translate -f Spanish -t English -i input.md -o output.md
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### CLI 用法
|
|
60
|
+
```bash
|
|
61
|
+
# 直接翻译文件
|
|
62
|
+
node dist/bin/ai-translate.js -f Spanish -t English -i input.md -o output.md
|
|
63
|
+
|
|
64
|
+
# 使用配置文件并从 stdin 读取
|
|
65
|
+
echo "translate" | node dist/bin/ai-translate.js -f en -t en -c .
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 开发态直接运行
|
|
69
|
+
```bash
|
|
70
|
+
npm run dev:cli -- -f en -t zh-CN -i input.md -o output.md
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## 配置说明
|
|
74
|
+
配置文件名为 `.ai-translate.json`,可通过命令行写入:
|
|
75
|
+
```bash
|
|
76
|
+
node dist/bin/ai-translate.js set provider ollama
|
|
77
|
+
node dist/bin/ai-translate.js set apiKey YOUR_API_KEY
|
|
78
|
+
node dist/bin/ai-translate.js set model qwen2.5:7b
|
|
79
|
+
node dist/bin/ai-translate.js set chunkSize 1000
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
支持的配置项:
|
|
83
|
+
- provider
|
|
84
|
+
- model
|
|
85
|
+
- apiKey
|
|
86
|
+
- baseUrl
|
|
87
|
+
- temperature
|
|
88
|
+
- maxRetries
|
|
89
|
+
- chunkSize
|
|
90
|
+
|
|
91
|
+
## 环境变量优先级
|
|
92
|
+
运行时读取优先级:环境变量 > 配置文件 > 默认值。
|
|
93
|
+
|
|
94
|
+
优先读取的通用环境变量:
|
|
95
|
+
- `AI_TRANSLATE_API_KEY`
|
|
96
|
+
- `AI_TRANSLATE_BASE_URL`
|
|
97
|
+
|
|
98
|
+
按提供方支持的环境变量:
|
|
99
|
+
- `OPENAI_API_KEY` / `OPENAI_BASE_URL`
|
|
100
|
+
- `ANTHROPIC_API_KEY` / `ANTHROPIC_BASE_URL`
|
|
101
|
+
- `MISTRAL_API_KEY` / `MISTRAL_BASE_URL`
|
|
102
|
+
- `DEEPSEEK_API_KEY` / `DEEPSEEK_BASE_URL`
|
|
103
|
+
- `OLLAMA_BASE_URL`
|
|
104
|
+
|
|
105
|
+
说明:
|
|
106
|
+
- 通用变量存在时会覆盖配置文件对应字段
|
|
107
|
+
- 未设置 apiKey 时,将由各 SDK 自行读取其默认环境变量
|
|
108
|
+
|
|
109
|
+
## 复用说明
|
|
110
|
+
本实现依赖 LangChain 的官方 SDK 与 `@commenthol/ai-translate` 的设计模式:
|
|
111
|
+
- 文本分块使用 `@langchain/textsplitters`
|
|
112
|
+
- 模型调用使用 `@langchain/*` 系列 ChatModel
|
|
113
|
+
- 配置管理使用 `@commenthol/app-config`
|
|
114
|
+
|
|
115
|
+
## 最小验证
|
|
116
|
+
```bash
|
|
117
|
+
npm run validate
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
该脚本使用伪模型进行本地验证,确保分块与转换流程可用。
|
package/SKILL.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: i18n-copywriter
|
|
3
|
+
description: 为 i18n JSON(以 en.json 为准)生成与优化高转化率营销文案,并同步到多语言文件(如 de.json、fr.json)。仅在用户明确要求“优化/生成国际化文案、翻译 i18n JSON、为 landing page 写多语言文案”时使用;其余代码与通用翻译请求不要使用。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# I18n Copywriter
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
你是一名 landing page 资深国际化文案写手:先基于目标关键词做轻量网络调研,提炼用户需求与痛点,再以 `en.json` 为“单一事实来源”写出高转化英文文案,并将相同 key 结构同步到其他语言 JSON(如 `de.json`),保证占位符与“受保护关键词”不被硬翻译。
|
|
11
|
+
|
|
12
|
+
使用这个 skill 时候不需要进入先写文档再写代码的流程,直接开始脚本翻译流程
|
|
13
|
+
|
|
14
|
+
## 使用边界(非常重要)
|
|
15
|
+
|
|
16
|
+
- 只处理“国际化文案”本身:`*.json` 文案内容(尤其是 `en.json` 及其同结构的多语言文件)。
|
|
17
|
+
- 不做:业务逻辑改动、组件重构、通用逐字翻译、与 i18n 无关的改文案。
|
|
18
|
+
- 不确定是否属于 i18n 文案任务时:先反问用户要改的 `en.json` 路径、目标页面与目标语言列表。
|
|
19
|
+
|
|
20
|
+
## 你需要向用户确认的信息(缺一会显著降质量)
|
|
21
|
+
|
|
22
|
+
- `en.json` 的真实路径(以及其他语言 JSON 所在目录)。
|
|
23
|
+
- 本次要优化的页面或模块(例如 pricing、homepage hero、generator 区域)。
|
|
24
|
+
- 目标关键词(可多个):哪些词必须保留为英文不翻译(例如 `sora 2 video`)。
|
|
25
|
+
- 目标语言:例如 `de, fr, ja, zh`。
|
|
26
|
+
- 语气与品牌约束:更偏“极简理性”还是“强促销转化”。
|
|
27
|
+
|
|
28
|
+
## 工作流(按顺序执行)
|
|
29
|
+
|
|
30
|
+
### 1)锁定范围与“受保护关键词”
|
|
31
|
+
|
|
32
|
+
- 从 `en.json` 中提取:品牌名、产品名、核心功能名、套餐名、以及用户指定的 SEO 关键词。
|
|
33
|
+
- 建立“受保护关键词清单”:这些词在任何语言文件中都必须保持原样(不硬翻译、不改大小写)。
|
|
34
|
+
- 典型例子:`Sora 2`、`Sora2 Cloud`、`sora 2 video`、`HD`、`Starter`、`Pro`、`Checkout`(以项目实际为准)。
|
|
35
|
+
|
|
36
|
+
需要参考时:打开 `references/protected-terms.md`,按模板补齐。
|
|
37
|
+
|
|
38
|
+
### 2)轻量网络调研(为“高转化文案”服务)
|
|
39
|
+
|
|
40
|
+
- 用目标关键词做 3~6 次搜索,重点收集:用户常见需求、痛点、反对理由、对比方案(竞品/替代品)。
|
|
41
|
+
- 输出为“洞察清单”:每条洞察对应 1 个文案策略(例如降低学习成本、强调速度、强调质量、强调可控性)。
|
|
42
|
+
- 目标不是写报告,而是为文案提供“可用弹药”。
|
|
43
|
+
|
|
44
|
+
### 3)先写好 `en.json`(单一事实来源)
|
|
45
|
+
|
|
46
|
+
- 只改 value,不改 key,不引入新结构(除非用户明确新增文案点并同意加 key)。
|
|
47
|
+
- 保留所有变量与占位符:例如 `{count}`、`{credits}`、`{{name}}`、`%s`(以文件实际为准)。
|
|
48
|
+
- 保留受保护关键词:例如不要把 `sora 2 video` 翻译成任何语言。
|
|
49
|
+
- Landing page 文案优先:短句、动词开头、清晰利益点、避免“空泛 AI 口号”。
|
|
50
|
+
|
|
51
|
+
### 4)复制 `en.json` 到其他语言文件并做本地化改写
|
|
52
|
+
|
|
53
|
+
- 每个语言文件应与 `en.json` 保持完全相同的 key 集合。
|
|
54
|
+
- 先用 `en.json` 结构覆盖(缺失 key 补齐),再逐条替换为目标语言文案。
|
|
55
|
+
- 禁止“硬翻译品牌/产品/关键词”:受保护关键词保持英文原样。
|
|
56
|
+
|
|
57
|
+
### 5)一致性与质量检查(必做)
|
|
58
|
+
|
|
59
|
+
- 运行 `scripts/check_i18n_keys.py` 确保各语言文件 key 集合一致。
|
|
60
|
+
- 检查占位符是否被破坏(特别是 `{}`、`{{}}`、`%`、换行符)。
|
|
61
|
+
- 检查“受保护关键词”是否被误翻译或改写。
|
|
62
|
+
- 统一标点与引号风格(同一语言内一致)。
|
|
63
|
+
|
|
64
|
+
## 常见硬性规则(避免踩坑)
|
|
65
|
+
|
|
66
|
+
- 任何语言都不要翻译项目指定关键词。
|
|
67
|
+
- 不要把 “产品名 + 功能名” 翻成“产品名 + 本地语言词”这种半截混搭(除非品牌策略要求)。
|
|
68
|
+
- 如果英文里刻意使用了 SEO 关键词(例如 `sora 2 video`),其他语言也优先保留该关键词,并围绕它调整句子结构。
|
|
69
|
+
|
|
70
|
+
## 资源
|
|
71
|
+
|
|
72
|
+
- `scripts/check_i18n_keys.py`:检查各语言 JSON 是否与 `en.json` key 集合一致。
|
|
73
|
+
- `scripts/sentence_json_translator.py`:逐句翻译 JSON 文案并回填结果,适合大段文案与输出可控场景。
|
|
74
|
+
- 常用参数:
|
|
75
|
+
- `--concurrency`:并发线程数,默认 6,可用 `CONTENT_LOCALIZE_CONCURRENCY` 覆盖。
|
|
76
|
+
- `--overwrite`:全量覆盖翻译,默认关闭(仅翻译缺失或等同英文的条目)。
|
|
77
|
+
- `--limit`:限制翻译条数,便于小范围验证。
|
|
78
|
+
- `--cache-file`:指定缓存文件路径,复用重复句子的翻译结果。
|
|
79
|
+
- `--protected-terms`:逗号分隔的受保护词列表,会写入系统提示。
|
|
80
|
+
- `--log-every`:进度输出步长,默认 20。
|
|
81
|
+
- `references/protected-terms.md`:受保护关键词清单模板与维护规则。
|
|
82
|
+
|
|
83
|
+
## 最小执行示例(给未来的你)
|
|
84
|
+
|
|
85
|
+
用户请求:
|
|
86
|
+
- “帮我优化 landing page 的 i18n 文案,`src/i18n/pages/pricing/en.json` 为准,同步到 `de/fr/ja`,关键词 `sora 2 video` 不要翻译。”
|
|
87
|
+
|
|
88
|
+
你应输出:
|
|
89
|
+
- 先给出 6~12 条“调研洞察 → 文案策略”的要点。
|
|
90
|
+
- 完整更新 `en.json` 文案。
|
|
91
|
+
- 复制并更新 `de.json / fr.json / ja.json`(同 key 结构)。
|
|
92
|
+
- 跑一次 key 检查脚本并修复缺失 key。
|
|
93
|
+
|
|
94
|
+
脚本示例(小范围验证):
|
|
95
|
+
```bash
|
|
96
|
+
python3 /Users/thor/.codex/skills/i18n-copywriter/scripts/sentence_json_translator.py \\
|
|
97
|
+
src/i18n/pages/landing \\
|
|
98
|
+
--locales de,fr,ja \\
|
|
99
|
+
--concurrency 6 \\
|
|
100
|
+
--limit 20 \\
|
|
101
|
+
--cache-file .i18n-translation-cache.json \\
|
|
102
|
+
--protected-terms "Sora 2,Sora2 Cloud,sora 2 video"
|
|
103
|
+
```
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Transform } from 'node:stream';
|
|
2
|
+
export declare class AsyncTransform extends Transform {
|
|
3
|
+
static toString(chunk: Buffer | object, encoding: BufferEncoding | 'buffer'): string;
|
|
4
|
+
_transform(chunk: Buffer | object, enc: BufferEncoding | 'buffer', cb: (error?: Error | null) => void): void;
|
|
5
|
+
protected _asyncTransform(_chunk: Buffer | object, _enc: BufferEncoding | 'buffer'): Promise<boolean | undefined>;
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=asyncTransform.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asyncTransform.d.ts","sourceRoot":"","sources":["../src/asyncTransform.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAEvC,qBAAa,cAAe,SAAQ,SAAS;IAC3C,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,QAAQ;IAK3E,UAAU,CACR,KAAK,EAAE,MAAM,GAAG,MAAM,EACtB,GAAG,EAAE,cAAc,GAAG,QAAQ,EAC9B,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,KAAK,IAAI;cAapB,eAAe,CAC7B,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,IAAI,EAAE,cAAc,GAAG,QAAQ,GAC9B,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC;CAGhC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Transform } from 'node:stream';
|
|
2
|
+
export class AsyncTransform extends Transform {
|
|
3
|
+
static toString(chunk, encoding) {
|
|
4
|
+
const enc = encoding !== 'buffer' ? encoding : undefined;
|
|
5
|
+
return Buffer.isBuffer(chunk) ? chunk.toString(enc) : String(chunk);
|
|
6
|
+
}
|
|
7
|
+
_transform(chunk, enc, cb) {
|
|
8
|
+
this._asyncTransform(chunk, enc)
|
|
9
|
+
.then((wait) => {
|
|
10
|
+
if (wait) {
|
|
11
|
+
this.once('drain', () => cb());
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
cb();
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
.catch((err) => this.emit('error', err));
|
|
18
|
+
}
|
|
19
|
+
async _asyncTransform(_chunk, _enc) {
|
|
20
|
+
throw new Error('needs implementation');
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=asyncTransform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asyncTransform.js","sourceRoot":"","sources":["../src/asyncTransform.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAEvC,MAAM,OAAO,cAAe,SAAQ,SAAS;IAC3C,MAAM,CAAC,QAAQ,CAAC,KAAsB,EAAE,QAAmC;QACzE,MAAM,GAAG,GAAG,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAA;QACxD,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IACrE,CAAC;IAED,UAAU,CACR,KAAsB,EACtB,GAA8B,EAC9B,EAAkC;QAElC,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,GAAG,CAAC;aAC7B,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;YACb,IAAI,IAAI,EAAE,CAAC;gBACT,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,CAAA;YAChC,CAAC;iBAAM,CAAC;gBACN,EAAE,EAAE,CAAA;YACN,CAAC;QACH,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAA;IAC5C,CAAC;IAES,KAAK,CAAC,eAAe,CAC7B,MAAuB,EACvB,IAA+B;QAE/B,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAA;IACzC,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-translate.d.ts","sourceRoot":"","sources":["../../src/bin/ai-translate.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-translate.js","sourceRoot":"","sources":["../../src/bin/ai-translate.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAA;AAE/B,MAAM,GAAG,EAAE,CAAA"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const argvParse: (args?: string[]) => {
|
|
2
|
+
cmd: Record<string, unknown>;
|
|
3
|
+
opts: Record<string, unknown>;
|
|
4
|
+
};
|
|
5
|
+
export declare const _injectConsole: (obj: typeof console) => void;
|
|
6
|
+
export declare const cli: (args?: string[]) => Promise<void>;
|
|
7
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AA2HA,eAAO,MAAM,SAAS,GAAI,OAAO,MAAM,EAAE;;;CAoBxC,CAAA;AAWD,eAAO,MAAM,cAAc,GAAI,KAAK,OAAO,OAAO,SAEjD,CAAA;AAuFD,eAAO,MAAM,GAAG,GAAU,OAAO,MAAM,EAAE,kBAqExC,CAAA"}
|