@astro-minimax/cli 0.5.0 → 0.7.1

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.
Files changed (174) hide show
  1. package/README.md +69 -0
  2. package/dist/commands/ai.d.ts +2 -0
  3. package/dist/commands/ai.d.ts.map +1 -0
  4. package/dist/commands/ai.js +99 -0
  5. package/dist/commands/ai.js.map +1 -0
  6. package/dist/commands/data.d.ts +2 -0
  7. package/dist/commands/data.d.ts.map +1 -0
  8. package/dist/commands/data.js +111 -0
  9. package/dist/commands/data.js.map +1 -0
  10. package/dist/commands/hooks.d.ts +2 -0
  11. package/dist/commands/hooks.d.ts.map +1 -0
  12. package/dist/commands/hooks.js +378 -0
  13. package/dist/commands/hooks.js.map +1 -0
  14. package/dist/commands/init.d.ts +2 -0
  15. package/dist/commands/init.d.ts.map +1 -0
  16. package/dist/commands/init.js +50 -0
  17. package/dist/commands/init.js.map +1 -0
  18. package/dist/commands/podcast.d.ts +2 -0
  19. package/dist/commands/podcast.d.ts.map +1 -0
  20. package/dist/commands/podcast.js +89 -0
  21. package/dist/commands/podcast.js.map +1 -0
  22. package/dist/commands/post.d.ts +2 -0
  23. package/dist/commands/post.d.ts.map +1 -0
  24. package/dist/commands/post.js +190 -0
  25. package/dist/commands/post.js.map +1 -0
  26. package/dist/commands/profile.d.ts +2 -0
  27. package/dist/commands/profile.d.ts.map +1 -0
  28. package/dist/commands/profile.js +88 -0
  29. package/dist/commands/profile.js.map +1 -0
  30. package/dist/index.d.ts +3 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +81 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/tools/ai-process.d.ts +20 -0
  35. package/dist/tools/ai-process.d.ts.map +1 -0
  36. package/dist/tools/ai-process.js +607 -0
  37. package/dist/tools/ai-process.js.map +1 -0
  38. package/dist/tools/build-author-context.d.ts +13 -0
  39. package/dist/tools/build-author-context.d.ts.map +1 -0
  40. package/dist/tools/build-author-context.js +313 -0
  41. package/dist/tools/build-author-context.js.map +1 -0
  42. package/dist/tools/build-voice-profile.d.ts +12 -0
  43. package/dist/tools/build-voice-profile.d.ts.map +1 -0
  44. package/dist/tools/build-voice-profile.js +270 -0
  45. package/dist/tools/build-voice-profile.js.map +1 -0
  46. package/dist/tools/eval-ai-chat.d.ts +17 -0
  47. package/dist/tools/eval-ai-chat.d.ts.map +1 -0
  48. package/dist/tools/eval-ai-chat.js +362 -0
  49. package/dist/tools/eval-ai-chat.js.map +1 -0
  50. package/dist/tools/generate-author-profile.d.ts +14 -0
  51. package/dist/tools/generate-author-profile.d.ts.map +1 -0
  52. package/dist/tools/generate-author-profile.js +289 -0
  53. package/dist/tools/generate-author-profile.js.map +1 -0
  54. package/dist/tools/generate-cover.d.ts +14 -0
  55. package/dist/tools/generate-cover.d.ts.map +1 -0
  56. package/dist/tools/generate-cover.js +95 -0
  57. package/dist/tools/generate-cover.js.map +1 -0
  58. package/dist/tools/generate-og.d.ts +3 -0
  59. package/dist/tools/generate-og.d.ts.map +1 -0
  60. package/dist/tools/generate-og.js +254 -0
  61. package/dist/tools/generate-og.js.map +1 -0
  62. package/dist/tools/generate-related.d.ts +11 -0
  63. package/dist/tools/generate-related.d.ts.map +1 -0
  64. package/dist/tools/generate-related.js +124 -0
  65. package/dist/tools/generate-related.js.map +1 -0
  66. package/dist/tools/generate-tags.d.ts +14 -0
  67. package/dist/tools/generate-tags.d.ts.map +1 -0
  68. package/dist/tools/generate-tags.js +182 -0
  69. package/dist/tools/generate-tags.js.map +1 -0
  70. package/dist/tools/lib/ai-provider.d.ts +43 -0
  71. package/dist/tools/lib/ai-provider.d.ts.map +1 -0
  72. package/dist/tools/lib/ai-provider.js +146 -0
  73. package/dist/tools/lib/ai-provider.js.map +1 -0
  74. package/dist/tools/lib/audio-processor.d.ts +46 -0
  75. package/dist/tools/lib/audio-processor.d.ts.map +1 -0
  76. package/dist/tools/lib/audio-processor.js +188 -0
  77. package/dist/tools/lib/audio-processor.js.map +1 -0
  78. package/dist/tools/lib/frontmatter.d.ts +11 -0
  79. package/dist/tools/lib/frontmatter.d.ts.map +1 -0
  80. package/dist/tools/lib/frontmatter.js +80 -0
  81. package/dist/tools/lib/frontmatter.js.map +1 -0
  82. package/dist/tools/lib/index.d.ts +7 -0
  83. package/dist/tools/lib/index.d.ts.map +1 -0
  84. package/{template/tools/lib/index.ts → dist/tools/lib/index.js} +1 -0
  85. package/dist/tools/lib/index.js.map +1 -0
  86. package/dist/tools/lib/markdown.d.ts +6 -0
  87. package/dist/tools/lib/markdown.d.ts.map +1 -0
  88. package/dist/tools/lib/markdown.js +34 -0
  89. package/dist/tools/lib/markdown.js.map +1 -0
  90. package/dist/tools/lib/posts.d.ts +25 -0
  91. package/dist/tools/lib/posts.d.ts.map +1 -0
  92. package/dist/tools/lib/posts.js +63 -0
  93. package/dist/tools/lib/posts.js.map +1 -0
  94. package/dist/tools/lib/script-generator.d.ts +61 -0
  95. package/dist/tools/lib/script-generator.d.ts.map +1 -0
  96. package/dist/tools/lib/script-generator.js +182 -0
  97. package/dist/tools/lib/script-generator.js.map +1 -0
  98. package/dist/tools/lib/tts-provider.d.ts +65 -0
  99. package/dist/tools/lib/tts-provider.d.ts.map +1 -0
  100. package/dist/tools/lib/tts-provider.js +116 -0
  101. package/dist/tools/lib/tts-provider.js.map +1 -0
  102. package/dist/tools/lib/types.d.ts +129 -0
  103. package/dist/tools/lib/types.d.ts.map +1 -0
  104. package/dist/tools/lib/types.js +64 -0
  105. package/dist/tools/lib/types.js.map +1 -0
  106. package/dist/tools/lib/utils.d.ts +18 -0
  107. package/dist/tools/lib/utils.d.ts.map +1 -0
  108. package/dist/tools/lib/utils.js +121 -0
  109. package/dist/tools/lib/utils.js.map +1 -0
  110. package/dist/tools/lib/vectors.d.ts +27 -0
  111. package/dist/tools/lib/vectors.d.ts.map +1 -0
  112. package/dist/tools/lib/vectors.js +64 -0
  113. package/dist/tools/lib/vectors.js.map +1 -0
  114. package/dist/tools/podcast-feed.d.ts +6 -0
  115. package/dist/tools/podcast-feed.d.ts.map +1 -0
  116. package/dist/tools/podcast-feed.js +121 -0
  117. package/dist/tools/podcast-feed.js.map +1 -0
  118. package/dist/tools/podcast-generate.d.ts +15 -0
  119. package/dist/tools/podcast-generate.d.ts.map +1 -0
  120. package/dist/tools/podcast-generate.js +318 -0
  121. package/dist/tools/podcast-generate.js.map +1 -0
  122. package/dist/tools/podcast-list.d.ts +6 -0
  123. package/dist/tools/podcast-list.d.ts.map +1 -0
  124. package/dist/tools/podcast-list.js +66 -0
  125. package/dist/tools/podcast-list.js.map +1 -0
  126. package/dist/tools/summarize.d.ts +16 -0
  127. package/dist/tools/summarize.d.ts.map +1 -0
  128. package/dist/tools/summarize.js +108 -0
  129. package/dist/tools/summarize.js.map +1 -0
  130. package/dist/tools/translate.d.ts +13 -0
  131. package/dist/tools/translate.d.ts.map +1 -0
  132. package/dist/tools/translate.js +46 -0
  133. package/dist/tools/translate.js.map +1 -0
  134. package/dist/tools/vectorize.d.ts +13 -0
  135. package/dist/tools/vectorize.d.ts.map +1 -0
  136. package/dist/tools/vectorize.js +87 -0
  137. package/dist/tools/vectorize.js.map +1 -0
  138. package/package.json +14 -9
  139. package/template/astro.config.ts +8 -28
  140. package/template/datas/ai-seo.json +8 -0
  141. package/template/datas/ai-skip-list.json +1 -0
  142. package/template/datas/author-profile-context.json +21 -0
  143. package/template/datas/author-profile-report.json +21 -0
  144. package/template/datas/eval/gold-set.json +72 -0
  145. package/template/functions/README.md +82 -0
  146. package/template/functions/api/ai-info.ts +2 -2
  147. package/template/functions/api/chat.ts +4 -1
  148. package/template/functions/api/notify/comment.ts +140 -68
  149. package/template/functions/api/notify/debug.ts +41 -0
  150. package/template/functions/api/notify/status.ts +97 -0
  151. package/template/functions/api/notify/test-ai-chat.ts +67 -0
  152. package/template/package.json +22 -25
  153. package/template/src/config.ts +11 -0
  154. package/template/src/content.config.ts +29 -16
  155. package/template/src/env.d.ts +0 -5
  156. package/index.js +0 -36
  157. package/template/tools/README.md +0 -169
  158. package/template/tools/ai-process.ts +0 -816
  159. package/template/tools/build-author-context.ts +0 -405
  160. package/template/tools/build-voice-profile.ts +0 -322
  161. package/template/tools/generate-author-profile.ts +0 -369
  162. package/template/tools/generate-cover.ts +0 -123
  163. package/template/tools/generate-og.ts +0 -280
  164. package/template/tools/generate-related.ts +0 -146
  165. package/template/tools/generate-tags.ts +0 -251
  166. package/template/tools/lib/ai-provider.ts +0 -240
  167. package/template/tools/lib/frontmatter.ts +0 -94
  168. package/template/tools/lib/markdown.ts +0 -40
  169. package/template/tools/lib/posts.ts +0 -89
  170. package/template/tools/lib/utils.ts +0 -138
  171. package/template/tools/lib/vectors.ts +0 -96
  172. package/template/tools/summarize.ts +0 -142
  173. package/template/tools/translate.ts +0 -60
  174. package/template/tools/vectorize.ts +0 -105
