|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class HuggingFaceIntegration {
|
|
|
constructor() {
|
|
|
this.apiEndpoint = '/static-proxy?url=https%3A%2F%2Fapi-inference.huggingface.co%2Fmodels%26%23x27%3B%3C%2Fspan%3E%3B
|
|
|
this.models = {
|
|
|
sentiment: 'cardiffnlp/twitter-roberta-base-sentiment-latest',
|
|
|
emotion: 'j-hartmann/emotion-english-distilroberta-base',
|
|
|
textClassification: 'distilbert-base-uncased-finetuned-sst-2-english',
|
|
|
summarization: 'facebook/bart-large-cnn',
|
|
|
translation: 'Helsinki-NLP/opus-mt-en-fa'
|
|
|
};
|
|
|
this.cache = new Map();
|
|
|
this.init();
|
|
|
}
|
|
|
|
|
|
init() {
|
|
|
this.setupSentimentAnalysis();
|
|
|
this.setupNewsSummarization();
|
|
|
this.setupEmotionDetection();
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async analyzeSentiment(text) {
|
|
|
const cacheKey = `sentiment_${text.substring(0, 50)}`;
|
|
|
if (this.cache.has(cacheKey)) {
|
|
|
return this.cache.get(cacheKey);
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
const response = await fetch(`${this.apiEndpoint}/${this.models.sentiment}`, {
|
|
|
method: 'POST',
|
|
|
headers: {
|
|
|
'Authorization': `Bearer ${this.getApiKey()}`,
|
|
|
'Content-Type': 'application/json'
|
|
|
},
|
|
|
body: JSON.stringify({ inputs: text })
|
|
|
});
|
|
|
|
|
|
if (!response.ok) {
|
|
|
throw new Error(`HF API error: ${response.status}`);
|
|
|
}
|
|
|
|
|
|
const data = await response.json();
|
|
|
const result = this.processSentimentResult(data);
|
|
|
|
|
|
this.cache.set(cacheKey, result);
|
|
|
return result;
|
|
|
} catch (error) {
|
|
|
console.error('Sentiment analysis error:', error);
|
|
|
return this.getFallbackSentiment(text);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
processSentimentResult(data) {
|
|
|
if (Array.isArray(data) && data[0]) {
|
|
|
const scores = data[0];
|
|
|
return {
|
|
|
label: scores[0]?.label || 'NEUTRAL',
|
|
|
score: scores[0]?.score || 0.5,
|
|
|
confidence: Math.round(scores[0]?.score * 100) || 50
|
|
|
};
|
|
|
}
|
|
|
return { label: 'NEUTRAL', score: 0.5, confidence: 50 };
|
|
|
}
|
|
|
|
|
|
getFallbackSentiment(text) {
|
|
|
|
|
|
const positiveWords = ['good', 'great', 'excellent', 'bullish', 'up', 'rise', 'gain', 'profit'];
|
|
|
const negativeWords = ['bad', 'terrible', 'bearish', 'down', 'fall', 'loss', 'crash'];
|
|
|
|
|
|
const lowerText = text.toLowerCase();
|
|
|
const positiveCount = positiveWords.filter(w => lowerText.includes(w)).length;
|
|
|
const negativeCount = negativeWords.filter(w => lowerText.includes(w)).length;
|
|
|
|
|
|
if (positiveCount > negativeCount) {
|
|
|
return { label: 'POSITIVE', score: 0.7, confidence: 70 };
|
|
|
} else if (negativeCount > positiveCount) {
|
|
|
return { label: 'NEGATIVE', score: 0.3, confidence: 70 };
|
|
|
}
|
|
|
return { label: 'NEUTRAL', score: 0.5, confidence: 50 };
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async summarizeNews(text, maxLength = 100) {
|
|
|
const cacheKey = `summary_${text.substring(0, 50)}`;
|
|
|
if (this.cache.has(cacheKey)) {
|
|
|
return this.cache.get(cacheKey);
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
const response = await fetch(`${this.apiEndpoint}/${this.models.summarization}`, {
|
|
|
method: 'POST',
|
|
|
headers: {
|
|
|
'Authorization': `Bearer ${this.getApiKey()}`,
|
|
|
'Content-Type': 'application/json'
|
|
|
},
|
|
|
body: JSON.stringify({
|
|
|
inputs: text,
|
|
|
parameters: { max_length: maxLength, min_length: 30 }
|
|
|
})
|
|
|
});
|
|
|
|
|
|
if (!response.ok) {
|
|
|
throw new Error(`HF API error: ${response.status}`);
|
|
|
}
|
|
|
|
|
|
const data = await response.json();
|
|
|
const summary = Array.isArray(data) ? data[0]?.summary_text : data.summary_text;
|
|
|
|
|
|
this.cache.set(cacheKey, summary);
|
|
|
return summary || text.substring(0, maxLength) + '...';
|
|
|
} catch (error) {
|
|
|
console.error('Summarization error:', error);
|
|
|
return text.substring(0, maxLength) + '...';
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async detectEmotion(text) {
|
|
|
try {
|
|
|
const response = await fetch(`${this.apiEndpoint}/${this.models.emotion}`, {
|
|
|
method: 'POST',
|
|
|
headers: {
|
|
|
'Authorization': `Bearer ${this.getApiKey()}`,
|
|
|
'Content-Type': 'application/json'
|
|
|
},
|
|
|
body: JSON.stringify({ inputs: text })
|
|
|
});
|
|
|
|
|
|
if (!response.ok) {
|
|
|
throw new Error(`HF API error: ${response.status}`);
|
|
|
}
|
|
|
|
|
|
const data = await response.json();
|
|
|
return this.processEmotionResult(data);
|
|
|
} catch (error) {
|
|
|
console.error('Emotion detection error:', error);
|
|
|
return { label: 'neutral', score: 0.5 };
|
|
|
}
|
|
|
}
|
|
|
|
|
|
processEmotionResult(data) {
|
|
|
if (Array.isArray(data) && data[0]) {
|
|
|
const emotions = data[0];
|
|
|
const topEmotion = emotions.reduce((max, curr) =>
|
|
|
curr.score > max.score ? curr : max
|
|
|
);
|
|
|
return {
|
|
|
label: topEmotion.label,
|
|
|
score: topEmotion.score,
|
|
|
confidence: Math.round(topEmotion.score * 100)
|
|
|
};
|
|
|
}
|
|
|
return { label: 'neutral', score: 0.5, confidence: 50 };
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setupSentimentAnalysis() {
|
|
|
|
|
|
document.addEventListener('newsLoaded', async (e) => {
|
|
|
const newsItems = e.detail;
|
|
|
for (const item of newsItems) {
|
|
|
if (item.title && !item.sentiment) {
|
|
|
item.sentiment = await this.analyzeSentiment(item.title + ' ' + (item.description || ''));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
document.dispatchEvent(new CustomEvent('newsAnalyzed', { detail: newsItems }));
|
|
|
});
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setupNewsSummarization() {
|
|
|
document.addEventListener('newsLoaded', async (e) => {
|
|
|
const newsItems = e.detail;
|
|
|
for (const item of newsItems) {
|
|
|
if (item.description && item.description.length > 200 && !item.summary) {
|
|
|
item.summary = await this.summarizeNews(item.description, 100);
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setupEmotionDetection() {
|
|
|
|
|
|
window.detectEmotion = async (text) => {
|
|
|
return await this.detectEmotion(text);
|
|
|
};
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
getApiKey() {
|
|
|
|
|
|
return window.HF_API_KEY ||
|
|
|
(window.DASHBOARD_CONFIG && window.DASHBOARD_CONFIG.HF_TOKEN) ||
|
|
|
'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';
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
if (document.readyState === 'loading') {
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
|
window.hfIntegration = new HuggingFaceIntegration();
|
|
|
});
|
|
|
} else {
|
|
|
window.hfIntegration = new HuggingFaceIntegration();
|
|
|
}
|
|
|
|
|
|
|