@blocklet/pages-kit-agents 0.5.14 → 0.5.16

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.
@@ -5,4 +5,7 @@ DEBUG=aigne:*
5
5
  OPENAI_API_KEY="" # Your OpenAI API key
6
6
  GEMINI_API_KEY=""
7
7
  CLAUDE_API_KEY=""
8
+ XAI_API_KEY=""
9
+ DEEPSEEK_API_KEY=""
10
+
8
11
  OPENAI_BASE_URL=https://openai.arcblock.io/v1
package/cli.ts CHANGED
@@ -7,11 +7,21 @@ import yargs from 'yargs';
7
7
  import { hideBin } from 'yargs/helpers';
8
8
  import { z } from 'zod';
9
9
 
10
+ import { contentReviewerAgent } from './agents/content-reviwer.js';
10
11
  import generatePageContentMultiAgent, { type GeneratePageContentInput } from './agents/multi-agent-page-writer.js';
11
12
  import { sampleHtmlGeneratorAgent } from './agents/sample-html-generator.js';
12
- import { generateHtmlFromTemplate, getModel, readFile, saveHtmlContent, updateFileList } from './utils/index.js';
13
+ import {
14
+ generateHtmlFromTemplate,
15
+ getModel,
16
+ readFile,
17
+ saveHtmlContent,
18
+ updateFileList,
19
+ saveJsonContent,
20
+ } from './utils/index.js';
13
21
  import { logger } from './utils/logger.js';
14
22
 
23
+ const REVIEW_MODEL_NAME = 'gemini-2.5-pro-preview-05-06';
24
+
15
25
  // 定义配置文件的结构
