focus-product-extractor2
Version:
Extract product information from chat/order data
226 lines (211 loc) • 7.62 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.OutputStandard = void 0;
var _messageTypes = require("../constants/messageTypes.js");
/**
* 商品信息标准化输出类
* 负责从不同平台获取商品信息并格式化为统一结构
*/
class OutputStandard {
/**
* 构造函数,初始化平台类型和API端点配置
*/
constructor() {
this.platformTypes = {
taobao: ['tb'],
domestic: ['jd', 'ks', 'dy', 'pdd', 'xhs'],
overseas: ['lazada', 'shopee', 'tiktok'] // 新增海外平台标识
};
// 提取API端点配置
this.apiEndpoints = {
taobao: 'https://gateway.1yangai.com/open/goods-center/gc/v2/goods_info',
domestic: 'https://gateway.xiaoduoai.com/open/goods-center/gc/v2/goods_info',
// 暂无海外平台API端点
overseas: ''
};
}
/**
* 获取商品详细信息
* @param {Object} item - 商品对象
* @param {string} item.goodsId - 商品ID
* @param {string} [item.platform] - 商品平台
* @param {string} [item.shopId] - 店铺ID
* @param {Object} [item.metadata] - 元数据
* @param {Object} authConfig - 认证配置
* @param {string} authConfig.taobaoAuth - 淘宝认证token
* @param {string} authConfig.domesticAuth - 国内非淘平台认证token
* @returns {Promise<Object|null>} 商品信息或错误对象
*/
async _fetchGoodsInfo(item, authConfig) {
var _item$metadata, _item$metadata2;
if (!item.goodsId || isNaN(item.goodsId)) {
return this._createErrorResponse('Invalid goods ID');
}
const platform = item.platform || ((_item$metadata = item.metadata) === null || _item$metadata === void 0 ? void 0 : _item$metadata.platform);
const shopId = item.shopId || ((_item$metadata2 = item.metadata) === null || _item$metadata2 === void 0 ? void 0 : _item$metadata2.shopId);
try {
const {
endpoint,
auth
} = this._getApiConfig(platform, authConfig);
if (!endpoint) {
return this._createErrorResponse('Unsupported platform');
}
const response = await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': auth
},
body: JSON.stringify({
plat_goods_id: item.goodsId,
platform,
shop_id: shopId
})
});
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
return this._createErrorResponse(`API request failed with status ${response.status}`, errorData);
}
return await response.json();
} catch (error) {
console.error('Fetch goods info error:', error);
return this._createErrorResponse(error.message, {
stack: error.stack
});
}
}
/**
* 获取API配置
* @private
* @param {string} platform - 平台标识
* @param {Object} authConfig - 认证配置
* @returns {Object} 包含endpoint和auth的对象
*/
_getApiConfig(platform, authConfig) {
if (this.platformTypes.taobao.includes(platform)) {
return {
endpoint: this.apiEndpoints.taobao,
auth: authConfig.taobaoAuth
};
}
if (this.platformTypes.domestic.includes(platform)) {
return {
endpoint: this.apiEndpoints.domestic,
auth: authConfig.domesticAuth
};
}
if (this.platformTypes.overseas.includes(platform)) {
return {
endpoint: this.apiEndpoints.overseas,
// TODO 需要先定义海外平台API端点
auth: authConfig.overseasAuth
};
}
return {};
}
/**
* 创建统一格式的错误响应
* @private
* @param {string} message - 错误消息
* @param {Object} [details={}] - 错误详情
* @returns {Object} 错误响应对象
*/
_createErrorResponse(message, details = {}) {
return {
error: message,
...details
};
}
_calcOrder(item) {
if (item.metadata.messageSubType === _messageTypes.MESSAGE_SUB_TYPES.BUYER_ENTER) return 100;
if (item.metadata.sender === _messageTypes.SENDER_TYPES.BUYER) return 90;
if (item.metadata.sender === _messageTypes.SENDER_TYPES.SERVICE) return 80;
if (item.metadata.sender === _messageTypes.SENDER_TYPES.SYSTEM) return 70;
return item.confidence || 0;
}
/**
* 格式化商品信息列表
* @param {Array} items - 商品信息数组
* @param {Object} authConfig - 认证配置
* @returns {Promise<Object>} 标准化后的商品信息
* @property {Array} items - 商品列表
* @property {number} timestamp - 时间戳
*/
async format(items = [], authConfig = {}) {
if (!Array.isArray(items)) {
return {
items: []
};
}
// 去重
let sortedItems = items.filter((item, index, self) => index === self.findIndex(t => t.goodsId === item.goodsId));
// 按type分组:order类型和其他类型
const orderItems = sortedItems.filter(item => item.type === 'order');
const otherItems = sortedItems.filter(item => item.type !== 'order');
// 分别对order类型和其他类型进行优先级排序
const sortedOrderItems = orderItems.sort((a, b) => {
const a_score = this._calcOrder(a);
const b_score = this._calcOrder(b);
if (a_score === b_score) {
return b.metadata.timestamp - a.metadata.timestamp;
}
return b_score - a_score;
});
const sortedOtherItems = otherItems.sort((a, b) => {
const a_score = this._calcOrder(a);
const b_score = this._calcOrder(b);
if (a_score === b_score) {
return b.metadata.timestamp - a.metadata.timestamp;
}
return b_score - a_score;
});
// console.log(sortedOrderItems, sortedOtherItems);
// 取两者优先级最高的商品组成列表
sortedItems = [];
if (sortedOrderItems.length > 0) {
sortedItems.push(sortedOrderItems[0]);
}
if (sortedOtherItems.length > 0) {
sortedItems.push(sortedOtherItems[0]);
}
// 如果设置了自定义规则,则获取全部商品信息,否则只获取前2个商品信息
// console.log(authConfig);
if (!authConfig.customRules || authConfig.customRules.length <= 0) {
sortedItems = sortedItems.slice(0, 2);
}
// TODO 按置信度降序排序
// const sortedItems = orderedItems.sort((a, b) => (b.confidence || 0) - (a.confidence || 0));
// 为每个商品获取详细信息
const enrichedItems = await Promise.all(sortedItems.map(async item => {
// 构建返回对象
const result = {
...item
};
// 只对类型为 sku 或 spu 且有 goodsId 的项目进行商品信息填充
if (item.goodsId && (item.type === 'sku' || item.type === 'spu')) {
const goodsInfo = await this._fetchGoodsInfo(item, authConfig);
if (goodsInfo && !goodsInfo.error) {
result.goodsInfo = goodsInfo.data;
} else {
result.goodsInfoError = goodsInfo !== null && goodsInfo !== void 0 && goodsInfo.error ? {
message: `Failed to fetch goods info for ID: ${item.goodsId}`,
details: goodsInfo
} : {
message: `Unknown error occurred for ID: ${item.goodsId}`
};
}
}
// 其他类型(order)或没有 goodsId 的项目不进行商品信息填充,直接返回
return result;
}));
return {
items: enrichedItems,
timestamp: Date.now()
};
}
}
exports.OutputStandard = OutputStandard;
var _default = exports.default = new OutputStandard();