@astro-minimax/cli 0.7.0 → 0.7.2

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 (53) hide show
  1. package/dist/commands/podcast.d.ts +2 -0
  2. package/dist/commands/podcast.d.ts.map +1 -0
  3. package/dist/commands/podcast.js +89 -0
  4. package/dist/commands/podcast.js.map +1 -0
  5. package/dist/commands/profile.d.ts.map +1 -1
  6. package/dist/commands/profile.js +7 -2
  7. package/dist/commands/profile.js.map +1 -1
  8. package/dist/tools/build-fact-registry.d.ts +14 -0
  9. package/dist/tools/build-fact-registry.d.ts.map +1 -0
  10. package/dist/tools/build-fact-registry.js +545 -0
  11. package/dist/tools/build-fact-registry.js.map +1 -0
  12. package/dist/tools/eval-ai-chat.js +34 -4
  13. package/dist/tools/eval-ai-chat.js.map +1 -1
  14. package/dist/tools/lib/audio-processor.d.ts +46 -0
  15. package/dist/tools/lib/audio-processor.d.ts.map +1 -0
  16. package/dist/tools/lib/audio-processor.js +188 -0
  17. package/dist/tools/lib/audio-processor.js.map +1 -0
  18. package/dist/tools/lib/script-generator.d.ts +61 -0
  19. package/dist/tools/lib/script-generator.d.ts.map +1 -0
  20. package/dist/tools/lib/script-generator.js +182 -0
  21. package/dist/tools/lib/script-generator.js.map +1 -0
  22. package/dist/tools/lib/tts-provider.d.ts +65 -0
  23. package/dist/tools/lib/tts-provider.d.ts.map +1 -0
  24. package/dist/tools/lib/tts-provider.js +116 -0
  25. package/dist/tools/lib/tts-provider.js.map +1 -0
  26. package/dist/tools/lib/types.d.ts +129 -0
  27. package/dist/tools/lib/types.d.ts.map +1 -0
  28. package/dist/tools/lib/types.js +64 -0
  29. package/dist/tools/lib/types.js.map +1 -0
  30. package/dist/tools/podcast-feed.d.ts +6 -0
  31. package/dist/tools/podcast-feed.d.ts.map +1 -0
  32. package/dist/tools/podcast-feed.js +121 -0
  33. package/dist/tools/podcast-feed.js.map +1 -0
  34. package/dist/tools/podcast-generate.d.ts +15 -0
  35. package/dist/tools/podcast-generate.d.ts.map +1 -0
  36. package/dist/tools/podcast-generate.js +318 -0
  37. package/dist/tools/podcast-generate.js.map +1 -0
  38. package/dist/tools/podcast-list.d.ts +6 -0
  39. package/dist/tools/podcast-list.d.ts.map +1 -0
  40. package/dist/tools/podcast-list.js +66 -0
  41. package/dist/tools/podcast-list.js.map +1 -0
  42. package/package.json +3 -2
  43. package/template/.gitignore +7 -0
  44. package/template/datas/fact-registry.json +17 -0
  45. package/template/eslint.config.js +3 -0
  46. package/template/functions/api/chat.ts +6 -1
  47. package/template/package.json +8 -6
  48. package/template/src/config.ts +6 -2
  49. package/template/src/data/blog/zh/alerts-examples.md +86 -0
  50. package/template/src/data/blog/zh/code-examples.md +168 -0
  51. package/template/src/data/blog/zh/markmap-examples.md +103 -0
  52. package/template/src/data/blog/zh/math-examples.md +81 -0
  53. package/template/src/data/blog/zh/mermaid-examples.md +82 -0
