@aiscene/aiserver 1.8.4 → 1.8.5

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.
@@ -0,0 +1,274 @@
1
+ /**
2
+ * knowledge-organizer.ts — LLM 知识梳理 + 上传到后端知识库
3
+ *
4
+ * 采集的页面快照数据交给 LLM 梳理成知识 Markdown 条目,
5
+ * 然后上传到 guada_ai 后端的知识库文件 API
6
+ */
7
+ import { createLogger } from '../core/logger.js';
8
+ import { getConfig } from '../config/index.js';
9
+ import axios from 'axios';
10
+ import FormData from 'form-data';
11
+ const logger = createLogger('KnowledgeOrganizer');
12
+ /**
13
+ * 默认的 LLM 梳理 prompt 模板
14
+ */
15
+ const DEFAULT_ORGANIZE_PROMPT = [
16
+ '你是一个知识库整理专家。请根据以下页面采集数据,梳理成结构清晰的知识文档。',
17
+ '',
18
+ '要求:',
19
+ '1. 保留页面中有价值的业务信息、操作流程、功能说明',
20
+ '2. 去除无意义的导航栏、广告、重复内容',
21
+ '3. 按主题/功能分章节组织,使用 Markdown 格式',
22
+ '4. 如果有多个页面的数据,合并梳理,去除重复',
23
+ '5. 标注数据来源(URL)',
24
+ '',
25
+ '请直接输出 Markdown 文档内容,不要有任何额外说明。',
26
+ '',
27
+ '以下是需要梳理的页面采集数据:',
28
+ '',
29
+ ].join('\n');
30
+ /**
31
+ * 将多个页面快照拼接成 LLM 输入文本
32
+ */
33
+ function buildSnapshotContext(snapshots) {
34
+ const parts = [];
35
+ for (const snapshot of snapshots) {
36
+ parts.push('---');
37
+ parts.push('## 页面: ' + snapshot.title);
38
+ parts.push('URL: ' + snapshot.url);
39
+ parts.push('采集时间: ' + snapshot.capturedAt);
40
+ parts.push('');
41
+ // Meta 信息
42
+ if (snapshot.meta && Object.keys(snapshot.meta).length > 0) {
43
+ const desc = snapshot.meta.description || snapshot.meta['og:description'] || '';
44
+ if (desc)
45
+ parts.push('描述: ' + desc);
46
+ const keywords = snapshot.meta.keywords || '';
47
+ if (keywords)
48
+ parts.push('关键词: ' + keywords);
49
+ }
50
+ // 正文内容(截断过长内容)
51
+ const maxContent = 4000;
52
+ if (snapshot.content.length > maxContent) {
53
+ parts.push('');
54
+ parts.push('### 正文(截断)');
55
+ parts.push(snapshot.content.substring(0, maxContent));
56
+ parts.push('... (内容过长,已截断)');
57
+ }
58
+ else {
59
+ parts.push('');
60
+ parts.push('### 正文');
61
+ parts.push(snapshot.content);
62
+ }
63
+ // 关键链接
64
+ if (snapshot.links && snapshot.links.length > 0) {
65
+ parts.push('');
66
+ parts.push('### 关键链接');
67
+ for (const link of snapshot.links.slice(0, 20)) {
68
+ parts.push('- [' + (link.text || link.title || '链接') + '](' + link.url + ')');
69
+ }
70
+ }
71
+ parts.push('');
72
+ }
73
+ return parts.join('\n');
74
+ }
75
+ /**
76
+ * 文件名安全化
77
+ */
78
+ function sanitize(value) {
79
+ return value
80
+ .replace(/[\\/:*?"<>|\u0000-\u001f]/g, '_')
81
+ .replace(/\s+/g, ' ')
82
+ .trim()
83
+ .slice(0, 120) || '未命名';
84
+ }
85
+ function stringifyErrorValue(value) {
86
+ if (value === null || value === undefined || value === '')
87
+ return '';
88
+ if (typeof value === 'string')
89
+ return value;
90
+ if (typeof value === 'number' || typeof value === 'boolean')
91
+ return String(value);
92
+ if (value instanceof Error)
93
+ return value.message || String(value);
94
+ if (typeof value === 'object') {
95
+ const knownMessage = value.message || value.error || value.detail || value.reason || value.msg;
96
+ const nestedMessage = stringifyErrorValue(knownMessage);
97
+ if (nestedMessage)
98
+ return nestedMessage;
99
+ try {
100
+ return JSON.stringify(value);
101
+ }
102
+ catch {
103
+ return String(value);
104
+ }
105
+ }
106
+ return String(value);
107
+ }
108
+ function buildUploadErrorMessage(error) {
109
+ const status = error?.response?.status;
110
+ const data = error?.response?.data;
111
+ const dataMessage = stringifyErrorValue(data?.message) ||
112
+ stringifyErrorValue(data?.error) ||
113
+ stringifyErrorValue(data?.detail) ||
114
+ stringifyErrorValue(data);
115
+ const baseMessage = dataMessage || stringifyErrorValue(error?.message) || '上传失败';
116
+ return status ? 'HTTP ' + status + ' ' + baseMessage : baseMessage;
117
+ }
118
+ /**
119
+ * 调用 LLM API
120
+ */
121
+ async function callLLM(aiConfig, prompt) {
122
+ const baseUrl = aiConfig.baseUrl;
123
+ const apiKey = aiConfig.apiKey;
124
+ const modelName = aiConfig.modelName;
125
+ const modelFamily = aiConfig.modelFamily;
126
+ // 根据模型家族选择不同的 API 格式
127
+ const isOllama = modelFamily === 'ollama';
128
+ const url = isOllama
129
+ ? baseUrl + '/api/generate'
130
+ : baseUrl + '/v1/chat/completions';
131
+ const headers = {
132
+ 'Content-Type': 'application/json',
133
+ };
134
+ if (!isOllama && apiKey) {
135
+ headers['Authorization'] = 'Bearer ' + apiKey;
136
+ }
137
+ const body = isOllama ? {
138
+ model: modelName,
139
+ prompt,
140
+ stream: false,
141
+ } : {
142
+ model: modelName,
143
+ messages: [{ role: 'user', content: prompt }],
144
+ stream: false,
145
+ };
146
+ const response = await axios.post(url, body, {
147
+ headers,
148
+ timeout: 120000,
149
+ });
150
+ if (isOllama) {
151
+ return response.data?.response || '';
152
+ }
153
+ else {
154
+ const choices = response.data?.choices || [];
155
+ return choices[0]?.message?.content || '';
156
+ }
157
+ }
158
+ /**
159
+ * 用 LLM 梳理采集的页面快照,生成 Markdown 文档
160
+ */
161
+ export async function organizeSnapshots(snapshots, sessionName) {
162
+ const config = getConfig();
163
+ // 无 LLM 配置时直接拼接
164
+ if (!config.ai?.baseUrl || !config.ai?.modelName) {
165
+ logger.info('No LLM config, using raw markdown fallback');
166
+ return buildRawMarkdown(snapshots, sessionName);
167
+ }
168
+ const context = buildSnapshotContext(snapshots);
169
+ const promptTemplate = config.knowledgeBase?.organizePromptTemplate || DEFAULT_ORGANIZE_PROMPT;
170
+ const prompt = promptTemplate + context;
171
+ logger.info('Calling LLM to organize ' + snapshots.length + ' snapshots (context: ' + context.length + ' chars)...');
172
+ try {
173
+ const response = await callLLM(config.ai, prompt);
174
+ logger.info('LLM organized successfully: ' + response.length + ' chars');
175
+ return response;
176
+ }
177
+ catch (error) {
178
+ logger.warn('LLM organizing failed: ' + error.message + ', falling back to raw content');
179
+ return buildRawMarkdown(snapshots, sessionName);
180
+ }
181
+ }
182
+ /**
183
+ * 无 LLM 时,直接拼接原始 Markdown
184
+ */
185
+ function buildRawMarkdown(snapshots, sessionName) {
186
+ const parts = [];
187
+ parts.push('# ' + sessionName + ' — 知识采集');
188
+ parts.push('');
189
+ parts.push('> 采集时间: ' + new Date().toLocaleString('zh-CN'));
190
+ parts.push('> 采集页数: ' + snapshots.length);
191
+ parts.push('');
192
+ for (const snapshot of snapshots) {
193
+ parts.push('---');
194
+ parts.push('');
195
+ parts.push('## ' + snapshot.title);
196
+ parts.push('');
197
+ parts.push('**来源:** ' + snapshot.url);
198
+ parts.push('**采集时间:** ' + snapshot.capturedAt);
199
+ parts.push('');
200
+ if (snapshot.meta?.description) {
201
+ parts.push('**描述:** ' + snapshot.meta.description);
202
+ }
203
+ if (snapshot.meta?.keywords) {
204
+ parts.push('**关键词:** ' + snapshot.meta.keywords);
205
+ }
206
+ parts.push('');
207
+ parts.push('### 正文内容');
208
+ parts.push('');
209
+ parts.push(snapshot.content);
210
+ parts.push('');
211
+ }
212
+ return parts.join('\n');
213
+ }
214
+ /**
215
+ * 将梳理后的 Markdown 上传到后端知识库
216
+ */
217
+ export async function uploadToKnowledgeBase(session, markdownContent) {
218
+ const kbId = session.knowledgeBaseId;
219
+ const apiUrl = session.knowledgeBaseApiUrl;
220
+ const token = session.knowledgeBaseToken;
221
+ const folder = session.relativeFolder;
222
+ // 生成文件名
223
+ const fileName = sanitize(session.name) + '.md';
224
+ const relativePath = folder ? folder + '/' + fileName : fileName;
225
+ logger.info('Uploading to knowledge base: kbId=' + kbId + ', path=' + relativePath + ', size=' + markdownContent.length + ' chars');
226
+ // 构建 FormData
227
+ const formData = new FormData();
228
+ formData.append('file', Buffer.from(markdownContent, 'utf-8'), {
229
+ filename: fileName,
230
+ contentType: 'text/markdown;charset=utf-8',
231
+ });
232
+ if (relativePath) {
233
+ formData.append('relativePath', relativePath);
234
+ }
235
+ const headers = {
236
+ ...formData.getHeaders(),
237
+ };
238
+ if (token) {
239
+ headers['Authorization'] = 'Bearer ' + token;
240
+ }
241
+ const uploadUrl = apiUrl + '/knowledge-bases/' + encodeURIComponent(kbId) + '/files/upload';
242
+ try {
243
+ const response = await axios.post(uploadUrl, formData, {
244
+ headers,
245
+ timeout: 60000,
246
+ maxContentLength: Infinity,
247
+ maxBodyLength: Infinity,
248
+ });
249
+ logger.info('Upload successful');
250
+ return {
251
+ fileName,
252
+ content: markdownContent,
253
+ uploadResult: response.data,
254
+ };
255
+ }
256
+ catch (error) {
257
+ const message = buildUploadErrorMessage(error);
258
+ logger.error('Upload failed: ' + message);
259
+ throw new Error('知识库上传失败: ' + message);
260
+ }
261
+ }
262
+ /**
263
+ * 完整的采集 -> 梳理 -> 上传流程
264
+ */
265
+ export async function processCaptureSession(session) {
266
+ logger.info('Processing capture session: ' + session.id + ' (' + session.snapshots.length + ' snapshots)');
267
+ // 1. LLM 梳理
268
+ const markdown = await organizeSnapshots(session.snapshots, session.name);
269
+ // 2. 上传到知识库
270
+ const result = await uploadToKnowledgeBase(session, markdown);
271
+ logger.info('Session processed successfully: ' + result.fileName);
272
+ return result;
273
+ }
274
+ //# sourceMappingURL=knowledge-organizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"knowledge-organizer.js","sourceRoot":"","sources":["../../src/capture/knowledge-organizer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { Page } from 'playwright';
2
+ import type { PageSnapshot } from './types.js';
3
+ /**
4
+ * 从 Playwright Page 中提取页面结构化数据
5
+ */
6
+ export declare function extractPageSnapshot(page: Page): Promise<PageSnapshot>;
7
+ /**
8
+ * 从 Android UI Hierarchy 提取 App 页面数据
9
+ * 生成类似浏览器快照的结构化数据(基于 UI 层级而非 HTML)
10
+ */
11
+ export declare function extractAppSnapshotFromHierarchy(hierarchyXml: string, screenshotBase64?: string, packageName?: string, activityName?: string): PageSnapshot;
12
+ //# sourceMappingURL=page-extractor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-extractor.d.ts","sourceRoot":"","sources":["../../src/capture/page-extractor.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AA2G/C;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC,CAoE3E;AAED;;;GAGG;AACH,wBAAgB,+BAA+B,CAC7C,YAAY,EAAE,MAAM,EACpB,gBAAgB,CAAC,EAAE,MAAM,EACzB,WAAW,CAAC,EAAE,MAAM,EACpB,YAAY,CAAC,EAAE,MAAM,GACpB,YAAY,CA6Bd"}
@@ -0,0 +1,245 @@
1
+ /**
2
+ * page-extractor.ts — 页面内容提取器
3
+ *
4
+ * 通过 Playwright page.evaluate() 注入 extractor-script.js 执行页面内容提取
5
+ * extractor-script.js 基于 browser-extension/extractor.js 改写
6
+ */
7
+ import { randomUUID } from 'node:crypto';
8
+ import { readFileSync } from 'node:fs';
9
+ import { resolve, dirname } from 'node:path';
10
+ import { fileURLToPath } from 'node:url';
11
+ import { createLogger } from '../core/logger.js';
12
+ const logger = createLogger('PageExtractor');
13
+ const MAX_CONTENT_CHARS = 12_000_000;
14
+ const EVALUATE_RETRY_COUNT = 3;
15
+ const EVALUATE_RETRY_DELAY_MS = 350;
16
+ // 读取提取脚本 — 从同目录的 extractor-script.js 加载
17
+ const __dirname = dirname(fileURLToPath(import.meta.url));
18
+ const EXTRACTOR_SCRIPT_PATH = resolve(__dirname, 'extractor-script.js');
19
+ let _extractorScript = null;
20
+ function getExtractorScript() {
21
+ if (_extractorScript)
22
+ return _extractorScript;
23
+ try {
24
+ _extractorScript = readFileSync(EXTRACTOR_SCRIPT_PATH, 'utf-8');
25
+ logger.info(`Extractor script loaded: ${_extractorScript.length} chars`);
26
+ }
27
+ catch (e) {
28
+ logger.error('Failed to load extractor-script.js: ' + e.message);
29
+ throw new Error('extractor-script.js not found at ' + EXTRACTOR_SCRIPT_PATH);
30
+ }
31
+ return _extractorScript;
32
+ }
33
+ function sleep(ms) {
34
+ return new Promise(resolve => setTimeout(resolve, ms));
35
+ }
36
+ function isTransientPageError(error) {
37
+ const message = error?.message || String(error || '');
38
+ return (message.includes('Execution context was destroyed') ||
39
+ message.includes('Cannot find context with specified id') ||
40
+ message.includes('Target closed') ||
41
+ message.includes('Target page, context or browser has been closed') ||
42
+ message.includes('Navigation failed because page was closed'));
43
+ }
44
+ async function waitForPageSettled(page) {
45
+ try {
46
+ await page.waitForLoadState('domcontentloaded', { timeout: 1500 });
47
+ }
48
+ catch {
49
+ // 页面可能是单页应用、长轮询页面,或者仍在跳转;这里不阻塞采集,交给后续重试兜底。
50
+ }
51
+ }
52
+ async function evaluateExtractorWithRetry(page, script) {
53
+ let lastError;
54
+ for (let attempt = 1; attempt <= EVALUATE_RETRY_COUNT; attempt++) {
55
+ try {
56
+ await waitForPageSettled(page);
57
+ return await page.evaluate(script);
58
+ }
59
+ catch (error) {
60
+ lastError = error;
61
+ if (!isTransientPageError(error) || attempt === EVALUATE_RETRY_COUNT) {
62
+ break;
63
+ }
64
+ logger.warn(`Page evaluate interrupted by navigation, retrying (${attempt}/${EVALUATE_RETRY_COUNT})...`);
65
+ await sleep(EVALUATE_RETRY_DELAY_MS * attempt);
66
+ }
67
+ }
68
+ throw lastError instanceof Error ? lastError : new Error(String(lastError));
69
+ }
70
+ async function buildFallbackSnapshotData(page, error) {
71
+ let title = '页面跳转中';
72
+ let url = '';
73
+ try {
74
+ title = await page.title();
75
+ }
76
+ catch { }
77
+ try {
78
+ url = page.url();
79
+ }
80
+ catch { }
81
+ return {
82
+ title,
83
+ url,
84
+ content: `页面正在跳转或刷新,本次仅记录基础信息。\n\n错误信息:${error?.message || String(error || '')}`,
85
+ capturedAt: new Date().toISOString(),
86
+ captureMode: 'fallback',
87
+ meta: {
88
+ fallback: true,
89
+ errorMessage: error?.message || String(error || ''),
90
+ },
91
+ openGraph: {},
92
+ jsonLd: [],
93
+ links: [],
94
+ tables: [],
95
+ forms: [],
96
+ pageStructure: {
97
+ title,
98
+ charset: '',
99
+ viewport: '',
100
+ domain: '',
101
+ tagCounts: {},
102
+ linkStats: { internal: 0, external: 0, anchor: 0 },
103
+ },
104
+ images: [],
105
+ };
106
+ }
107
+ /**
108
+ * 从 Playwright Page 中提取页面结构化数据
109
+ */
110
+ export async function extractPageSnapshot(page) {
111
+ logger.info('Extracting page snapshot...');
112
+ const script = getExtractorScript();
113
+ let result;
114
+ try {
115
+ result = await evaluateExtractorWithRetry(page, script);
116
+ }
117
+ catch (error) {
118
+ if (!isTransientPageError(error)) {
119
+ throw error;
120
+ }
121
+ logger.warn('Page evaluate still failed after retries, using fallback snapshot: ' + error.message);
122
+ result = await buildFallbackSnapshotData(page, error);
123
+ }
124
+ // 截图
125
+ let screenshotBase64;
126
+ try {
127
+ const screenshotBuffer = await page.screenshot({ type: 'png', fullPage: false });
128
+ screenshotBase64 = screenshotBuffer.toString('base64');
129
+ }
130
+ catch (e) {
131
+ logger.warn('Screenshot failed, skipping: ' + e.message);
132
+ }
133
+ const snapshot = {
134
+ id: randomUUID(),
135
+ title: result.title || '未命名页面',
136
+ url: result.url || page.url(),
137
+ content: result.content || '',
138
+ capturedAt: result.capturedAt || new Date().toISOString(),
139
+ captureMode: result.captureMode || 'auto',
140
+ meta: result.meta || {},
141
+ openGraph: result.openGraph || {},
142
+ jsonLd: result.jsonLd || [],
143
+ links: (result.links || []).map((l) => ({
144
+ url: l.url || '',
145
+ text: l.text || '',
146
+ title: l.title || '',
147
+ })),
148
+ tables: (result.tables || []).map((t) => ({
149
+ caption: t.caption || '',
150
+ headers: t.headers || [],
151
+ rows: t.rows || [],
152
+ })),
153
+ forms: (result.forms || []).map((f) => ({
154
+ action: f.action || '',
155
+ method: f.method || 'get',
156
+ inputs: f.inputs || [],
157
+ })),
158
+ pageStructure: {
159
+ title: result.pageStructure?.title || '',
160
+ charset: result.pageStructure?.charset || '',
161
+ viewport: result.pageStructure?.viewport || '',
162
+ domain: result.pageStructure?.domain || '',
163
+ tagCounts: result.pageStructure?.tagCounts || {},
164
+ linkStats: result.pageStructure?.linkStats || { internal: 0, external: 0, anchor: 0 },
165
+ },
166
+ images: (result.images || []).map((img) => ({
167
+ url: img.url || '',
168
+ alt: img.alt || '',
169
+ width: img.width || 0,
170
+ height: img.height || 0,
171
+ })),
172
+ screenshotBase64,
173
+ };
174
+ logger.info(`Snapshot extracted: "${snapshot.title}" (${snapshot.content.length} chars, ${snapshot.images.length} images)`);
175
+ return snapshot;
176
+ }
177
+ /**
178
+ * 从 Android UI Hierarchy 提取 App 页面数据
179
+ * 生成类似浏览器快照的结构化数据(基于 UI 层级而非 HTML)
180
+ */
181
+ export function extractAppSnapshotFromHierarchy(hierarchyXml, screenshotBase64, packageName, activityName) {
182
+ logger.info('Extracting app snapshot from UI hierarchy...');
183
+ const content = buildMarkdownFromHierarchy(hierarchyXml);
184
+ return {
185
+ id: randomUUID(),
186
+ title: activityName || packageName || 'App 页面',
187
+ url: `${packageName}/${activityName || 'unknown'}`,
188
+ content,
189
+ capturedAt: new Date().toISOString(),
190
+ captureMode: 'auto',
191
+ meta: { packageName: packageName || '', activity: activityName || '' },
192
+ openGraph: {},
193
+ jsonLd: [],
194
+ links: [],
195
+ tables: [],
196
+ forms: [],
197
+ pageStructure: {
198
+ title: packageName || '',
199
+ charset: '',
200
+ viewport: '',
201
+ domain: '',
202
+ tagCounts: {},
203
+ linkStats: { internal: 0, external: 0, anchor: 0 },
204
+ },
205
+ images: [],
206
+ screenshotBase64,
207
+ };
208
+ }
209
+ /**
210
+ * 从 Android UI Hierarchy XML 构建 Markdown 描述
211
+ */
212
+ function buildMarkdownFromHierarchy(xml) {
213
+ const lines = [];
214
+ lines.push('# App 页面结构');
215
+ lines.push('');
216
+ lines.push('## 可见元素列表');
217
+ lines.push('');
218
+ const nodeRegex = /<node[^>]*>/g;
219
+ let match;
220
+ let elementCount = 0;
221
+ while ((match = nodeRegex.exec(xml)) !== null && elementCount < 100) {
222
+ const attrs = match[0];
223
+ const textAttr = attrs.match(/text="([^"]*)"/);
224
+ const descAttr = attrs.match(/content-desc="([^"]*)"/);
225
+ const classAttr = attrs.match(/class="([^"]*)"/);
226
+ const boundsAttr = attrs.match(/bounds="\[([^\]]*)\]\[([^\]]*)\]"/);
227
+ const text = textAttr?.[1] || '';
228
+ const desc = descAttr?.[1] || '';
229
+ const className = classAttr?.[1] || '';
230
+ const bounds = boundsAttr ? `${boundsAttr[1]} → ${boundsAttr[2]}` : '';
231
+ if (text || desc) {
232
+ const label = text || desc;
233
+ const elementType = className.split('.').pop() || className;
234
+ lines.push(`- **${elementType}**: "${label}" (${bounds})`);
235
+ elementCount++;
236
+ }
237
+ }
238
+ if (elementCount === 0) {
239
+ lines.push('> 未发现可见文字元素');
240
+ }
241
+ lines.push('');
242
+ lines.push(`> 共识别 ${elementCount} 个可见元素`);
243
+ return lines.join('\n');
244
+ }
245
+ //# sourceMappingURL=page-extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-extractor.js","sourceRoot":"","sources":["../../src/capture/page-extractor.ts"],"names":[],"mappings":"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"}