markdown-ai-rewriter 0.2.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/CHANGELOG.md +29 -0
- package/README.md +298 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +87 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/full-rewriter.d.ts +28 -0
- package/dist/core/full-rewriter.d.ts.map +1 -0
- package/dist/core/full-rewriter.js +195 -0
- package/dist/core/full-rewriter.js.map +1 -0
- package/dist/core/parser.d.ts +21 -0
- package/dist/core/parser.d.ts.map +1 -0
- package/dist/core/parser.js +239 -0
- package/dist/core/parser.js.map +1 -0
- package/dist/core/providers/anthropic.d.ts +12 -0
- package/dist/core/providers/anthropic.d.ts.map +1 -0
- package/dist/core/providers/anthropic.js +77 -0
- package/dist/core/providers/anthropic.js.map +1 -0
- package/dist/core/providers/base.d.ts +8 -0
- package/dist/core/providers/base.d.ts.map +1 -0
- package/dist/core/providers/base.js +28 -0
- package/dist/core/providers/base.js.map +1 -0
- package/dist/core/providers/minimax.d.ts +20 -0
- package/dist/core/providers/minimax.d.ts.map +1 -0
- package/dist/core/providers/minimax.js +87 -0
- package/dist/core/providers/minimax.js.map +1 -0
- package/dist/core/providers/openai.d.ts +12 -0
- package/dist/core/providers/openai.d.ts.map +1 -0
- package/dist/core/providers/openai.js +76 -0
- package/dist/core/providers/openai.js.map +1 -0
- package/dist/core/quota-manager.d.ts +17 -0
- package/dist/core/quota-manager.d.ts.map +1 -0
- package/dist/core/quota-manager.js +60 -0
- package/dist/core/quota-manager.js.map +1 -0
- package/dist/core/rewriter.d.ts +13 -0
- package/dist/core/rewriter.d.ts.map +1 -0
- package/dist/core/rewriter.js +88 -0
- package/dist/core/rewriter.js.map +1 -0
- package/dist/core/section-parser.d.ts +20 -0
- package/dist/core/section-parser.d.ts.map +1 -0
- package/dist/core/section-parser.js +199 -0
- package/dist/core/section-parser.js.map +1 -0
- package/dist/core/section-rewriter.d.ts +25 -0
- package/dist/core/section-rewriter.d.ts.map +1 -0
- package/dist/core/section-rewriter.js +152 -0
- package/dist/core/section-rewriter.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +40 -0
- package/dist/index.js.map +1 -0
- package/dist/types/index.d.ts +81 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +64 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [0.2.0] - 2026-03-27
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- **MiniMax** provider (`provider: 'minimax'` / `-p minimax`): OpenAI-compatible API via `openai` package; configure `MINIMAX_API_KEY` and optional `MINIMAX_BASE_URL` or `minimaxBaseUrl` / `--minimax-base-url`.
|
|
9
|
+
- `prepublishOnly` build and explicit `files` field for npm package contents.
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
- README 中文版与 CLI、章节/全文模式说明更新。
|
|
13
|
+
- OpenAI / Anthropic Provider 复用客户端实例;章节模式尊重 `concurrency`。
|
|
14
|
+
- CLI 版本号从 `package.json` 读取。
|
|
15
|
+
|
|
16
|
+
### Removed
|
|
17
|
+
- **Breaking:** Paragraph-level rewrite mode (`paragraph`) removed. Use `section` (default) or `full` via `mode` in config or `--mode` on the CLI.
|
|
18
|
+
|
|
19
|
+
## [0.1.0] - 2026-03-23
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
- Initial release
|
|
23
|
+
- Markdown structure parser that preserves document structure
|
|
24
|
+
- AI rewriter with OpenAI and Anthropic support
|
|
25
|
+
- Multiple writing styles (casual, formal, technical, creative)
|
|
26
|
+
- CLI tool for command-line usage
|
|
27
|
+
- Programmatic API for integration
|
|
28
|
+
- Concurrent processing for better performance
|
|
29
|
+
- Comprehensive documentation and examples
|
package/README.md
ADDED
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
# markdown-ai-rewriter
|
|
2
|
+
|
|
3
|
+
面向 **Markdown 长文与文档** 的 AI 改写工具:在 **保留标题层级、代码块、表格、图片等结构** 的前提下,对正文进行润色、降重或换表述,适合博客、技术文档、公众号稿、新闻稿整理等场景。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 核心特点与优势
|
|
8
|
+
|
|
9
|
+
| 维度 | 说明 |
|
|
10
|
+
|------|------|
|
|
11
|
+
| **结构优先** | 不是简单「全文扔给模型」,而是按文档结构处理,减少标题错乱、代码被改写、版式被打乱的风险。 |
|
|
12
|
+
| **双模式可切换** | **章节模式**(默认)按标题切块并行,成本与连贯性平衡好;**全文模式**整篇一次生成,语气最连贯,适合短文或强叙事。 |
|
|
13
|
+
| **多模型** | 支持 **OpenAI**、**Anthropic**、**MiniMax**(OpenAI 兼容接口),也可接入 **自定义 Provider**。 |
|
|
14
|
+
| **风格可控** | 内置 casual / formal / technical / creative / custom,并支持温度、长度倾向、`--prompt` 自定义指令。 |
|
|
15
|
+
| **工程化友好** | 提供 **CLI**(`markdown-ai-rewrite` / `md-rewrite`)与 **TypeScript API**,可嵌入脚本、CI 或内容流水线。 |
|
|
16
|
+
| **并发可配** | 章节模式下可配置并发请求数,在长文档场景下兼顾速度与 API 限流。 |
|
|
17
|
+
|
|
18
|
+
**一句话**:把「能改的部分」交给模型,把「必须稳的结构」留在本地解析与重组逻辑里,**更适合严肃内容生产**,而不是聊天式随意生成。
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 两种改写模式
|
|
23
|
+
|
|
24
|
+
| 模式 | CLI | 适用场景 | 优势 |
|
|
25
|
+
|------|-----|----------|------|
|
|
26
|
+
| **章节** `section` | `--mode section`(默认) | 中长篇、多小节、技术文档 | 按标题分章改写,可带上下文章摘要,**调用次数可预期、成本更可控**。 |
|
|
27
|
+
| **全文** `full` | `--mode full` | 短文、强叙事、整篇语气统一 | **一次请求覆盖全文**,连贯性通常最好;全文模式会先用占位符保护图片再还原。 |
|
|
28
|
+
|
|
29
|
+
章节模式可通过 `--section-level 1|2|3` 指定按几级标题切分(默认 1 级 `#`)。
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## 安装
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm install markdown-ai-rewriter
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
按需安装官方 SDK(至少其一):
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm install openai
|
|
43
|
+
# MiniMax 使用与 OpenAI 相同的 SDK + 兼容 Base URL,见下文
|
|
44
|
+
# 或
|
|
45
|
+
npm install @anthropic-ai/sdk
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 快速开始
|
|
51
|
+
|
|
52
|
+
### 命令行
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# OpenAI
|
|
56
|
+
export OPENAI_API_KEY="your-api-key"
|
|
57
|
+
markdown-ai-rewrite rewrite \
|
|
58
|
+
--input article.md \
|
|
59
|
+
--output article-rewritten.md \
|
|
60
|
+
--provider openai \
|
|
61
|
+
--style casual
|
|
62
|
+
|
|
63
|
+
# Anthropic
|
|
64
|
+
export ANTHROPIC_API_KEY="your-api-key"
|
|
65
|
+
markdown-ai-rewrite rewrite \
|
|
66
|
+
--input article.md \
|
|
67
|
+
--output article-rewritten.md \
|
|
68
|
+
--provider anthropic \
|
|
69
|
+
--style formal
|
|
70
|
+
|
|
71
|
+
# MiniMax(需已安装 openai;密钥在 MiniMax 开放平台创建)
|
|
72
|
+
export MINIMAX_API_KEY="your-minimax-api-key"
|
|
73
|
+
# 可选:国内/国际 endpoint 不同可设置 MINIMAX_BASE_URL,见下方说明
|
|
74
|
+
markdown-ai-rewrite rewrite \
|
|
75
|
+
-i article.md \
|
|
76
|
+
-o out.md \
|
|
77
|
+
-p minimax \
|
|
78
|
+
-m MiniMax-M2.1 \
|
|
79
|
+
--style casual
|
|
80
|
+
|
|
81
|
+
# 全文模式示例
|
|
82
|
+
markdown-ai-rewrite rewrite -i article.md -o out.md -p openai --mode full -v
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### 在代码中使用
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
import { MarkdownRewriter } from 'markdown-ai-rewriter';
|
|
89
|
+
|
|
90
|
+
const rewriter = new MarkdownRewriter({
|
|
91
|
+
provider: 'openai',
|
|
92
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
93
|
+
model: 'gpt-4o-mini',
|
|
94
|
+
mode: 'section', // 或 'full'
|
|
95
|
+
sectionLevel: 1,
|
|
96
|
+
verbose: true,
|
|
97
|
+
concurrency: 3,
|
|
98
|
+
options: {
|
|
99
|
+
style: 'casual',
|
|
100
|
+
temperature: 0.7,
|
|
101
|
+
maxTokens: 2000, // 未传时 Provider 侧有默认值;CLI 默认常为 4000,以实际调用为准
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const result = await rewriter.rewrite(markdown);
|
|
106
|
+
console.log(result.rewritten);
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## 常用 CLI 参数
|
|
112
|
+
|
|
113
|
+
| 参数 | 含义 |
|
|
114
|
+
|------|------|
|
|
115
|
+
| `-i, --input` | 输入 Markdown 文件(必填) |
|
|
116
|
+
| `-o, --output` | 输出 Markdown 文件(必填) |
|
|
117
|
+
| `-p, --provider` | `openai`、`anthropic` 或 `minimax`(必填) |
|
|
118
|
+
| `-k, --api-key` | API Key;也可使用 `OPENAI_API_KEY` / `ANTHROPIC_API_KEY` / `MINIMAX_API_KEY` |
|
|
119
|
+
| `-m, --model` | 模型名(MiniMax 示例:`MiniMax-M2.1`、`MiniMax-M2.7`,以官方文档为准) |
|
|
120
|
+
| `--minimax-base-url` | 仅 MiniMax:API Base URL(默认 `https://api.minimax.io/v1`,也可用环境变量 `MINIMAX_BASE_URL`) |
|
|
121
|
+
| `-s, --style` | `casual` \| `formal` \| `technical` \| `creative` \| `custom` |
|
|
122
|
+
| `--prompt` | 自定义系统提示补充(常与 `custom` 风格配合) |
|
|
123
|
+
| `-t, --temperature` | 采样温度 0~1,默认约 0.7 |
|
|
124
|
+
| `--max-tokens` | 单次回复上限(CLI 默认 4000) |
|
|
125
|
+
| `--preserve-length` | 尽量保持与原文相近篇幅 |
|
|
126
|
+
| `-c, --concurrency` | 并发数,默认 3(主要影响章节模式) |
|
|
127
|
+
| `-v, --verbose` | 打印详细日志 |
|
|
128
|
+
| `--mode` | `section`(默认)或 `full` |
|
|
129
|
+
| `--section-level` | 章节模式下的标题级别 1~3,默认 1 |
|
|
130
|
+
|
|
131
|
+
完整说明可执行:`markdown-ai-rewrite rewrite --help`。
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## 写作风格(`--style`)
|
|
136
|
+
|
|
137
|
+
- **casual**:轻松、口语化
|
|
138
|
+
- **formal**:正式、商务或书面语
|
|
139
|
+
- **technical**:偏术语与准确性
|
|
140
|
+
- **creative**:更有表现力
|
|
141
|
+
- **custom**:配合 `--prompt` 自行描述要求
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## 改写时大致会发生什么
|
|
146
|
+
|
|
147
|
+
- **章节 / 全文** 两种模式都会在「尊重结构」的前提下改写正文;标题、代码块、表格等会按实现策略尽量保留或由占位符保护(全文模式下的图片采用占位符机制)。
|
|
148
|
+
- 具体列表、引用等是否逐条保留,与模型输出有关;若你需要强保留列表结构,可在 `--prompt` 中明确要求。
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## 示例
|
|
153
|
+
|
|
154
|
+
### casual 风格(片段)
|
|
155
|
+
|
|
156
|
+
**输入:**
|
|
157
|
+
|
|
158
|
+
```markdown
|
|
159
|
+
# Product Launch
|
|
160
|
+
|
|
161
|
+
The new product will be released next month. It features advanced technology.
|
|
162
|
+
|
|
163
|
+
- High performance
|
|
164
|
+
- Low cost
|
|
165
|
+
- Easy to use
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**输出(示意):**
|
|
169
|
+
|
|
170
|
+
```markdown
|
|
171
|
+
# Product Launch
|
|
172
|
+
|
|
173
|
+
Hey, exciting news! Our new product drops next month and it's packed with some seriously cool tech.
|
|
174
|
+
|
|
175
|
+
- Lightning-fast performance
|
|
176
|
+
- Won't break the bank
|
|
177
|
+
- Super simple to get started
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### formal 风格(引用块)
|
|
181
|
+
|
|
182
|
+
**输入:** `> This is an important announcement.`
|
|
183
|
+
|
|
184
|
+
**输出(示意):** `> We wish to inform you of a significant development that requires your attention.`
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## 与内容流水线配合(示例)
|
|
189
|
+
|
|
190
|
+
可与抓取、转换工具串联,例如先得到 Markdown,再改写,最后发布:
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
convert-url --url "https://news.com/article" --output article.md
|
|
194
|
+
|
|
195
|
+
markdown-ai-rewrite rewrite \
|
|
196
|
+
--input article.md \
|
|
197
|
+
--output article-rewritten.md \
|
|
198
|
+
--provider openai \
|
|
199
|
+
--style casual
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## 自定义 AI 后端
|
|
205
|
+
|
|
206
|
+
实现 `BaseProvider`,即可对接自有网关或其它兼容接口:
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
import { MarkdownRewriter, BaseProvider, RewriteOptions } from 'markdown-ai-rewriter';
|
|
210
|
+
|
|
211
|
+
class MyCustomProvider extends BaseProvider {
|
|
212
|
+
name = 'my-provider';
|
|
213
|
+
|
|
214
|
+
async rewrite(text: string, options: RewriteOptions): Promise<string> {
|
|
215
|
+
// 调用你的模型 API,返回改写后的纯文本
|
|
216
|
+
return rewrittenText;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const rewriter = new MarkdownRewriter({
|
|
221
|
+
provider: 'custom',
|
|
222
|
+
customProvider: new MyCustomProvider(),
|
|
223
|
+
});
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## API 摘要
|
|
229
|
+
|
|
230
|
+
### `MarkdownRewriter`
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
constructor(config: RewriterConfig)
|
|
234
|
+
async rewrite(markdown: string): Promise<RewriteResult>
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### `RewriterConfig`(节选)
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
interface RewriterConfig {
|
|
241
|
+
provider: 'openai' | 'anthropic' | 'minimax' | 'custom';
|
|
242
|
+
apiKey?: string;
|
|
243
|
+
model?: string;
|
|
244
|
+
minimaxBaseUrl?: string;
|
|
245
|
+
options?: RewriteOptions;
|
|
246
|
+
customProvider?: AIProvider;
|
|
247
|
+
verbose?: boolean;
|
|
248
|
+
concurrency?: number;
|
|
249
|
+
mode?: 'section' | 'full';
|
|
250
|
+
sectionLevel?: 1 | 2 | 3;
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### `RewriteResult`
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
interface RewriteResult {
|
|
258
|
+
original: string;
|
|
259
|
+
rewritten: string;
|
|
260
|
+
blocksProcessed: number;
|
|
261
|
+
blocksRewritten: number;
|
|
262
|
+
tokensUsed?: number;
|
|
263
|
+
cost?: number;
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## 环境变量
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
export OPENAI_API_KEY="sk-..."
|
|
273
|
+
export ANTHROPIC_API_KEY="sk-ant-..."
|
|
274
|
+
export MINIMAX_API_KEY="..."
|
|
275
|
+
# export MINIMAX_BASE_URL="https://api.minimax.io/v1"
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## 费用参考(量级)
|
|
281
|
+
|
|
282
|
+
以约 **1000 英文单词** 的文章为量级(实际随结构、`--mode`、模型与并发变化):
|
|
283
|
+
|
|
284
|
+
- **OpenAI GPT-4o-mini**:约 \$0.01~0.02
|
|
285
|
+
- **Anthropic Claude 3.5 一类模型**:约 \$0.05~0.10
|
|
286
|
+
- **MiniMax**:以 [MiniMax 定价说明](https://platform.minimax.io/docs/guides/pricing) 为准
|
|
287
|
+
|
|
288
|
+
请以各厂商定价与实测为准。
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## 许可证
|
|
293
|
+
|
|
294
|
+
MIT
|
|
295
|
+
|
|
296
|
+
## 作者
|
|
297
|
+
|
|
298
|
+
Ping Si <sipingme@gmail.com>
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
const rewriter_1 = require("./core/rewriter");
|
|
8
|
+
const pkg = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(__dirname, '..', 'package.json'), 'utf-8'));
|
|
9
|
+
const program = new commander_1.Command();
|
|
10
|
+
program
|
|
11
|
+
.name('markdown-ai-rewrite')
|
|
12
|
+
.description('AI-powered Markdown content rewriter that preserves document structure')
|
|
13
|
+
.version(pkg.version);
|
|
14
|
+
program
|
|
15
|
+
.command('rewrite')
|
|
16
|
+
.description('Rewrite a Markdown file using AI')
|
|
17
|
+
.requiredOption('-i, --input <file>', 'Input Markdown file')
|
|
18
|
+
.requiredOption('-o, --output <file>', 'Output Markdown file')
|
|
19
|
+
.requiredOption('-p, --provider <provider>', 'AI provider: openai, anthropic, minimax')
|
|
20
|
+
.option('-k, --api-key <key>', 'API key (or env: OPENAI_API_KEY, ANTHROPIC_API_KEY, MINIMAX_API_KEY)')
|
|
21
|
+
.option('-m, --model <model>', 'Model (OpenAI default gpt-4o-mini; Anthropic claude-3-5-sonnet; MiniMax MiniMax-M2.1)')
|
|
22
|
+
.option('--minimax-base-url <url>', 'MiniMax API base URL (default: https://api.minimax.io/v1 or MINIMAX_BASE_URL)')
|
|
23
|
+
.option('-s, --style <style>', 'Writing style: casual, formal, technical, creative, custom', 'custom')
|
|
24
|
+
.option('--prompt <prompt>', 'Custom rewrite prompt')
|
|
25
|
+
.option('-t, --temperature <number>', 'Temperature (0-1)', parseFloat, 0.7)
|
|
26
|
+
.option('--max-tokens <number>', 'Max tokens per request', parseInt, 4000)
|
|
27
|
+
.option('--preserve-length', 'Try to preserve original length')
|
|
28
|
+
.option('-c, --concurrency <number>', 'Concurrent API requests', parseInt, 3)
|
|
29
|
+
.option('-v, --verbose', 'Verbose output')
|
|
30
|
+
.option('--mode <mode>', 'Rewrite mode: section (按标题分章,默认), full (整篇一次,最连贯)', 'section')
|
|
31
|
+
.option('--section-level <level>', 'Section level for section mode (1-3)', parseInt, 1)
|
|
32
|
+
.action(async (options) => {
|
|
33
|
+
try {
|
|
34
|
+
if (!['section', 'full'].includes(options.mode)) {
|
|
35
|
+
console.error('❌ 错误:mode 必须是 section 或 full');
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
if (options.mode === 'full') {
|
|
39
|
+
console.log('ℹ️ 使用全文改写模式(最连贯,但token消耗较大)\n');
|
|
40
|
+
}
|
|
41
|
+
const apiKey = options.apiKey ||
|
|
42
|
+
(options.provider === 'openai'
|
|
43
|
+
? process.env.OPENAI_API_KEY
|
|
44
|
+
: options.provider === 'anthropic'
|
|
45
|
+
? process.env.ANTHROPIC_API_KEY
|
|
46
|
+
: process.env.MINIMAX_API_KEY);
|
|
47
|
+
if (!apiKey) {
|
|
48
|
+
console.error('❌ 错误:需要 API key');
|
|
49
|
+
console.error(' 设置环境变量: OPENAI_API_KEY、ANTHROPIC_API_KEY 或 MINIMAX_API_KEY(与 --provider 对应)');
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
const markdown = (0, fs_1.readFileSync)(options.input, 'utf-8');
|
|
53
|
+
const config = {
|
|
54
|
+
provider: options.provider,
|
|
55
|
+
apiKey,
|
|
56
|
+
model: options.model,
|
|
57
|
+
minimaxBaseUrl: options.minimaxBaseUrl,
|
|
58
|
+
verbose: options.verbose,
|
|
59
|
+
concurrency: options.concurrency,
|
|
60
|
+
mode: options.mode,
|
|
61
|
+
sectionLevel: options.sectionLevel,
|
|
62
|
+
options: {
|
|
63
|
+
style: options.style,
|
|
64
|
+
prompt: options.prompt,
|
|
65
|
+
temperature: options.temperature,
|
|
66
|
+
maxTokens: options.maxTokens,
|
|
67
|
+
preserveLength: options.preserveLength,
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
const modeLabel = options.mode === 'section' ? '章节级' : '全文';
|
|
71
|
+
console.log(`🚀 开始${modeLabel}改写 (${options.provider})...`);
|
|
72
|
+
const rewriter = new rewriter_1.MarkdownRewriter(config);
|
|
73
|
+
const result = await rewriter.rewrite(markdown);
|
|
74
|
+
(0, fs_1.writeFileSync)(options.output, result.rewritten, 'utf-8');
|
|
75
|
+
console.log('\n✅ 改写完成!');
|
|
76
|
+
console.log('📊 统计:');
|
|
77
|
+
console.log(` - 处理单元: ${result.blocksProcessed}`);
|
|
78
|
+
console.log(` - 已改写: ${result.blocksRewritten}`);
|
|
79
|
+
console.log(` - 输出文件: ${options.output}`);
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
console.error(`❌ 错误:${error.message}`);
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
program.parse();
|
|
87
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { RewriteResult, RewriteOptions, AIProvider } from '../types';
|
|
2
|
+
export declare class FullRewriter {
|
|
3
|
+
private provider;
|
|
4
|
+
private verbose;
|
|
5
|
+
constructor(provider: AIProvider, verbose?: boolean);
|
|
6
|
+
rewrite(markdown: string, options: RewriteOptions): Promise<RewriteResult>;
|
|
7
|
+
/**
|
|
8
|
+
* 保护图片:替换为占位符
|
|
9
|
+
*/
|
|
10
|
+
private protectImages;
|
|
11
|
+
/**
|
|
12
|
+
* 构建带图片保护的提示词
|
|
13
|
+
*/
|
|
14
|
+
private buildProtectedPrompt;
|
|
15
|
+
/**
|
|
16
|
+
* 验证占位符是否都保留了
|
|
17
|
+
*/
|
|
18
|
+
private validateAnchors;
|
|
19
|
+
/**
|
|
20
|
+
* 尝试修复丢失的占位符
|
|
21
|
+
*/
|
|
22
|
+
private fixMissingAnchors;
|
|
23
|
+
/**
|
|
24
|
+
* 恢复图片
|
|
25
|
+
*/
|
|
26
|
+
private restoreImages;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=full-rewriter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"full-rewriter.d.ts","sourceRoot":"","sources":["../../src/core/full-rewriter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAe,MAAM,UAAU,CAAC;AAElF,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,OAAO,CAAU;gBAEb,QAAQ,EAAE,UAAU,EAAE,OAAO,GAAE,OAAe;IAKpD,OAAO,CACX,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,aAAa,CAAC;IAwCzB;;OAEG;IACH,OAAO,CAAC,aAAa;IAkDrB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAkC5B;;OAEG;IACH,OAAO,CAAC,eAAe;IAkBvB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA2DzB;;OAEG;IACH,OAAO,CAAC,aAAa;CAsBtB"}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FullRewriter = void 0;
|
|
4
|
+
class FullRewriter {
|
|
5
|
+
constructor(provider, verbose = false) {
|
|
6
|
+
this.provider = provider;
|
|
7
|
+
this.verbose = verbose;
|
|
8
|
+
}
|
|
9
|
+
async rewrite(markdown, options) {
|
|
10
|
+
// 1. 提取并保护图片
|
|
11
|
+
const { content, anchors } = this.protectImages(markdown);
|
|
12
|
+
if (this.verbose) {
|
|
13
|
+
console.log(`🖼️ 检测到 ${anchors.length} 张图片`);
|
|
14
|
+
console.log(`📝 准备改写全文 (${content.length} 字符)`);
|
|
15
|
+
}
|
|
16
|
+
// 2. 构建强约束提示词
|
|
17
|
+
const enhancedPrompt = this.buildProtectedPrompt(options, anchors.length);
|
|
18
|
+
// 3. AI 改写
|
|
19
|
+
const rewritten = await this.provider.rewrite(content, {
|
|
20
|
+
...options,
|
|
21
|
+
prompt: enhancedPrompt,
|
|
22
|
+
});
|
|
23
|
+
// 4. 验证占位符是否保留
|
|
24
|
+
const validation = this.validateAnchors(rewritten, anchors);
|
|
25
|
+
if (!validation.success) {
|
|
26
|
+
if (this.verbose) {
|
|
27
|
+
console.warn(`⚠️ 警告:${validation.missing.length} 个图片占位符丢失,尝试修复...`);
|
|
28
|
+
}
|
|
29
|
+
// 尝试修复
|
|
30
|
+
const fixed = this.fixMissingAnchors(rewritten, anchors, validation.missing);
|
|
31
|
+
return this.restoreImages(fixed, anchors, markdown);
|
|
32
|
+
}
|
|
33
|
+
// 5. 恢复图片
|
|
34
|
+
const final = this.restoreImages(rewritten, anchors, markdown);
|
|
35
|
+
if (this.verbose) {
|
|
36
|
+
console.log('✅ 改写完成,图片位置已恢复');
|
|
37
|
+
}
|
|
38
|
+
return final;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* 保护图片:替换为占位符
|
|
42
|
+
*/
|
|
43
|
+
protectImages(markdown) {
|
|
44
|
+
const anchors = [];
|
|
45
|
+
const lines = markdown.split('\n');
|
|
46
|
+
const result = [];
|
|
47
|
+
for (let i = 0; i < lines.length; i++) {
|
|
48
|
+
const line = lines[i];
|
|
49
|
+
// 检测图片行
|
|
50
|
+
const imageMatch = line.match(/^!\[([^\]]*)\]\(([^)]+)\)/);
|
|
51
|
+
if (imageMatch) {
|
|
52
|
+
const anchorId = `IMAGE_ANCHOR_${String(anchors.length + 1).padStart(3, '0')}`;
|
|
53
|
+
const placeholder = `{{${anchorId}}}`;
|
|
54
|
+
// 获取上下文(前后各2行)
|
|
55
|
+
const contextBefore = lines.slice(Math.max(0, i - 2), i)
|
|
56
|
+
.join('\n')
|
|
57
|
+
.trim();
|
|
58
|
+
const contextAfter = lines.slice(i + 1, Math.min(lines.length, i + 3))
|
|
59
|
+
.join('\n')
|
|
60
|
+
.trim();
|
|
61
|
+
anchors.push({
|
|
62
|
+
id: anchorId,
|
|
63
|
+
syntax: line,
|
|
64
|
+
placeholder,
|
|
65
|
+
contextBefore: contextBefore.substring(0, 100),
|
|
66
|
+
contextAfter: contextAfter.substring(0, 100),
|
|
67
|
+
});
|
|
68
|
+
result.push(placeholder);
|
|
69
|
+
if (this.verbose) {
|
|
70
|
+
console.log(` 🔒 保护: ${imageMatch[1] || imageMatch[2]} → ${anchorId}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
result.push(line);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
content: result.join('\n'),
|
|
79
|
+
anchors,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* 构建带图片保护的提示词
|
|
84
|
+
*/
|
|
85
|
+
buildProtectedPrompt(options, imageCount) {
|
|
86
|
+
const basePrompt = options.prompt || '改写以下内容,保持核心信息但改变表达方式。';
|
|
87
|
+
if (imageCount === 0) {
|
|
88
|
+
return basePrompt;
|
|
89
|
+
}
|
|
90
|
+
return `${basePrompt}
|
|
91
|
+
|
|
92
|
+
⚠️ 重要约束:
|
|
93
|
+
文中包含 ${imageCount} 个图片占位符,格式为 {{IMAGE_ANCHOR_XXX}}
|
|
94
|
+
|
|
95
|
+
**你必须严格遵守以下规则:**
|
|
96
|
+
1. ✅ 保留所有 {{IMAGE_ANCHOR_XXX}} 占位符,一个都不能删除或修改
|
|
97
|
+
2. ✅ 占位符必须独立成行,前后都有空行
|
|
98
|
+
3. ✅ 占位符的顺序不能改变(001, 002, 003...)
|
|
99
|
+
4. ✅ 可以调整占位符前后的文字内容,但占位符本身必须完整保留
|
|
100
|
+
5. ❌ 不要在占位符中添加任何文字说明或解释
|
|
101
|
+
|
|
102
|
+
示例正确格式:
|
|
103
|
+
"""
|
|
104
|
+
改写后的段落内容。
|
|
105
|
+
|
|
106
|
+
{{IMAGE_ANCHOR_001}}
|
|
107
|
+
|
|
108
|
+
继续改写的内容。
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
现在开始改写:`;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* 验证占位符是否都保留了
|
|
115
|
+
*/
|
|
116
|
+
validateAnchors(content, anchors) {
|
|
117
|
+
const missing = [];
|
|
118
|
+
for (const anchor of anchors) {
|
|
119
|
+
if (!content.includes(anchor.placeholder)) {
|
|
120
|
+
missing.push(anchor);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
success: missing.length === 0,
|
|
125
|
+
missing,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* 尝试修复丢失的占位符
|
|
130
|
+
*/
|
|
131
|
+
fixMissingAnchors(content, allAnchors, missingAnchors) {
|
|
132
|
+
let fixed = content;
|
|
133
|
+
for (const missing of missingAnchors) {
|
|
134
|
+
// 策略1: 在上下文附近查找合适位置
|
|
135
|
+
if (missing.contextAfter) {
|
|
136
|
+
const afterMatch = fixed.indexOf(missing.contextAfter.substring(0, 30));
|
|
137
|
+
if (afterMatch !== -1) {
|
|
138
|
+
// 在找到的上下文之前插入占位符
|
|
139
|
+
fixed =
|
|
140
|
+
fixed.substring(0, afterMatch) +
|
|
141
|
+
`\n\n${missing.placeholder}\n\n` +
|
|
142
|
+
fixed.substring(afterMatch);
|
|
143
|
+
if (this.verbose) {
|
|
144
|
+
console.log(` 🔧 修复: ${missing.id} (通过下文上下文)`);
|
|
145
|
+
}
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// 策略2: 根据相对位置估算
|
|
150
|
+
const index = allAnchors.indexOf(missing);
|
|
151
|
+
if (index > 0 && index < allAnchors.length - 1) {
|
|
152
|
+
const prevAnchor = allAnchors[index - 1];
|
|
153
|
+
const nextAnchor = allAnchors[index + 1];
|
|
154
|
+
const prevPos = fixed.indexOf(prevAnchor.placeholder);
|
|
155
|
+
const nextPos = fixed.indexOf(nextAnchor.placeholder);
|
|
156
|
+
if (prevPos !== -1 && nextPos !== -1) {
|
|
157
|
+
// 在两个占位符之间插入
|
|
158
|
+
const middlePos = prevPos + Math.floor((nextPos - prevPos) / 2);
|
|
159
|
+
fixed =
|
|
160
|
+
fixed.substring(0, middlePos) +
|
|
161
|
+
`\n\n${missing.placeholder}\n\n` +
|
|
162
|
+
fixed.substring(middlePos);
|
|
163
|
+
if (this.verbose) {
|
|
164
|
+
console.log(` 🔧 修复: ${missing.id} (通过相对位置)`);
|
|
165
|
+
}
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// 策略3: 追加到末尾(最后的手段)
|
|
170
|
+
if (this.verbose) {
|
|
171
|
+
console.warn(` ⚠️ 无法精确定位 ${missing.id},追加到末尾`);
|
|
172
|
+
}
|
|
173
|
+
fixed += `\n\n${missing.placeholder}\n`;
|
|
174
|
+
}
|
|
175
|
+
return fixed;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* 恢复图片
|
|
179
|
+
*/
|
|
180
|
+
restoreImages(content, anchors, original) {
|
|
181
|
+
let restored = content;
|
|
182
|
+
// 按顺序替换占位符为原始图片语法
|
|
183
|
+
for (const anchor of anchors) {
|
|
184
|
+
restored = restored.replace(new RegExp(anchor.placeholder.replace(/[{}]/g, '\\$&'), 'g'), anchor.syntax);
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
original,
|
|
188
|
+
rewritten: restored,
|
|
189
|
+
blocksProcessed: 1,
|
|
190
|
+
blocksRewritten: 1,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
exports.FullRewriter = FullRewriter;
|
|
195
|
+
//# sourceMappingURL=full-rewriter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"full-rewriter.js","sourceRoot":"","sources":["../../src/core/full-rewriter.ts"],"names":[],"mappings":"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"}
|