@@ -0,0 +1,545 @@
1
+ #!/usr/bin/env npx tsx
2
+ /**
3
+ * 构建事实注册表 (Fact Registry)
4
+ *
5
+ * 从博客内容、作者上下文、AI 摘要等数据中提取可验证的事实,
6
+ * 生成 fact-registry.json 供 AI 对话时注入 Prompt,减少幻觉。
7
+ *
8
+ * 用法:
9
+ * pnpm facts:build 构建事实注册表
10
+ * pnpm facts:build --force 强制全量重建
11
+ * pnpm facts:build --verbose 显示详细输出
12
+ */
13
+ import { readdir, readFile } from "node:fs/promises";
14
+ import { join } from "node:path";
15
+ import { loadEnv, readJson, writeJson, truncate, parseCliArgs, DATA_DIR, BLOG_DIR, } from "./lib/utils.js";
16
+ import { extractFrontmatter } from "./lib/frontmatter.js";
17
+ // ─── Constants ────────────────────────────────────────────────
18
+ const OUTPUT_FILE = join(DATA_DIR, "fact-registry.json");
19
+ const SCHEMA_VERSION = 1;
20
+ function parseArgs() {
21
+ return parseCliArgs({ force: false, verbose: false });
22
+ }
23
+ // ─── Fact Builders ────────────────────────────────────────────
24
+ function buildAuthorFacts(ctx, env) {
25
+ const facts = [];
26
+ const profile = ctx.profile;
27
+ const authorName = profile?.name || env.SITE_AUTHOR || "";
28
+ const siteUrl = profile?.siteUrl || env.SITE_URL || "";
29
+ if (authorName) {
30
+ facts.push({
31
+ id: "author-name",
32
+ category: "author",
33
+ statement: `博客作者名为 ${authorName}`,
34
+ evidence: "author-context.json → profile.name",
35
+ source: "explicit",
36
+ confidence: 1.0,
37
+ tags: ["作者", "名字", "author", "name", authorName.toLowerCase()],
38
+ lang: "zh",
39
+ });
40
+ facts.push({
41
+ id: "author-name-en",
42
+ category: "author",
43
+ statement: `The blog author is ${authorName}`,
44
+ evidence: "author-context.json → profile.name",
45
+ source: "explicit",
46
+ confidence: 1.0,
47
+ tags: ["author", "name", authorName.toLowerCase()],
48
+ lang: "en",
49
+ });
50
+ }
51
+ if (siteUrl) {
52
+ facts.push({
53
+ id: "author-site",
54
+ category: "author",
55
+ statement: `博客网址为 ${siteUrl}`,
56
+ evidence: "author-context.json → profile.siteUrl",
57
+ source: "explicit",
58
+ confidence: 1.0,
59
+ tags: ["网址", "URL", "site", "url", "博客"],
60
+ lang: "zh",
61
+ });
62
+ }
63
+ if (profile?.description) {
64
+ facts.push({
65
+ id: "author-desc",
66
+ category: "author",
67
+ statement: `博客简介:${truncate(profile.description, 200)}`,
68
+ evidence: "author-context.json → profile.description",
69
+ source: "explicit",
70
+ confidence: 1.0,
71
+ tags: ["简介", "description", "about", "关于"],
72
+ lang: "zh",
73
+ });
74
+ }
75
+ return facts;
76
+ }
77
+ function buildBlogStatsFacts(ctx) {
78
+ const facts = [];
79
+ const footprint = ctx.stableFacts?.contentFootprint;
80
+ const posts = ctx.posts ?? [];
81
+ if (footprint) {
82
+ facts.push({
83
+ id: "blog-total-posts",
84
+ category: "blog",
85
+ statement: `博客共有 ${footprint.posts} 篇文章(中文 ${footprint.zhPosts} 篇,英文 ${footprint.enPosts} 篇)`,
86
+ evidence: "author-context.json → stableFacts.contentFootprint",
87
+ source: "derived",
88
+ confidence: 1.0,
89
+ tags: [
90
+ "文章数", "总数", "统计", "多少", "数量",
91
+ "posts", "count", "total", "how many",
92
+ ],
93
+ lang: "zh",
94
+ });
95
+ facts.push({
96
+ id: "blog-total-posts-en",
97
+ category: "blog",
98
+ statement: `The blog has ${footprint.posts} posts (${footprint.zhPosts} in Chinese, ${footprint.enPosts} in English)`,
99
+ evidence: "author-context.json → stableFacts.contentFootprint",
100
+ source: "derived",
101
+ confidence: 1.0,
102
+ tags: ["posts", "count", "total", "how many", "statistics"],
103
+ lang: "en",
104
+ });
105
+ }
106
+ else if (posts.length) {
107
+ facts.push({
108
+ id: "blog-total-posts",
109
+ category: "blog",
110
+ statement: `博客共有 ${posts.length} 篇文章`,
111
+ evidence: `author-context.json → posts.length (${posts.length})`,
112
+ source: "derived",
113
+ confidence: 1.0,
114
+ tags: ["文章数", "总数", "统计", "多少", "数量", "posts", "count"],
115
+ lang: "zh",
116
+ });
117
+ }
118
+ // Categories
119
+ const categories = ctx.stableFacts?.focusAreas;
120
+ if (categories?.length) {
121
+ facts.push({
122
+ id: "blog-categories",
123
+ category: "blog",
124
+ statement: `博客的主要分类包括:${categories.join("、")}`,
125
+ evidence: "author-context.json → stableFacts.focusAreas",
126
+ source: "derived",
127
+ confidence: 0.95,
128
+ tags: [
129
+ "分类", "类别", "领域", "方向",
130
+ "category", "area", "focus",
131
+ ...categories.map((c) => c.toLowerCase()),
132
+ ],
133
+ lang: "zh",
134
+ });
135
+ }
136
+ // Top tags
137
+ const topTags = ctx.stableFacts?.topTags;
138
+ if (topTags?.length) {
139
+ facts.push({
140
+ id: "blog-top-tags",
141
+ category: "blog",
142
+ statement: `博客最常用的标签有:${topTags.slice(0, 10).join("、")}`,
143
+ evidence: "author-context.json → stableFacts.topTags",
144
+ source: "derived",
145
+ confidence: 0.9,
146
+ tags: [
147
+ "标签", "tag", "topic", "主题",
148
+ ...topTags.slice(0, 10).map((t) => t.toLowerCase()),
149
+ ],
150
+ lang: "zh",
151
+ });
152
+ }
153
+ // Recurring topics
154
+ const topics = ctx.stableFacts?.recurringTopics;
155
+ if (topics?.length) {
156
+ facts.push({
157
+ id: "blog-recurring-topics",
158
+ category: "blog",
159
+ statement: `博客反复讨论的技术话题包括:${topics.slice(0, 8).join("、")}`,
160
+ evidence: "author-context.json → stableFacts.recurringTopics",
161
+ source: "aggregated",
162
+ confidence: 0.85,
163
+ tags: [
164
+ "话题", "主题", "讨论", "topic", "recurring",
165
+ ...topics.slice(0, 8).map((t) => t.toLowerCase()),
166
+ ],
167
+ lang: "zh",
168
+ });
169
+ }
170
+ // Date range
171
+ if (posts.length >= 2) {
172
+ const sorted = [...posts].sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime());
173
+ const oldest = sorted[0];
174
+ const newest = sorted[sorted.length - 1];
175
+ const oldDate = new Date(oldest.date).toISOString().slice(0, 10);
176
+ const newDate = new Date(newest.date).toISOString().slice(0, 10);
177
+ facts.push({
178
+ id: "blog-date-range",
179
+ category: "blog",
180
+ statement: `博客的文章时间跨度从 ${oldDate} 到 ${newDate}`,
181
+ evidence: `earliest: ${oldest.title} (${oldDate}), latest: ${newest.title} (${newDate})`,
182
+ source: "derived",
183
+ confidence: 1.0,
184
+ tags: ["时间", "日期", "最早", "最新", "date", "range", "when"],
185
+ lang: "zh",
186
+ });
187
+ }
188
+ // Language distribution
189
+ if (posts.length) {
190
+ const langs = new Map();
191
+ for (const p of posts) {
192
+ langs.set(p.lang, (langs.get(p.lang) || 0) + 1);
193
+ }
194
+ if (langs.size > 1) {
195
+ const desc = [...langs.entries()]
196
+ .sort((a, b) => b[1] - a[1])
197
+ .map(([lang, count]) => `${lang === "zh" ? "中文" : "英文"} ${count} 篇`)
198
+ .join(",");
199
+ facts.push({
200
+ id: "blog-lang-dist",
201
+ category: "blog",
202
+ statement: `博客文章的语言分布:${desc}`,
203
+ evidence: "author-context.json → posts[].lang aggregation",
204
+ source: "derived",
205
+ confidence: 1.0,
206
+ tags: ["语言", "中文", "英文", "language", "chinese", "english"],
207
+ lang: "zh",
208
+ });
209
+ }
210
+ }
211
+ return facts;
212
+ }
213
+ function buildContentFacts(ctx) {
214
+ const facts = [];
215
+ const posts = ctx.posts ?? [];
216
+ // Category distribution with counts
217
+ const catCounts = new Map();
218
+ for (const p of posts) {
219
+ if (p.category) {
220
+ catCounts.set(p.category, (catCounts.get(p.category) || 0) + 1);
221
+ }
222
+ }
223
+ if (catCounts.size > 0) {
224
+ const desc = [...catCounts.entries()]
225
+ .sort((a, b) => b[1] - a[1])
226
+ .map(([cat, count]) => `${cat}(${count}篇)`)
227
+ .join("、");
228
+ facts.push({
229
+ id: "content-category-dist",
230
+ category: "content",
231
+ statement: `按分类统计:${desc}`,
232
+ evidence: "author-context.json → posts[].category aggregation",
233
+ source: "derived",
234
+ confidence: 1.0,
235
+ tags: ["分类", "统计", "category", "distribution"],
236
+ lang: "zh",
237
+ });
238
+ }
239
+ // Flagship/latest posts
240
+ const flagship = ctx.stableFacts?.flagshipPosts;
241
+ if (flagship?.length) {
242
+ const desc = flagship
243
+ .map((p) => `《${p.title}》(${new Date(p.date).toISOString().slice(0, 10)})`)
244
+ .join("、");
245
+ facts.push({
246
+ id: "content-flagship",
247
+ category: "content",
248
+ statement: `最新的代表性文章:${desc}`,
249
+ evidence: "author-context.json → stableFacts.flagshipPosts",
250
+ source: "derived",
251
+ confidence: 0.95,
252
+ tags: ["最新", "代表", "推荐", "latest", "recent", "flagship"],
253
+ lang: "zh",
254
+ });
255
+ }
256
+ return facts;
257
+ }
258
+ async function buildTechStackFacts() {
259
+ const facts = [];
260
+ // Try to detect tech stack from config files
261
+ try {
262
+ const pkgRaw = await readFile(join(process.cwd(), "package.json"), "utf-8");
263
+ const pkg = JSON.parse(pkgRaw);
264
+ const allDeps = {
265
+ ...(pkg.dependencies ?? {}),
266
+ ...(pkg.devDependencies ?? {}),
267
+ };
268
+ const techStack = [];
269
+ const techTags = [];
270
+ if (allDeps.astro) {
271
+ techStack.push(`Astro ${allDeps.astro.replace(/[^0-9.]/g, "")}`);
272
+ techTags.push("astro");
273
+ }
274
+ if (allDeps.preact || allDeps.react) {
275
+ const framework = allDeps.preact ? "Preact" : "React";
276
+ techStack.push(framework);
277
+ techTags.push(framework.toLowerCase());
278
+ }
279
+ if (allDeps.tailwindcss || allDeps["@tailwindcss/vite"]) {
280
+ techStack.push("Tailwind CSS");
281
+ techTags.push("tailwindcss", "tailwind");
282
+ }
283
+ if (allDeps.typescript) {
284
+ techStack.push("TypeScript");
285
+ techTags.push("typescript", "ts");
286
+ }
287
+ // Check for AI-related deps
288
+ if (allDeps["@astro-minimax/ai"]) {
289
+ techTags.push("ai", "rag", "llm");
290
+ }
291
+ if (techStack.length > 0) {
292
+ const zhStack = allDeps["@astro-minimax/ai"]
293
+ ? [...techStack, "AI 对话(RAG)"]
294
+ : techStack;
295
+ const enStack = allDeps["@astro-minimax/ai"]
296
+ ? [...techStack, "AI Chat (RAG)"]
297
+ : techStack;
298
+ facts.push({
299
+ id: "tech-stack",
300
+ category: "tech",
301
+ statement: `博客使用的技术栈包括:${zhStack.join("、")}`,
302
+ evidence: "package.json → dependencies + devDependencies",
303
+ source: "explicit",
304
+ confidence: 1.0,
305
+ tags: [
306
+ "技术栈", "技术", "框架", "工具",
307
+ "tech", "stack", "framework",
308
+ ...techTags,
309
+ ],
310
+ lang: "zh",
311
+ });
312
+ facts.push({
313
+ id: "tech-stack-en",
314
+ category: "tech",
315
+ statement: `The blog is built with: ${enStack.join(", ")}`,
316
+ evidence: "package.json → dependencies + devDependencies",
317
+ source: "explicit",
318
+ confidence: 1.0,
319
+ tags: ["tech", "stack", "framework", "built with", ...techTags],
320
+ lang: "en",
321
+ });
322
+ }
323
+ }
324
+ catch {
325
+ // package.json not found or unreadable
326
+ }
327
+ return facts;
328
+ }
329
+ function buildSummaryDerivedFacts(summaries) {
330
+ const facts = [];
331
+ const articles = summaries.articles ?? {};
332
+ const entries = Object.entries(articles);
333
+ if (!entries.length)
334
+ return facts;
335
+ // Aggregate all tags from AI summaries
336
+ const tagCounts = new Map();
337
+ for (const [, entry] of entries) {
338
+ for (const tag of entry.data?.tags ?? []) {
339
+ tagCounts.set(tag, (tagCounts.get(tag) || 0) + 1);
340
+ }
341
+ }
342
+ if (tagCounts.size > 0) {
343
+ const topAiTags = [...tagCounts.entries()]
344
+ .sort((a, b) => b[1] - a[1])
345
+ .slice(0, 15)
346
+ .map(([tag]) => tag);
347
+ facts.push({
348
+ id: "content-ai-tags",
349
+ category: "content",
350
+ statement: `AI 分析得出的高频主题标签:${topAiTags.join("、")}`,
351
+ evidence: `ai-summaries.json → ${entries.length} articles aggregated tags`,
352
+ source: "aggregated",
353
+ confidence: 0.85,
354
+ tags: [
355
+ "标签", "主题", "AI", "tag", "topic",
356
+ ...topAiTags.map((t) => t.toLowerCase()),
357
+ ],
358
+ lang: "zh",
359
+ });
360
+ }
361
+ // Extract highly recurring key points
362
+ const keyPointCounts = new Map();
363
+ for (const [, entry] of entries) {
364
+ for (const kp of entry.data?.keyPoints ?? []) {
365
+ const normalized = kp.trim().toLowerCase();
366
+ if (normalized.length >= 10) {
367
+ keyPointCounts.set(normalized, (keyPointCounts.get(normalized) || 0) + 1);
368
+ }
369
+ }
370
+ }
371
+ const recurringKPs = [...keyPointCounts.entries()]
372
+ .filter(([, count]) => count >= 2)
373
+ .sort((a, b) => b[1] - a[1])
374
+ .slice(0, 5);
375
+ if (recurringKPs.length) {
376
+ const desc = recurringKPs.map(([kp]) => truncate(kp, 60)).join(";");
377
+ facts.push({
378
+ id: "content-recurring-kp",
379
+ category: "content",
380
+ statement: `在多篇文章中反复出现的要点:${desc}`,
381
+ evidence: `ai-summaries.json → keyPoints cross-article aggregation`,
382
+ source: "aggregated",
383
+ confidence: 0.8,
384
+ tags: ["要点", "核心", "反复", "key point", "recurring"],
385
+ lang: "zh",
386
+ });
387
+ }
388
+ return facts;
389
+ }
390
+ // ─── Article-level Fact Extraction ────────────────────────────
391
+ async function buildArticleFacts() {
392
+ const facts = [];
393
+ try {
394
+ const files = await collectMarkdownFiles(BLOG_DIR);
395
+ // Extract facts about explicitly mentioned technologies from frontmatter tags
396
+ const explicitTechMentions = new Map();
397
+ for (const filePath of files) {
398
+ const raw = await readFile(filePath, "utf-8");
399
+ const fm = extractFrontmatter(raw);
400
+ if (fm.data.draft)
401
+ continue;
402
+ const tags = Array.isArray(fm.data.tags) ? fm.data.tags : [];
403
+ for (const tag of tags) {
404
+ explicitTechMentions.set(tag, (explicitTechMentions.get(tag) || 0) + 1);
405
+ }
406
+ }
407
+ // Top mentioned technologies from tags
408
+ const topMentions = [...explicitTechMentions.entries()]
409
+ .filter(([, count]) => count >= 3)
410
+ .sort((a, b) => b[1] - a[1])
411
+ .slice(0, 10);
412
+ if (topMentions.length) {
413
+ const desc = topMentions
414
+ .map(([tech, count]) => `${tech}(${count}次)`)
415
+ .join("、");
416
+ facts.push({
417
+ id: "content-tech-mentions",
418
+ category: "content",
419
+ statement: `文章中高频提及的技术/话题(按标签统计):${desc}`,
420
+ evidence: `${files.length} markdown files → frontmatter.tags aggregation`,
421
+ source: "aggregated",
422
+ confidence: 0.9,
423
+ tags: [
424
+ "技术", "提及", "频率", "tech", "mention",
425
+ ...topMentions.map(([t]) => t.toLowerCase()),
426
+ ],
427
+ lang: "zh",
428
+ });
429
+ }
430
+ }
431
+ catch {
432
+ // BLOG_DIR doesn't exist or is unreadable
433
+ }
434
+ return facts;
435
+ }
436
+ async function collectMarkdownFiles(dir) {
437
+ const entries = await readdir(dir, { withFileTypes: true });
438
+ const files = [];
439
+ for (const entry of entries) {
440
+ const fullPath = join(dir, entry.name);
441
+ if (entry.isDirectory() && !entry.name.startsWith("_")) {
442
+ files.push(...(await collectMarkdownFiles(fullPath)));
443
+ }
444
+ else if (entry.isFile() && entry.name.endsWith(".md")) {
445
+ files.push(fullPath);
446
+ }
447
+ }
448
+ return files;
449
+ }
450
+ // ─── Stats Computation ────────────────────────────────────────
451
+ function computeStats(facts) {
452
+ const byCategory = {
453
+ author: 0,
454
+ blog: 0,
455
+ content: 0,
456
+ project: 0,
457
+ tech: 0,
458
+ };
459
+ let totalConfidence = 0;
460
+ for (const fact of facts) {
461
+ byCategory[fact.category]++;
462
+ totalConfidence += fact.confidence;
463
+ }
464
+ return {
465
+ total: facts.length,
466
+ byCategory,
467
+ avgConfidence: facts.length > 0 ? +(totalConfidence / facts.length).toFixed(3) : 0,
468
+ };
469
+ }
470
+ // ─── Main ─────────────────────────────────────────────────────
471
+ async function main() {
472
+ const args = parseArgs();
473
+ await loadEnv();
474
+ console.log("📊 构建事实注册表 (Fact Registry)");
475
+ console.log("━".repeat(50));
476
+ // Load existing data sources
477
+ const authorContext = await readJson(join(DATA_DIR, "author-context.json"), {});
478
+ const aiSummaries = await readJson(join(DATA_DIR, "ai-summaries.json"), {});
479
+ const voiceProfile = await readJson(join(DATA_DIR, "voice-profile.json"), {});
480
+ const hasAuthorContext = !!authorContext.profile;
481
+ const hasSummaries = !!aiSummaries.articles && Object.keys(aiSummaries.articles).length > 0;
482
+ console.log(`\n📂 数据源检测:`);
483
+ console.log(` author-context.json: ${hasAuthorContext ? "✅" : "❌ (缺失)"}`);
484
+ console.log(` ai-summaries.json: ${hasSummaries ? `✅ (${Object.keys(aiSummaries.articles ?? {}).length} 篇)` : "❌ (缺失)"}`);
485
+ console.log(` voice-profile.json: ${voiceProfile.tone ? "✅" : "⚠️ (部分)"}`);
486
+ // Build facts from all sources
487
+ console.log("\n🔍 提取事实...");
488
+ const allFacts = [];
489
+ // Author facts
490
+ const authorFacts = buildAuthorFacts(authorContext, process.env);
491
+ allFacts.push(...authorFacts);
492
+ if (args.verbose)
493
+ console.log(` 作者事实: ${authorFacts.length} 条`);
494
+ // Blog stats facts
495
+ const blogFacts = buildBlogStatsFacts(authorContext);
496
+ allFacts.push(...blogFacts);
497
+ if (args.verbose)
498
+ console.log(` 博客统计: ${blogFacts.length} 条`);
499
+ // Content facts
500
+ const contentFacts = buildContentFacts(authorContext);
501
+ allFacts.push(...contentFacts);
502
+ if (args.verbose)
503
+ console.log(` 内容事实: ${contentFacts.length} 条`);
504
+ // Tech stack facts
505
+ const techFacts = await buildTechStackFacts();
506
+ allFacts.push(...techFacts);
507
+ if (args.verbose)
508
+ console.log(` 技术栈: ${techFacts.length} 条`);
509
+ // Summary-derived facts
510
+ const summaryFacts = buildSummaryDerivedFacts(aiSummaries);
511
+ allFacts.push(...summaryFacts);
512
+ if (args.verbose)
513
+ console.log(` 摘要衍生: ${summaryFacts.length} 条`);
514
+ // Article-level facts
515
+ const articleFacts = await buildArticleFacts();
516
+ allFacts.push(...articleFacts);
517
+ if (args.verbose)
518
+ console.log(` 文章分析: ${articleFacts.length} 条`);
519
+ // Compute stats
520
+ const stats = computeStats(allFacts);
521
+ // Write output
522
+ const output = {
523
+ $schema: "fact-registry-v1",
524
+ generatedAt: new Date().toISOString(),
525
+ version: SCHEMA_VERSION,
526
+ facts: allFacts,
527
+ stats,
528
+ };
529
+ await writeJson(OUTPUT_FILE, output);
530
+ console.log(`\n✅ 事实注册表构建完成`);
531
+ console.log(`📄 输出文件: ${OUTPUT_FILE}`);
532
+ console.log(`\n📊 统计:`);
533
+ console.log(` 总事实数: ${stats.total}`);
534
+ console.log(` 平均置信度: ${stats.avgConfidence}`);
535
+ console.log(` 按分类:`);
536
+ for (const [cat, count] of Object.entries(stats.byCategory)) {
537
+ if (count > 0)
538
+ console.log(` ${cat}: ${count}`);
539
+ }
540
+ }
541
+ main().catch((error) => {
542
+ console.error("❌ 构建失败:", error.message);
543
+ process.exit(1);
544
+ });
545
+ //# sourceMappingURL=build-fact-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-fact-registry.js","sourceRoot":"","sources":["../../src/tools/build-fact-registry.ts"],"names":[],"mappings":"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"}
@@ -183,6 +183,31 @@ function checkAnswerMode(response, answerMode) {
183
183
  return { name: "answer_mode", passed: true, detail: `Mode: ${answerMode}` };
184
184
  }