@@ -0,0 +1,318 @@
1
+ #!/usr/bin/env npx tsx
2
+ /**
3
+ * Podcast Generation Script
4
+ *
5
+ * Usage:
6
+ * pnpm podcast:generate Generate all podcasts
7
+ * pnpm podcast:generate --slug=zh/xxx Single article
8
+ * pnpm podcast:generate --task=script Script only
9
+ * pnpm podcast:generate --task=audio Audio only
10
+ * pnpm podcast:generate --force Ignore cache
11
+ * pnpm podcast:generate --dry-run Preview only
12
+ * pnpm podcast:generate --lang=zh Specific language
13
+ */
14
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
15
+ import { join } from "node:path";
16
+ import crypto from "node:crypto";
17
+ import { getAllPosts } from "./lib/posts.js";
18
+ import { extractFrontmatter } from "./lib/frontmatter.js";
19
+ import { hasAPIKey, getConfig } from "./lib/ai-provider.js";
20
+ import { hasTTSApiKey } from "./lib/tts-provider.js";
21
+ import { textToSpeech } from "./lib/tts-provider.js";
22
+ import { concatenateAudio, getAudioDuration } from "./lib/audio-processor.js";
23
+ import { generateScript } from "./lib/script-generator.js";
24
+ import { DEFAULT_SPEAKERS, isValidOpenAIVoice, } from "./lib/types.js";
25
+ const DATA_DIR = join(process.cwd(), "datas");
26
+ const PUBLIC_DIR = join(process.cwd(), "public", "podcasts");
27
+ const SCRIPTS_FILE = join(DATA_DIR, "podcast-scripts.json");
28
+ const AUDIO_FILE = join(DATA_DIR, "podcast-audio.json");
29
+ const SKIP_LIST_FILE = join(DATA_DIR, "ai-skip-list.json");
30
+ function parseArgs() {
31
+ const args = process.argv.slice(2);
32
+ const flags = {
33
+ force: false,
34
+ slug: null,
35
+ task: null,
36
+ dryRun: false,
37
+ concurrency: 5,
38
+ lang: null,
39
+ };
40
+ for (const arg of args) {
41
+ if (arg === "--force")
42
+ flags.force = true;
43
+ else if (arg === "--dry-run")
44
+ flags.dryRun = true;
45
+ else if (arg.startsWith("--slug="))
46
+ flags.slug = arg.split("=")[1];
47
+ else if (arg.startsWith("--task="))
48
+ flags.task = arg.split("=")[1];
49
+ else if (arg.startsWith("--concurrency="))
50
+ flags.concurrency = parseInt(arg.split("=")[1], 10);
51
+ else if (arg.startsWith("--lang="))
52
+ flags.lang = arg.split("=")[1];
53
+ }
54
+ return flags;
55
+ }
56
+ function createCacheManager(cacheFile) {
57
+ let cache = null;
58
+ let writeQueue = Promise.resolve();
59
+ return {
60
+ async load() {
61
+ const cachePath = join(DATA_DIR, cacheFile);
62
+ try {
63
+ const raw = await readFile(cachePath, "utf-8");
64
+ cache = JSON.parse(raw);
65
+ }
66
+ catch {
67
+ cache = {
68
+ meta: { lastUpdated: null, totalProcessed: 0 },
69
+ articles: {},
70
+ };
71
+ }
72
+ return cache;
73
+ },
74
+ getCache() {
75
+ return cache;
76
+ },
77
+ async writeEntry(slug, entry, model) {
78
+ writeQueue = writeQueue.then(async () => {
79
+ if (!cache)
80
+ return;
81
+ cache.articles[slug] = entry;
82
+ cache.meta.lastUpdated = new Date().toISOString();
83
+ cache.meta.totalProcessed = Object.keys(cache.articles).length;
84
+ await mkdir(DATA_DIR, { recursive: true });
85
+ const cachePath = join(DATA_DIR, cacheFile);
86
+ await writeFile(cachePath, JSON.stringify(cache, null, 2), "utf-8");
87
+ });
88
+ return writeQueue;
89
+ },
90
+ };
91
+ }
92
+ function createAudioCacheManager() {
93
+ let cache = null;
94
+ let writeQueue = Promise.resolve();
95
+ return {
96
+ async load() {
97
+ try {
98
+ const raw = await readFile(AUDIO_FILE, "utf-8");
99
+ cache = JSON.parse(raw);
100
+ }
101
+ catch {
102
+ cache = {
103
+ meta: { lastUpdated: null, totalProcessed: 0 },
104
+ articles: {},
105
+ };
106
+ }
107
+ return cache;
108
+ },
109
+ async writeEntry(slug, entry) {
110
+ writeQueue = writeQueue.then(async () => {
111
+ if (!cache)
112
+ return;
113
+ cache.articles[slug] = entry;
114
+ cache.meta.lastUpdated = new Date().toISOString();
115
+ cache.meta.totalProcessed = Object.keys(cache.articles).length;
116
+ await mkdir(DATA_DIR, { recursive: true });
117
+ await writeFile(AUDIO_FILE, JSON.stringify(cache, null, 2), "utf-8");
118
+ });
119
+ return writeQueue;
120
+ },
121
+ };
122
+ }
123
+ async function loadSkipList() {
124
+ try {
125
+ const raw = await readFile(SKIP_LIST_FILE, "utf-8");
126
+ return JSON.parse(raw);
127
+ }
128
+ catch {
129
+ return {};
130
+ }
131
+ }
132
+ async function saveSkipList(skipList) {
133
+ await mkdir(DATA_DIR, { recursive: true });
134
+ await writeFile(SKIP_LIST_FILE, JSON.stringify(skipList, null, 2), "utf-8");
135
+ }
136
+ function sleep(ms) {
137
+ return new Promise((resolve) => setTimeout(resolve, ms));
138
+ }
139
+ async function scanArticles(flags) {
140
+ const allPosts = await getAllPosts({ includeDrafts: false, stripBody: false });
141
+ const articles = [];
142
+ for (const post of allPosts) {
143
+ if (post.draft)
144
+ continue;
145
+ if (flags.lang && post.lang !== flags.lang)
146
+ continue;
147
+ const rawContent = await readFile(post.filePath, "utf-8");
148
+ const fm = extractFrontmatter(rawContent);
149
+ const contentHash = crypto
150
+ .createHash("md5")
151
+ .update(fm.body)
152
+ .digest("hex")
153
+ .slice(0, 8);
154
+ const pubDatetime = fm.data.pubDatetime;
155
+ const pubTimestamp = pubDatetime
156
+ ? new Date(pubDatetime).getTime()
157
+ : 0;
158
+ articles.push({
159
+ ...post,
160
+ contentHash,
161
+ fullContent: fm.body,
162
+ pubTimestamp,
163
+ });
164
+ }
165
+ articles.sort((a, b) => b.pubTimestamp - a.pubTimestamp);
166
+ return articles;
167
+ }
168
+ async function processArticle(article, flags, scriptCache, audioCache, skipList) {
169
+ const config = getConfig();
170
+ const lang = article.lang;
171
+ const speakers = DEFAULT_SPEAKERS[lang];
172
+ try {
173
+ let script = null;
174
+ if (flags.task !== "audio") {
175
+ script = await generateScript({
176
+ id: article.id,
177
+ title: article.title,
178
+ lang,
179
+ body: article.fullContent,
180
+ category: article.category || "",
181
+ tags: article.tags,
182
+ }, { speakers });
183
+ script.contentHash = article.contentHash;
184
+ if (!flags.dryRun) {
185
+ await scriptCache.writeEntry(article.id, script, config.model);
186
+ }
187
+ }
188
+ if (flags.task !== "script") {
189
+ if (!script) {
190
+ const cache = scriptCache.getCache();
191
+ script = cache?.articles[article.id] || null;
192
+ }
193
+ if (!script) {
194
+ return { success: false, error: "No script available for audio generation" };
195
+ }
196
+ if (!hasTTSApiKey()) {
197
+ return { success: false, error: "TTS API key not configured" };
198
+ }
199
+ const audioSegments = [];
200
+ for (const segment of script.segments) {
201
+ const speaker = speakers.find((s) => s.id === segment.speaker) || speakers[0];
202
+ const voice = isValidOpenAIVoice(speaker.voiceId) ? speaker.voiceId : "alloy";
203
+ const audio = await textToSpeech(segment.text, { voice });
204
+ audioSegments.push(audio);
205
+ await sleep(200);
206
+ }
207
+ const finalAudio = await concatenateAudio(audioSegments);
208
+ const duration = await getAudioDuration(finalAudio);
209
+ const outputDir = join(PUBLIC_DIR, lang);
210
+ await mkdir(outputDir, { recursive: true });
211
+ const outputFile = join(outputDir, `${article.id.split("/")[1]}.mp3`);
212
+ await writeFile(outputFile, finalAudio);
213
+ const audioMeta = {
214
+ slug: article.id,
215
+ lang,
216
+ duration,
217
+ fileSize: finalAudio.length,
218
+ format: "mp3",
219
+ generatedAt: new Date().toISOString(),
220
+ contentHash: article.contentHash,
221
+ };
222
+ if (!flags.dryRun) {
223
+ await audioCache.writeEntry(article.id, audioMeta);
224
+ }
225
+ }
226
+ const skipKey = `podcast:${article.id}`;
227
+ if (skipList[skipKey]) {
228
+ delete skipList[skipKey];
229
+ await saveSkipList(skipList);
230
+ }
231
+ return { success: true };
232
+ }
233
+ catch (err) {
234
+ const errorMsg = err.message;
235
+ await saveSkipList({
236
+ ...skipList,
237
+ [`podcast:${article.id}`]: {
238
+ slug: article.id,
239
+ task: "podcast",
240
+ reason: errorMsg,
241
+ },
242
+ });
243
+ return { success: false, error: errorMsg };
244
+ }
245
+ }
246
+ async function main() {
247
+ const flags = parseArgs();
248
+ if (!hasAPIKey()) {
249
+ console.error("Missing AI API Key. Set AI_API_KEY environment variable.");
250
+ process.exit(1);
251
+ }
252
+ const config = getConfig();
253
+ let skipList = await loadSkipList();
254
+ console.log("Podcast Generator (astro-minimax)");
255
+ console.log("─".repeat(50));
256
+ console.log(`Model: ${config.model}`);
257
+ console.log(`API: ${config.baseUrl}`);
258
+ console.log("");
259
+ console.log("Scanning articles...");
260
+ let articles = await scanArticles(flags);
261
+ console.log(`Found ${articles.length} articles`);
262
+ if (flags.slug) {
263
+ articles = articles.filter((a) => a.id === flags.slug);
264
+ if (articles.length === 0) {
265
+ console.error(`Article not found: ${flags.slug}`);
266
+ process.exit(1);
267
+ }
268
+ console.log(`Processing single article: ${flags.slug}`);
269
+ }
270
+ const scriptCache = createCacheManager("podcast-scripts.json");
271
+ await scriptCache.load();
272
+ const audioCache = createAudioCacheManager();
273
+ await audioCache.load();
274
+ const queue = [];
275
+ for (const article of articles) {
276
+ const skipKey = `podcast:${article.id}`;
277
+ if (!flags.force && skipList[skipKey]) {
278
+ continue;
279
+ }
280
+ const cached = scriptCache.getCache()?.articles[article.id];
281
+ if (flags.force || !cached || cached.contentHash !== article.contentHash) {
282
+ queue.push(article);
283
+ }
284
+ }
285
+ console.log(`Processing: ${queue.length} articles`);
286
+ if (flags.dryRun) {
287
+ console.log("\nDry run - would process:");
288
+ for (const a of queue) {
289
+ console.log(` - ${a.id}`);
290
+ }
291
+ return;
292
+ }
293
+ if (queue.length === 0) {
294
+ console.log("Nothing to process");
295
+ return;
296
+ }
297
+ let success = 0;
298
+ let failed = 0;
299
+ for (let i = 0; i < queue.length; i++) {
300
+ const article = queue[i];
301
+ console.log(`\n[${i + 1}/${queue.length}] Processing: ${article.id}`);
302
+ const result = await processArticle(article, flags, scriptCache, audioCache, skipList);
303
+ if (result.success) {
304
+ success++;
305
+ console.log(` Done`);
306
+ }
307
+ else {
308
+ failed++;
309
+ console.error(` Failed: ${result.error}`);
310
+ }
311
+ }
312
+ console.log(`\nCompleted: ${success} success, ${failed} failed`);
313
+ }
314
+ main().catch((err) => {
315
+ console.error("Fatal error:", err.message);
316
+ process.exit(1);
317
+ });
318
+ //# sourceMappingURL=podcast-generate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"podcast-generate.js","sourceRoot":"","sources":["../../src/tools/podcast-generate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env npx tsx
2
+ /**
3
+ * List generated podcasts
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=podcast-list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"podcast-list.d.ts","sourceRoot":"","sources":["../../src/tools/podcast-list.ts"],"names":[],"mappings":";AACA;;GAEG"}
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env npx tsx
2
+ /**
3
+ * List generated podcasts
4
+ */
5
+ import { readFile } from "node:fs/promises";
6
+ import { join } from "node:path";
7
+ const DATA_DIR = join(process.cwd(), "datas");
8
+ const SCRIPTS_FILE = join(DATA_DIR, "podcast-scripts.json");
9
+ const AUDIO_FILE = join(DATA_DIR, "podcast-audio.json");
10
+ async function main() {
11
+ console.log("Generated Podcasts");
12
+ console.log("─".repeat(60));
13
+ let scripts = {};
14
+ let audio = {};
15
+ try {
16
+ const scriptsData = await readFile(SCRIPTS_FILE, "utf-8");
17
+ scripts = JSON.parse(scriptsData).articles || {};
18
+ }
19
+ catch {
20
+ console.log("No scripts found. Run 'astro-minimax podcast generate' first.");
21
+ return;
22
+ }
23
+ try {
24
+ const audioData = await readFile(AUDIO_FILE, "utf-8");
25
+ audio = JSON.parse(audioData).articles || {};
26
+ }
27
+ catch { }
28
+ const slugs = Object.keys(scripts);
29
+ if (slugs.length === 0) {
30
+ console.log("No podcasts generated yet.");
31
+ return;
32
+ }
33
+ console.log(`Total: ${slugs.length} podcasts\n`);
34
+ for (const slug of slugs.sort()) {
35
+ const script = scripts[slug];
36
+ const audioMeta = audio[slug] || {};
37
+ const title = script.title || slug;
38
+ const segments = script.segments?.length || 0;
39
+ const duration = audioMeta.duration
40
+ ? formatDuration(audioMeta.duration)
41
+ : "N/A";
42
+ const size = audioMeta.fileSize
43
+ ? formatSize(audioMeta.fileSize)
44
+ : "N/A";
45
+ console.log(`${slug}`);
46
+ console.log(` Title: ${title}`);
47
+ console.log(` Segments: ${segments}`);
48
+ console.log(` Duration: ${duration}`);
49
+ console.log(` Size: ${size}`);
50
+ console.log("");
51
+ }
52
+ }
53
+ function formatDuration(seconds) {
54
+ const mins = Math.floor(seconds / 60);
55
+ const secs = Math.floor(seconds % 60);
56
+ return `${mins}:${secs.toString().padStart(2, "0")}`;
57
+ }
58
+ function formatSize(bytes) {
59
+ if (bytes < 1024)
60
+ return `${bytes} B`;
61
+ if (bytes < 1024 * 1024)
62
+ return `${(bytes / 1024).toFixed(1)} KB`;
63
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
64
+ }
65
+ main().catch(console.error);
66
+ //# sourceMappingURL=podcast-list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"podcast-list.js","sourceRoot":"","sources":["../../src/tools/podcast-list.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env npx tsx
2
+ /**
3
+ * AI 辅助写作 - 文章摘要生成
4
+ *
5
+ * 用法:
6
+ * pnpm run tools:summarize <文章路径> # 为单篇文章生成摘要
7
+ * pnpm run tools:summarize <文章路径> --write # 生成并写入 frontmatter
8
+ * pnpm run tools:summarize --all # 分析所有缺少 description 的文章
9
+ * pnpm run tools:summarize --all --dry-run # 预览所有推荐但不写入
10
+ * pnpm run tools:summarize --all --write # 批量生成并写入
11
+ *
12
+ * 环境变量:
13
+ * AI_API_KEY / OPENAI_API_KEY(可选,无 key 时使用前 200 字摘录)
14
+ */
15
+ export {};
16
+ //# sourceMappingURL=summarize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summarize.d.ts","sourceRoot":"","sources":["../../src/tools/summarize.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;GAYG"}
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env npx tsx
2
+ /**
3
+ * AI 辅助写作 - 文章摘要生成
4
+ *
5
+ * 用法:
6
+ * pnpm run tools:summarize <文章路径> # 为单篇文章生成摘要
7
+ * pnpm run tools:summarize <文章路径> --write # 生成并写入 frontmatter
8
+ * pnpm run tools:summarize --all # 分析所有缺少 description 的文章
9
+ * pnpm run tools:summarize --all --dry-run # 预览所有推荐但不写入
10
+ * pnpm run tools:summarize --all --write # 批量生成并写入
11
+ *
12
+ * 环境变量:
13
+ * AI_API_KEY / OPENAI_API_KEY(可选,无 key 时使用前 200 字摘录)
14
+ */
15
+ import { readFile } from "node:fs/promises";
16
+ import { join } from "node:path";
17
+ import { extractFrontmatter, updateFrontmatterField, } from "./lib/frontmatter.js";
18
+ import { stripMarkdown } from "./lib/markdown.js";
19
+ import { getAllPosts } from "./lib/posts.js";
20
+ import { chatCompletion, hasAPIKey } from "./lib/ai-provider.js";
21
+ import { writeFile } from "node:fs/promises";
22
+ async function generateSummary(content, title) {
23
+ if (!hasAPIKey()) {
24
+ return content.replace(/\n+/g, " ").slice(0, 200).trim() + "...";
25
+ }
26
+ try {
27
+ return await chatCompletion([
28
+ {
29
+ role: "system",
30
+ content: "你是一个技术博客编辑,擅长撰写简洁的文章摘要。根据文章内容生成 100-150 字的摘要,要求准确概括核心内容。使用与文章相同的语言。",
31
+ },
32
+ {
33
+ role: "user",
34
+ content: `文章标题: ${title}\n\n正文:\n${content.slice(0, 4000)}`,
35
+ },
36
+ ], { maxTokens: 200 });
37
+ }
38
+ catch (err) {
39
+ console.error(" 摘要生成失败:", err.message);
40
+ return content.replace(/\n+/g, " ").slice(0, 200).trim() + "...";
41
+ }
42
+ }
43
+ async function main() {
44
+ const args = process.argv.slice(2);
45
+ const all = args.includes("--all");
46
+ const dryRun = args.includes("--dry-run");
47
+ const write = args.includes("--write");
48
+ const filePath = args.find(a => !a.startsWith("--"));
49
+ const mode = hasAPIKey() ? "AI" : "文本摘录";
50
+ console.log(`📝 摘要生成模式: ${mode}\n`);
51
+ if (all) {
52
+ const allPosts = await getAllPosts();
53
+ const needsSummary = allPosts.filter(p => !p.description || p.description.length < 10);
54
+ console.log(`📚 共 ${allPosts.length} 篇文章,${needsSummary.length} 篇需要摘要\n`);
55
+ if (needsSummary.length === 0) {
56
+ console.log("✅ 所有文章都已有摘要!");
57
+ return;
58
+ }
59
+ for (const post of needsSummary) {
60
+ const relativePath = post.filePath.replace(process.cwd() + "/", "");
61
+ console.log(`📄 ${relativePath}`);
62
+ console.log(` 标题: ${post.title}`);
63
+ const summary = await generateSummary(post.body, post.title);
64
+ console.log(` 摘要: ${summary.slice(0, 100)}${summary.length > 100 ? "..." : ""}`);
65
+ if (write && !dryRun) {
66
+ const content = await readFile(post.filePath, "utf-8");
67
+ const newContent = updateFrontmatterField(content, "description", JSON.stringify(summary));
68
+ await writeFile(post.filePath, newContent, "utf-8");
69
+ console.log(` ✍️ 已写入 frontmatter`);
70
+ }
71
+ else if (dryRun) {
72
+ console.log(` (dry-run 模式,未写入)`);
73
+ }
74
+ console.log("");
75
+ if (hasAPIKey())
76
+ await new Promise(r => setTimeout(r, 500));
77
+ }
78
+ console.log(`✅ 完成!处理了 ${needsSummary.length} 篇文章`);
79
+ }
80
+ else if (filePath) {
81
+ const fullPath = join(process.cwd(), filePath);
82
+ const content = await readFile(fullPath, "utf-8");
83
+ const fm = extractFrontmatter(content);
84
+ const body = stripMarkdown(content);
85
+ const title = fm.data.title || "";
86
+ console.log(`📄 文件: ${filePath}`);
87
+ console.log(` 标题: ${title}`);
88
+ console.log(` 当前摘要: ${fm.data.description || "(无)"}\n`);
89
+ const summary = await generateSummary(body, title);
90
+ console.log(`🔍 生成的摘要:\n ${summary}\n`);
91
+ if (write) {
92
+ const newContent = updateFrontmatterField(content, "description", JSON.stringify(summary));
93
+ await writeFile(fullPath, newContent, "utf-8");
94
+ console.log(`✍️ 已写入 frontmatter`);
95
+ }
96
+ else {
97
+ console.log(`💡 使用 --write 参数写入 frontmatter`);
98
+ }
99
+ }
100
+ else {
101
+ console.error("用法:");
102
+ console.error(" pnpm run tools:summarize <文章路径> [--write]");
103
+ console.error(" pnpm run tools:summarize --all [--dry-run] [--write]");
104
+ process.exit(1);
105
+ }
106
+ }
107
+ main().catch(console.error);
108
+ //# sourceMappingURL=summarize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summarize.js","sourceRoot":"","sources":["../../src/tools/summarize.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env npx tsx
2
+ /**
3
+ * 多语言翻译工具 - 将文章翻译为目标语言
4
+ *
5
+ * 用法:
6
+ * pnpm run tools:translate <源文件> [目标语言]
7
+ * 示例: pnpm run tools:translate src/data/blog/zh/post.md en
8
+ *
9
+ * 环境变量:
10
+ * AI_API_KEY / OPENAI_API_KEY — API key
11
+ */
12
+ export {};
13
+ //# sourceMappingURL=translate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translate.d.ts","sourceRoot":"","sources":["../../src/tools/translate.ts"],"names":[],"mappings":";AACA;;;;;;;;;GASG"}
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env npx tsx
2
+ /**
3
+ * 多语言翻译工具 - 将文章翻译为目标语言
4
+ *
5
+ * 用法:
6
+ * pnpm run tools:translate <源文件> [目标语言]
7
+ * 示例: pnpm run tools:translate src/data/blog/zh/post.md en
8
+ *
9
+ * 环境变量:
10
+ * AI_API_KEY / OPENAI_API_KEY — API key
11
+ */
12
+ import { readFile, writeFile, mkdir } from "node:fs/promises";
13
+ import { resolve, dirname, basename, join } from "node:path";
14
+ import { chatCompletion } from "./lib/ai-provider.js";
15
+ async function main() {
16
+ const args = process.argv.slice(2);
17
+ const filePath = args[0];
18
+ const targetLang = args[1] || "en";
19
+ if (!filePath) {
20
+ console.error("用法: pnpm run tools:translate <源文件> [目标语言]");
21
+ process.exit(1);
22
+ }
23
+ const fullPath = resolve(process.cwd(), filePath);
24
+ const content = await readFile(fullPath, "utf-8");
25
+ const langName = targetLang === "en" ? "英文" : targetLang === "zh" ? "中文" : targetLang;
26
+ console.log(`🌐 翻译为 ${langName}...`);
27
+ const translated = await chatCompletion([
28
+ {
29
+ role: "system",
30
+ content: `你是一个专业的技术文档翻译。将内容翻译为${langName},保持 Markdown 格式和 frontmatter 结构。只输出翻译结果。`,
31
+ },
32
+ { role: "user", content },
33
+ ], { maxTokens: 4000 });
34
+ const outDir = dirname(fullPath)
35
+ .replace(/\/zh\/?$/, `/${targetLang}`)
36
+ .replace(/\/en\/?$/, `/${targetLang}`);
37
+ const outPath = join(outDir, basename(fullPath));
38
+ await mkdir(outDir, { recursive: true });
39
+ await writeFile(outPath, translated, "utf-8");
40
+ console.log(`✅ 已翻译并保存到: ${outPath}`);
41
+ }
42
+ main().catch(err => {
43
+ console.error("❌ 错误:", err.message || err);
44
+ process.exit(1);
45
+ });
46
+ //# sourceMappingURL=translate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translate.js","sourceRoot":"","sources":["../../src/tools/translate.ts"],"names":[],"mappings":";AACA;;;;;;;;;GASG;AAEH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACzB,MAAM,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;IAEnC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAC3D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,CAAC,CAAC;IAClD,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAElD,MAAM,QAAQ,GACZ,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC;IAEvE,OAAO,CAAC,GAAG,CAAC,UAAU,QAAQ,KAAK,CAAC,CAAC;IAErC,MAAM,UAAU,GAAG,MAAM,cAAc,CACrC;QACE;YACE,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,uBAAuB,QAAQ,0CAA0C;SACnF;QACD,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE;KAC1B,EACD,EAAE,SAAS,EAAE,IAAI,EAAE,CACpB,CAAC;IAEF,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;SAC7B,OAAO,CAAC,UAAU,EAAE,IAAI,UAAU,EAAE,CAAC;SACrC,OAAO,CAAC,UAAU,EAAE,IAAI,UAAU,EAAE,CAAC,CAAC;IACzC,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEjD,MAAM,KAAK,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,MAAM,SAAS,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;IAE9C,OAAO,CAAC,GAAG,CAAC,cAAc,OAAO,EAAE,CAAC,CAAC;AACvC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE;IACjB,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,CAAC;IAC3C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env npx tsx
2
+ /**
3
+ * 博客内容向量化与索引生成
4
+ *
5
+ * 用法:
6
+ * pnpm run tools:vectorize # TF-IDF 模式(无需 API Key)
7
+ * pnpm run tools:vectorize --openai # OpenAI Embeddings 模式
8
+ *
9
+ * 环境变量:
10
+ * AI_API_KEY / OPENAI_API_KEY(仅 --openai 模式需要)
11
+ */
12
+ export {};
13
+ //# sourceMappingURL=vectorize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vectorize.d.ts","sourceRoot":"","sources":["../../src/tools/vectorize.ts"],"names":[],"mappings":";AACA;;;;;;;;;GASG"}