// api/find-brand-assets.js - Phase 2: Enhanced with OpenAI Intelligence
import {
BREVILLE_PRODUCTS,
ASSET_SECTIONS,
REGIONAL_MAPPING,
USE_CASE_OPTIMIZATION,
findProduct,
findBestSections
} from '../config/breville-vault-intelligence.js';
import {
ENHANCED_INTENT_PARSING_PROMPT,
getIntentParsingPrompt
} from '../config/openai-prompts.js';
export default async function handler(req, res) {
// CORS headers for ChatGPT Enterprise
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
if (req.method === 'OPTIONS') {
return res.status(200).end();
}
if (req.method !== 'POST') {
return res.status(405).json({
error: 'method_not_allowed',
message: 'Only POST method allowed for asset search'
});
}
try {
const { request, context = {} } = req.body;
// Validate request
if (!request || typeof request !== 'string') {
return res.status(400).json({
error: 'invalid_request',
message: 'Request field is required and must be a string',
example: 'Oracle Jet logo for my presentation'
});
}
if (request.length < 3 || request.length > 500) {
return res.status(400).json({
error: 'invalid_request_length',
message: 'Request must be between 3 and 500 characters'
});
}
// Check authentication status
const hasOAuth = !!process.env.BRANDFOLDER_CLIENT_ID && !!process.env.BRANDFOLDER_CLIENT_SECRET;
if (!hasOAuth) {
return res.status(401).json({
error: 'authentication_required',
message: 'Brandfolder OAuth not configured. Please complete setup.',
auth_url: `https://${req.headers.host}/authenticate`,
setup_status: 'oauth_pending'
});
}
// Execute enhanced asset search with OpenAI
const searchResult = await executeAssetSearchWithAI(request, context);
// Return results with enhanced intelligence
return res.json({
success: true,
intent: searchResult.intent,
results: searchResult.results,
suggestions: searchResult.suggestions,
intelligence: {
parsing_method: searchResult.parsingMethod,
detected_sections: searchResult.intent.sections?.map(s => s.name || s.section?.section || s),
regional_context: searchResult.intent.regionalContext,
confidence_score: searchResult.intent.confidence,
openai_enhanced: !!process.env.OPENAI_API_KEY
},
metadata: {
query: request,
timestamp: new Date().toISOString(),
response_time: `${Date.now() - (req.startTime || Date.now())}ms`
}
});
} catch (error) {
console.error('[Phase 2 Enhanced Asset Search Error]', error);
// Handle specific error types
if (error.message.includes('authenticate')) {
return res.status(401).json({
error: 'authentication_required',
message: 'Please authenticate with Brandfolder to access assets',
auth_url: `https://${req.headers.host}/authenticate`
});
}
if (error.message.includes('rate limit')) {
return res.status(429).json({
error: 'rate_limit_exceeded',
message: 'Too many requests. Please wait a moment and try again.',
retry_after: 60
});
}
// Generic server error
return res.status(500).json({
error: 'search_failed',
message: 'Asset search failed. Please try again or contact support.',
timestamp: new Date().toISOString()
});
}
}
// Enhanced asset search with OpenAI intelligence
async function executeAssetSearchWithAI(userRequest, context) {
// Try OpenAI-enhanced parsing first, fall back to pattern matching
const intent = await parseUserIntentWithAI(userRequest, context);
// Generate intelligent mock results based on enhanced intent
const mockResults = generateAdvancedIntelligentResults(intent);
// Generate AI-powered suggestions
const suggestions = generateAIEnhancedSuggestions(intent, mockResults);
return {
intent: intent,
results: mockResults,
suggestions: suggestions,
parsingMethod: intent.parsingMethod || 'enhanced'
};
}
// AI-Enhanced Intent Parsing (Phase 2 upgrade)
async function parseUserIntentWithAI(userRequest, context = {}) {
const hasOpenAI = !!process.env.OPENAI_API_KEY;
if (hasOpenAI) {
try {
console.log('π€ Using OpenAI-enhanced intent parsing');
return await parseIntentWithOpenAI(userRequest, context);
} catch (error) {
console.error('OpenAI parsing failed, falling back to enhanced pattern matching:', error);
return parseUserIntentEnhanced(userRequest, context, 'openai_fallback');
}
} else {
console.log('π§ Using enhanced pattern matching (no OpenAI key)');
return parseUserIntentEnhanced(userRequest, context, 'pattern_matching');
}
}
// OpenAI-powered intent parsing
async function parseIntentWithOpenAI(userRequest, context) {
try {
// Dynamic import of axios (since we can't guarantee it's available)
const axios = (await import('axios')).default;
const response = await axios.post('https://api.openai.com/v1/chat/completions', {
model: 'gpt-4o-mini',
messages: [
{
role: 'system',
content: ENHANCED_INTENT_PARSING_PROMPT
},
{
role: 'user',
content: `Parse this asset request: "${userRequest}"${Object.keys(context).length ? ` (Context: ${JSON.stringify(context)})` : ''}`
}
],
max_tokens: 1000,
temperature: 0.1
}, {
headers: {
'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`,
'Content-Type': 'application/json'
}
});
const content = response.data.choices[0].message.content.trim();
// Handle potential markdown wrapping
const jsonString = content.replace(/```json\n?/g, '').replace(/```\n?/g, '').trim();
const aiIntent = JSON.parse(jsonString);
// Enhance with additional processing
const enhancedIntent = {
...aiIntent,
originalRequest: userRequest,
context: context,
parsingMethod: 'openai_enhanced',
timestamp: new Date().toISOString(),
// Add regional context if detected
regionalContext: aiIntent.region && aiIntent.region !== 'global' ?
REGIONAL_MAPPING[aiIntent.region.toUpperCase()] : null
};
// Validate and ensure required fields
enhancedIntent.confidence = Math.min(Math.max(enhancedIntent.confidence || 0.8, 0.1), 1.0);
enhancedIntent.products = enhancedIntent.products || [];
enhancedIntent.sections = enhancedIntent.sections || [];
enhancedIntent.useCase = enhancedIntent.useCase || 'general';
enhancedIntent.formats = enhancedIntent.formats || ['PNG'];
console.log('β
OpenAI parsing successful, confidence:', enhancedIntent.confidence);
return enhancedIntent;
} catch (error) {
console.error('OpenAI API error:', error.response?.data || error.message);
throw new Error(`OpenAI parsing failed: ${error.message}`);
}
}
// Enhanced pattern matching (fallback method, but still intelligent)
function parseUserIntentEnhanced(userRequest, context = {}, parsingMethod = 'enhanced') {
const intent = {
products: [],
sections: [],
assetTypes: [],
specificDeliverables: [],
useCase: context.use_case || inferUseCase(userRequest),
formats: ['PNG'],
region: context.region || inferRegion(userRequest),
brand: null,
regionalContext: null,
confidence: 0.7,
originalRequest: userRequest,
reasoning: [],
parsingMethod: parsingMethod
};
// 1. Smart product detection using intelligence config
const detectedProduct = findProduct(userRequest);
if (detectedProduct) {
intent.products.push(detectedProduct);
intent.reasoning.push(`Detected product: ${detectedProduct.name} (${detectedProduct.modelNumber})`);
intent.confidence += 0.15;
}
// 2. Smart section detection
const bestSections = findBestSections(userRequest, intent.useCase);
if (bestSections.length > 0) {
intent.sections = bestSections.slice(0, 2).map(match => ({
name: match.section.section,
deliverables: match.section.deliverables,
confidence: Math.min(match.score / 5, 1.0)
}));
intent.reasoning.push(`Targeting sections: ${bestSections.map(s => s.section.section).join(', ')}`);
intent.confidence += 0.1;
}
// 3. Regional and brand context
if (intent.region && intent.region !== 'global') {
const regionalInfo = REGIONAL_MAPPING[intent.region.toUpperCase()];
if (regionalInfo) {
intent.brand = regionalInfo.brand;
intent.regionalContext = regionalInfo;
intent.reasoning.push(`Region: ${intent.region} β Brand: ${intent.brand}`);
// Adjust product model for region
if (intent.products.length > 0 && intent.brand === 'Sage') {
const product = intent.products[0];
if (product.sageModel) {
intent.reasoning.push(`Using Sage model: ${product.sageModel} instead of ${product.modelNumber}`);
}
}
}
}
// 4. Use case optimization
const useCaseConfig = USE_CASE_OPTIMIZATION[intent.useCase];
if (useCaseConfig) {
intent.formats = useCaseConfig.preferredFormats;
intent.usageNotes = useCaseConfig.notes;
intent.reasoning.push(`Use case: ${intent.useCase} β Formats: ${intent.formats.join(', ')}`);
}
// 5. Extract specific deliverables from sections
intent.sections.forEach(section => {
if (section.deliverables) {
// Add relevant deliverables based on the request
const relevantDeliverables = section.deliverables.filter(deliverable => {
return bestSections.some(match =>
match.section.keywords.some(keyword =>
userRequest.toLowerCase().includes(keyword.toLowerCase())
)
);
});
intent.specificDeliverables.push(...relevantDeliverables.slice(0, 3));
}
});
// 6. Legacy asset type extraction (for backward compatibility)
intent.assetTypes = intent.sections.map(s => s.name?.toLowerCase().replace(/\s+/g, '_') || 'general');
return intent;
}
// Smart use case inference (enhanced)
function inferUseCase(userRequest) {
const request = userRequest.toLowerCase();
if (/presentation|slide|ppt|powerpoint|keynote/i.test(request)) return 'presentation';
if (/web|website|online|digital|homepage/i.test(request)) return 'web';
if (/social|instagram|facebook|twitter|linkedin|tiktok/i.test(request)) return 'social';
if (/amazon|marketplace|ecommerce|a\+|aplus/i.test(request)) return 'amazon';
if (/retail|store|pos|point.of.sale|in.?store/i.test(request)) return 'retail';
if (/print|brochure|flyer|poster|catalogue/i.test(request)) return 'print';
if (/email|edm|newsletter|mailchimp/i.test(request)) return 'email';
if (/video|youtube|tutorial|demo/i.test(request)) return 'video';
return 'general';
}
// Smart region inference (enhanced)
function inferRegion(userRequest) {
const request = userRequest.toLowerCase();
if (/australia|australian|au\b|aussie/i.test(request)) return 'AU';
if (/america|usa|us\b|united states|american/i.test(request)) return 'US';
if (/canada|canadian|ca\b/i.test(request)) return 'CA';
if (/uk\b|britain|british|united kingdom|england/i.test(request)) return 'GB';
if (/germany|german|de\b|deutschland/i.test(request)) return 'DE';
if (/europe|european|eu\b|emea/i.test(request)) return 'EU';
if (/sage/i.test(request)) return 'GB'; // Sage implies UK/EU market
return 'global';
}
// Generate advanced intelligent mock results (Phase 2 enhanced)
function generateAdvancedIntelligentResults(intent) {
const results = [];
// Generate product-specific results with AI insights
if (intent.products.length > 0) {
const product = intent.products[0];
const modelToUse = (intent.brand === 'Sage' && product.sageModel) ? product.sageModel : product.modelNumber;
// Generate assets based on detected sections with AI naming
intent.sections.forEach((section, index) => {
const sectionName = section.name || section.section?.section;
const primaryFormat = intent.formats[0] || 'PNG';
// Create AI-enhanced asset based on section type
const asset = {
id: `asset_ai_${Date.now()}_${index}`,
name: generateAIEnhancedAssetName(product, sectionName, intent),
url: `https://vault.breville.com/download/${modelToUse}_${sectionName.replace(/\s+/g, '_').toLowerCase()}`,
thumbnail: `https://vault.breville.com/thumb/${modelToUse}_${sectionName.replace(/\s+/g, '_').toLowerCase()}`,
format: primaryFormat,
size: getAIOptimalSize(sectionName, intent.useCase),
section: sectionName,
deliverableType: intent.specificDeliverables[index] || section.deliverables?.[0] || 'Standard Asset',
aiSummary: generateAIEnhancedSummary(product, sectionName, intent),
usageNotes: generateAIEnhancedUsageNotes(sectionName, intent),
regionalContext: intent.regionalContext,
confidenceScore: section.confidence || 0.85
};
results.push(asset);
});
}
// If no specific sections detected, generate smart generic result
if (results.length === 0) {
results.push({
id: 'asset_ai_generic_001',
name: intent.products.length > 0 ?
`${intent.products[0].name} - ${intent.brand || 'Breville'} Brand Asset` :
`${intent.brand || 'Breville'} Logo - Primary`,
url: 'https://vault.breville.com/download/generic_brand_asset',
thumbnail: 'https://vault.breville.com/thumb/generic_brand_asset',
format: intent.formats[0] || 'PNG',
size: '2048x1024',
section: 'Logos',
deliverableType: 'Brands & Logos',
aiSummary: `${intent.brand || 'Breville'} brand asset in ${intent.formats[0]} format. Optimized for ${intent.useCase} use.`,
usageNotes: generateGenericAIUsageNotes(intent),
confidenceScore: 0.75
});
}
return results.slice(0, 3); // Limit to top 3 results
}
// AI-Enhanced asset naming
function generateAIEnhancedAssetName(product, sectionName, intent) {
const brand = intent.brand || 'Breville';
const useCase = intent.useCase;
if (sectionName === 'Logos') {
return `${product.name} - ${brand} Logo${useCase === 'presentation' ? ' (Presentation Ready)' : ''}`;
} else if (sectionName === 'Product Photography') {
return `${product.name} - Hero Photography${useCase === 'amazon' ? ' (Amazon Optimized)' : ''}`;
} else if (sectionName === 'Lifestyle Photography') {
return `${product.name} - Lifestyle Shot${useCase === 'social' ? ' (Social Media Ready)' : ''}`;
} else if (sectionName.includes('Social')) {
return `${product.name} - Social Media Asset (${intent.region === 'GB' ? 'Sage' : 'Breville'} Branding)`;
} else if (sectionName.includes('Digital')) {
return `${product.name} - ${useCase === 'amazon' ? 'Amazon A+' : 'Digital'} Asset`;
} else {
return `${product.name} - ${sectionName}${intent.regionalContext ? ` (${intent.regionalContext.theater})` : ''}`;
}
}
// AI-Enhanced summaries
function generateAIEnhancedSummary(product, sectionName, intent) {
const format = intent.formats[0];
const useCase = intent.useCase;
const brand = intent.brand || 'Breville';
let summary = `${product.name} asset from ${sectionName} section in ${format} format.`;
if (useCase === 'presentation') {
summary += ' High-resolution with transparent background, perfect for slide presentations and corporate materials.';
} else if (useCase === 'social') {
summary += ' Social media optimized with engaging composition and platform-specific dimensions.';
} else if (useCase === 'amazon') {
summary += ' Amazon marketplace optimized meeting A+ content requirements and product listing guidelines.';
} else if (useCase === 'retail') {
summary += ' Print-ready with CMYK color profile for retail point-of-sale materials.';
} else if (useCase === 'web') {
summary += ' Web-optimized for fast loading and responsive design across devices.';
}
if (intent.regionalContext) {
summary += ` Features ${brand} branding specifically for ${intent.regionalContext.theater} market compliance.`;
}
return summary;
}
// AI-Enhanced usage notes
function generateAIEnhancedUsageNotes(sectionName, intent) {
const notes = [];
const useCaseConfig = USE_CASE_OPTIMIZATION[intent.useCase];
// Format-specific AI notes
if (intent.formats.includes('PNG')) {
notes.push('β
PNG format with alpha channel transparency');
}
if (intent.formats.includes('SVG')) {
notes.push('β
Vector format - infinite scalability without quality loss');
}
if (intent.formats.includes('WebP')) {
notes.push('β
Next-gen WebP format for 30% smaller file sizes');
}
// AI-enhanced use case notes
if (useCaseConfig && useCaseConfig.notes) {
useCaseConfig.notes.forEach(note => notes.push(`π― ${note}`));
}
// AI-enhanced section-specific notes
if (sectionName === 'Product Photography') {
notes.push('πΈ Professional studio photography with optimal lighting');
} else if (sectionName === 'Lifestyle Photography') {
notes.push('π Authentic kitchen environment showing product in real use');
} else if (sectionName.includes('Social')) {
notes.push('π± Optimized for social media algorithms and engagement');
} else if (sectionName.includes('Digital')) {
notes.push('π» Optimized for digital platforms and e-commerce');
}
// AI-enhanced regional notes
if (intent.regionalContext) {
notes.push(`π ${intent.brand} branding compliant with ${intent.regionalContext.theater} market standards`);
}
return notes;
}
// AI-optimal size detection
function getAIOptimalSize(sectionName, useCase) {
const sizeMap = {
'Logos': {
'presentation': '4096x2048',
'web': '2048x1024',
'social': '1080x1080',
'print': '5000x2500',
'default': '2048x1024'
},
'Product Photography': {
'amazon': '2000x2000',
'web': '1920x1920',
'social': '1080x1080',
'print': '4000x4000',
'default': '3000x3000'
},
'Social': {
'social': '1080x1080',
'default': '1080x1080'
},
'Digital': {
'amazon': '2000x2000',
'web': '1920x1080',
'default': '1920x1080'
}
};
const sectionKey = Object.keys(sizeMap).find(key =>
sectionName.includes(key) || sectionName.toLowerCase().includes(key.toLowerCase())
);
if (sectionKey && sizeMap[sectionKey][useCase]) {
return sizeMap[sectionKey][useCase];
} else if (sectionKey) {
return sizeMap[sectionKey].default;
}
return '2048x1024';
}
// Generate AI-enhanced generic usage notes
function generateGenericAIUsageNotes(intent) {
const notes = [];
if (intent.useCase === 'presentation') {
notes.push('π― Presentation-optimized with high DPI for projectors');
notes.push('β
Transparent background for flexible slide layouts');
} else if (intent.useCase === 'web') {
notes.push('π Web-optimized with progressive loading');
notes.push('π± Responsive design compatible');
} else if (intent.useCase === 'social') {
notes.push('π± Social media algorithm optimized');
notes.push('π¨ Engaging visual composition for maximum reach');
} else if (intent.useCase === 'amazon') {
notes.push('π Amazon A+ content guidelines compliant');
notes.push('β‘ Optimized for marketplace conversion');
}
return notes;
}
// Generate AI-enhanced suggestions
function generateAIEnhancedSuggestions(intent, results) {
const suggestions = [];
if (results.length === 0) {
suggestions.push({
type: 'no_results_ai',
message: 'AI analysis found no matching assets with current parameters.',
action: intent.products.length > 0 ?
`Try: "${intent.products[0].name} photography" or "${intent.products[0].name} in kitchen"` :
'Try: "Oracle Jet coffee machine" or "Breville espresso machine logos"'
});
}
if (intent.products.length === 0) {
suggestions.push({
type: 'ai_product_recommendation',
message: 'AI detected generic request. Specify a Breville product for 10x better results.',
action: 'Try: "Oracle Jet social posts" or "Sage Oracle Dual Boiler Amazon listing"'
});
}
if (intent.confidence < 0.8) {
suggestions.push({
type: 'ai_confidence_boost',
message: 'AI confidence can be improved with more specific details.',
action: 'Try: "Oracle Jet hero photography for Australian e-commerce site" or "Sage logo white background for UK presentation"'
});
}
if (intent.useCase === 'general') {
suggestions.push({
type: 'ai_use_case_optimization',
message: 'AI can optimize format and sizing if you specify intended use.',
action: 'Add context: "for my presentation", "for Instagram post", "for Amazon listing", or "for retail display"'
});
}
if (intent.region === 'global' && intent.products.length > 0) {
suggestions.push({
type: 'ai_regional_optimization',
message: 'AI can provide region-specific branding (Breville vs Sage).',
action: 'Specify market: "for UK customers" (β Sage branding) or "for Australian market" (β Breville branding)'
});
}
// AI-powered cross-selling suggestions
if (results.length > 0 && intent.sections.length === 1) {
const currentSection = intent.sections[0].name;
if (currentSection === 'Product Photography') {
suggestions.push({
type: 'ai_cross_sell',
message: 'AI recommends: Lifestyle photography often performs better for engagement.',
action: `Try: "${intent.originalRequest.replace(/product|photo/gi, 'lifestyle scene')}"`
});
} else if (currentSection.includes('Social')) {
suggestions.push({
type: 'ai_video_recommendation',
message: 'AI insight: Video content generates 5x more engagement on social platforms.',
action: `Try: "${intent.products[0]?.name || 'product'} demo video" or "how to use ${intent.products[0]?.name}"`
});
}
}
// AI-powered format optimization suggestions
if (intent.parsingMethod === 'openai_enhanced' && intent.confidence > 0.9) {
suggestions.push({
type: 'ai_format_optimization',
message: `AI optimized this request for ${intent.useCase} use case with ${intent.formats.join('/')} format${intent.formats.length > 1 ? 's' : ''}.`,
action: 'Perfect! This search is AI-optimized for your specific needs.'
});
}
return suggestions;
}