server / services /aiService.js
Mark-Lasfar
Fix: Optimize loadStore function, fix preview mode and follow-status
03fcf73
Raw
History Blame Contribute Delete
28.8 kB
/**
* ุฎุฏู…ุฉ ุงู„ุฐูƒุงุก ุงู„ุงุตุทู†ุงุนูŠ - ุฏุนู… ู†ู…ุงุฐุฌ ู…ุชุนุฏุฏุฉ
* @version 3.0.0
*/
const axios = require('axios');
const crypto = require('crypto');
class AIService {
constructor() {
// ุฅุนุฏุงุฏุงุช Hugging Face API
this.hfApiKey = process.env.HF_API_KEY;
// ู†ู…ุงุฐุฌ ู…ุชุนุฏุฏุฉ
this.models = {
// ู†ู…ูˆุฐุฌ ุณุฑูŠุน ู„ู„ู…ู‡ุงู… ุงู„ุจุณูŠุทุฉ (ุชูˆู„ูŠุฏ ShortcodesุŒ ุงู‚ุชุฑุงุญุงุช ุณุฑูŠุนุฉ)
fast: process.env.AI_MODEL_FAST || 'Qwen/Qwen2.5-7B-Instruct',
// ู†ู…ูˆุฐุฌ ุฏู‚ูŠู‚ ู„ู„ู…ู‡ุงู… ุงู„ู…ุนู‚ุฏุฉ (ุชูˆู„ูŠุฏ ู‚ูˆุงู„ุจ ูƒุงู…ู„ุฉุŒ ุชุตุงู…ูŠู…)
precise: process.env.AI_MODEL_PRECISE || 'deepseek-ai/DeepSeek-R1',
// ู†ู…ูˆุฐุฌ ุงุญุชูŠุงุทูŠ
fallback: 'Qwen/Qwen2.5-7B-Instruct'
};
// ุนู†ูˆุงู† API
this.apiUrl = 'https://router.huggingface.co/v1/chat/completions';
// ุชุฎุฒูŠู† ู…ุคู‚ุช ู„ู„ู†ุชุงุฆุฌ
this.cache = new Map();
this.cacheTTL = 3600000; // ุณุงุนุฉ ูˆุงุญุฏุฉ
// ุฅุญุตุงุฆูŠุงุช ุงุณุชุฎุฏุงู… ุงู„ู†ู…ุงุฐุฌ
this.modelStats = {
fast: { calls: 0, avgTime: 0 },
precise: { calls: 0, avgTime: 0 }
};
console.log(`๐Ÿค– AI Service initialized with models:
- Fast Model: ${this.models.fast}
- Precise Model: ${this.models.precise}`);
}
/**
* ุงุฎุชูŠุงุฑ ุงู„ู†ู…ูˆุฐุฌ ุงู„ู…ู†ุงุณุจ ู„ู„ู…ู‡ู…ุฉ
*/
selectModel(taskType) {
// โœ… ุฏุงุฆู…ุงู‹ ุงุณุชุฎุฏู… ุงู„ู†ู…ูˆุฐุฌ ุงู„ุณุฑูŠุน (Qwen) ู„ูƒู„ ุดูŠุก ุฃูˆู„ุงู‹
// DeepSeek ุณูŠูุณุชุฎุฏู… ูู‚ุท ูƒุงุญุชูŠุงุทูŠ ุฅุฐุง ูุดู„ Qwen
return this.models.fast; // Qwen/Qwen2.5-7B-Instruct
}
/**
* ุงู„ุญุตูˆู„ ุนู„ู‰ ู…ูุชุงุญ ุงู„ุชุฎุฒูŠู† ุงู„ู…ุคู‚ุช
*/
getCacheKey(prompt, type, model) {
return crypto.createHash('md5').update(`${type}:${prompt}:${model}`).digest('hex');
}
/**
* ุงุณุชุฏุนุงุก Hugging Face API ู…ุน ู†ู…ูˆุฐุฌ ู…ุญุฏุฏ
*/
async callHuggingFace(prompt, temperature = 0.7, model = null) {
if (!this.hfApiKey) {
console.warn('โš ๏ธ HF_API_KEY not configured, using fallback responses');
return null;
}
const selectedModel = model || this.models.fast;
const startTime = Date.now();
try {
const response = await axios.post(
this.apiUrl,
{
model: selectedModel,
messages: [
{
role: 'system',
content: `You are an expert e-commerce and web design assistant for MGZon platform.
Platform capabilities:
- Products: digital, projects, services
- Pages: custom pages with HTML/CSS/JS
- Shortcodes: products, product, contact-form, store-info, categories, testimonials, social-links
- Themes: custom colors, fonts, layouts, full templates
- Store sections: hero, featured, products, categories, testimonials, faq, contact, html, products_grid
Respond with valid JSON when requested. Be concise, professional, and ensure output matches MGZon format.`
},
{
role: 'user',
content: prompt
}
],
temperature: temperature,
max_tokens: 4096,
top_p: 0.95
},
{
headers: {
'Authorization': `Bearer ${this.hfApiKey}`,
'Content-Type': 'application/json'
},
timeout: 30000 // 90 seconds timeout for complex tasks
}
);
const content = response.data?.choices?.[0]?.message?.content;
if (!content) {
throw new Error('Empty response from Hugging Face');
}
// ุชุญุฏูŠุซ ุงู„ุฅุญุตุงุฆูŠุงุช
const modelType = selectedModel === this.models.precise ? 'precise' : 'fast';
const timeTaken = Date.now() - startTime;
this.modelStats[modelType].calls++;
this.modelStats[modelType].avgTime =
(this.modelStats[modelType].avgTime * (this.modelStats[modelType].calls - 1) + timeTaken) /
this.modelStats[modelType].calls;
return content;
} catch (error) {
console.error(`Hugging Face API error (${selectedModel}):`, error.response?.data || error.message);
return null;
}
}
/**
* ุงุณุชุฏุนุงุก AI ู…ุน ุงุฎุชูŠุงุฑ ุฐูƒูŠ ู„ู„ู†ู…ูˆุฐุฌ
*/
async callAI(prompt, temperature = 0.7, taskType = 'general') {
// โœ… ุงุณุชุฎุฏู… ุงู„ู†ู…ูˆุฐุฌ ุงู„ุณุฑูŠุน (Qwen) ุฃูˆู„ุงู‹
const primaryModel = this.models.fast; // Qwen
const cacheKey = this.getCacheKey(prompt, taskType, primaryModel);
const cached = this.cache.get(cacheKey);
if (cached && (Date.now() - cached.timestamp) < this.cacheTTL) {
return cached.result;
}
console.log(`๐Ÿค– Trying primary model: ${primaryModel}`);
let result = await this.callHuggingFace(prompt, temperature, primaryModel);
// โœ… ูู‚ุท ุฅุฐุง ูุดู„ QwenุŒ ุฌุฑุจ DeepSeek ูƒุงุญุชูŠุงุทูŠ
if (!result) {
const fallbackModel = this.models.precise; // DeepSeek
console.log(`โš ๏ธ Primary model failed, trying fallback: ${fallbackModel}`);
result = await this.callHuggingFace(prompt, temperature, fallbackModel);
}
// โœ… ุฅุฐุง ูุดู„ ูƒู„ุงู‡ู…ุงุŒ ุงุณุชุฎุฏู… ุงู„ุงุญุชูŠุงุทูŠ ุงู„ู†ู‡ุงุฆูŠ
if (!result) {
console.log(`โš ๏ธ Both models failed, using final fallback: ${this.models.fallback}`);
result = await this.callHuggingFace(prompt, temperature, this.models.fallback);
}
if (result) {
this.cache.set(cacheKey, { result, timestamp: Date.now() });
return result;
}
return null;
}
/**
* ุชูˆู„ูŠุฏ ุชุฎุทูŠุท ุตูุญุฉ ูƒุงู…ู„ - ู…ุญุณู† ู…ุน ุฏุนู… ุงู„ู‚ูˆุงู„ุจ
*/
async generatePageLayout(description, storeType = 'general') {
const prompt = `
You are an expert e-commerce web designer for MGZon platform. Generate a complete store page layout.
User description: "${description}"
Store type: ${storeType}
Available section types: hero, products, featured, categories, testimonials, faq, contact, html, products_grid
Generate a JSON object with this exact structure:
{
"name": "Suggested page name (max 50 chars)",
"sections": [
{
"type": "section_type",
"title": "Section title (if applicable)",
"order": 1,
"enabled": true,
"limit": 6,
"layout": "grid",
"columns": 4,
"content": {}
}
],
"theme": {
"primaryColor": "#hex",
"secondaryColor": "#hex",
"accentColor": "#hex",
"fontFamily": "Inter, sans-serif",
"layout": "full-width",
"backgroundType": "default",
"borderRadius": 16,
"animationType": "lift"
},
"seo": {
"title": "Suggested SEO title (50-60 chars)",
"description": "Suggested meta description (150-160 chars)",
"keywords": ["keyword1", "keyword2", "keyword3"]
}
}
Return ONLY valid JSON, no explanation. Ensure all colors are valid hex codes.
`;
try {
const response = await this.callAI(prompt, 0.8, 'layout');
if (!response) {
return this.getFallbackLayout(description, storeType);
}
const cleanResponse = response
.replace(/```json\n?/g, '')
.replace(/```\n?/g, '')
.replace(/`/g, '')
.trim();
const layout = JSON.parse(cleanResponse);
// ุงู„ุชุญู‚ู‚ ู…ู† ุตุญุฉ ุงู„ุจูŠุงู†ุงุช
layout.sections = layout.sections.map((s, i) => ({
...s,
order: s.order || i + 1,
enabled: s.enabled !== false
}));
return {
success: true,
layout: layout,
modelUsed: this.modelStats.fast.calls > this.modelStats.precise.calls ? this.models.fast : this.models.precise,
modelStats: this.modelStats
};
} catch (error) {
console.error('AI layout generation error:', error);
return {
success: false,
error: error.message,
fallback: this.getFallbackLayout(description, storeType)
};
}
}
/**
* ู‚ูˆุงู„ุจ ุงุญุชูŠุงุทูŠุฉ ู…ุญุณู‘ู†ุฉ ูˆู…ุชูˆุงูู‚ุฉ ู…ุน ุงู„ู†ุธุงู…
*/
getFallbackLayout(description, storeType) {
const layouts = {
fashion: {
name: 'Fashion Store',
sections: [
{ type: 'hero', order: 1, enabled: true, content: { title: 'New Collection', subtitle: 'Discover the latest trends', buttonText: 'Shop Now', buttonLink: '#products' } },
{ type: 'featured', order: 2, enabled: true, title: 'Featured Products', limit: 6, layout: 'grid' },
{ type: 'categories', order: 3, enabled: true, title: 'Shop by Category', layout: 'grid' },
{ type: 'products', order: 4, enabled: true, title: 'All Products', limit: 12, layout: 'grid', columns: 4 },
{ type: 'testimonials', order: 5, enabled: true, title: 'What Our Customers Say', limit: 4 },
{ type: 'contact', order: 6, enabled: true, title: 'Get in Touch' }
],
theme: {
primaryColor: '#ec4899',
secondaryColor: '#8b5cf6',
accentColor: '#f43f5e',
fontFamily: 'Poppins, sans-serif',
layout: 'full-width',
backgroundType: 'gradient',
backgroundValue: 'linear-gradient(135deg, #fdf2f8 0%, #fce7f3 100%)',
borderRadius: 20,
animationType: 'lift'
},
seo: {
title: 'Fashion Store | Latest Trends & Styles',
description: 'Discover the latest fashion trends. Shop our collection of clothing, accessories, and more. Free shipping on orders over $50.',
keywords: ['fashion', 'clothing', 'trends', 'style', 'shop', 'online store']
}
},
electronics: {
name: 'Tech Store',
sections: [
{ type: 'hero', order: 1, enabled: true, content: { title: 'Latest Technology', subtitle: 'Cutting-edge gadgets at best prices', buttonText: 'Shop Now', buttonLink: '#products' } },
{ type: 'categories', order: 2, enabled: true, title: 'Shop by Category', layout: 'grid' },
{ type: 'featured', order: 3, enabled: true, title: 'Best Sellers', limit: 6, sort: 'popular' },
{ type: 'products', order: 4, enabled: true, title: 'All Products', limit: 12, layout: 'grid', columns: 4 },
{ type: 'faq', order: 5, enabled: true, title: 'Frequently Asked Questions' },
{ type: 'contact', order: 6, enabled: true, title: 'Support' }
],
theme: {
primaryColor: '#06b6d4',
secondaryColor: '#3b82f6',
accentColor: '#10b981',
fontFamily: 'Inter, sans-serif',
layout: 'full-width',
backgroundType: 'grid',
borderRadius: 12,
animationType: 'scale'
},
seo: {
title: 'Tech Store | Electronics & Gadgets',
description: 'Shop the latest electronics, gadgets, and tech accessories. Best prices and fast shipping. 30-day return policy.',
keywords: ['electronics', 'gadgets', 'technology', 'tech', 'shop', 'online store']
}
},
food: {
name: 'Food & Restaurant',
sections: [
{ type: 'hero', order: 1, enabled: true, content: { title: 'Delicious Food', subtitle: 'Order online for delivery', buttonText: 'Order Now', buttonLink: '#products' } },
{ type: 'featured', order: 2, enabled: true, title: 'Popular Dishes', limit: 6, type: 'service' },
{ type: 'categories', order: 3, enabled: true, title: 'Menu Categories', layout: 'grid' },
{ type: 'products', order: 4, enabled: true, title: 'Full Menu', limit: 12, layout: 'grid', columns: 3, type: 'service' },
{ type: 'testimonials', order: 5, enabled: true, title: 'Customer Reviews', limit: 3 },
{ type: 'contact', order: 6, enabled: true, title: 'Contact Us' }
],
theme: {
primaryColor: '#f59e0b',
secondaryColor: '#ef4444',
accentColor: '#22c55e',
fontFamily: 'Playfair Display, serif',
layout: 'full-width',
backgroundType: 'dots',
borderRadius: 24,
animationType: 'lift'
},
seo: {
title: 'Food & Restaurant | Order Online',
description: 'Delicious food delivered to your door. Browse our menu and order online for fast delivery. Fresh ingredients, great taste.',
keywords: ['food', 'restaurant', 'delivery', 'order online', 'menu', 'catering']
}
},
art: {
name: 'Art Gallery',
sections: [
{ type: 'hero', order: 1, enabled: true, content: { title: 'Art Gallery', subtitle: 'Discover unique artworks', buttonText: 'Browse Art', buttonLink: '#products' } },
{ type: 'featured', order: 2, enabled: true, title: 'Featured Artworks', limit: 6 },
{ type: 'categories', order: 3, enabled: true, title: 'Categories', layout: 'grid' },
{ type: 'products', order: 4, enabled: true, title: 'All Artworks', limit: 12, layout: 'masonry', columns: 3 },
{ type: 'testimonials', order: 5, enabled: true, title: 'Collector Reviews', limit: 4 }
],
theme: {
primaryColor: '#a855f7',
secondaryColor: '#ec4899',
accentColor: '#06b6d4',
fontFamily: 'Poppins, sans-serif',
layout: 'boxed',
backgroundType: 'cross',
borderRadius: 16,
animationType: 'glow'
},
seo: {
title: 'Art Gallery | Original Artworks',
description: 'Discover unique original artworks from talented artists. Paintings, sculptures, digital art. Worldwide shipping.',
keywords: ['art', 'gallery', 'artwork', 'painting', 'sculpture', 'artist']
}
},
general: {
name: 'My Store',
sections: [
{ type: 'hero', order: 1, enabled: true, content: { title: 'Welcome to My Store', subtitle: 'Quality products at great prices', buttonText: 'Shop Now', buttonLink: '#products' } },
{ type: 'featured', order: 2, enabled: true, title: 'Featured Products', limit: 6 },
{ type: 'categories', order: 3, enabled: true, title: 'Categories', layout: 'grid' },
{ type: 'products', order: 4, enabled: true, title: 'All Products', limit: 12, layout: 'grid', columns: 4 },
{ type: 'testimonials', order: 5, enabled: true, title: 'What Our Customers Say', limit: 3 },
{ type: 'faq', order: 6, enabled: true, title: 'Frequently Asked Questions' },
{ type: 'contact', order: 7, enabled: true, title: 'Contact Us' }
],
theme: {
primaryColor: '#3b82f6',
secondaryColor: '#8b5cf6',
accentColor: '#f59e0b',
fontFamily: 'Inter, sans-serif',
layout: 'full-width',
backgroundType: 'default',
borderRadius: 16,
animationType: 'lift'
},
seo: {
title: 'My Store | Quality Products',
description: 'Shop our collection of quality products. Best prices, fast shipping, and excellent customer service.',
keywords: ['store', 'shop', 'products', 'online store', 'ecommerce']
}
}
};
return {
success: false,
fallback: true,
layout: layouts[storeType] || layouts.general,
message: 'Using fallback layout (AI service unavailable)'
};
}
/**
* ุชูˆู„ูŠุฏ ู‚ุงู„ุจ ูƒุงู…ู„ ู„ู„ู…ุชุฌุฑ
*/
async generateCompleteTemplate(description, style = 'modern') {
const prompt = `
Generate a complete store template for MGZon platform.
Description: "${description}"
Style preference: ${style} (modern/minimal/elegant/bold)
Return a JSON object with:
{
"name": "Template name",
"description": "Template description",
"category": "fashion|electronics|food|art|general",
"sections": [array of sections],
"theme": { theme settings },
"seo": { seo settings },
"shortcodes": ["[products limit=\"6\"]", "[contact-form]"]
}
Ensure the template is fully compatible with MGZon platform's store system.
Return ONLY valid JSON.
`;
try {
const response = await this.callAI(prompt, 0.85, 'template');
if (!response) {
return this.getFallbackTemplate(description, style);
}
const cleanResponse = response
.replace(/```json\n?/g, '')
.replace(/```\n?/g, '')
.replace(/`/g, '')
.trim();
const template = JSON.parse(cleanResponse);
return {
success: true,
template: template,
modelUsed: this.models.precise,
modelStats: this.modelStats
};
} catch (error) {
console.error('AI template generation error:', error);
return this.getFallbackTemplate(description, style);
}
}
getFallbackTemplate(description, style) {
return {
success: false,
fallback: true,
template: {
name: `${style.charAt(0).toUpperCase() + style.slice(1)} Store`,
description: description || `A beautiful ${style} store template`,
category: 'general',
sections: [
{ type: 'hero', order: 1, content: { title: 'Welcome', buttonText: 'Shop Now' } },
{ type: 'products', order: 2, title: 'Products', limit: 12 }
],
theme: {
primaryColor: '#3b82f6',
secondaryColor: '#8b5cf6',
fontFamily: 'Inter, sans-serif'
},
shortcodes: ['[products limit="6"]', '[contact-form]']
},
message: 'Using fallback template (AI service unavailable)'
};
}
/**
* ุจุงู‚ูŠ ุงู„ุฏูˆุงู„ (generateShortcode, suggestDesign, enhanceProductDescription, etc.)
* ุชุจู‚ู‰ ูƒู…ุง ู‡ูŠ ู…ุน ุฅุถุงูุฉ modelStats
*/
async generateShortcode(description) {
const prompt = `
Based on this description: "${description}"
Generate an appropriate shortcode from these available shortcodes:
- [products] - products grid (parameters: limit, type, layout, sort, columns, category)
- [product] - single product (parameters: id, layout)
- [contact-form] - contact form (parameters: title, fields)
- [testimonials] - customer reviews (parameters: limit, autoplay)
- [categories] - categories (parameters: layout, showCount)
- [search-form] - search box (parameters: placeholder, showFilters)
- [store-info] - store info (parameters: field)
- [cart-count] - cart count
- [social-links] - social links (parameters: layout)
Return ONLY the shortcode, no explanation.
Example: [products limit="6" type="digital" layout="grid" sort="popular"]
`;
try {
const response = await this.callAI(prompt, 0.5, 'shortcode');
if (!response) {
return {
success: false,
fallback: '[products limit="6"]',
message: 'AI service unavailable, using fallback'
};
}
const cleanShortcode = response
.trim()
.replace(/`/g, '')
.replace(/^\[/, '[')
.replace(/\]$/, ']');
return {
success: true,
shortcode: cleanShortcode,
modelUsed: this.modelStats.fast.calls > this.modelStats.precise.calls ? this.models.fast : this.models.precise,
modelStats: this.modelStats
};
} catch (error) {
return {
success: false,
error: error.message,
fallback: '[products limit="6"]'
};
}
}
suggestDesign(storeType) {
const suggestions = {
fashion: {
primaryColor: '#ec4899',
secondaryColor: '#8b5cf6',
accentColor: '#f43f5e',
fontFamily: 'Poppins, sans-serif',
headingFont: 'Poppins, sans-serif',
backgroundType: 'gradient',
backgroundValue: 'linear-gradient(135deg, #fdf2f8 0%, #fce7f3 100%)',
borderRadius: 20,
animationType: 'lift'
},
electronics: {
primaryColor: '#06b6d4',
secondaryColor: '#3b82f6',
accentColor: '#10b981',
fontFamily: 'Inter, sans-serif',
headingFont: 'Inter, sans-serif',
backgroundType: 'grid',
borderRadius: 12,
animationType: 'scale'
},
food: {
primaryColor: '#f59e0b',
secondaryColor: '#ef4444',
accentColor: '#22c55e',
fontFamily: 'Playfair Display, serif',
headingFont: 'Playfair Display, serif',
backgroundType: 'dots',
borderRadius: 24,
animationType: 'lift'
},
art: {
primaryColor: '#a855f7',
secondaryColor: '#ec4899',
accentColor: '#06b6d4',
fontFamily: 'Poppins, sans-serif',
headingFont: 'Poppins, sans-serif',
backgroundType: 'cross',
borderRadius: 16,
animationType: 'glow'
},
general: {
primaryColor: '#3b82f6',
secondaryColor: '#8b5cf6',
accentColor: '#f59e0b',
fontFamily: 'Inter, sans-serif',
headingFont: 'Inter, sans-serif',
backgroundType: 'default',
borderRadius: 16,
animationType: 'lift'
}
};
return suggestions[storeType] || suggestions.general;
}
async enhanceProductDescription(title, currentDescription, tags = []) {
const prompt = `
Improve this product description:
Title: ${title}
Current: ${currentDescription || 'No description'}
Tags: ${tags.join(', ')}
Write an engaging, SEO-friendly description (150-200 words) with benefits, keywords, and call to action.
Return ONLY the description, no explanation.
`;
try {
const response = await this.callAI(prompt, 0.7, 'description_enhance');
if (!response) {
return {
success: false,
description: currentDescription || `${title} - High quality product. Shop now!`
};
}
return {
success: true,
description: response.trim(),
modelUsed: this.modelStats.fast.calls > this.modelStats.precise.calls ? this.models.fast : this.models.precise
};
} catch (error) {
return {
success: false,
description: currentDescription,
error: error.message
};
}
}
async suggestKeywords(title, category, storeType) {
const prompt = `
Suggest 10 SEO keywords for:
Title: ${title}
Category: ${category}
Store Type: ${storeType}
Return ONLY comma-separated keywords, no explanation.
`;
try {
const response = await this.callAI(prompt, 0.3, 'keyword');
if (!response) {
return {
success: false,
keywords: [title, category, storeType, 'online store', 'buy online']
};
}
const keywords = response
.trim()
.split(',')
.map(k => k.trim())
.filter(k => k.length > 0);
return {
success: true,
keywords: keywords.slice(0, 10),
modelUsed: this.modelStats.fast.calls > this.modelStats.precise.calls ? this.models.fast : this.models.precise
};
} catch (error) {
return {
success: false,
keywords: [title, category, storeType, 'online store', 'buy online']
};
}
}
async generateStoreDescription(storeName, industry, products) {
const prompt = `
Write a store description for:
Store Name: ${storeName}
Industry: ${industry}
Products: ${products.join(', ')}
Write 100-150 words, welcoming, unique, with call to action.
Return ONLY the description.
`;
try {
const response = await this.callAI(prompt, 0.6, 'general');
if (!response) {
return {
success: false,
description: `Welcome to ${storeName}! We offer high-quality ${industry} products. Shop now!`
};
}
return {
success: true,
description: response.trim(),
modelUsed: this.modelStats.fast.calls > this.modelStats.precise.calls ? this.models.fast : this.models.precise
};
} catch (error) {
return {
success: false,
description: `Welcome to ${storeName}! We offer high-quality ${industry} products. Shop now!`
};
}
}
clearCache() {
this.cache.clear();
console.log('๐Ÿ—‘๏ธ AI cache cleared');
console.log('๐Ÿ“Š Model stats:', this.modelStats);
}
async testConnection() {
try {
const testPrompt = "Say 'API works' and nothing else.";
const response = await this.callHuggingFace(testPrompt, 0.1, this.models.fast);
if (response && response.includes('API works')) {
console.log('โœ… Hugging Face API connection successful');
return true;
}
console.log('โš ๏ธ Hugging Face API test failed');
return false;
} catch (error) {
console.error('โŒ Hugging Face API connection failed:', error.message);
return false;
}
}
}
module.exports = new AIService();