82 lines
2.9 KiB
JavaScript
82 lines
2.9 KiB
JavaScript
const { LocalAIApi, decodeJsonFromResponse } = require('../ai/LocalAIApi');
|
|
const db = require('../db/models');
|
|
|
|
class AIRecommendationsService {
|
|
static async getRecommendations(userId, limit = 4) {
|
|
try {
|
|
// 1. Get recent product views
|
|
const recentViews = await db.page_views.findAll({
|
|
where: { userId },
|
|
include: [{ model: db.products, as: 'product' }],
|
|
order: [['createdAt', 'DESC']],
|
|
limit: 10
|
|
});
|
|
|
|
// 2. Get current cart items
|
|
const cart = await db.carts.findOne({
|
|
where: { userId },
|
|
include: [{
|
|
model: db.cart_items,
|
|
as: 'cart_items_cart',
|
|
include: [{ model: db.products, as: 'product' }]
|
|
}]
|
|
});
|
|
|
|
const viewedProducts = [...new Set(recentViews.map(v => v.product?.title).filter(Boolean))];
|
|
const cartProducts = cart?.cart_items_cart?.map(i => i.product?.title).filter(Boolean) || [];
|
|
|
|
if (viewedProducts.length === 0 && cartProducts.length === 0) {
|
|
// Return top products as fallback
|
|
return await db.products.findAll({ limit });
|
|
}
|
|
|
|
// 3. Get all available product titles for catalog
|
|
const allProducts = await db.products.findAll({ attributes: ['id', 'title'], limit: 50 });
|
|
const productListString = allProducts.map(p => p.title).join(', ');
|
|
|
|
const prompt = `
|
|
A user has viewed these products: ${viewedProducts.join(', ')}.
|
|
They have these products in their cart: ${cartProducts.join(', ')}.
|
|
Based on this, recommend up to ${limit} products from the following catalog: ${productListString}.
|
|
Focus on similar categories or complementary items.
|
|
Return ONLY a JSON array of strings containing the recommended product titles exactly as they appear in the catalog.
|
|
`;
|
|
|
|
const aiResponse = await LocalAIApi.createResponse({
|
|
input: [
|
|
{ role: 'system', content: 'You are an e-commerce recommendation engine. Return only JSON array of strings.' },
|
|
{ role: 'user', content: prompt }
|
|
]
|
|
});
|
|
|
|
if (aiResponse.success) {
|
|
try {
|
|
const recommendedTitles = decodeJsonFromResponse(aiResponse);
|
|
if (Array.isArray(recommendedTitles)) {
|
|
const recommendedProducts = await db.products.findAll({
|
|
where: {
|
|
title: { [db.Sequelize.Op.in]: recommendedTitles }
|
|
},
|
|
limit
|
|
});
|
|
if (recommendedProducts.length > 0) return recommendedProducts;
|
|
}
|
|
} catch (e) {
|
|
console.error('AI JSON parse error:', e);
|
|
}
|
|
}
|
|
|
|
// Fallback: Return some products if AI fails or no recommendations
|
|
return await db.products.findAll({
|
|
order: db.sequelize.random(),
|
|
limit
|
|
});
|
|
} catch (error) {
|
|
console.error('Error in AIRecommendationsService:', error);
|
|
return await db.products.findAll({ limit });
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = AIRecommendationsService;
|