-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrecom.js
More file actions
172 lines (147 loc) · 5.62 KB
/
Copy pathrecom.js
File metadata and controls
172 lines (147 loc) · 5.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
const { genAI } = require('./models/ConfigGem.model.js');
const User = require('./models/users.model.js');
const Product = require('./models/product.model.js');
const dotenv = require('dotenv');
dotenv.config();
class RecommendationService {
static async getSafeProducts(userProfile, searchQuery = '', limit = 10) {
try {
// Build MongoDB filter
const filter = { $and: [] };
// budget range
if (userProfile.budgetRange) {
const budgetRanges = {
under_25: { price: { $lt: 25 } },
'25_50': { price: { $gte: 25, $lt: 50 } },
'50_100': { price: { $gte: 50, $lt: 100 } },
'100_200': { price: { $gte: 100, $lt: 200 } },
over_200: { price: { $gte: 200 } },
};
if (budgetRanges[userProfile.budgetRange]) {
filter.$and.push(budgetRanges[userProfile.budgetRange]);
}
}
// allergies filter
if (userProfile.allergies && userProfile.allergies.length > 0) {
filter.$and.push({
activeIngredients: {
$not: {
$elemMatch: {
$in: userProfile.allergies,
},
},
},
});
}
// skin concerns filter
if (userProfile.skinConcerns && userProfile.skinConcerns.length > 0) {
const concernRegex = userProfile.skinConcerns.join('|');
filter.$and.push({
$or: [
{ category: { $regex: concernRegex, $options: 'i' } },
{ subcategory: { $regex: concernRegex, $options: 'i' } },
{ description: { $regex: concernRegex, $options: 'i' } },
...(userProfile.skinConcerns.includes('dark spots')
? [
{
subcategory: {
$regex: 'anti-aging|brightening',
$options: 'i',
},
},
]
: []),
],
});
}
// stock filter
filter.$and.push({ quantity: { $gt: 0 } });
if (filter.$and.length === 0) delete filter.$and;
console.log('MongoDB Filter:', JSON.stringify(filter, null, 2));
const products = await Product.find(filter).limit(limit);
console.log(`Found ${products.length} products matching criteria`);
return Array.isArray(products) ? products : [];
} catch (error) {
console.error('Error getting safe products:', error);
return [];
}
}
static async generateRecommendations(userId, userQuery) {
try {
const user = await User.findById(userId);
if (!user) throw new Error('User not found');
// Extract nested customerProfile fields safely
const userProfile = {
allergies: user.customerProfile?.allergies || [],
skinType: user.customerProfile?.skinType || null,
skinConcerns: user.customerProfile?.skinConcerns || [],
skinGoals: user.customerProfile?.skinGoals || [],
budgetRange: user.customerProfile?.budgetRange || null,
currentMedications: user.customerProfile?.currentMedications || [],
};
console.log('User Profile for filtering:', userProfile);
// products that suit the user
const safeProducts = await this.getSafeProducts(userProfile, userQuery, 10);
if (!Array.isArray(safeProducts) || safeProducts.length === 0) {
return {
message:
"I couldn't find any safe products matching your criteria. Please consult with a pharmacist.",
recommendations: [],
};
}
const prompt = `You are PharmaAI, a pharmacy assistant. Recommend products ONLY from the provided list based on the user's profile and query.
USER PROFILE:
- Allergies: ${userProfile.allergies.join(', ') || 'None specified'}
- Skin Type: ${userProfile.skinType || 'Not specified'}
- Skin Concerns: ${userProfile.skinConcerns.join(', ') || 'None specified'}
- Skin Goals: ${userProfile.skinGoals.join(', ') || 'None specified'}
- Budget: ${userProfile.budgetRange || 'Not specified'}
- Current Medications: ${userProfile.currentMedications.join(', ') || 'None specified'}
SAFETY RULES:
1. NEVER recommend products containing user's allergens
2. Always mention relevant warnings and side effects
3. Only recommend from the provided product list
4. Explain why each product is suitable for the user's specific needs
5. Consider the user's budget constraints
User Query: "${userQuery}"
AVAILABLE PRODUCTS:
${safeProducts
.map(
(product, idx) => `
${idx + 1}. ${product.name}
Brand: ${product.brandName || 'N/A'}
Category: ${product.category}
Price: $${product.price}
Description: ${product.description}
Active Ingredients: ${product.activeIngredients?.join(', ') || 'N/A'}
Side Effects: ${product.sideEffects?.join(', ') || 'None listed'}
Stock: ${product.quantity > 0 ? 'In Stock' : 'Out of Stock'}`
)
.join('\n')}
Based on the user's profile and query, recommend 2-3 most suitable products with detailed explanations for each choice.`;
console.log(
'Loaded key (first 10 chars):',
process.env.GEMINI_API_KEY?.slice(0, 10)
);
// GEMINI API CALL
const model = genAI.getGenerativeModel({
model: 'gemini-1.5-flash',
generationConfig: {
temperature: 0.1,
topP: 0.8,
topK: 40,
},
});
const result = await model.generateContent(prompt);
const aiMessage = result.response.text();
return {
message: aiMessage,
recommendations: safeProducts.slice(0, 3),
};
} catch (error) {
console.error('Error generating recommendations:', error);
throw error;
}
}
}
module.exports = RecommendationService;