Add prompts table and settings page to create/read/update/delete from it, incorporate company specific prompts into ai validation
This commit is contained in:
@@ -289,7 +289,76 @@ async function generateDebugResponse(productsToUse, res) {
|
||||
});
|
||||
|
||||
try {
|
||||
const prompt = await loadPrompt(promptConnection, productsToUse);
|
||||
// Get the local PostgreSQL pool to fetch prompts
|
||||
const pool = res.app.locals.pool;
|
||||
if (!pool) {
|
||||
console.warn("⚠️ Local database pool not available for prompts");
|
||||
throw new Error("Database connection not available");
|
||||
}
|
||||
|
||||
// First, fetch the general prompt
|
||||
const generalPromptResult = await pool.query(`
|
||||
SELECT * FROM ai_prompts
|
||||
WHERE prompt_type = 'general'
|
||||
`);
|
||||
|
||||
if (generalPromptResult.rows.length === 0) {
|
||||
console.warn("⚠️ No general prompt found in database");
|
||||
throw new Error("No general prompt found in database");
|
||||
}
|
||||
|
||||
// Get the general prompt text and info
|
||||
const generalPrompt = generalPromptResult.rows[0];
|
||||
console.log("📝 Loaded general prompt from database, ID:", generalPrompt.id);
|
||||
|
||||
// Fetch company-specific prompts if we have products to validate
|
||||
let companyPrompts = [];
|
||||
if (productsToUse && Array.isArray(productsToUse)) {
|
||||
// Extract unique company IDs from products
|
||||
const companyIds = new Set();
|
||||
productsToUse.forEach(product => {
|
||||
if (product.company) {
|
||||
companyIds.add(String(product.company));
|
||||
}
|
||||
});
|
||||
|
||||
if (companyIds.size > 0) {
|
||||
console.log(`🔍 Found ${companyIds.size} unique companies in products:`, Array.from(companyIds));
|
||||
|
||||
// Fetch company-specific prompts
|
||||
const companyPromptsResult = await pool.query(`
|
||||
SELECT * FROM ai_prompts
|
||||
WHERE prompt_type = 'company_specific'
|
||||
AND company = ANY($1)
|
||||
`, [Array.from(companyIds)]);
|
||||
|
||||
companyPrompts = companyPromptsResult.rows;
|
||||
console.log(`📝 Loaded ${companyPrompts.length} company-specific prompts`);
|
||||
}
|
||||
}
|
||||
|
||||
// Find company names from taxonomy
|
||||
const companyPromptsWithNames = companyPrompts.map(prompt => {
|
||||
let companyName = "Unknown Company";
|
||||
if (taxonomy.companies && Array.isArray(taxonomy.companies)) {
|
||||
const companyData = taxonomy.companies.find(company =>
|
||||
String(company[0]) === String(prompt.company)
|
||||
);
|
||||
if (companyData && companyData[1]) {
|
||||
companyName = companyData[1];
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
id: prompt.id,
|
||||
company: prompt.company,
|
||||
companyName: companyName,
|
||||
prompt_text: prompt.prompt_text
|
||||
};
|
||||
});
|
||||
|
||||
// Now use loadPrompt to get the actual combined prompt
|
||||
const prompt = await loadPrompt(promptConnection, productsToUse, res.app.locals.pool);
|
||||
const fullPrompt = prompt + "\n" + JSON.stringify(productsToUse);
|
||||
|
||||
// Create the response with taxonomy stats
|
||||
@@ -330,9 +399,16 @@ async function generateDebugResponse(productsToUse, res) {
|
||||
: null,
|
||||
}
|
||||
: null,
|
||||
basePrompt: prompt,
|
||||
basePrompt: generalPrompt.prompt_text,
|
||||
sampleFullPrompt: fullPrompt,
|
||||
promptLength: fullPrompt.length,
|
||||
promptSources: {
|
||||
generalPrompt: {
|
||||
id: generalPrompt.id,
|
||||
prompt_text: generalPrompt.prompt_text
|
||||
},
|
||||
companyPrompts: companyPromptsWithNames
|
||||
}
|
||||
};
|
||||
|
||||
console.log("Sending response with taxonomy stats:", response.taxonomyStats);
|
||||
@@ -513,22 +589,107 @@ SELECT t.cat_id,t.name,null as master_cat_id,1 AS level_order FROM product_categ
|
||||
}
|
||||
}
|
||||
|
||||
// Load the prompt from file and inject taxonomy data
|
||||
async function loadPrompt(connection, productsToValidate = null) {
|
||||
// Load prompts from database and inject taxonomy data
|
||||
async function loadPrompt(connection, productsToValidate = null, appPool = null) {
|
||||
try {
|
||||
const promptPath = path.join(
|
||||
__dirname,
|
||||
"..",
|
||||
"prompts",
|
||||
"product-validation.txt"
|
||||
);
|
||||
const basePrompt = await fs.readFile(promptPath, "utf8");
|
||||
|
||||
// Get taxonomy data using the provided MySQL connection
|
||||
const taxonomy = await getTaxonomyData(connection);
|
||||
|
||||
// Add system instructions to the prompt
|
||||
// Initialize default system instructions
|
||||
const systemInstructions = `You are a specialized e-commerce product data processor for a crafting supplies website tasked with providing complete, correct, appealing, and SEO-friendly product listings. You should write professionally, but in a friendly and engaging tone. You have meticulous attention to detail and are a master at your craft.`;
|
||||
|
||||
// Use the provided pool parameter instead of global.app
|
||||
const pool = appPool;
|
||||
if (!pool) {
|
||||
console.warn("⚠️ Local database pool not available for prompts");
|
||||
throw new Error("Database connection not available");
|
||||
}
|
||||
|
||||
// Fetch the general prompt
|
||||
const generalPromptResult = await pool.query(`
|
||||
SELECT * FROM ai_prompts
|
||||
WHERE prompt_type = 'general'
|
||||
`);
|
||||
|
||||
if (generalPromptResult.rows.length === 0) {
|
||||
console.warn("⚠️ No general prompt found in database");
|
||||
throw new Error("No general prompt found in database");
|
||||
}
|
||||
|
||||
// Get the general prompt text
|
||||
const basePrompt = generalPromptResult.rows[0].prompt_text;
|
||||
console.log("📝 Loaded general prompt from database");
|
||||
|
||||
// Fetch company-specific prompts if we have products to validate
|
||||
let companyPrompts = [];
|
||||
if (productsToValidate && Array.isArray(productsToValidate)) {
|
||||
// Extract unique company IDs from products
|
||||
const companyIds = new Set();
|
||||
productsToValidate.forEach(product => {
|
||||
if (product.company) {
|
||||
companyIds.add(String(product.company));
|
||||
}
|
||||
});
|
||||
|
||||
if (companyIds.size > 0) {
|
||||
console.log(`🔍 Found ${companyIds.size} unique companies in products:`, Array.from(companyIds));
|
||||
|
||||
// Fetch company-specific prompts
|
||||
const companyPromptsResult = await pool.query(`
|
||||
SELECT * FROM ai_prompts
|
||||
WHERE prompt_type = 'company_specific'
|
||||
AND company = ANY($1)
|
||||
`, [Array.from(companyIds)]);
|
||||
|
||||
companyPrompts = companyPromptsResult.rows;
|
||||
console.log(`📝 Loaded ${companyPrompts.length} company-specific prompts`);
|
||||
}
|
||||
}
|
||||
|
||||
// Find company names from taxonomy for the validation endpoint
|
||||
const companyPromptsWithNames = companyPrompts.map(prompt => {
|
||||
let companyName = "Unknown Company";
|
||||
if (taxonomy.companies && Array.isArray(taxonomy.companies)) {
|
||||
const companyData = taxonomy.companies.find(company =>
|
||||
String(company[0]) === String(prompt.company)
|
||||
);
|
||||
if (companyData && companyData[1]) {
|
||||
companyName = companyData[1];
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
id: prompt.id,
|
||||
company: prompt.company,
|
||||
companyName: companyName,
|
||||
prompt_text: prompt.prompt_text
|
||||
};
|
||||
});
|
||||
|
||||
// Combine prompts - start with the general prompt
|
||||
let combinedPrompt = basePrompt;
|
||||
|
||||
// Add any company-specific prompts with annotations
|
||||
if (companyPrompts.length > 0) {
|
||||
combinedPrompt += "\n\n--- COMPANY-SPECIFIC INSTRUCTIONS ---\n";
|
||||
|
||||
for (const prompt of companyPrompts) {
|
||||
// Find company name from taxonomy
|
||||
let companyName = "Unknown Company";
|
||||
if (taxonomy.companies && Array.isArray(taxonomy.companies)) {
|
||||
const companyData = taxonomy.companies.find(company =>
|
||||
String(company[0]) === String(prompt.company)
|
||||
);
|
||||
if (companyData && companyData[1]) {
|
||||
companyName = companyData[1];
|
||||
}
|
||||
}
|
||||
|
||||
combinedPrompt += `\n[SPECIFIC TO COMPANY: ${companyName} (ID: ${prompt.company})]:\n${prompt.prompt_text}\n`;
|
||||
}
|
||||
|
||||
combinedPrompt += "\n--- END COMPANY-SPECIFIC INSTRUCTIONS ---\n";
|
||||
}
|
||||
|
||||
// If we have products to validate, create a filtered prompt
|
||||
if (productsToValidate) {
|
||||
@@ -656,7 +817,7 @@ ${JSON.stringify(mixedTaxonomy.sizeCategories)}${
|
||||
----------Here is the product data to validate----------`;
|
||||
|
||||
// Return the filtered prompt
|
||||
return systemInstructions + basePrompt + "\n" + taxonomySection;
|
||||
return systemInstructions + combinedPrompt + "\n" + taxonomySection;
|
||||
}
|
||||
|
||||
// Generate the full unfiltered prompt
|
||||
@@ -687,7 +848,7 @@ ${JSON.stringify(taxonomy.artists)}
|
||||
|
||||
Here is the product data to validate:`;
|
||||
|
||||
return systemInstructions + basePrompt + "\n" + taxonomySection;
|
||||
return systemInstructions + combinedPrompt + "\n" + taxonomySection;
|
||||
} catch (error) {
|
||||
console.error("Error loading prompt:", error);
|
||||
throw error; // Re-throw to be handled by the calling function
|
||||
@@ -735,7 +896,7 @@ router.post("/validate", async (req, res) => {
|
||||
|
||||
// Load the prompt with the products data to filter taxonomy
|
||||
console.log("🔄 Loading prompt with filtered taxonomy...");
|
||||
const prompt = await loadPrompt(connection, products);
|
||||
const prompt = await loadPrompt(connection, products, req.app.locals.pool);
|
||||
const fullPrompt = prompt + "\n" + JSON.stringify(products);
|
||||
promptLength = fullPrompt.length; // Store prompt length for performance metrics
|
||||
console.log("📝 Generated prompt length:", promptLength);
|
||||
@@ -884,7 +1045,72 @@ router.post("/validate", async (req, res) => {
|
||||
console.error("⚠️ Failed to record performance metrics:", metricError);
|
||||
}
|
||||
|
||||
// Include performance metrics in the response
|
||||
// Get sources of the prompts for tracking
|
||||
let promptSources = null;
|
||||
|
||||
try {
|
||||
// Get general prompt
|
||||
const generalPromptResult = await pool.query(`
|
||||
SELECT * FROM ai_prompts WHERE prompt_type = 'general'
|
||||
`);
|
||||
|
||||
// Extract unique company IDs from products
|
||||
const companyIds = new Set();
|
||||
products.forEach(product => {
|
||||
if (product.company) {
|
||||
companyIds.add(String(product.company));
|
||||
}
|
||||
});
|
||||
|
||||
let companyPrompts = [];
|
||||
if (companyIds.size > 0) {
|
||||
// Fetch company-specific prompts
|
||||
const companyPromptsResult = await pool.query(`
|
||||
SELECT * FROM ai_prompts
|
||||
WHERE prompt_type = 'company_specific'
|
||||
AND company = ANY($1)
|
||||
`, [Array.from(companyIds)]);
|
||||
|
||||
companyPrompts = companyPromptsResult.rows;
|
||||
}
|
||||
|
||||
// Find company names from taxonomy
|
||||
const companyPromptsWithNames = companyPrompts.map(prompt => {
|
||||
let companyName = "Unknown Company";
|
||||
if (taxonomy.companies && Array.isArray(taxonomy.companies)) {
|
||||
const companyData = taxonomy.companies.find(company =>
|
||||
String(company[0]) === String(prompt.company)
|
||||
);
|
||||
if (companyData && companyData[1]) {
|
||||
companyName = companyData[1];
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
id: prompt.id,
|
||||
company: prompt.company,
|
||||
companyName: companyName,
|
||||
prompt_text: prompt.prompt_text
|
||||
};
|
||||
});
|
||||
|
||||
// Set prompt sources
|
||||
if (generalPromptResult.rows.length > 0) {
|
||||
const generalPrompt = generalPromptResult.rows[0];
|
||||
promptSources = {
|
||||
generalPrompt: {
|
||||
id: generalPrompt.id,
|
||||
prompt_text: generalPrompt.prompt_text
|
||||
},
|
||||
companyPrompts: companyPromptsWithNames
|
||||
};
|
||||
}
|
||||
} catch (promptSourceError) {
|
||||
console.error("⚠️ Error getting prompt sources:", promptSourceError);
|
||||
// Don't fail the entire validation if just prompt sources retrieval fails
|
||||
}
|
||||
|
||||
// Include prompt sources in the response
|
||||
res.json({
|
||||
success: true,
|
||||
changeDetails: changeDetails,
|
||||
@@ -895,6 +1121,7 @@ router.post("/validate", async (req, res) => {
|
||||
isEstimate: true,
|
||||
productCount: products.length
|
||||
},
|
||||
promptSources: promptSources,
|
||||
...aiResponse,
|
||||
});
|
||||
} catch (parseError) {
|
||||
|
||||
Reference in New Issue
Block a user