feat: update xianyu web login and Hermes optimizer
This commit is contained in:
@@ -5,7 +5,8 @@ import { genId, timestamp } from './utils.mjs';
|
||||
import { checkLogin } from './login.mjs';
|
||||
import { searchProducts } from './search.mjs';
|
||||
import { coarseFilter, fineFilter } from './filter.mjs';
|
||||
import { buildAnalysis } from './analyzer.mjs';
|
||||
import { buildAnalysis, renderAnalysisMarkdown } from './analyzer.mjs';
|
||||
import { sendNotifications } from './notifier.mjs';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const DATA_DIR = path.join(__dirname, '..', 'data');
|
||||
@@ -36,6 +37,8 @@ export class TaskManager {
|
||||
finePrompt: config.finePrompt || '',
|
||||
maxPages: Math.max(1, Math.min(20, Number(config.maxPages || 3))),
|
||||
maxItems: Math.max(1, Math.min(500, Number(config.maxItems || 60))),
|
||||
autoAnalyze: config.autoAnalyze !== false,
|
||||
autoNotify: config.autoNotify !== false,
|
||||
schedule: {
|
||||
enabled: !!scheduleEnabled,
|
||||
intervalMinutes: Math.max(0, Number(scheduleIntervalMinutes || 0) || 0),
|
||||
@@ -123,7 +126,7 @@ export class TaskManager {
|
||||
|
||||
async startTask(id, configUpdates = {}) {
|
||||
const task = this.tasks.get(id);
|
||||
if (!task || task.running) return;
|
||||
if (!task || task.running) return null;
|
||||
|
||||
if (Object.keys(configUpdates || {}).length) {
|
||||
const { reset, scheduled, ...patch } = configUpdates;
|
||||
@@ -151,6 +154,7 @@ export class TaskManager {
|
||||
try {
|
||||
await this._runPipeline(task, emitLog, shouldStop);
|
||||
if (!task.stopped) {
|
||||
await this._runAutoAnalysis(task, emitLog);
|
||||
task.stage = 'completed';
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -268,6 +272,52 @@ export class TaskManager {
|
||||
return task;
|
||||
}
|
||||
|
||||
async _runAutoAnalysis(task, emitLog) {
|
||||
if (task.config?.autoAnalyze === false) {
|
||||
emitLog('🦐 已关闭自动 Hermes 分析:可在详情页手动执行分析');
|
||||
return null;
|
||||
}
|
||||
if (!task.products?.fineFiltered?.length) {
|
||||
emitLog('🦐 没有细筛候选,跳过自动 Hermes 分析');
|
||||
return null;
|
||||
}
|
||||
|
||||
emitLog(`🦐 自动执行 Hermes 分析:${task.products.fineFiltered.length} 个候选`);
|
||||
const analysis = this.analyzeTask(task.id, { limit: Number(task.config.maxItems || 50) });
|
||||
if (!analysis?.summary) {
|
||||
emitLog('⚠️ Hermes 分析未生成结果');
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const report = renderAnalysisMarkdown(this.getTaskFull(task.id), analysis.summary);
|
||||
analysis.summary.reportPath = report.path;
|
||||
this.setTaskAnalysis(task.id, analysis);
|
||||
emitLog(`📝 Hermes 分析报告已生成:${report.path}`);
|
||||
} catch (err) {
|
||||
emitLog(`⚠️ Hermes 报告生成失败:${err.message}`);
|
||||
}
|
||||
|
||||
if (task.config?.autoNotify !== false) {
|
||||
try {
|
||||
const notification = await sendNotifications(this.getTaskFull(task.id), analysis.summary);
|
||||
if (notification?.skipped) {
|
||||
emitLog(`🔕 自动通知跳过:${notification.reason || '未达到通知条件'}`);
|
||||
} else if (notification?.ok) {
|
||||
emitLog('📣 自动通知已发送');
|
||||
} else {
|
||||
const errors = (notification?.results || []).filter(r => !r.ok).map(r => `${r.name || r.id}: ${r.error}`).join(';');
|
||||
emitLog(`⚠️ 自动通知部分失败:${errors || '未知错误'}`);
|
||||
}
|
||||
} catch (err) {
|
||||
emitLog(`⚠️ 自动通知失败:${err.message}`);
|
||||
}
|
||||
} else {
|
||||
emitLog('🔕 已关闭自动通知');
|
||||
}
|
||||
return analysis;
|
||||
}
|
||||
|
||||
getAllTasks() {
|
||||
return [...this.tasks.values()].map(t => this._serialize(t));
|
||||
}
|
||||
@@ -370,7 +420,7 @@ export class TaskManager {
|
||||
task.chatSessionsFull = [];
|
||||
this._emit(task.id, 'task:chats', task.chatSessions);
|
||||
this._persistToDisk();
|
||||
emitLog(`🦐 已关闭联系卖家功能:保留 ${task.products.fineFiltered.length} 个候选商品,后续由 Hermes 读取 data/tasks.json 做深度分析报告`);
|
||||
emitLog(`🦐 采集和本地预筛完成:保留 ${task.products.fineFiltered.length} 个候选,准备自动执行 Hermes 分析`);
|
||||
emitLog('========== 采集流程结束 ==========');
|
||||
}
|
||||
|
||||
@@ -547,6 +597,7 @@ export class TaskManager {
|
||||
}
|
||||
|
||||
_startScheduler() {
|
||||
if (process.env.XIANHU_DISABLE_SCHEDULER === '1') return;
|
||||
this.schedulerTimer = setInterval(() => this._tickSchedules(), 30000);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user