125 lines
4.4 KiB
TypeScript
125 lines
4.4 KiB
TypeScript
|
|
import { logger } from '../utils/logger';
|
|||
|
|
import db from '../config/database';
|
|||
|
|
import { AdviceService } from '../domains/Strategy/AdviceService';
|
|||
|
|
|
|||
|
|
export interface PixelEvent {
|
|||
|
|
tenantId: string;
|
|||
|
|
shopId: string;
|
|||
|
|
externalProductId: string;
|
|||
|
|
eventType: 'VIEW' | 'ADD_TO_CART' | 'PURCHASE';
|
|||
|
|
revenue?: number;
|
|||
|
|
currency?: string;
|
|||
|
|
timestamp: Date;
|
|||
|
|
traceId?: string; // 增加 traceId 支持
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* [BIZ_AIS_01] 流量与转化套利回流 (Pixel Feedback Loop)
|
|||
|
|
* @description 监听独立站转化事件,并反哺套利策略模型
|
|||
|
|
*/
|
|||
|
|
export class PixelFeedbackService {
|
|||
|
|
private static readonly PIXEL_LOGS_TABLE = 'cf_pixel_logs';
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 记录转化事件 (BIZ_AIS_01)
|
|||
|
|
*/
|
|||
|
|
static async recordEvent(event: PixelEvent): Promise<void> {
|
|||
|
|
const traceId = event.traceId || `PIXEL-${Date.now()}`;
|
|||
|
|
logger.info(`[Pixel] Recording ${event.eventType} for Product: ${event.externalProductId}, Tenant: ${event.tenantId}`);
|
|||
|
|
|
|||
|
|
// 1. 持久化事件日志
|
|||
|
|
await db(this.PIXEL_LOGS_TABLE).insert({
|
|||
|
|
tenant_id: event.tenantId,
|
|||
|
|
shop_id: event.shopId,
|
|||
|
|
external_product_id: event.externalProductId,
|
|||
|
|
event_type: event.eventType,
|
|||
|
|
revenue: event.revenue || 0,
|
|||
|
|
currency: event.currency || 'USD',
|
|||
|
|
created_at: event.timestamp
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 2. 如果是购买事件,触发套利策略回流 (BIZ_AIS_01)
|
|||
|
|
if (event.eventType === 'PURCHASE') {
|
|||
|
|
await this.processPurchaseFeedback(event, traceId);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 处理购买反馈:更新套利记录的转化率与销量 (BIZ_AIS_01)
|
|||
|
|
*/
|
|||
|
|
private static async processPurchaseFeedback(event: PixelEvent, traceId: string): Promise<void> {
|
|||
|
|
// 查找关联的套利记录
|
|||
|
|
const arbitrageRecord = await db('cf_arbitrage_records')
|
|||
|
|
.where({ tenant_id: event.tenantId, external_product_id: event.externalProductId })
|
|||
|
|
.first();
|
|||
|
|
|
|||
|
|
if (!arbitrageRecord) {
|
|||
|
|
logger.info(`[Pixel] No matching arbitrage record for Product: ${event.externalProductId}`);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 更新销量与转化率
|
|||
|
|
const newSalesCount = (arbitrageRecord.sales_count || 0) + 1;
|
|||
|
|
const totalViews = await db(this.PIXEL_LOGS_TABLE)
|
|||
|
|
.where({ external_product_id: event.externalProductId, event_type: 'VIEW' })
|
|||
|
|
.count('id as count')
|
|||
|
|
.first();
|
|||
|
|
|
|||
|
|
const viewCount = totalViews ? Number(totalViews.count) : 1;
|
|||
|
|
const newConversionRate = newSalesCount / Math.max(viewCount, 1);
|
|||
|
|
|
|||
|
|
await db('cf_arbitrage_records')
|
|||
|
|
.where({ id: arbitrageRecord.id })
|
|||
|
|
.update({
|
|||
|
|
sales_count: newSalesCount,
|
|||
|
|
conversion_rate: newConversionRate,
|
|||
|
|
updated_at: new Date()
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 3. 识别失衡场景并生成策略建议 (BIZ_AIS_01-EXT)
|
|||
|
|
await this.analyzeAndTriggerAdvice(arbitrageRecord, newConversionRate, traceId);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 性能异常识别与 Advice 生成 (BIZ_AIS_01-EXT)
|
|||
|
|
*/
|
|||
|
|
private static async analyzeAndTriggerAdvice(record: any, conversionRate: number, traceId: string): Promise<void> {
|
|||
|
|
const profitRate = record.initial_profit_rate;
|
|||
|
|
|
|||
|
|
// 场景 1: 高毛利低转化 (建议降价)
|
|||
|
|
if (profitRate > 0.4 && conversionRate < 0.01) {
|
|||
|
|
await AdviceService.recordAdvice({
|
|||
|
|
tenantId: record.tenant_id,
|
|||
|
|
shopId: record.shop_id || 'DEFAULT',
|
|||
|
|
traceId,
|
|||
|
|
insight: {
|
|||
|
|
type: 'PRICING',
|
|||
|
|
title: 'High Profit / Low Conversion Anomaly',
|
|||
|
|
description: `Product has ${ (profitRate * 100).toFixed(0) }% margin but <1% conversion. Suggest lowering price to stimulate sales.`,
|
|||
|
|
impact: 'high',
|
|||
|
|
confidence: 0.85,
|
|||
|
|
suggestedAction: 'Lower price by 10% to test conversion lift.',
|
|||
|
|
metadata: { productId: record.product_id, currentMargin: profitRate, conversionRate }
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
// 场景 2: 高转化低毛利 (建议提价)
|
|||
|
|
else if (profitRate < 0.15 && conversionRate > 0.05) {
|
|||
|
|
await AdviceService.recordAdvice({
|
|||
|
|
tenantId: record.tenant_id,
|
|||
|
|
shopId: record.shop_id || 'DEFAULT',
|
|||
|
|
traceId,
|
|||
|
|
insight: {
|
|||
|
|
type: 'PRICING',
|
|||
|
|
title: 'Low Profit / High Conversion Opportunity',
|
|||
|
|
description: `Product has high conversion (>5%) but thin margin (<15%). Suggest increasing price to capture more net profit.`,
|
|||
|
|
impact: 'medium',
|
|||
|
|
confidence: 0.80,
|
|||
|
|
suggestedAction: 'Increase price by 5% to optimize ROI.',
|
|||
|
|
metadata: { productId: record.product_id, currentMargin: profitRate, conversionRate }
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|