37980-vm/backend/src/services/aiRecommendations.js
2026-01-30 19:04:14 +00:00

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;