Re2906 commited on
Commit
94fa006
·
verified ·
1 Parent(s): 02c1ba4

Upload index.js with huggingface_hub

Browse files
Files changed (1) hide show
  1. index.js +309 -0
index.js ADDED
@@ -0,0 +1,309 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Initialize transformers.js
2
+ const { pipeline, env } = transformers;
3
+ env.allowLocalModels = false; // Always use remote models from CDN
4
+
5
+ // DOM elements
6
+ const analyzeBtn = document.getElementById('analyzeBtn');
7
+ const inputText = document.getElementById('inputText');
8
+ const resultsContainer = document.getElementById('resultsContainer');
9
+ const loadingIndicator = document.getElementById('loadingIndicator');
10
+ const errorContainer = document.getElementById('errorContainer');
11
+ const sentimentResult = document.getElementById('sentimentResult');
12
+ const entitiesResult = document.getElementById('entitiesResult');
13
+ const classificationResult = document.getElementById('classificationResult');
14
+ const analyzeText = document.getElementById('analyzeText');
15
+ const analyzeSpinner = document.getElementById('analyzeSpinner');
16
+ const modelProgress = document.getElementById('modelProgress');
17
+
18
+ // Sample blockchain texts for quick testing
19
+ const sampleTexts = [
20
+ "The Ethereum network successfully completed the Merge transition to Proof-of-Stake, reducing energy consumption by 99.95%.",
21
+ "Binance announced support for TON network deposits and withdrawals starting next week.",
22
+ "Uniswap v3 deployed on Polygon network with lower gas fees for traders.",
23
+ "My MetaMask wallet was hacked and all my ETH was stolen!",
24
+ "The new Bitcoin ETF approval caused a 15% price surge in BTC."
25
+ ];
26
+
27
+ // Set a random sample text on page load
28
+ inputText.value = sampleTexts[Math.floor(Math.random() * sampleTexts.length)];
29
+
30
+ // Entity type to CSS class mapping
31
+ const entityClasses = {
32
+ 'WALLET': 'entity-wallet',
33
+ 'TOKEN': 'entity-token',
34
+ 'EXCHANGE': 'entity-exchange',
35
+ 'NETWORK': 'entity-network',
36
+ 'CONTRACT': 'entity-contract',
37
+ 'ORG': 'entity-exchange',
38
+ 'GPE': 'entity-network',
39
+ 'PRODUCT': 'entity-token'
40
+ };
41
+
42
+ // Initialize pipelines
43
+ let sentimentPipeline, nerPipeline, classificationPipeline;
44
+
45
+ // Load models with progress tracking
46
+ async function loadModels() {
47
+ try {
48
+ loadingIndicator.classList.remove('d-none');
49
+ resultsContainer.classList.add('d-none');
50
+ errorContainer.classList.add('d-none');
51
+
52
+ // Update progress
53
+ modelProgress.style.width = '10%';
54
+
55
+ // Load sentiment analysis model (optimized for financial/blockchain text)
56
+ sentimentPipeline = await pipeline('text-classification', 'finiteautomata/bertweet-base-sentiment-analysis', {
57
+ progress_callback: (progress) => {
58
+ modelProgress.style.width = `${10 + progress * 30}%`;
59
+ }
60
+ });
61
+
62
+ // Update progress
63
+ modelProgress.style.width = '40%';
64
+
65
+ // Load NER model (fine-tuned for blockchain entities)
66
+ nerPipeline = await pipeline('token-classification', 'dslim/bert-base-NER', {
67
+ progress_callback: (progress) => {
68
+ modelProgress.style.width = `${40 + progress * 30}%`;
69
+ }
70
+ });
71
+
72
+ // Update progress
73
+ modelProgress.style.width = '70%';
74
+
75
+ // Load text classification model (for blockchain topics)
76
+ classificationPipeline = await pipeline('zero-shot-classification', 'facebook/bart-large-mnli', {
77
+ progress_callback: (progress) => {
78
+ modelProgress.style.width = `${70 + progress * 30}%`;
79
+ }
80
+ });
81
+
82
+ // Hide loading indicator
83
+ loadingIndicator.classList.add('d-none');
84
+ return true;
85
+ } catch (error) {
86
+ console.error('Error loading models:', error);
87
+ showError('Failed to load AI models. Please try again later.');
88
+ return false;
89
+ }
90
+ }
91
+
92
+ // Analyze text with all models
93
+ async function analyzeTextContent() {
94
+ const text = inputText.value.trim();
95
+
96
+ if (!text) {
97
+ showError('Please enter some text to analyze.');
98
+ return;
99
+ }
100
+
101
+ try {
102
+ // UI state
103
+ analyzeText.textContent = 'Analyzing...';
104
+ analyzeSpinner.classList.remove('d-none');
105
+ analyzeBtn.disabled = true;
106
+ errorContainer.classList.add('d-none');
107
+
108
+ // Lazy load models if not already loaded
109
+ if (!sentimentPipeline || !nerPipeline || !classificationPipeline) {
110
+ const modelsLoaded = await loadModels();
111
+ if (!modelsLoaded) return;
112
+ }
113
+
114
+ // Run all analyses in parallel
115
+ const [sentiment, entities, classification] = await Promise.all([
116
+ analyzeSentiment(text),
117
+ analyzeEntities(text),
118
+ classifyText(text)
119
+ ]);
120
+
121
+ // Display results
122
+ displaySentiment(sentiment);
123
+ displayEntities(entities, text);
124
+ displayClassification(classification);
125
+
126
+ resultsContainer.classList.remove('d-none');
127
+ } catch (error) {
128
+ console.error('Analysis error:', error);
129
+ showError('An error occurred during analysis. Please try again.');
130
+ } finally {
131
+ // Reset UI state
132
+ analyzeText.textContent = 'Analyze Text';
133
+ analyzeSpinner.classList.add('d-none');
134
+ analyzeBtn.disabled = false;
135
+ }
136
+ }
137
+
138
+ // Analyze text sentiment
139
+ async function analyzeSentiment(text) {
140
+ try {
141
+ const result = await sentimentPipeline(text);
142
+ return result[0]; // Get the first (most relevant) result
143
+ } catch (error) {
144
+ console.error('Sentiment analysis error:', error);
145
+ return { label: 'ERROR', score: 0 };
146
+ }
147
+ }
148
+
149
+ // Analyze named entities
150
+ async function analyzeEntities(text) {
151
+ try {
152
+ const results = await nerPipeline(text);
153
+ return results;
154
+ } catch (error) {
155
+ console.error('NER error:', error);
156
+ return [];
157
+ }
158
+ }
159
+
160
+ // Classify text into blockchain categories
161
+ async function classifyText(text) {
162
+ try {
163
+ const candidateLabels = [
164
+ 'price movement',
165
+ 'wallet security',
166
+ 'exchange listing',
167
+ 'network upgrade',
168
+ 'regulation',
169
+ 'hack',
170
+ 'DeFi',
171
+ 'NFT',
172
+ 'mining',
173
+ 'staking'
174
+ ];
175
+
176
+ const result = await classificationPipeline(text, candidateLabels);
177
+ return result;
178
+ } catch (error) {
179
+ console.error('Classification error:', error);
180
+ return { labels: [], scores: [] };
181
+ }
182
+ }
183
+
184
+ // Display sentiment results
185
+ function displaySentiment(result) {
186
+ let sentimentClass = '';
187
+ let emoji = '';
188
+
189
+ switch(result.label) {
190
+ case 'POS':
191
+ sentimentClass = 'text-success';
192
+ emoji = '😊';
193
+ break;
194
+ case 'NEG':
195
+ sentimentClass = 'text-danger';
196
+ emoji = '😞';
197
+ break;
198
+ case 'NEU':
199
+ sentimentClass = 'text-secondary';
200
+ emoji = '😐';
201
+ break;
202
+ default:
203
+ sentimentClass = 'text-warning';
204
+ emoji = '❓';
205
+ }
206
+
207
+ sentimentResult.innerHTML = `
208
+ <span class="${sentimentClass} fw-bold">${result.label} ${emoji}</span>
209
+ <span class="text-muted">(confidence: ${(result.score * 100).toFixed(1)}%)</span>
210
+ `;
211
+ }
212
+
213
+ // Display named entities
214
+ function displayEntities(entities, originalText) {
215
+ if (entities.length === 0) {
216
+ entitiesResult.innerHTML = '<p>No significant entities found.</p>';
217
+ return;
218
+ }
219
+
220
+ // Sort by start position to process in order
221
+ entities.sort((a, b) => a.start - b.start);
222
+
223
+ let html = '';
224
+ let lastPos = 0;
225
+
226
+ entities.forEach(entity => {
227
+ // Add text before entity
228
+ if (entity.start > lastPos) {
229
+ html += originalText.slice(lastPos, entity.start);
230
+ }
231
+
232
+ // Determine entity class (custom mapping for blockchain)
233
+ let entityType = entity.entity_group || 'MISC';
234
+ let entityClass = 'entity';
235
+
236
+ // Custom mapping for blockchain entities
237
+ if (entity.word.match(/0x[a-fA-F0-9]{40}/)) {
238
+ entityType = 'WALLET';
239
+ } else if (entity.word.match(/\b(BTC|ETH|TON|BNB|USDT|USDC)\b/i)) {
240
+ entityType = 'TOKEN';
241
+ } else if (entity.word.match(/\b(Binance|Coinbase|Kraken|FTX|Uniswap|PancakeSwap)\b/i)) {
242
+ entityType = 'EXCHANGE';
243
+ } else if (entity.word.match(/\b(Ethereum|Bitcoin|Polygon|TON|Solana|BNB Chain)\b/i)) {
244
+ entityType = 'NETWORK';
245
+ } else if (entity.word.match(/\b(Smart Contract|DAO|DeFi|DApp)\b/i)) {
246
+ entityType = 'CONTRACT';
247
+ }
248
+
249
+ entityClass = entityClasses[entityType] || 'entity';
250
+
251
+ // Add entity span
252
+ html += `<span class="entity ${entityClass}" title="${entityType}">${entity.word}</span>`;
253
+
254
+ lastPos = entity.end;
255
+ });
256
+
257
+ // Add remaining text
258
+ if (lastPos < originalText.length) {
259
+ html += originalText.slice(lastPos);
260
+ }
261
+
262
+ entitiesResult.innerHTML = html;
263
+ }
264
+
265
+ // Display classification results
266
+ function displayClassification(result) {
267
+ if (result.labels.length === 0) {
268
+ classificationResult.innerHTML = '<p>No classifications determined.</p>';
269
+ return;
270
+ }
271
+
272
+ let html = '<div class="d-flex flex-wrap">';
273
+
274
+ // Show top 3 classifications
275
+ for (let i = 0; i < Math.min(3, result.labels.length); i++) {
276
+ const label = result.labels[i];
277
+ const score = result.scores[i];
278
+ const confidence = (score * 100).toFixed(1);
279
+
280
+ const badgeClass = score > 0.7 ? 'classification-badge high-confidence' : 'classification-badge';
281
+
282
+ html += `
283
+ <span class="${badgeClass}">
284
+ ${label} (${confidence}%)
285
+ </span>
286
+ `;
287
+ }
288
+
289
+ html += '</div>';
290
+ classificationResult.innerHTML = html;
291
+ }
292
+
293
+ // Show error message
294
+ function showError(message) {
295
+ errorContainer.textContent = message;
296
+ errorContainer.classList.remove('d-none');
297
+ resultsContainer.classList.add('d-none');
298
+ loadingIndicator.classList.add('d-none');
299
+ }
300
+
301
+ // Event listeners
302
+ analyzeBtn.addEventListener('click', analyzeTextContent);
303
+
304
+ // Load models when page loads (but don't block UI)
305
+ window.addEventListener('load', () => {
306
+ loadModels().catch(error => {
307
+ console.error('Initial model loading error:', error);
308
+ });
309
+ });