16
26
  const ConfigSchema = z.object({
17
27
  models: z.array(
@@ -23,6 +33,7 @@ const ConfigSchema = z.object({
23
33
  outputSettings: z.object({
24
34
  useTemplate: z.boolean().default(true),
25
35
  openBrowserAfterComplete: z.boolean().default(true),
36
+ locale: z.string().default('zh'),
26
37
  }),
27
38
  logging: z.object({
28
39
  showProgress: z.boolean().default(true),
@@ -42,6 +53,7 @@ const defaultConfig: Config = {
42
53
  outputSettings: {
43
54
  useTemplate: true,
44
55
  openBrowserAfterComplete: true,
56
+ locale: 'zh',
45
57
  },
46
58
  logging: {
47
59
  showProgress: true,
@@ -126,19 +138,55 @@ const generatePageContent = async (
126
138
  }
127
139
 
128
140
  if (showProgress) {
129
- logger.info(`[${modelName}] Step 1/2: Generating content structure...`);
141
+ logger.info(`[${modelName}] Step 1/3: Generating content structure...`);
130
142
  }
131
143
 
132
- const result = await generatePageContentMultiAgent(input);
144
+ let result = null;
145
+ let retryCount = 0;
146
+ const maxRetries = 2; // 最多重试2次,加上初始尝试共3次
147
+
148
+ while (retryCount <= maxRetries) {
149
+ try {
150
+ // eslint-disable-next-line no-await-in-loop
151
+ result = await generatePageContentMultiAgent(input);
152
+
153
+ if (result) {
154
+ break;
155
+ } else {
156
+ throw new Error('Empty result from generatePageContentMultiAgent');
157
+ }
158
+ } catch (error) {
159
+ retryCount++;
160
+ if (retryCount > maxRetries) {
161
+ throw new Error(
162
+ `Failed to generate page content after ${maxRetries} retries: ${error instanceof Error ? error.message : String(error)}`
163
+ );
164
+ }
165
+
166
+ if (showProgress) {
167
+ logger.warn(`[${modelName}] Content generation failed, retrying (${retryCount}/${maxRetries})...`);
168
+ }
169
+
170
+ // 增加短暂延迟后重试
171
+ // eslint-disable-next-line no-await-in-loop
172
+ await new Promise((resolve) => {
173
+ setTimeout(resolve, 1000);
174
+ });
175
+ }
176
+ }
133
177
 
134
178
  if (!result) {
135
179
  throw new Error('Failed to generate page content');
136
180
  }
137
181
 
138
182
  if (showProgress) {
139
- logger.info(`[${modelName}] Step 2/2: Creating HTML output...`);
183
+ logger.info(`[${modelName}] Step 2/3: Creating HTML output...`);
140
184
  }
141
185
 
186
+ const model = getModel(REVIEW_MODEL_NAME);
187
+ const engine = new AIGNE({
188
+ model,
189
+ });
142
190
  if (outputUseTemplate) {
143
191
  await generateHtmlFromTemplate({
144
192
  jsonData: result,
@@ -146,11 +194,6 @@ const generatePageContent = async (
146
194
  outputFileName: modelName,
147
195
  });
148
196
  } else {
149
- const model = getModel('gemini-2.5-pro-preview-05-06');
150
- const engine = new AIGNE({
151
- model,
152
- });
153
-
154
197
  const htmlResult = await engine.invoke(sampleHtmlGeneratorAgent, {
155
198
  jsonData: JSON.stringify(result),
156
199
  });
@@ -163,6 +206,26 @@ const generatePageContent = async (
163
206
  });
164
207
  }
165
208
 
209
+ if (showProgress) {
210
+ logger.info(`[${modelName}] Step 3/3: Reviewing content...`);
211
+ }
212
+ const reviewResult = await engine.invoke(contentReviewerAgent, {
213
+ dataSource: input.context,
214
+ content: JSON.stringify(result),
215
+ question: '请对输入的文案进行严格的打分',
216
+ locale: input.locale,
217
+ });
218
+
219
+ // 保存评审结果到JSON文件
220
+ await saveJsonContent({
221
+ jsonContent: reviewResult,
222
+ outputFolder: runTime,
223
+ outputFileName: modelName,
224
+ });
225
+ logger.info(
226
+ `save review result to ${path.join(process.cwd(), 'sample-output', runTime, `${modelName}-review.json`)}`
227
+ );
228
+
166
229
  if (showProgress) {
167
230
  logger.info(`[${modelName}] HTML output completed`);
168
231
  }
@@ -198,6 +261,8 @@ async function main() {
198
261
  },
199
262
  };
200
263
 
264
+ logger.info('effective config: ', effectiveConfig);
265
+
201
266
  // 如果指定了单个模型,则只运行该模型
202
267
  const modelsToRun = args.model
203
268
  ? [{ name: String(args.model), enabled: true }]
@@ -227,7 +292,7 @@ ${imagesContext}`;
227
292
  尽可能多的包含 context 中相关的信息。
228
293
  `;
229
294
 
230
- const locale = 'zh';
295
+ const locale = effectiveConfig.outputSettings.locale || 'zh';
231
296
 
232
297
  const input = {
233
298
  context,
@@ -336,9 +401,14 @@ ${imagesContext}`;
336
401
  }
337
402
  }
338
403
 
404
+ logger.info('All models completed');
405
+
406
+ logger.info('Updating file list...');
339
407
  // 更新文件列表
340
408
  await updateFileList();
341
409
 
410
+ logger.info('All tasks completed');
411
+
342
412
  // 如果配置启用了浏览器自动打开,则打开index.html
343
413
  if (effectiveConfig.outputSettings.openBrowserAfterComplete) {
344
414
  const indexPath = path.join(process.cwd(), 'sample-output', 'index.html');
@@ -0,0 +1,19 @@
1
+ import { AIAgent } from '@aigne/core';
2
+ export declare const contentReviewerAgent: AIAgent<{
3
+ question: string;
4
+ locale: string;
5
+ dataSource: string;
6
+ content: string;
7
+ }, {
8
+ result: {
9
+ total_score: number;
10
+ level: string;
11
+ suggestions: string[];
12
+ dimension_scores: {
13
+ name: string;
14
+ score: number;
15
+ maxScore: number;
16
+ comment: string;
17
+ }[];
18
+ };
19
+ }>;
@@ -0,0 +1,154 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.contentReviewerAgent = void 0;
4
+ const core_1 = require("@aigne/core");
5
+ const zod_1 = require("zod");
6
+ const prompt = `
7
+ 你是一个专业的网页文案评估专家,具备丰富的多行业文案分析经验。现在你将对一段网站文案进行全面评估,这些文案以结构化 JSON 格式提供,每一个字段对应网页中的一部分内容,主要字段包括:
8
+
9
+ - title: 页面主标题
10
+ - description: 页面描述
11
+ - sectionsData: 页面内容部分,由多个模块(如 heroSection、featuresSection、faqSection 等)组成,每个模块有自己的标题、描述、详细内容等字段
12
+
13
+ 目标是:帮助创作者发现文案中的逻辑、表达、结构或营销短板,从而优化出更具影响力和传播力的内容。
14
+
15
+ ** 不要轻易给出高分**,除非你真的觉得提供的文案十分优秀。
16
+
17
+ 你可以参考提供原始数据来了解产品信息,帮助你判断文案中的信息是否准确、完整。
18
+
19
+ ---
20
+
21
+ ### 打分区间说明(满分 100 分)
22
+
23
+ - **95-100 卓越级**:极具说服力与感染力,逻辑、节奏、表现力、SEO 全维度优秀,能直接用于投放或上线。
24
+ - **90-94 优秀级**:表达清晰有力,有一定记忆点,结构严谨,整体完成度高,稍作优化即可达到专业发布水平。
25
+ - **85-89 合格上乘**:表达准确、结构清楚,但较中规中矩,缺乏差异化或语言张力,建议提升亮点与传播力。
26
+ - **80-84 可用但平庸**:内容基本清晰,但语言或结构平淡,缺乏吸引力或说服力,有明显可优化之处。
27
+ - **70-79 结构与逻辑需优化**:存在信息遗漏、表达冗长或语言生硬等问题,可能影响理解或转化。
28
+ - **<70 不达标**:表达混乱、价值不清、逻辑缺失,建议重写或从受众视角重新构思。
29
+
30
+ ---
31
+
32
+ ### 评估维度(共 7 项)
33
+
34
+ ** 每个维度的分数不能超过最大分数 **
35
+
36
+ 1. **信息完整性(15分)**
37
+ - 是否明确传达核心价值或主张?
38
+ - 是否覆盖了“是什么、能做什么、为什么值得关注”?
39
+
40
+ 2. **结构与逻辑清晰度(15分)**
41
+ - sectionsData 中的数据表示页面中的 Section ,页面结构是否完整清晰?
42
+ - 结构是否符合读者的阅读预期(如金字塔结构、FAB 模式等)?
43
+
44
+ 3. **语言表达质量(15分)**
45
+ - 表达是否简练、自然、口语/书面语风格合适?
46
+ - 是否避免术语堆砌、空话套话?
47
+
48
+ 4. **吸引力与情绪感染力(15分)**
49
+ - 是否有记忆点或引发兴趣?
50
+ - 是否有利益点、情绪驱动或视觉画面感?
51
+
52
+ 5. **品牌调性与目标受众匹配度(15分)**
53
+ - 是否符合品牌语气?
54
+ - 是否贴合目标受众的心理与语境?
55
+
56
+ 6. **差异化与独特性(10分)**
57
+ - 是否展现出区别于竞品的亮点或立场?
58
+ - 是否传递出“为什么选我”?
59
+
60
+ 7. **SEO 友好度(15分)**
61
+ - 是否包含明确关键词?
62
+ - 是否具备良好的标题、副标题与语义层级?
63
+ - 是否利于搜索引擎抓取和用户点击?
64
+
65
+ ---
66
+
67
+ ### 输出格式要求:
68
+
69
+ 1. 每个维度请给出【分数(x/总分)】+ 简洁点评;
70
+ 2. 总结总体得分(满分 100);
71
+ 3. 提供 3-5 条具体、可操作的优化建议,不能泛泛而谈;
72
+ 4. 如内容已接近满分,也需说明“进一步打磨”的方向。
73
+
74
+ ### 📦 输出格式要求(结构化)
75
+
76
+ 请使用以下结构输出评分结果:
77
+ ** 下面的 json 只是示例,只参考输出格式,不能影响评估结果**
78
+ 只返回 json 不要包含其他描述信息。
79
+
80
+ \`\`\`json
81
+ {
82
+ "total_score": xx,
83
+ "level": "xx",
84
+ "dimension_scores": [
85
+ {
86
+ "name": "信息完整性",
87
+ "score": xx,
88
+ "maxScore": xx,
89
+ "comment": "xxxxxx"
90
+ },
91
+ {
92
+ "name": "结构与逻辑清晰度",
93
+ "score": xx,
94
+ "maxScore": xx,
95
+ "comment": "xx"
96
+ },
97
+ {
98
+ "name": "语言表达质量",
99
+ "score": xx,
100
+ "maxScore": xx,
101
+ "comment": "xx"
102
+ },
103
+ ...
104
+ ],
105
+ "suggestions": [
106
+ "xxxx",
107
+ "xxxxxxx",
108
+ "xxxxxx。",
109
+ "xxxxxxxxxxx。"
110
+ ]
111
+ }
112
+ \`\`\`
113
+ ---
114
+
115
+ ### 📌 适用场景举例:
116
+
117
+ - SEO 内容型页面(如博客、产品 landing page、产品介绍页)
118
+
119
+ ### 原始数据
120
+ {{dataSource}}
121
+
122
+
123
+ ### 输入的营销文案
124
+ {{ content }}
125
+
126
+ ### 其他要求
127
+ {{ question }}
128
+
129
+ ### 语言
130
+ 请使用{{ locale }}语言输出
131
+ `;
132
+ exports.contentReviewerAgent = core_1.AIAgent.from({
133
+ name: 'Content Reviewer',
134
+ instructions: prompt,
135
+ inputSchema: zod_1.z.object({
136
+ dataSource: zod_1.z.string(),
137
+ content: zod_1.z.string(),
138
+ question: zod_1.z.string(),
139
+ locale: zod_1.z.string(),
140
+ }),
141
+ outputSchema: zod_1.z.object({
142
+ result: zod_1.z.object({
143
+ total_score: zod_1.z.number(),
144
+ level: zod_1.z.string(),
145
+ dimension_scores: zod_1.z.array(zod_1.z.object({
146
+ name: zod_1.z.string(),
147
+ score: zod_1.z.number(),
148
+ maxScore: zod_1.z.number(),
149
+ comment: zod_1.z.string(),
150
+ })),
151
+ suggestions: zod_1.z.array(zod_1.z.string()),
152
+ }),
153
+ }),
154
+ });
@@ -24,7 +24,7 @@ const section_content_generator_js_1 = require("./section-content-generator.js")
24
24
  async function generatePageContentMultiAgent(input) {
25
25
  const { context = '', question = '', locale = '', outputSchema, onProgress, checkConnection, sectionsRules, modelName = 'gpt-4o-mini', } = input;
26
26
  try {
27
- logger_js_1.logger.info('Starting multi-agent page content generation');
27
+ logger_js_1.logger.info(`[${modelName}] Starting multi-agent page content generation`);
28
28
  // 检查客户端连接状态的辅助函数
29
29
  const isClientConnected = () => {
30
30
  // 如果没有提供检查函数,默认认为客户端仍连接
@@ -45,10 +45,10 @@ async function generatePageContentMultiAgent(input) {
45
45
  });
46
46
  }
47
47
  // 2. 初始页面结构规划
48
- logger_js_1.logger.info('Planning initial page structure');
48
+ logger_js_1.logger.info(`[${modelName}] Planning initial page structure`);
49
49
  // 检查客户端是否仍然连接
50
50
  if (!isClientConnected()) {
51
- logger_js_1.logger.warn('Client disconnected during structure planning, aborting generation');
51
+ logger_js_1.logger.warn(`[${modelName}] Client disconnected during structure planning, aborting generation`);
52
52
  throw new Error('Client disconnected');
53
53
  }
54
54
  let structurePlanMap = {};
@@ -58,7 +58,7 @@ async function generatePageContentMultiAgent(input) {
58
58
  model,
59
59
  agents: [page_structure_planner_js_1.pageStructurePlannerAgent, page_structure_validator_js_1.pageStructureValidatorAgent],
60
60
  limits: {
61
- maxAgentInvokes: 20,
61
+ maxAgentInvokes: 30,
62
62
  },
63
63
  });
64
64
  await planningEngine.invoke(page_structure_planner_js_1.pageStructurePlannerAgent, {
@@ -74,8 +74,7 @@ async function generatePageContentMultiAgent(input) {
74
74
  });
75
75
  const structurePlanResult = await planningEngine.subscribe(core_1.UserOutputTopic);
76
76
  const { structurePlan } = structurePlanResult.message;
77
- // const { structurePlan } = structurePlanResult;
78
- logger_js_1.logger.info('Initial structure plan generated', structurePlan);
77
+ logger_js_1.logger.info(`[${modelName}] Initial structure plan generated`, structurePlan);
79
78
  await planningEngine.shutdown();
80
79
  // 触发页面结构生成成功事件
81
80
  if (onProgress) {
@@ -104,7 +103,7 @@ async function generatePageContentMultiAgent(input) {
104
103
  logger_js_1.logger.warn(`Client disconnected before generating section ${sectionName}, aborting generation`);
105
104
  return null;
106
105
  }
107
- logger_js_1.logger.info(`Generating content for section: ${sectionName}`);
106
+ logger_js_1.logger.info(`[${modelName}] Generating content for section: ${sectionName}`);
108
107
  // 通知当前正在处理的section
109
108
  if (onProgress) {
110
109
  onProgress({
@@ -129,7 +128,7 @@ async function generatePageContentMultiAgent(input) {
129
128
  // eslint-disable-next-line no-await-in-loop
130
129
  const sectionContent = await engine.invoke(sectionContentAgent, sectionContentInput);
131
130
  sectionsData[sectionName] = sectionContent;
132
- logger_js_1.logger.info(`Content generated for section: ${sectionName}`);
131
+ logger_js_1.logger.info(`[${modelName}] Content generated for section: ${sectionName}`);
133
132
  // 通知该section已生成完成
134
133
  if (onProgress) {
135
134
  const sectionDataObj = {};
@@ -143,10 +142,10 @@ async function generatePageContentMultiAgent(input) {
143
142
  }
144
143
  }
145
144
  // 6. 生成页面元数据
146
- logger_js_1.logger.info('Generating page metadata');
145
+ logger_js_1.logger.info(`[${modelName}] Generating page metadata`);
147
146
  // 检查客户端是否仍然连接
148
147
  if (!isClientConnected()) {
149
- logger_js_1.logger.warn('Client disconnected before generating metadata, aborting generation');
148
+ logger_js_1.logger.warn(`[${modelName}] Client disconnected before generating metadata, aborting generation`);
150
149
  throw new Error('Client disconnected');
151
150
  }
152
151
  const metadata = await engine.invoke(page_metadata_generator_js_1.generatePageMetadataAgent, {
@@ -161,11 +160,11 @@ async function generatePageContentMultiAgent(input) {
161
160
  description: metadata.description,
162
161
  sectionsData,
163
162
  };
164
- logger_js_1.logger.info('Multi-agent page content generation completed');
163
+ logger_js_1.logger.info(`[${modelName}] Multi-agent page content generation completed`);
165
164
  return result;
166
165
  }
167
166
  catch (error) {
168
- logger_js_1.logger.error('Error in multi-agent page content generation:', error);
167
+ logger_js_1.logger.error(`[${modelName}] Error in multi-agent page content generation:`, error);
169
168
  throw error;
170
169
  }
171
170
  }
@@ -72,7 +72,6 @@ exports.pageStructurePlannerAgent = core_1.AIAgent.from({
72
72
  logger_js_1.logger.info('page structure planner output', JSON.stringify(output.structurePlan));
73
73
  return 'validation_request';
74
74
  },
75
- // publishTopic: UserOutputTopic,
76
75
  instructions: prompt,
77
76
  inputSchema: zod_1.z.object({
78
77
  context: zod_1.z.string(),