myavana-bot-test-core 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
File without changes
package/package.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "myavana-bot-test-core",
3
+ "version": "1.0.0",
4
+ "description": "Shared bot functionality",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "dependencies": {
10
+ "@genkit-ai/googleai": "^0.9.12",
11
+ "dotenv": "^16.4.7",
12
+ "genkit": "^0.9.12",
13
+ "pg": "^8.13.1",
14
+ "redis": "^4.7.0"
15
+ }
16
+ }
package/src/ai.js ADDED
@@ -0,0 +1,13 @@
1
+ // ai.js
2
+ const { genkit } = require('genkit');
3
+ const { googleAI, gemini15Flash, gemini20FlashExp } = require('@genkit-ai/googleai');
4
+ const config = require('./config');
5
+
6
+ const ai = genkit({
7
+ plugins: [googleAI({
8
+ apiKey: config.genkitApiKey,
9
+ })],
10
+ model: gemini20FlashExp,
11
+ });
12
+
13
+ module.exports = ai;
package/src/config.js ADDED
@@ -0,0 +1,26 @@
1
+ // config.js
2
+ require('dotenv').config();
3
+
4
+ module.exports = {
5
+ dbConfig: {
6
+ host: process.env.DB_HOST,
7
+ user: process.env.DB_USER,
8
+ password: process.env.DB_PASSWORD,
9
+ database: process.env.DB_NAME,
10
+ port: parseInt(process.env.DB_PORT, 10) || 5432, // Default PostgreSQL port
11
+ },
12
+ redisConfig: {
13
+ username: process.env.REDIS_USERNAME,
14
+ password: process.env.REDIS_PASSWORD,
15
+ socket: {
16
+ host: process.env.REDIS_HOST,
17
+ port: parseInt(process.env.REDIS_PORT, 10) || 6379, // Default Redis port
18
+ }
19
+
20
+ },
21
+ genkitApiKey: process.env.GENKIT_API_KEY,
22
+ openaiApiKey: process.env.OPENAI_API_KEY,
23
+ defaultModel: 'gemini15Flash',
24
+ experimentalModel: 'gemini20FlashExp',
25
+ temperature: 1.1,
26
+ };
@@ -0,0 +1,156 @@
1
+ // conversation.js
2
+ const { pgClient, redisClient } = require('./database');
3
+ const ai = require('./ai');
4
+ const {gemini15Flash} = require("@genkit-ai/googleai");
5
+
6
+ const saveConversationSummary = async (conversationId, userId, summary) => {
7
+ const query = `
8
+ INSERT INTO conversations (conversation_id, user_id, summary)
9
+ VALUES ($1, $2, $3)
10
+ ON CONFLICT (conversation_id)
11
+ DO UPDATE SET summary = EXCLUDED.summary
12
+ RETURNING *;
13
+ `;
14
+ const values = [conversationId, userId, summary];
15
+ try {
16
+ const res = await pgClient.query(query, values);
17
+ await redisClient.set(`summary:${userId}`, summary, { EX: 3600 });
18
+ return res.rows[0];
19
+ } catch (err) {
20
+ console.error('Error saving conversation summary:', err);
21
+ throw err;
22
+ }
23
+ };
24
+
25
+ const generateConversationSummary = async (chatHistory) => {
26
+ if (!chatHistory || chatHistory.length === 0) {
27
+ return "No conversation history available.";
28
+ }
29
+ const summaryPrompt = `Summarize the following conversation, getting all important information, especially the user's hair details, name, and location: ${JSON.stringify(chatHistory)}`;
30
+ const { text } = await ai.chat({
31
+ model: gemini15Flash,
32
+ system: summaryPrompt,
33
+ });
34
+ return text;
35
+ };
36
+
37
+ const getAllConversationsSummary = async (userId) => {
38
+ try {
39
+ // Check Redis cache first
40
+ const cachedSummary = await redisClient.get(`summary:${userId}`);
41
+ if (cachedSummary) return cachedSummary;
42
+
43
+ // If not in Redis, query PostgreSQL
44
+ const query = `SELECT summary FROM conversations WHERE user_id = $1 ORDER BY created_at DESC LIMIT 1;`;
45
+ const values = [userId];
46
+ const res = await pgClient.query(query, values);
47
+
48
+ if (Array.isArray(res.rows) && res.rows.length > 0 && res.rows[0]?.summary) {
49
+ // Cache the summary in Redis
50
+ await redisClient.set(`summary:${userId}`, res.rows[0].summary, { EX: 3600 }); // Cache for 1 hour
51
+ return res.rows[0].summary;
52
+ }
53
+
54
+ return 'conversation summary not available.'; // No summary available
55
+ } catch (err) {
56
+ console.error('Error retrieving all conversations summary:', err);
57
+ return 'conversation summary not available.';
58
+ }
59
+ };
60
+
61
+ const getConversationHistory = async (conversationId, userId) => {
62
+ try {
63
+ // Check Redis cache first
64
+ const cachedConversation = await redisClient.get(`conversation:${conversationId}`);
65
+ if (cachedConversation) return JSON.parse(cachedConversation).chatHistory;
66
+
67
+ // If not in Redis, query PostgreSQL
68
+ const query = `SELECT chat_history FROM conversations WHERE conversation_id = $1 AND user_id = $2;`;
69
+ const values = [conversationId, userId];
70
+ const res = await pgClient.query(query, values);
71
+
72
+ if (res.rows[0]) {
73
+ // Cache the conversation history in Redis
74
+ await redisClient.set(`conversation:${conversationId}`, JSON.stringify({ chatHistory: res.rows[0].chat_history }));
75
+ return res.rows[0].chat_history;
76
+ }
77
+
78
+ return []; // New conversation
79
+ } catch (err) {
80
+ console.error('Error retrieving conversation history:', err);
81
+ return []; // New conversation
82
+ }
83
+ };
84
+
85
+ const saveConversation = async (conversationId, userId, chatHistory, summary) => {
86
+ const query = `
87
+ INSERT INTO conversations (conversation_id, user_id, chat_history, summary)
88
+ VALUES ($1, $2, $3, $4)
89
+ ON CONFLICT (conversation_id)
90
+ DO UPDATE SET chat_history = EXCLUDED.chat_history, summary = EXCLUDED.summary
91
+ RETURNING *;
92
+ `;
93
+ const res = await pgClient.query(query, [conversationId, userId, JSON.stringify(chatHistory), summary]);
94
+ await redisClient.set(`conversation:${conversationId}`, JSON.stringify({ chatHistory: chatHistory }));
95
+ return res.rows[0];
96
+ };
97
+
98
+ const getAllChatsAsSingleArray = async (userId) => {
99
+ try {
100
+ const query = `
101
+ SELECT chat_history
102
+ FROM conversations
103
+ WHERE user_id = $1
104
+ ORDER BY created_at ASC;
105
+ `;
106
+ const values = [userId];
107
+
108
+ const res = await pgClient.query(query, values);
109
+
110
+ if (!res.rows || res.rows.length === 0) {
111
+ return [];
112
+ }
113
+
114
+ let allChats = [];
115
+
116
+ for (const row of res.rows) {
117
+ if (row.chat_history && Array.isArray(row.chat_history)) {
118
+ allChats = allChats.concat(row.chat_history);
119
+ } else if (row.chat_history) {
120
+ try {
121
+ const parsedHistory = JSON.parse(row.chat_history);
122
+ if (Array.isArray(parsedHistory)) {
123
+ allChats = allChats.concat(parsedHistory);
124
+ } else {
125
+ console.warn(`Unexpected chat_history format for user ${userId}:`, row.chat_history);
126
+ }
127
+ } catch (parseError) {
128
+ console.error(`Error parsing chat_history for user ${userId}:`, parseError, row.chat_history);
129
+ }
130
+ }
131
+ }
132
+
133
+ return allChats;
134
+
135
+ } catch (err) {
136
+ console.error('Error retrieving all chats:', err);
137
+ return [];
138
+ }
139
+ };
140
+
141
+ const generateAndSaveSummary = async (userId, conversationId, chatHistory) => {
142
+ const allChatz = await getAllChatsAsSingleArray(userId);
143
+ const newSummary = await generateConversationSummary(allChatz.length ? allChatz : chatHistory);
144
+ await saveConversationSummary(conversationId, userId, newSummary);
145
+ return newSummary;
146
+ };
147
+
148
+ module.exports = {
149
+ saveConversationSummary,
150
+ generateConversationSummary,
151
+ getAllConversationsSummary,
152
+ getConversationHistory,
153
+ saveConversation,
154
+ getAllChatsAsSingleArray,
155
+ generateAndSaveSummary
156
+ };
@@ -0,0 +1,26 @@
1
+ // database.js
2
+ const { Client } = require('pg');
3
+ const { createClient } = require('redis');
4
+ const config = require('./config');
5
+ require('dotenv').config();
6
+
7
+ const pgClient = new Client(config.dbConfig);
8
+ const redisClient = createClient(config.redisConfig);
9
+ redisClient.on('error', (err) => console.error('Redis error:', err));
10
+
11
+ const connectDatabases = async () => {
12
+ try {
13
+ await pgClient.connect();
14
+ await redisClient.connect();
15
+ console.log('Connected to PostgreSQL and Redis');
16
+ } catch (err) {
17
+ console.error('Database connection error:', err);
18
+ process.exit(1);
19
+ }
20
+ };
21
+
22
+ module.exports = {
23
+ pgClient,
24
+ redisClient,
25
+ connectDatabases,
26
+ };
@@ -0,0 +1,40 @@
1
+ // hairIssues.js
2
+ const { pgClient } = require('./database');
3
+
4
+ const saveHairIssue = async (userId, issueDescription, botAdvice) => {
5
+ const query = `
6
+ INSERT INTO hair_issues (user_id, issue_description, bot_advice, advice_given_at)
7
+ VALUES ($1, $2, $3, NOW())
8
+ RETURNING *;
9
+ `;
10
+ const values = [userId, issueDescription, botAdvice];
11
+ try {
12
+ const res = await pgClient.query(query, values);
13
+ return res.rows[0];
14
+ } catch (err) {
15
+ console.error('Error saving hair issue:', err);
16
+ return [];
17
+ }
18
+ };
19
+
20
+ const getHairIssuesForUser = async (userId) => {
21
+ const query = `
22
+ SELECT *
23
+ FROM hair_issues
24
+ WHERE user_id = $1
25
+ ORDER BY reported_at DESC;
26
+ `;
27
+ const values = [userId];
28
+ try {
29
+ const res = await pgClient.query(query, values);
30
+ return res.rows; // Returns an array of hair issue objects
31
+ } catch (err) {
32
+ console.error('Error retrieving hair issues for user:', err);
33
+ return []
34
+ }
35
+ };
36
+
37
+ module.exports = {
38
+ saveHairIssue,
39
+ getHairIssuesForUser
40
+ }
package/src/index.js ADDED
@@ -0,0 +1,28 @@
1
+ // Re-export all shared modules
2
+ module.exports = {
3
+ // Database and utilities
4
+ connectDatabases: require('./src/database').connectDatabases,
5
+ pgClient: require('./src/database').pgClient,
6
+ redisClient: require('./src/database').redisClient,
7
+
8
+ // AI and session management
9
+ ai: require('./src/ai'),
10
+ DatabaseSessionStore: require('./src/session'),
11
+
12
+ // User and conversation management
13
+ getUserDetails: require('./src/user').getUserDetails,
14
+ getAllConversationsSummary: require('./src/conversation').getAllConversationsSummary,
15
+ getConversationHistory: require('./src/conversation').getConversationHistory,
16
+ saveConversation: require('./src/conversation').saveConversation,
17
+ generateConversationSummary: require('./src/conversation').generateConversationSummary,
18
+
19
+ // Post-processing and hair issues
20
+ postProcessConversation: require('./src/postResponseProcessing').postProcessConversation,
21
+ postResponseProcessing: require('./src/postResponseProcessing').postResponseProcessing,
22
+ saveHairIssue: require('./src/hairIssues').saveHairIssue,
23
+ getHairIssuesForUser: require('./src/hairIssues').getHairIssuesForUser,
24
+
25
+ // Utilities
26
+ getAllProducts: require('./src/utils').getAllProducts,
27
+ getAllFaqs: require('./src/utils').getAllFaqs,
28
+ };
@@ -0,0 +1,205 @@
1
+ // postResponseProcessing.js
2
+ const ai = require("./ai");
3
+ const {gemini15Flash} = require("@genkit-ai/googleai");
4
+ const DatabaseSessionStore = require("./session");
5
+ const { pgClient, redisClient } = require('./database');
6
+ const {generateAndSaveSummary, saveConversationSummary, saveConversation} = require("./conversation");
7
+ const {saveHairIssue} = require("./hairIssues");
8
+ const {postProcessingPrompt} = require("./constructPrompt");
9
+
10
+
11
+ const processBotResponse = (botResponse) => {
12
+ if (!botResponse || !Array.isArray(botResponse) || botResponse.length === 0) {
13
+ return "No bot response received.";
14
+ }
15
+
16
+ let processedResponse = "";
17
+ for (const responseItem of botResponse) {
18
+ const messageType = responseItem.messageType;
19
+ const message = responseItem.message;
20
+ const metadata = responseItem.metadata;
21
+
22
+ if (messageType === 'html') {
23
+ // Extract plain text from HTML message (basic - can be improved for complex HTML)
24
+ const plainText = message ? message.replace(/<[^>]*>?/gm, '').trim() : '';
25
+ processedResponse += `Text Response: ${plainText}\n`;
26
+ } else if (metadata && metadata.templateId) {
27
+ const templateId = metadata.templateId;
28
+ if (templateId === '10') { // card
29
+ const payload = metadata.payload && metadata.payload[0];
30
+ if (payload) {
31
+ processedResponse += `Service Card: ${payload.title || 'No Title'}, ${payload.subtitle || 'No Subtitle'}, URL: ${payload.buttons && payload.buttons[0] && payload.buttons[0].action && payload.buttons[0].action.payload ? payload.buttons[0].action.payload.url : 'No URL'}\n`;
32
+ } else {
33
+ processedResponse += "Service Card: (No details extracted)\n";
34
+ }
35
+ } else if (templateId === '9') { // Image carousel
36
+ const payload = metadata.payload;
37
+ if (payload && Array.isArray(payload)) {
38
+ processedResponse += "Image Carousel: ";
39
+ payload.forEach((image, index) => {
40
+ processedResponse += `Image ${index + 1} - Caption: ${image.caption || 'No Caption'}, URL: ${image.url || 'No URL'}; `;
41
+ });
42
+ processedResponse += "\n";
43
+ } else {
44
+ processedResponse += "Image Carousel: (No images extracted)\n";
45
+ }
46
+ } else if (templateId === '3') { // Button template
47
+ const payload = metadata.payload && metadata.payload[0];
48
+ if (payload) {
49
+ processedResponse += `Button: ${payload.name || 'No Name'}, URL: ${payload.url || 'No URL'}\n`;
50
+ } else {
51
+ processedResponse += "Button: (No button details extracted)\n";
52
+ }
53
+ } else if (templateId === '6') { // Suggested replies
54
+ const payload = metadata.payload;
55
+ if (payload && Array.isArray(payload)) {
56
+ processedResponse += "Suggested Replies: ";
57
+ payload.forEach((reply, index) => {
58
+ processedResponse += `${reply.title || 'Reply ' + (index + 1)}; `;
59
+ });
60
+ processedResponse += "\n";
61
+ } else {
62
+ processedResponse += "Suggested Replies: (No replies extracted)\n";
63
+ }
64
+ } else if (templateId === '7') { // List template (Welcome message)
65
+ processedResponse += "Welcome Message Card (List Template)\n"; // Simplified for brevity
66
+ }
67
+ else {
68
+ processedResponse += `Unknown Card Template (ID: ${templateId}): Message: ${message}\n`;
69
+ }
70
+ }
71
+ else if (message) { // Fallback for any other message type (or just plain text if no html)
72
+ processedResponse += `Raw Message: ${message}\n`;
73
+ }
74
+ else {
75
+ processedResponse += `Unknown Response Type: No message content found.\n`;
76
+ }
77
+ }
78
+
79
+ return processedResponse.trim(); // Remove trailing newline and whitespace
80
+ };
81
+
82
+ const postProcessConversation = async (chatHistory, message) => {
83
+
84
+
85
+ const extractionPrompt = await postProcessingPrompt(chatHistory, message);
86
+ console.log('Extraction prompt: ', extractionPrompt);
87
+ try {
88
+ const chat = ai.chat({
89
+ model: gemini15Flash,
90
+ config: {
91
+ temperature: 1.1,
92
+ },
93
+
94
+ });
95
+ const { output } = await chat.send(extractionPrompt);
96
+ console.log("Raw post-processing output:", JSON.stringify(output));
97
+
98
+ if (!output) {
99
+ console.warn("Post-processing output is empty. Returning default empty JSON.");
100
+ return {}; // Or return a default empty JSON object based on your schema if needed
101
+ }
102
+
103
+ return output;
104
+ } catch (error) {
105
+ console.error("Error in postProcessConversation:", error);
106
+ return {}; // Return empty object in case of error
107
+ }
108
+ };
109
+
110
+ const updateUserProfile = async (userId, updates) => {
111
+ if (!updates || Object.keys(updates).length === 0) {
112
+ console.log("No user profile updates to apply.");
113
+ return null; // No updates to apply
114
+ }
115
+
116
+ // Filter out null or undefined values from updates
117
+ const validUpdates = Object.entries(updates)
118
+ .filter(([key, value]) => value !== null && value !== undefined)
119
+ .reduce((obj, [key, value]) => {
120
+ obj[key] = value;
121
+ return obj;
122
+ }, {});
123
+
124
+ if (Object.keys(validUpdates).length === 0) {
125
+ console.log("No valid user profile updates to apply (all values were null or undefined).");
126
+ return null; // No valid updates to apply
127
+ }
128
+ // Update chat session state here
129
+ try {
130
+ const session = await ai.loadSession(userId, {
131
+ store: new DatabaseSessionStore(),
132
+ });
133
+
134
+ // Update the session state
135
+ await session.updateState({
136
+ userProfile: validUpdates,
137
+ lastInteractionTime: new Date().toISOString(),
138
+ // ... any other state properties you need to update
139
+ });
140
+
141
+ }catch (e){
142
+ console.log(e)
143
+ }
144
+
145
+ const updateKeys = Object.keys(validUpdates);
146
+ const updateValues = updateKeys.map(key => validUpdates[key]);
147
+
148
+ const setClauses = updateKeys.map((key, index) => `${key} = $${index + 2}`).join(', '); // Start parameter index from 2
149
+
150
+ const query = {
151
+ text: `
152
+ UPDATE users
153
+ SET ${setClauses}, updated_at = NOW()
154
+ WHERE user_id = $1
155
+ RETURNING *;
156
+ `,
157
+ values: [userId, ...updateValues], // userId is $1, updates are $2, $3, ...
158
+ };
159
+
160
+ try {
161
+ const res = await pgClient.query(query);
162
+ if (res.rows.length > 0) {
163
+ // Update Redis cache with the updated user profile
164
+ await redisClient.set(`user:${userId}`, JSON.stringify(res.rows[0]));
165
+ console.log(`User profile updated successfully for user ${userId} with fields: ${updateKeys.join(', ')}`);
166
+ return res.rows[0]; // Return the updated user object
167
+ } else {
168
+ console.warn(`User profile update failed for user ${userId}: User not found.`);
169
+ return null; // User not found or update failed
170
+ }
171
+ } catch (err) {
172
+ console.error(`Error updating user profile for user ${userId}:`, err);
173
+ throw err; // Propagate the error
174
+ }
175
+ };
176
+
177
+ const postResponseProcessing = async (postProcessData, userId, output, allchatsSummary, conversationId, chatHistory )=>{
178
+ if (postProcessData.user_profile_updates) {
179
+ // TODO: Update user profile in database based on postProcessData.user_profile_updates
180
+ console.log("User profile updates to be applied:", postProcessData.user_profile_updates);
181
+ await updateUserProfile(userId, postProcessData.user_profile_updates);
182
+ }
183
+
184
+ if (postProcessData.hair_issue_extractions && postProcessData.hair_issue_extractions.hair_issues_reported && postProcessData.hair_issue_extractions.hair_issues_reported.length > 0) {
185
+ for (const issue of postProcessData.hair_issue_extractions.hair_issues_reported) {
186
+ await saveHairIssue(userId, issue, JSON.stringify(output)); // Or refine advice from output
187
+ console.log(`Hair issue reported and saved: ${issue}`);
188
+ }
189
+ }
190
+
191
+
192
+ if (!allchatsSummary) {
193
+ await generateAndSaveSummary(userId, conversationId, chatHistory);
194
+ }
195
+
196
+ await saveConversationSummary(conversationId, userId, allchatsSummary);
197
+ return await saveConversation(conversationId, userId, chatHistory, allchatsSummary);
198
+ };
199
+
200
+ module.exports = {
201
+ postResponseProcessing,
202
+ postProcessConversation,
203
+ processBotResponse,
204
+ updateUserProfile
205
+ }
package/src/session.js ADDED
@@ -0,0 +1,41 @@
1
+ // session.js
2
+ const { pgClient } = require('./database');
3
+
4
+ class DatabaseSessionStore {
5
+ async get(sessionId) {
6
+ const query = `
7
+ SELECT session_data
8
+ FROM sessions
9
+ WHERE session_id = $1;
10
+ `;
11
+ const values = [sessionId];
12
+ try {
13
+ const res = await pgClient.query(query, values);
14
+ if (res.rows.length > 0 && res.rows[0].session_data) {
15
+ return res.rows[0].session_data;
16
+ }
17
+ return undefined; // Session not found or no data
18
+ } catch (err) {
19
+ console.error('Error retrieving session data from database:', err);
20
+ return undefined;
21
+ }
22
+ }
23
+
24
+ async save(sessionId, sessionData) {
25
+ const query = `
26
+ INSERT INTO sessions (session_id, user_id, session_data, last_accessed_at)
27
+ VALUES ($1, $2, $3, NOW())
28
+ ON CONFLICT (session_id)
29
+ DO UPDATE SET session_data = $3, last_accessed_at = NOW();
30
+ `;
31
+ const values = [sessionId, sessionId, sessionData];
32
+ try {
33
+ await pgClient.query(query, values);
34
+ console.log(`Session data saved to database for sessionId: ${sessionId}`);
35
+ } catch (err) {
36
+ console.error('Error saving session data to database:', err);
37
+ }
38
+ }
39
+ }
40
+
41
+ module.exports = DatabaseSessionStore;
package/src/user.js ADDED
@@ -0,0 +1,37 @@
1
+ // user.js
2
+ const { pgClient, redisClient } = require('./database');
3
+
4
+ const getUserDetails = async (userId) => {
5
+ try {
6
+ const cachedUser = await redisClient.get(`user:${userId}`);
7
+ if (cachedUser) return JSON.parse(cachedUser);
8
+
9
+ const query = `SELECT * FROM users WHERE user_id = $1;`;
10
+ const values = [userId];
11
+ const res = await pgClient.query(query, values);
12
+
13
+ if (res.rows[0]) {
14
+ await redisClient.set(`user:${userId}`, JSON.stringify(res.rows[0]));
15
+ return res.rows[0];
16
+ }
17
+
18
+ const createUserQuery = `
19
+ INSERT INTO users (user_id)
20
+ VALUES ($1)
21
+ RETURNING *;
22
+ `;
23
+ const createUserRes = await pgClient.query(createUserQuery, [userId]);
24
+ if (createUserRes.rows[0]) {
25
+ await redisClient.set(`user:${userId}`, JSON.stringify(createUserRes.rows[0]));
26
+ return createUserRes.rows[0];
27
+ }
28
+ return null;
29
+ } catch (err) {
30
+ console.error('Error retrieving user details:', err);
31
+ throw err;
32
+ }
33
+ };
34
+
35
+ module.exports = {
36
+ getUserDetails,
37
+ };
package/src/utils.js ADDED
@@ -0,0 +1,32 @@
1
+ const { pgClient } = require('./database'); // Import pgClient from core's database.js
2
+
3
+ async function getAllProducts() {
4
+ try {
5
+ const result = await pgClient.query('SELECT * FROM products');
6
+ return result.rows;
7
+ } catch (error) {
8
+ console.error("Error fetching all products:", error);
9
+ return [];
10
+ }
11
+ }
12
+
13
+ async function getAllFaqs() {
14
+ try {
15
+ const result = await pgClient.query('SELECT * FROM faqs');
16
+ return result.rows;
17
+ } catch (error) {
18
+ console.error("Error fetching all FAQs:", error);
19
+ return [];
20
+ }
21
+ }
22
+
23
+ async function getHairIssuesForUser(userId) {
24
+ // Return empty for now (or implement logic later)
25
+ return [];
26
+ }
27
+
28
+ module.exports = {
29
+ getAllProducts,
30
+ getAllFaqs,
31
+ getHairIssuesForUser,
32
+ };