@anyul/koishi-plugin-rss 5.2.3 → 5.2.41
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.
- package/README.md +92 -37
- package/lib/commands/error-handler.js +13 -1
- package/lib/commands/index.d.ts +3 -0
- package/lib/commands/index.js +7 -1
- package/lib/commands/runtime.d.ts +17 -0
- package/lib/commands/runtime.js +27 -0
- package/lib/commands/subscription-create.d.ts +23 -0
- package/lib/commands/subscription-create.js +145 -0
- package/lib/commands/web-monitor.d.ts +15 -0
- package/lib/commands/web-monitor.js +222 -0
- package/lib/config.js +7 -1
- package/lib/constants.d.ts +1 -1
- package/lib/constants.js +46 -83
- package/lib/core/ai-cache.d.ts +27 -0
- package/lib/core/ai-cache.js +169 -0
- package/lib/core/ai-client.d.ts +12 -0
- package/lib/core/ai-client.js +65 -0
- package/lib/core/ai-selector.d.ts +2 -0
- package/lib/core/ai-selector.js +80 -0
- package/lib/core/ai-summary.d.ts +10 -0
- package/lib/core/ai-summary.js +73 -0
- package/lib/core/ai-utils.d.ts +10 -0
- package/lib/core/ai-utils.js +104 -0
- package/lib/core/ai.d.ts +3 -91
- package/lib/core/ai.js +13 -522
- package/lib/core/feeder-arg.d.ts +17 -0
- package/lib/core/feeder-arg.js +234 -0
- package/lib/core/feeder-runtime.d.ts +96 -0
- package/lib/core/feeder-runtime.js +233 -0
- package/lib/core/feeder.d.ts +3 -5
- package/lib/core/feeder.js +61 -358
- package/lib/core/item-processor-runtime.d.ts +46 -0
- package/lib/core/item-processor-runtime.js +215 -0
- package/lib/core/item-processor-template.d.ts +16 -0
- package/lib/core/item-processor-template.js +158 -0
- package/lib/core/item-processor.d.ts +1 -15
- package/lib/core/item-processor.js +44 -319
- package/lib/core/notification-queue-retry.d.ts +25 -0
- package/lib/core/notification-queue-retry.js +78 -0
- package/lib/core/notification-queue-sender.d.ts +20 -0
- package/lib/core/notification-queue-sender.js +118 -0
- package/lib/core/notification-queue-store.d.ts +19 -0
- package/lib/core/notification-queue-store.js +137 -0
- package/lib/core/notification-queue-types.d.ts +49 -0
- package/lib/core/notification-queue-types.js +2 -0
- package/lib/core/notification-queue.d.ts +11 -72
- package/lib/core/notification-queue.js +81 -258
- package/lib/core/search-format.d.ts +3 -0
- package/lib/core/search-format.js +36 -0
- package/lib/core/search-providers.d.ts +13 -0
- package/lib/core/search-providers.js +175 -0
- package/lib/core/search-rotation.d.ts +4 -0
- package/lib/core/search-rotation.js +55 -0
- package/lib/core/search-service.d.ts +3 -0
- package/lib/core/search-service.js +100 -0
- package/lib/core/search-types.d.ts +39 -0
- package/lib/core/search-types.js +2 -0
- package/lib/core/search.d.ts +4 -101
- package/lib/core/search.js +10 -508
- package/lib/index.js +27 -381
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/types.d.ts +27 -6
- package/lib/utils/legacy-config.d.ts +12 -0
- package/lib/utils/legacy-config.js +56 -0
- package/lib/utils/logger.js +50 -29
- package/lib/utils/proxy.d.ts +3 -0
- package/lib/utils/proxy.js +14 -0
- package/lib/utils/structured-logger.d.ts +7 -3
- package/lib/utils/structured-logger.js +26 -19
- package/package.json +1 -1
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.requestAiText = requestAiText;
|
|
7
|
+
exports.callAiApi = callAiApi;
|
|
8
|
+
const axios_1 = __importDefault(require("axios"));
|
|
9
|
+
const logger_1 = require("../utils/logger");
|
|
10
|
+
const proxy_1 = require("../utils/proxy");
|
|
11
|
+
async function requestAiText(config, prompt, options = {}) {
|
|
12
|
+
const requestConfig = {
|
|
13
|
+
headers: {
|
|
14
|
+
'Authorization': `Bearer ${config.ai.apiKey}`,
|
|
15
|
+
'Content-Type': 'application/json'
|
|
16
|
+
},
|
|
17
|
+
timeout: options.timeout ?? config.ai?.timeout,
|
|
18
|
+
...(0, proxy_1.buildAxiosProxyConfig)(config)
|
|
19
|
+
};
|
|
20
|
+
const response = await axios_1.default.post(`${config.ai.baseUrl.replace(/\/+$/, '')}/chat/completions`, {
|
|
21
|
+
model: config.ai.model,
|
|
22
|
+
messages: [{ role: 'user', content: prompt }],
|
|
23
|
+
temperature: options.temperature ?? 0.7
|
|
24
|
+
}, requestConfig);
|
|
25
|
+
const summary = response.data?.choices?.[0]?.message?.content?.trim();
|
|
26
|
+
if (!summary) {
|
|
27
|
+
throw new Error('AI 返回空结果');
|
|
28
|
+
}
|
|
29
|
+
return summary;
|
|
30
|
+
}
|
|
31
|
+
async function callAiApi(config, prompt, context) {
|
|
32
|
+
const maxRetries = 2;
|
|
33
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
34
|
+
try {
|
|
35
|
+
(0, logger_1.debug)(config, `AI 请求尝试 ${attempt + 1}/${maxRetries + 1}: ${context}`, 'AI', 'info');
|
|
36
|
+
const summary = await requestAiText(config, prompt);
|
|
37
|
+
(0, logger_1.debug)(config, `AI 摘要生成成功: ${summary.substring(0, 20)}...`, 'AI', 'details');
|
|
38
|
+
return {
|
|
39
|
+
success: true,
|
|
40
|
+
summary,
|
|
41
|
+
cached: false
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
const isLastAttempt = attempt === maxRetries;
|
|
46
|
+
(0, logger_1.debug)(config, `AI 请求失败 (尝试 ${attempt + 1}/${maxRetries + 1}): ${error.message}`, 'AI', isLastAttempt ? 'error' : 'info');
|
|
47
|
+
if (isLastAttempt) {
|
|
48
|
+
return {
|
|
49
|
+
success: false,
|
|
50
|
+
summary: '',
|
|
51
|
+
cached: false,
|
|
52
|
+
error: error.message
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
const waitTime = Math.pow(2, attempt) * 1000;
|
|
56
|
+
await new Promise(resolve => setTimeout(resolve, waitTime));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
success: false,
|
|
61
|
+
summary: '',
|
|
62
|
+
cached: false,
|
|
63
|
+
error: '未知错误'
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.generateSelectorByAI = generateSelectorByAI;
|
|
37
|
+
const cheerio = __importStar(require("cheerio"));
|
|
38
|
+
const logger_1 = require("../utils/logger");
|
|
39
|
+
const ai_client_1 = require("./ai-client");
|
|
40
|
+
async function generateSelectorByAI(config, url, instruction, html) {
|
|
41
|
+
if (!config.ai?.enabled || !config.ai?.apiKey) {
|
|
42
|
+
throw new Error('需在配置中开启 AI 功能并填写 API Key');
|
|
43
|
+
}
|
|
44
|
+
const $ = cheerio.load(html);
|
|
45
|
+
$('script, style, svg, path, link, meta, noscript').remove();
|
|
46
|
+
$('*').contents().each((_, element) => {
|
|
47
|
+
if (element.type === 'comment') {
|
|
48
|
+
$(element).remove();
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
const cleanHtml = $('body').html()?.replace(/\s+/g, ' ').trim().substring(0, 15000) || '';
|
|
52
|
+
const prompt = `
|
|
53
|
+
作为一名爬虫专家,请根据提供的 HTML 代码片段,为一个网页监控工具生成一个 CSS Selector。
|
|
54
|
+
|
|
55
|
+
目标网页:${url}
|
|
56
|
+
用户需求:${instruction}
|
|
57
|
+
|
|
58
|
+
要求:
|
|
59
|
+
1. 只返回 CSS Selector 字符串,不要包含任何解释、Markdown 标记或代码块符号。
|
|
60
|
+
2. Selector 必须尽可能精确,通常用于提取列表中的一项或多项。
|
|
61
|
+
3. 如果是列表,请确保 Selector 能选中列表项的容器。
|
|
62
|
+
|
|
63
|
+
HTML片段:
|
|
64
|
+
${cleanHtml}
|
|
65
|
+
`;
|
|
66
|
+
try {
|
|
67
|
+
(0, logger_1.debug)(config, `正在请求 AI 生成选择器: ${instruction}`, 'AI-Selector', 'info');
|
|
68
|
+
let selector = await (0, ai_client_1.requestAiText)(config, prompt, {
|
|
69
|
+
temperature: 0.1,
|
|
70
|
+
timeout: 60000
|
|
71
|
+
});
|
|
72
|
+
selector = selector.replace(/`/g, '').replace(/^css/i, '').trim();
|
|
73
|
+
(0, logger_1.debug)(config, `AI 生成的选择器: ${selector}`, 'AI-Selector', 'info');
|
|
74
|
+
return selector || '';
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
(0, logger_1.debug)(config, `AI 生成选择器失败: ${error.message}`, 'AI-Selector', 'error');
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Config } from '../types';
|
|
2
|
+
export declare function getAiSummary(config: Config, title: string, contentHtml: string): Promise<string>;
|
|
3
|
+
export declare function getBatchAiSummary(config: Config, items: Array<{
|
|
4
|
+
title: string;
|
|
5
|
+
content: string;
|
|
6
|
+
}>): Promise<string>;
|
|
7
|
+
export declare function getSmartAiSummary(config: Config, items: Array<{
|
|
8
|
+
title: string;
|
|
9
|
+
content: string;
|
|
10
|
+
}>): Promise<string>;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getAiSummary = getAiSummary;
|
|
4
|
+
exports.getBatchAiSummary = getBatchAiSummary;
|
|
5
|
+
exports.getSmartAiSummary = getSmartAiSummary;
|
|
6
|
+
const logger_1 = require("../utils/logger");
|
|
7
|
+
const ai_cache_1 = require("./ai-cache");
|
|
8
|
+
const ai_client_1 = require("./ai-client");
|
|
9
|
+
const ai_utils_1 = require("./ai-utils");
|
|
10
|
+
function shouldSkipAiSummary(config) {
|
|
11
|
+
return !config.ai?.enabled || !config.ai?.apiKey;
|
|
12
|
+
}
|
|
13
|
+
function getSummaryCache(config) {
|
|
14
|
+
return (0, ai_cache_1.getOrInitAiCache)(undefined, config.security?.maxCacheSize);
|
|
15
|
+
}
|
|
16
|
+
async function getAiSummary(config, title, contentHtml) {
|
|
17
|
+
if (shouldSkipAiSummary(config))
|
|
18
|
+
return '';
|
|
19
|
+
const cache = getSummaryCache(config);
|
|
20
|
+
const plainText = (0, ai_utils_1.cleanHtmlContent)(contentHtml, config.ai.maxInputLength);
|
|
21
|
+
if (!plainText || plainText.length < 50)
|
|
22
|
+
return '';
|
|
23
|
+
const cachedSummary = cache.get(title, plainText);
|
|
24
|
+
if (cachedSummary) {
|
|
25
|
+
(0, logger_1.debug)(config, `使用缓存的 AI 摘要: ${title}`, 'AI-Cache', 'details');
|
|
26
|
+
return cachedSummary;
|
|
27
|
+
}
|
|
28
|
+
let prompt = (0, ai_utils_1.buildSingleSummaryPrompt)(config.ai.prompt, title, plainText);
|
|
29
|
+
const searchQuery = title || plainText.substring(0, 100);
|
|
30
|
+
prompt = await (0, ai_utils_1.enhancePromptWithSearch)(config, prompt, searchQuery);
|
|
31
|
+
const result = await (0, ai_client_1.callAiApi)(config, prompt, `单条摘要: ${title}`);
|
|
32
|
+
if (result.success && result.summary) {
|
|
33
|
+
cache.set(title, plainText, result.summary);
|
|
34
|
+
}
|
|
35
|
+
return result.summary;
|
|
36
|
+
}
|
|
37
|
+
async function getBatchAiSummary(config, items) {
|
|
38
|
+
if (shouldSkipAiSummary(config) || items.length === 0)
|
|
39
|
+
return '';
|
|
40
|
+
if (items.length === 1) {
|
|
41
|
+
return getAiSummary(config, items[0].title, items[0].content);
|
|
42
|
+
}
|
|
43
|
+
(0, logger_1.debug)(config, `批量生成 AI 摘要: ${items.length} 条内容`, 'AI-Batch', 'info');
|
|
44
|
+
try {
|
|
45
|
+
const cleanedItems = (0, ai_utils_1.cleanSummaryItems)(items, config.ai.maxInputLength);
|
|
46
|
+
if (cleanedItems.length === 0) {
|
|
47
|
+
(0, logger_1.debug)(config, '所有内容都太短,无法生成批量摘要', 'AI-Batch', 'info');
|
|
48
|
+
return '';
|
|
49
|
+
}
|
|
50
|
+
let prompt = (0, ai_utils_1.buildBatchSummaryPrompt)(cleanedItems);
|
|
51
|
+
prompt = await (0, ai_utils_1.enhancePromptWithSearch)(config, prompt, cleanedItems[0].title, '批量摘要 - ');
|
|
52
|
+
const result = await (0, ai_client_1.callAiApi)(config, prompt, `批量摘要: ${cleanedItems.length}条`);
|
|
53
|
+
if (result.success && result.summary) {
|
|
54
|
+
(0, logger_1.debug)(config, `批量摘要生成成功: ${result.summary.substring(0, 50)}...`, 'AI-Batch', 'details');
|
|
55
|
+
}
|
|
56
|
+
return result.summary;
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
(0, logger_1.debug)(config, `批量摘要生成失败: ${error.message}`, 'AI-Batch', 'error');
|
|
60
|
+
return '';
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async function getSmartAiSummary(config, items) {
|
|
64
|
+
if (shouldSkipAiSummary(config) || items.length === 0) {
|
|
65
|
+
return '';
|
|
66
|
+
}
|
|
67
|
+
const threshold = 3;
|
|
68
|
+
if (items.length > threshold) {
|
|
69
|
+
return getBatchAiSummary(config, items);
|
|
70
|
+
}
|
|
71
|
+
const summaries = await Promise.all(items.map(item => getAiSummary(config, item.title, item.content)));
|
|
72
|
+
return summaries.filter(summary => summary).join('\n\n');
|
|
73
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Config } from '../types';
|
|
2
|
+
export interface AiSummaryItem {
|
|
3
|
+
title: string;
|
|
4
|
+
content: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function cleanHtmlContent(contentHtml: string, maxLength: number): string;
|
|
7
|
+
export declare function buildSingleSummaryPrompt(promptTemplate: string, title: string, plainText: string): string;
|
|
8
|
+
export declare function buildBatchSummaryPrompt(items: AiSummaryItem[]): string;
|
|
9
|
+
export declare function cleanSummaryItems(items: AiSummaryItem[], maxInputLength: number): AiSummaryItem[];
|
|
10
|
+
export declare function enhancePromptWithSearch(config: Config, prompt: string, searchQuery: string, logPrefix?: string): Promise<string>;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.cleanHtmlContent = cleanHtmlContent;
|
|
37
|
+
exports.buildSingleSummaryPrompt = buildSingleSummaryPrompt;
|
|
38
|
+
exports.buildBatchSummaryPrompt = buildBatchSummaryPrompt;
|
|
39
|
+
exports.cleanSummaryItems = cleanSummaryItems;
|
|
40
|
+
exports.enhancePromptWithSearch = enhancePromptWithSearch;
|
|
41
|
+
const cheerio = __importStar(require("cheerio"));
|
|
42
|
+
const config_1 = require("../config");
|
|
43
|
+
const logger_1 = require("../utils/logger");
|
|
44
|
+
const search_format_1 = require("./search-format");
|
|
45
|
+
const search_service_1 = require("./search-service");
|
|
46
|
+
function cleanHtmlContent(contentHtml, maxLength) {
|
|
47
|
+
const $ = cheerio.load(contentHtml || '');
|
|
48
|
+
$('script').remove();
|
|
49
|
+
$('style').remove();
|
|
50
|
+
$('img').remove();
|
|
51
|
+
$('video').remove();
|
|
52
|
+
let plainText = $.text().replace(/\s+/g, ' ').trim();
|
|
53
|
+
if (plainText.length > maxLength) {
|
|
54
|
+
plainText = plainText.substring(0, maxLength) + '...';
|
|
55
|
+
}
|
|
56
|
+
return plainText;
|
|
57
|
+
}
|
|
58
|
+
function buildSingleSummaryPrompt(promptTemplate, title, plainText) {
|
|
59
|
+
return promptTemplate
|
|
60
|
+
.replace('{{title}}', title || '')
|
|
61
|
+
.replace('{{content}}', plainText);
|
|
62
|
+
}
|
|
63
|
+
function buildBatchSummaryPrompt(items) {
|
|
64
|
+
return `请简要总结以下 ${items.length} 条新闻/文章的核心内容,要求:
|
|
65
|
+
1. 语言简洁流畅,每条总结不超过30字
|
|
66
|
+
2. 按顺序总结,使用数字编号
|
|
67
|
+
3. 突出重点信息
|
|
68
|
+
|
|
69
|
+
${items.map((item, index) => `
|
|
70
|
+
${index + 1}. 标题:${item.title}
|
|
71
|
+
内容:${item.content}
|
|
72
|
+
`).join('\n')}
|
|
73
|
+
|
|
74
|
+
总结:`;
|
|
75
|
+
}
|
|
76
|
+
function cleanSummaryItems(items, maxInputLength) {
|
|
77
|
+
return items
|
|
78
|
+
.map(item => ({
|
|
79
|
+
title: item.title,
|
|
80
|
+
content: cleanHtmlContent(item.content, maxInputLength / items.length)
|
|
81
|
+
}))
|
|
82
|
+
.filter(item => item.content.length >= 50);
|
|
83
|
+
}
|
|
84
|
+
async function enhancePromptWithSearch(config, prompt, searchQuery, logPrefix = '') {
|
|
85
|
+
if (!config.search?.enabled) {
|
|
86
|
+
return prompt;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
const normalizedSearchConfig = (0, config_1.normalizeSearchConfig)(config.search);
|
|
90
|
+
(0, logger_1.debug)(config, `${logPrefix}正在联网搜索: ${searchQuery}`, 'AI-Search', 'info');
|
|
91
|
+
const searchResults = await (0, search_service_1.webSearch)(config, searchQuery, normalizedSearchConfig);
|
|
92
|
+
if (searchResults.success && searchResults.results.length > 0) {
|
|
93
|
+
(0, logger_1.debug)(config, `${logPrefix}联网搜索成功,找到 ${searchResults.results.length} 条结果`, 'AI-Search', 'details');
|
|
94
|
+
return (0, search_format_1.buildPromptWithSearchContext)(prompt, searchResults, searchQuery);
|
|
95
|
+
}
|
|
96
|
+
if (searchResults.error) {
|
|
97
|
+
(0, logger_1.debug)(config, `${logPrefix}联网搜索失败: ${searchResults.error}`, 'AI-Search', 'info');
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
(0, logger_1.debug)(config, `${logPrefix}联网搜索异常: ${error.message}`, 'AI-Search', 'error');
|
|
102
|
+
}
|
|
103
|
+
return prompt;
|
|
104
|
+
}
|
package/lib/core/ai.d.ts
CHANGED
|
@@ -1,91 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
*/
|
|
5
|
-
export declare class AiSummaryCache {
|
|
6
|
-
private cache;
|
|
7
|
-
private ttl;
|
|
8
|
-
private maxSize;
|
|
9
|
-
private accessOrder;
|
|
10
|
-
constructor(ttl?: number, maxSize?: number);
|
|
11
|
-
/**
|
|
12
|
-
* 触发 LRU 淘汰,移除最久未访问的条目
|
|
13
|
-
*/
|
|
14
|
-
private evictIfNeeded;
|
|
15
|
-
/**
|
|
16
|
-
* 更新访问顺序(LRU)
|
|
17
|
-
*/
|
|
18
|
-
private updateAccessOrder;
|
|
19
|
-
/**
|
|
20
|
-
* 从访问顺序中移除指定键
|
|
21
|
-
*/
|
|
22
|
-
private removeAccessOrder;
|
|
23
|
-
/**
|
|
24
|
-
* 生成缓存键(基于内容的哈希)
|
|
25
|
-
*/
|
|
26
|
-
private generateKey;
|
|
27
|
-
/**
|
|
28
|
-
* 获取缓存
|
|
29
|
-
*/
|
|
30
|
-
get(title: string, content: string): string | null;
|
|
31
|
-
/**
|
|
32
|
-
* 设置缓存
|
|
33
|
-
*/
|
|
34
|
-
set(title: string, content: string, summary: string): void;
|
|
35
|
-
/**
|
|
36
|
-
* 清除过期缓存
|
|
37
|
-
*/
|
|
38
|
-
cleanExpired(): void;
|
|
39
|
-
/**
|
|
40
|
-
* 清空所有缓存
|
|
41
|
-
*/
|
|
42
|
-
clear(): void;
|
|
43
|
-
/**
|
|
44
|
-
* 获取缓存统计
|
|
45
|
-
*/
|
|
46
|
-
getStats(): {
|
|
47
|
-
size: number;
|
|
48
|
-
keys: string[];
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* 初始化 AI 摘要缓存
|
|
53
|
-
*/
|
|
54
|
-
export declare function initAiCache(ttl?: number, maxSize?: number): void;
|
|
55
|
-
/**
|
|
56
|
-
* 生成单条 AI 摘要(带缓存和降级)
|
|
57
|
-
*/
|
|
58
|
-
export declare function getAiSummary(config: Config, title: string, contentHtml: string): Promise<string>;
|
|
59
|
-
/**
|
|
60
|
-
* 批量生成 AI 摘要(多条更新合并为一条)
|
|
61
|
-
*/
|
|
62
|
-
export declare function getBatchAiSummary(config: Config, items: Array<{
|
|
63
|
-
title: string;
|
|
64
|
-
content: string;
|
|
65
|
-
}>): Promise<string>;
|
|
66
|
-
/**
|
|
67
|
-
* 智能摘要:根据内容数量自动选择单条或批量摘要
|
|
68
|
-
*/
|
|
69
|
-
export declare function getSmartAiSummary(config: Config, items: Array<{
|
|
70
|
-
title: string;
|
|
71
|
-
content: string;
|
|
72
|
-
}>): Promise<string>;
|
|
73
|
-
/**
|
|
74
|
-
* 清除过期缓存
|
|
75
|
-
*/
|
|
76
|
-
export declare function cleanExpiredCache(): void;
|
|
77
|
-
/**
|
|
78
|
-
* 清空所有缓存
|
|
79
|
-
*/
|
|
80
|
-
export declare function clearAiCache(): void;
|
|
81
|
-
/**
|
|
82
|
-
* 获取缓存统计信息
|
|
83
|
-
*/
|
|
84
|
-
export declare function getAiCacheStats(): {
|
|
85
|
-
size: number;
|
|
86
|
-
keys: string[];
|
|
87
|
-
} | null;
|
|
88
|
-
/**
|
|
89
|
-
* AI 智能生成 CSS 选择器(保持原有功能)
|
|
90
|
-
*/
|
|
91
|
-
export declare function generateSelectorByAI(config: Config, url: string, instruction: string, html: string): Promise<string>;
|
|
1
|
+
export { AiSummaryCache, cleanExpiredCache, clearAiCache, getAiCacheStats, initAiCache } from './ai-cache';
|
|
2
|
+
export { generateSelectorByAI } from './ai-selector';
|
|
3
|
+
export { getAiSummary, getBatchAiSummary, getSmartAiSummary } from './ai-summary';
|