content_generator.js
18.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
/**
* WeChatAI Content Generation Workflow
* 内容生成工作流 - 读取选题、匹配模板、生成文章
*/
const fs = require('fs');
const path = require('path');
// 配置
const CONFIG = {
baseDir: '/Users/yibo/Documents/LemonAI/lemonboss/data/workspace/wechatai',
templatesDir: '/Users/yibo/Documents/LemonAI/lemonboss/data/workspace/wechatai/config/templates',
outputDir: '/Users/yibo/Documents/LemonAI/lemonboss/data/workspace/wechatai/articles',
hotspotsDir: '/Users/yibo/Documents/LemonAI/lemonboss/data/workspace/wechatai/hotspots',
};
// 模板配置
const TEMPLATE_CONFIG = {
morning_report: {
file: 'morning_report.md',
minWords: 300,
maxWords: 500,
description: 'AI早报'
},
hotspot_analysis: {
file: 'hotspot_analysis.md',
minWords: 1000,
maxWords: 1500,
description: '热点解读'
},
deep_dive: {
file: 'deep_dive.md',
minWords: 2000,
maxWords: 3000,
description: '深度专题'
},
weekly_digest: {
file: 'weekly_digest.md',
minWords: 1500,
maxWords: 2000,
description: '周盘点'
}
};
/**
* 读取精选选题
* @param {string} date - 日期 YYYY-MM-DD
* @returns {Array} 选题列表
*/
function readCuratedTopics(date) {
const filePath = path.join(CONFIG.hotspotsDir, date, 'curated_topics.json');
if (!fs.existsSync(filePath)) {
console.error(`[ERROR] 选题文件不存在: ${filePath}`);
return [];
}
try {
const content = fs.readFileSync(filePath, 'utf-8');
return JSON.parse(content);
} catch (error) {
console.error(`[ERROR] 解析选题文件失败: ${error.message}`);
return [];
}
}
/**
* 读取模板
* @param {string} contentType - 内容类型
* @returns {string} 模板内容
*/
function readTemplate(contentType) {
const config = TEMPLATE_CONFIG[contentType];
if (!config) {
console.error(`[ERROR] 未知的模板类型: ${contentType}`);
return null;
}
const templatePath = path.join(CONFIG.templatesDir, config.file);
if (!fs.existsSync(templatePath)) {
console.error(`[ERROR] 模板文件不存在: ${templatePath}`);
return null;
}
return fs.readFileSync(templatePath, 'utf-8');
}
/**
* 生成文章大纲
* @param {Object} topic - 选题对象
* @returns {Object} 大纲对象
*/
function generateOutline(topic) {
const outlines = {
morning_report: {
sections: ['今日亮点', '要闻速览', '一句话总结'],
keyPoints: [
{ title: '亮点事件', angle: '最有价值的AI进展' },
{ title: '行业动态', angle: '公司和产品更新' },
{ title: '技术突破', angle: '研究论文和开源项目' }
]
},
hotspot_analysis: {
sections: ['背景速览', '核心解读', '影响与展望', '小结'],
keyPoints: [
{ title: '事件背景', angle: '时间线和来龙去脉' },
{ title: '技术细节', angle: '核心功能和原理' },
{ title: '市场影响', angle: '对行业和用户的影响' }
]
},
deep_dive: {
sections: ['背景铺垫', '技术分析', '竞争格局', '应用案例', '趋势预测', '总结'],
keyPoints: [
{ title: '发展脉络', angle: '技术演进历程' },
{ title: '核心原理', angle: '深入技术细节' },
{ title: '对比分析', angle: '与竞品的优劣势' },
{ title: '实际应用', angle: '落地场景和案例' },
{ title: '未来趋势', angle: '发展方向预测' }
]
},
weekly_digest: {
sections: ['本周Top5', '分类速览', '下周预告'],
keyPoints: [
{ title: '重大发布', angle: '本周最重要的5个事件' },
{ title: '模型进展', angle: '大模型更新和性能提升' },
{ title: '商业动态', angle: '投融资和产品发布' },
{ title: '下周看点', angle: '预告值得关注的事件' }
]
}
};
return outlines[topic.content_type] || outlines.hotspot_analysis;
}
/**
* 使用模板生成文章
* @param {Object} topic - 选题对象
* @param {string} template - 模板内容
* @returns {string} 生成的文章
*/
function generateArticle(topic, template) {
const now = new Date();
const dateStr = now.toISOString().split('T')[0];
const outline = generateOutline(topic);
// 基础变量替换
let article = template
.replace(/\{\{TITLE\}\}/g, topic.title)
.replace(/\{\{DATE\}\}/g, dateStr)
.replace(/\{\{SOURCE\}\}/g, topic.source || 'WeChatAI')
.replace(/\{\{SOURCES\}\}/g, topic.sources?.join(', ') || topic.source || '综合整理')
.replace(/\{\{TAGS\}\}/g, topic.tags?.join(', ') || 'AI, 人工智能')
.replace(/\{\{SUMMARY\}\}/g, topic.summary || '');
// 根据内容类型生成不同内容
switch (topic.content_type) {
case 'morning_report':
article = generateMorningReportContent(article, topic);
break;
case 'hotspot_analysis':
article = generateHotspotAnalysisContent(article, topic);
break;
case 'deep_dive':
article = generateDeepDiveContent(article, topic, outline);
break;
case 'weekly_digest':
article = generateWeeklyDigestContent(article, topic);
break;
}
return article;
}
/**
* 生成早报内容
*/
function generateMorningReportContent(article, topic) {
// 生成开头导语
const opening = `早上好!这里是 WeChatAI 早报。
今天是 ${new Date().toLocaleDateString('zh-CN')},AI 领域又发生了哪些新鲜事?让我们一起来看看。`;
// 生成新闻条目(模拟数据,实际应从 topic 数据中提取)
const newsItems = topic.news_items || [
{ title: 'AI 领域最新动态', summary: '详细内容待填充...' },
{ title: '技术突破', summary: '详细内容待填充...' },
{ title: '产品发布', summary: '详细内容待填充...' }
];
let newsContent = '';
newsItems.forEach((news, index) => {
newsContent += `### ${index + 1}. ${news.title}\n${news.summary}\n\n`;
});
const summary = 'AI 行业持续高速发展,新技术和新产品不断涌现。保持关注,把握先机!';
return article
.replace(/\{\{SUMMARY\}\}/g, opening)
.replace(/\{\{HIGHLIGHT_ITEM\}\}/g, newsItems[0]?.title || '今日AI要闻')
.replace(/\{\{NEWS_1_TITLE\}\}/g, newsItems[0]?.title || '')
.replace(/\{\{NEWS_1_SUMMARY\}\}/g, newsItems[0]?.summary || '')
.replace(/\{\{NEWS_2_TITLE\}\}/g, newsItems[1]?.title || '')
.replace(/\{\{NEWS_2_SUMMARY\}\}/g, newsItems[1]?.summary || '')
.replace(/\{\{NEWS_3_TITLE\}\}/g, newsItems[2]?.title || '')
.replace(/\{\{NEWS_3_SUMMARY\}\}/g, newsItems[2]?.summary || '')
.replace(/\{\{NEWS_4_TITLE\}\}/g, newsItems[3]?.title || '')
.replace(/\{\{NEWS_4_SUMMARY\}\}/g, newsItems[3]?.summary || '')
.replace(/\{\{NEWS_5_TITLE\}\}/g, newsItems[4]?.title || '')
.replace(/\{\{NEWS_5_SUMMARY\}\}/g, newsItems[4]?.summary || '')
.replace(/\{\{ONE_SENTENCE_SUMMARY\}\}/g, summary)
.replace(/\{\{SOURCE_COUNT\}\}/g, String(newsItems.length));
}
/**
* 生成热点解读内容
*/
function generateHotspotAnalysisContent(article, topic) {
// 开头三句话
const opening = `${topic.title}是近期AI领域最受关注的热点事件。
它的发布不仅标志着技术的重大突破,更可能对整个行业格局产生深远影响。
本文将带你快速了解事件背景、深入解读核心看点、并展望其未来影响。`;
// 背景
const background = `${topic.title}于近期正式发布,引发了业界广泛关注。
从技术层面看,这一进展代表了AI领域的最新突破。
从市场反应来看,各方评价普遍积极。`;
// 核心解读
const keyPoint1 = `${topic.title}在**技术架构**上实现了重要创新。
相比前代产品,在性能和效率方面都有显著提升。
这种改进使其在实际应用场景中更具竞争力。`;
const keyPoint2 = `从**商业角度**分析,这一发布将加剧市场竞争。
主要厂商纷纷跟进,行业格局可能因此重塑。
对于用户而言,这意味着将有更多优质选择。`;
const keyPoint3 = `长期来看,这项技术将**推动整个行业**向前发展。
新的应用场景将不断涌现,商业价值也将持续释放。
我们可以期待更多基于此技术的创新产品出现。`;
// 影响与展望
const impact = `${topic.title}的发布是一个重要里程碑。
短期内,我们将看到更多基于该技术的产品和应用落地。
中长期来看,它可能重新定义行业标准和用户期望。
建议读者持续关注后续发展,把握机遇。`;
// 小结
const conclusion = `${topic.title}代表了AI领域的最新进展,值得关注。
无论是技术从业者还是普通用户,都将从中受益。
我们将继续跟进报道,敬请期待。`;
return article
.replace(/\{\{OPENING_PARAGRAPH\}\}/g, opening)
.replace(/\{\{BACKGROUND_CONTENT\}\}/g, background)
.replace(/\{\{KEY_POINT_1_TITLE\}\}/g, '技术突破')
.replace(/\{\{KEY_POINT_1_CONTENT\}\}/g, keyPoint1)
.replace(/\{\{KEY_POINT_2_TITLE\}\}/g, '商业影响')
.replace(/\{\{KEY_POINT_2_CONTENT\}\}/g, keyPoint2)
.replace(/\{\{KEY_POINT_3_TITLE\}\}/g, '未来展望')
.replace(/\{\{KEY_POINT_3_CONTENT\}\}/g, keyPoint3)
.replace(/\{\{IMPACT_CONTENT\}\}/g, impact)
.replace(/\{\{CONCLUSION\}\}/g, conclusion);
}
/**
* 生成深度专题内容
*/
function generateDeepDiveContent(article, topic, outline) {
const opening = `${topic.title}是近年来AI领域最重要的技术突破之一。
它不仅改变了我们对AI能力的认知,更开启了全新的应用可能。
本文将从技术原理、发展历程、应用案例和未来趋势四个维度,为你全面解析这一革命性进展。`;
const section1 = `${topic.title}的诞生并非偶然,而是多年技术积累的结果。
从最初的构想到最终落地,经历了多次技术迭代和突破。
关键里程碑包括基础架构的确立、核心算法的优化、以及大规模验证的成功。`;
const section2 = `在技术层面,${topic.title}采用了创新的架构设计。
其核心优势在于**高效的信息处理能力**和**优秀的泛化性能**。
具体来说,它通过改进的注意力机制和优化的训练策略,实现了性能的质的飞跃。`;
const section3 = `当前市场上,${topic.title}面临着激烈的竞争。
主要竞品包括来自各大科技巨头的同类产品。
但凭借独特的技术优势和先发制人的策略,${topic.title}在市场上占据了有利地位。`;
const section4 = `${topic.title}的实际应用已经覆盖多个领域。
在**内容创作**方面,它能够辅助生成高质量的文本、图像和视频。
在**代码开发**领域,它可以显著提高开发效率,降低错误率。
在**数据分析**场景,它展现了强大的洞察力和决策支持能力。`;
const section5 = `展望未来,${topic.title}将继续演进和完善。
预计下一代产品将在**多模态理解**和**推理能力**方面取得突破。
同时,随着成本的降低和易用性的提升,它将在更多行业和场景中得到应用。
我们可以期待一个AI能力更加普惠的未来。`;
const discussion = `你觉得${topic.title}最令人兴奋的应用场景是什么?
欢迎在评论区分享你的想法!`;
return article
.replace(/\{\{OPENING_PARAGRAPH\}\}/g, opening)
.replace(/\{\{SECTION_1_TITLE\}\}/g, '发展历程')
.replace(/\{\{SECTION_1_CONTENT\}\}/g, section1)
.replace(/\{\{SECTION_2_TITLE\}\}/g, '技术解析')
.replace(/\{\{SECTION_2_CONTENT\}\}/g, section2)
.replace(/\{\{SECTION_3_TITLE\}\}/g, '竞争格局')
.replace(/\{\{SECTION_3_CONTENT\}\}/g, section3)
.replace(/\{\{SECTION_4_TITLE\}\}/g, '应用案例')
.replace(/\{\{SECTION_4_CONTENT\}\}/g, section4)
.replace(/\{\{SECTION_5_TITLE\}\}/g, '未来趋势')
.replace(/\{\{SECTION_5_CONTENT\}\}/g, section5)
.replace(/\{\{DISCUSSION_QUESTION\}\}/g, discussion);
}
/**
* 生成周盘点内容
*/
function generateWeeklyDigestContent(article, topic) {
const opening = `本周AI领域精彩纷呈,多个重磅消息值得关注。
从大模型更新到产品发布,从技术突破到商业动态,信息量巨大。
本文为你梳理本周最值得关注的5大事件,以及各类别的重要进展。`;
const weekRange = `${new Date().toLocaleDateString('zh-CN')} 所在周`;
// 模拟本周Top5
const topItems = topic.top_items || [
{ title: '大模型重要更新', summary: '性能大幅提升,引发行业热议。' },
{ title: '新产品发布', summary: '创新功能惊艳亮相,用户体验升级。' },
{ title: '开源项目亮点', summary: '社区贡献显著,生态系统进一步完善。' },
{ title: '研究论文突破', summary: '理论基础得到加强,应用前景广阔。' },
{ title: '商业合作动态', summary: '产业链整合加速,市场格局生变。' }
];
const modelSummary = '本周大模型领域进展显著。主要厂商发布了重要更新,性能指标全面提升。开源社区也有诸多贡献,生态日益繁荣。';
const fundingSummary = '资本市场对AI领域持续看好。本周有多起融资事件,涉及大模型、应用层和基础设施等多个方向。';
const productSummary = '产品层面,多个创新功能上线。用户体验得到显著改善,应用场景进一步拓展。';
const policySummary = '政策层面,各国继续加强对AI的监管和规范。行业自律也在加强,可持续发展成为共识。';
const nextWeekPreview = '下周值得关注的是几家主要厂商的发布会,以及多个重要学术会议。预计将有更多技术和产品动态发布。';
return article
.replace(/\{\{OPENING_PARAGRAPH\}\}/g, opening)
.replace(/\{\{WEEK_RANGE\}\}/g, weekRange)
.replace(/\{\{TOP_1_TITLE\}\}/g, topItems[0]?.title || '')
.replace(/\{\{TOP_1_SUMMARY\}\}/g, topItems[0]?.summary || '')
.replace(/\{\{TOP_2_TITLE\}\}/g, topItems[1]?.title || '')
.replace(/\{\{TOP_2_SUMMARY\}\}/g, topItems[1]?.summary || '')
.replace(/\{\{TOP_3_TITLE\}\}/g, topItems[2]?.title || '')
.replace(/\{\{TOP_3_SUMMARY\}\}/g, topItems[2]?.summary || '')
.replace(/\{\{TOP_4_TITLE\}\}/g, topItems[3]?.title || '')
.replace(/\{\{TOP_4_SUMMARY\}\}/g, topItems[3]?.summary || '')
.replace(/\{\{TOP_5_TITLE\}\}/g, topItems[4]?.title || '')
.replace(/\{\{TOP_5_SUMMARY\}\}/g, topItems[4]?.summary || '')
.replace(/\{\{MODEL_SUMMARY\}\}/g, modelSummary)
.replace(/\{\{FUNDING_SUMMARY\}\}/g, fundingSummary)
.replace(/\{\{PRODUCT_SUMMARY\}\}/g, productSummary)
.replace(/\{\{POLICY_SUMMARY\}\}/g, policySummary)
.replace(/\{\{NEXT_WEEK_PREVIEW\}\}/g, nextWeekPreview);
}
/**
* 质量自检
* @param {string} article - 文章内容
* @param {string} contentType - 内容类型
* @returns {Object} 检查结果
*/
function qualityCheck(article, contentType) {
const config = TEMPLATE_CONFIG[contentType];
const checks = {
wordCount: { passed: false, value: 0, required: `${config.minWords}-${config.maxWords}` },
hasOpening3Sentences: { passed: false, note: '开头3句话检查' },
hasBoldText: { passed: false, note: '加粗标记检查' },
paragraphLength: { passed: false, note: '段落长度检查' },
formatCheck: { passed: true, note: '格式规范检查' }
};
// 字数检查
const chineseChars = article.match(/[\u4e00-\u9fa5]/g) || [];
const wordCount = chineseChars.length;
checks.wordCount.value = wordCount;
checks.wordCount.passed = wordCount >= config.minWords && wordCount <= config.maxWords;
// 开头3句话检查(检查是否有「这是/什么/本文」等关键词)
const openingPattern = /这是|什么|本文|为什么|重要|讲什么/;
checks.hasOpening3Sentences.passed = openingPattern.test(article.substring(0, 500));
// 加粗检查
checks.hasBoldText.passed = /\*\*.+?\*\*/.test(article);
// 段落长度检查(每段不超过150字)
const paragraphs = article.split('\n\n');
const longParagraphs = paragraphs.filter(p => p.length > 150);
checks.paragraphLength.passed = longParagraphs.length <= 3;
const allPassed = Object.values(checks).every(c => c.passed);
return {
passed: allPassed,
contentType,
wordCount,
checks,
issues: allPassed ? [] : Object.entries(checks)
.filter(([_, c]) => !c.passed)
.map(([name, _]) => name)
};
}
/**
* 保存文章
* @param {string} topicId - 选题ID
* @param {string} date - 日期
* @param {string} content - 文章内容
*/
function saveArticle(topicId, date, content) {
const dir = path.join(CONFIG.outputDir, date);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
const filePath = path.join(dir, `${topicId}.md`);
fs.writeFileSync(filePath, content, 'utf-8');
console.log(`[INFO] 文章已保存: ${filePath}`);
return filePath;
}
/**
* 主流程:生成文章
* @param {string} date - 日期
* @param {string} topicId - 特定选题ID(可选)
*/
async function generate(date, topicId = null) {
console.log(`[INFO] 开始生成文章: date=${date}, topicId=${topicId || 'all'}`);
const topics = readCuratedTopics(date);
if (topics.length === 0) {
console.log('[WARN] 没有找到选题');
return [];
}
const results = [];
for (const topic of topics) {
if (topicId && topic.topic_id !== topicId) continue;
console.log(`[INFO] 处理选题: ${topic.topic_id} - ${topic.title}`);
// 读取模板
const template = readTemplate(topic.content_type);
if (!template) {
console.error(`[ERROR] 无法获取模板: ${topic.content_type}`);
continue;
}
// 生成文章
const article = generateArticle(topic, template);
// 质量检查
const check = qualityCheck(article, topic.content_type);
console.log(`[INFO] 质量检查: ${check.passed ? '通过' : '未通过'} (${check.wordCount}字)`);
if (!check.passed) {
console.log(`[WARN] 检查未通过项: ${check.issues.join(', ')}`);
}
// 保存文章
const filePath = saveArticle(topic.topic_id, date, article);
results.push({
topicId: topic.topic_id,
title: topic.title,
contentType: topic.content_type,
wordCount: check.wordCount,
filePath,
qualityCheck: check
});
}
console.log(`[INFO] 文章生成完成: ${results.length} 篇`);
return results;
}
// CLI 入口
if (require.main === module) {
const args = process.argv.slice(2);
const date = args[0] || new Date().toISOString().split('T')[0];
const topicId = args[1] || null;
generate(date, topicId).then(results => {
console.log('\n=== 生成结果 ===');
results.forEach(r => {
console.log(`✓ ${r.topicId}: ${r.title} (${r.wordCount}字)`);
});
process.exit(0);
}).catch(err => {
console.error('[ERROR] 生成失败:', err);
process.exit(1);
});
}
module.exports = {
generate,
readCuratedTopics,
readTemplate,
generateOutline,
generateArticle,
qualityCheck,
TEMPLATE_CONFIG
};