185
185
  }
186
+ function checkSourceHit(response, mustHitSourceIds, mustHitSourceCount) {
187
+ if (!mustHitSourceIds?.length && mustHitSourceCount === undefined) {
188
+ return { name: "source_hit", passed: true, detail: "No source requirements" };
189
+ }
190
+ const linkPattern = /\[([^\]]+)\]\(([^)]+)\)/g;
191
+ const links = [...response.matchAll(linkPattern)].map((m) => m[2]);
192
+ const hitSources = mustHitSourceIds?.filter((id) => links.some((link) => link.includes(id))) ?? [];
193
+ const minRequired = mustHitSourceCount ?? mustHitSourceIds?.length ?? 0;
194
+ const passed = hitSources.length >= minRequired;
195
+ return {
196
+ name: "source_hit",
197
+ passed,
198
+ detail: passed
199
+ ? `Hit ${hitSources.length}/${mustHitSourceIds?.length ?? 0} required sources`
200
+ : `Missing sources: ${mustHitSourceIds?.filter((id) => !hitSources.includes(id)).join(", ")}`,
201
+ };
202
+ }
203
+ const CHECK_WEIGHTS = {
204
+ not_empty: 1,
205
+ topic_coverage: 3,
206
+ forbidden_claims: 5,
207
+ has_links: 2,
208
+ answer_mode: 3,
209
+ source_hit: 4,
210
+ };
186
211
  function evaluateResponse(evalCase, response) {
187
212
  return [
188
213
  checkNotEmpty(response),
@@ -190,6 +215,7 @@ function evaluateResponse(evalCase, response) {
190
215
  checkForbiddenClaims(response, evalCase.forbiddenClaims),
191
216
  checkHasLinks(response, evalCase.mustHaveLinks),
192
217
  checkAnswerMode(response, evalCase.answerMode),
218
+ checkSourceHit(response, evalCase.mustHitSourceIds, evalCase.mustHitSourceCount),
193
219
  ];
194
220
  }
195
221
  // ─── Main ──────────────────────────────────────────────────
@@ -232,9 +258,13 @@ async function main() {
232
258
  const { response, latency } = await sendChatRequest(flags.url, evalCase.question, evalCase.lang);
233
259
  totalLatency += latency;
234
260
  const checks = evaluateResponse(evalCase, response);
235
- const passedChecks = checks.filter((c) => c.passed).length;
236
- const score = passedChecks;
237
- const maxScore = checks.length;
261
+ const score = checks.reduce((total, check) => {
262
+ const weight = CHECK_WEIGHTS[check.name] ?? 1;
263
+ return total + (check.passed ? weight : 0);
264
+ }, 0);
265
+ const maxScore = checks.reduce((total, check) => {
266
+ return total + (CHECK_WEIGHTS[check.name] ?? 1);
267
+ }, 0);
238
268
  const allPassed = checks.every((c) => c.passed);
239
269
  if (allPassed)
240
270
  passedCount++;
@@ -273,7 +303,7 @@ async function main() {
273
303
  question: evalCase.question,
274
304
  passed: false,
275
305
  score: 0,
276
- maxScore: 5,
306
+ maxScore: 18,
277
307
  response: "",
278
308
  latency: 0,
279
309
  checks: [],