Really-amin commited on
Commit
edf738b
Β·
verified Β·
1 Parent(s): 6f5b87b

Upload 1067 files

Browse files
.vscode/settings.json CHANGED
@@ -1,447 +1,3 @@
1
  {
2
- // ============================================
3
- // TOKEN REDUCTION STRATEGY (PHASE 1)
4
- // ============================================
5
-
6
- // CRITICAL: Disable Memories (saves 4000+ tokens per request)
7
- "cursor.memories.enabled": false,
8
-
9
- // Limit context to reduce token usage
10
- "cursor.chat.includeCurrentFile": false,
11
- "cursor.chat.includeRecentChanges": false,
12
- "cursor.composer.maxContext": 8000,
13
-
14
- // Disable chat history to reduce context bloat
15
- "cursor.experimental.chatHistory": false,
16
-
17
- // Optimize codebase indexing - Limit files and exclude patterns
18
- "cursor.codebaseIndexing.maxFiles": 1000,
19
- "cursor.codebaseIndexing.excludePatterns": [
20
- "node_modules",
21
- "dist",
22
- "build",
23
- ".git",
24
- "*.log",
25
- "*.cache",
26
- "__pycache__",
27
- "*.pyc",
28
- ".pytest_cache",
29
- ".coverage"
30
- ],
31
-
32
- // Smart chat settings - Reduce background token use
33
- "cursor.chat.autoSuggest": false,
34
- "cursor.chat.streamResponse": true,
35
- "cursor.composer.autoApply": false,
36
-
37
- // ============================================
38
- // EXISTING CUSTOM SETTINGS (PRESERVED)
39
- // ============================================
40
- "git.ignoreLimitWarning": true,
41
- "geminicodeassist.agentYoloMode": true,
42
-
43
- // ============================================
44
- // CURSOR AGENT & AUTO-RUN SETTINGS
45
- // ============================================
46
-
47
- // VERIFIED CURSOR SETTINGS (Priority)
48
- "cursor.chat.autoRun": true,
49
- "cursor.agent.autoFix": true,
50
- "cursor.experimental.agentMode": true,
51
- "cursor.background.agents.enabled": true,
52
-
53
- // Enable Agent mode - Core AI assistant functionality
54
- "cursor.agent.enabled": true,
55
-
56
- // Auto-run mode - Agents execute automatically without confirmation
57
- "cursor.agent.autoRun": true,
58
-
59
- // Agent optimizations - Performance improvements for agent operations
60
- "cursor.agent.optimizations": true,
61
-
62
- // Agent context awareness - Better understanding of project context
63
- "cursor.agent.contextAwareness": true,
64
-
65
- // Agent experimental features - Access to beta/experimental AI features
66
- "cursor.agent.experimentalFeatures": true,
67
-
68
- // Agent max context window - REDUCED from 200000 to 8000 for token efficiency
69
- "cursor.agent.maxContextWindow": 8000,
70
-
71
- // Agent streaming responses - Real-time response streaming
72
- "cursor.agent.streaming": true,
73
-
74
- // Agent parallel operations - Allow multiple agent operations simultaneously
75
- "cursor.agent.parallelOperations": true,
76
-
77
- // ============================================
78
- // COMPOSER (AI CHAT) ADVANCED SETTINGS
79
- // ============================================
80
-
81
- // Enable Composer advanced features
82
- "cursor.composer.enabled": true,
83
-
84
- // Persist Agent mode selection across sessions
85
- "cursor.composer.persistAgentMode": true,
86
-
87
- // Auto-scroll in Composer for better UX
88
- "cursor.composer.autoScroll": true,
89
-
90
- // Allow edits outside context window
91
- "cursor.composer.allowOutsideContext": true,
92
-
93
- // Collapse pills to save space
94
- "cursor.composer.collapsePills": true,
95
-
96
- // Collapse code blocks for cleaner view
97
- "cursor.composer.collapseCodeBlocks": true,
98
-
99
- // Iterative error fixing - Fix errors automatically
100
- "cursor.composer.iterativeErrorFixing": true,
101
-
102
- // Composer auto-suggest - DISABLED to reduce token use
103
- "cursor.composer.autoSuggest": false,
104
-
105
- // Composer inline editing - Edit code directly in chat
106
- "cursor.composer.inlineEditing": true,
107
-
108
- // Composer multi-file editing - Edit multiple files simultaneously
109
- "cursor.composer.multiFileEditing": true,
110
-
111
- // Composer context window - REDUCED from 200000 to 8000 for token efficiency
112
- "cursor.composer.maxContextWindow": 8000,
113
-
114
- // Composer experimental features - Beta features for Composer
115
- "cursor.composer.experimentalFeatures": true,
116
-
117
- // Composer streaming - Stream responses in real-time
118
- "cursor.composer.streaming": true,
119
-
120
- // Composer code actions - Enable code actions in Composer
121
- "cursor.composer.codeActions": true,
122
-
123
- // ============================================
124
- // CODE COMPLETION & INLINE SUGGESTIONS
125
- // ============================================
126
-
127
- // Enable inline code suggestions
128
- "editor.inlineSuggest.enabled": true,
129
-
130
- // Show inline suggestions automatically
131
- "editor.inlineSuggest.showToolbar": "always",
132
-
133
- // Enable AI-powered code completion
134
- "editor.suggest.preview": true,
135
-
136
- // Enhanced code completion with AI
137
- "editor.suggest.showKeywords": true,
138
-
139
- // Code completion delay (ms) - Lower for faster suggestions
140
- "editor.quickSuggestionsDelay": 100,
141
-
142
- // Enable parameter hints
143
- "editor.parameterHints.enabled": true,
144
-
145
- // Enable AI-enhanced autocomplete
146
- "cursor.autocomplete.enabled": true,
147
-
148
- // Autocomplete delay (ms)
149
- "cursor.autocomplete.delay": 100,
150
-
151
- // Autocomplete max suggestions
152
- "cursor.autocomplete.maxSuggestions": 10,
153
-
154
- // VERIFIED CURSOR SETTING (Priority)
155
- "cursor.codeCompletion.enabled": true,
156
-
157
- // Enable code completion enhancements
158
- "cursor.codeCompletion.enhancements": true,
159
-
160
- // Context-aware code completion
161
- "cursor.codeCompletion.contextAware": true,
162
-
163
- // ============================================
164
- // TERMINAL AI FEATURES
165
- // ============================================
166
-
167
- // VERIFIED CURSOR SETTING (Priority)
168
- "cursor.terminal.ai.enabled": true,
169
-
170
- // Show AI hover tips in terminal
171
- "cursor.terminal.aiHoverTips": true,
172
-
173
- // Preview terminal output before execution
174
- "cursor.terminal.previewBox": true,
175
-
176
- // Enable terminal AI integration (legacy format)
177
- "cursor.terminal.aiEnabled": true,
178
-
179
- // Terminal AI auto-complete commands
180
- "cursor.terminal.aiAutoComplete": true,
181
-
182
- // Terminal AI suggestions
183
- "cursor.terminal.aiSuggestions": true,
184
-
185
- // Terminal AI error detection
186
- "cursor.terminal.aiErrorDetection": true,
187
-
188
- // Terminal AI command explanation
189
- "cursor.terminal.aiCommandExplanation": true,
190
-
191
- // Integrated terminal AI features
192
- "terminal.integrated.enableAI": true,
193
-
194
- // Terminal AI context awareness
195
- "cursor.terminal.aiContextAware": true,
196
-
197
- // ============================================
198
- // YOLO MODE (TERMINAL AUTOMATION) - TOKEN OPTIMIZED
199
- // ============================================
200
-
201
- // Enable YOLO mode for automatic terminal command execution
202
- // Optimized command list for token efficiency
203
- "cursor.terminal.yoloMode": true,
204
-
205
- // Command allow list for YOLO mode - Token efficient commands only
206
- "cursor.yolo.allowedCommands": [
207
- "git status",
208
- "git add",
209
- "git commit",
210
- "npm test",
211
- "npm run build",
212
- "python -m pytest",
213
- "ls",
214
- "cat",
215
- "mkdir",
216
- "touch"
217
- ],
218
-
219
- // Block dangerous commands automatically
220
- "cursor.yolo.blockDangerousCommands": true,
221
-
222
- // Require confirmation for high-risk operations
223
- "cursor.yolo.requireConfirmation": [
224
- "git push",
225
- "rm",
226
- "del",
227
- "install",
228
- "deploy"
229
- ],
230
-
231
- // Legacy YOLO settings (preserved for compatibility)
232
- "cursor.terminal.yoloModeAllowedCommands": [
233
- "npm",
234
- "pnpm",
235
- "yarn",
236
- "git",
237
- "mkdir",
238
- "touch",
239
- "ls",
240
- "cat",
241
- "pytest",
242
- "python"
243
- ],
244
- "cursor.terminal.yoloModeDeleteProtection": true,
245
-
246
- // ============================================
247
- // ERROR DETECTION & AUTO-FIX
248
- // ============================================
249
-
250
- // Enable automatic error detection
251
- "cursor.errors.autoDetect": true,
252
-
253
- // Auto-fix on save
254
- "editor.codeActionsOnSave": {
255
- "source.fixAll": "explicit",
256
- "source.organizeImports": "explicit"
257
- },
258
-
259
- // Enable AI-powered error fixes
260
- "cursor.errors.aiFix": true,
261
-
262
- // Auto-fix linting errors
263
- "cursor.errors.autoFixLinting": true,
264
-
265
- // Error detection sensitivity
266
- "cursor.errors.detectionSensitivity": "high",
267
-
268
- // ============================================
269
- // CONTEXT AWARENESS & INTELLIGENCE
270
- // ============================================
271
-
272
- // Enhanced context awareness
273
- "cursor.contextAwareness.enabled": true,
274
-
275
- // Project-wide context understanding
276
- "cursor.contextAwareness.projectWide": true,
277
-
278
- // Codebase indexing for better context
279
- "cursor.contextAwareness.indexing": true,
280
-
281
- // Semantic code understanding
282
- "cursor.contextAwareness.semantic": true,
283
-
284
- // Cross-file context awareness
285
- "cursor.contextAwareness.crossFile": true,
286
-
287
- // Git context awareness
288
- "cursor.contextAwareness.git": true,
289
-
290
- // ============================================
291
- // CODEBASE INDEXING
292
- // ============================================
293
-
294
- // Enable codebase indexing for better AI understanding
295
- "cursor.codebaseIndexing.enabled": true,
296
-
297
- // Auto-index new files as they're created
298
- "cursor.codebaseIndexing.autoIndex": true,
299
-
300
- // Include git history in indexing
301
- "cursor.codebaseIndexing.includeGitHistory": true,
302
-
303
- // ============================================
304
- // AI MODEL & PERFORMANCE SETTINGS
305
- // ============================================
306
-
307
- // Enable advanced AI models
308
- "cursor.ai.advancedModels": true,
309
-
310
- // AI response speed optimization
311
- "cursor.ai.optimizeSpeed": true,
312
-
313
- // AI caching for faster responses
314
- "cursor.ai.caching": true,
315
-
316
- // AI model selection (auto = best model for task)
317
- "cursor.ai.model": "auto",
318
-
319
- // Enable AI streaming
320
- "cursor.ai.streaming": true,
321
-
322
- // AI temperature (creativity) - 0.0 to 1.0
323
- "cursor.ai.temperature": 0.7,
324
-
325
- // AI max tokens per request
326
- "cursor.ai.maxTokens": 8000,
327
-
328
- // ============================================
329
- // CODE GENERATION & REFACTORING
330
- // ============================================
331
-
332
- // Enable AI code generation
333
- "cursor.codeGeneration.enabled": true,
334
-
335
- // Auto-generate code suggestions
336
- "cursor.codeGeneration.autoSuggest": true,
337
-
338
- // Enable AI refactoring
339
- "cursor.refactoring.aiEnabled": true,
340
-
341
- // AI-powered code explanations
342
- "cursor.codeExplanations.enabled": true,
343
-
344
- // Generate tests automatically
345
- "cursor.testGeneration.enabled": true,
346
-
347
- // Generate documentation automatically
348
- "cursor.documentationGeneration.enabled": true,
349
-
350
- // ============================================
351
- // FILE & SEARCH AI FEATURES
352
- // ============================================
353
-
354
- // AI-powered file search
355
- "cursor.search.aiEnabled": true,
356
-
357
- // Semantic code search
358
- "cursor.search.semantic": true,
359
-
360
- // AI file recommendations
361
- "cursor.files.aiRecommendations": true,
362
-
363
- // Smart file navigation
364
- "cursor.navigation.aiEnabled": true,
365
-
366
- // ============================================
367
- // EXPERIMENTAL & BETA FEATURES
368
- // ============================================
369
-
370
- // Enable experimental features
371
- "cursor.experimental.enabled": true,
372
-
373
- // Experimental AI features
374
- "cursor.experimental.aiFeatures": true,
375
-
376
- // Experimental agent features
377
- "cursor.experimental.agentFeatures": true,
378
-
379
- // Beta code completion
380
- "cursor.experimental.betaCompletion": true,
381
-
382
- // Experimental context features
383
- "cursor.experimental.contextFeatures": true,
384
-
385
- // ============================================
386
- // WORKSPACE & PROJECT SETTINGS
387
- // ============================================
388
-
389
- // Enable workspace-wide AI features
390
- "cursor.workspace.aiEnabled": true,
391
-
392
- // Project-specific AI context
393
- "cursor.workspace.projectContext": true,
394
-
395
- // Auto-index project for AI
396
- "cursor.workspace.autoIndex": true,
397
-
398
- // Index all file types
399
- "cursor.workspace.indexAllTypes": true,
400
-
401
- // ============================================
402
- // EDITOR ENHANCEMENTS
403
- // ============================================
404
-
405
- // Enable AI-powered editor features
406
- "cursor.editor.aiEnabled": true,
407
-
408
- // Show inline diffs for changes
409
- "cursor.editor.inlineDiff": true,
410
-
411
- // Auto-resolve links in code
412
- "cursor.editor.autoResolveLinks": true,
413
-
414
- // Auto-select code regions for better editing
415
- "cursor.editor.autoSelectRegions": true,
416
-
417
- // Show chat tooltips in editor
418
- "cursor.editor.chatTooltips": true,
419
-
420
- // Smart code formatting
421
- "cursor.editor.smartFormatting": true,
422
-
423
- // AI-powered code navigation
424
- "cursor.editor.aiNavigation": true,
425
-
426
- // Enhanced syntax highlighting
427
- "cursor.editor.enhancedHighlighting": true,
428
-
429
- // AI code review suggestions
430
- "cursor.editor.aiCodeReview": true,
431
-
432
- // ============================================
433
- // PERFORMANCE & OPTIMIZATION
434
- // ============================================
435
-
436
- // Enable performance optimizations
437
- "cursor.performance.optimizations": true,
438
-
439
- // Background indexing
440
- "cursor.performance.backgroundIndexing": true,
441
-
442
- // Lazy loading for large projects
443
- "cursor.performance.lazyLoading": true,
444
-
445
- // Cache AI responses
446
- "cursor.performance.cacheResponses": true
447
- }
 
1
  {
2
+ "git.ignoreLimitWarning": true
3
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
README.md CHANGED
@@ -1,10 +1,3 @@
1
- ---
2
- sdk: docker
3
- emoji: πŸ“š
4
- colorFrom: yellow
5
- colorTo: red
6
- pinned: true
7
- ---
8
  # πŸš€ Crypto Intelligence Hub
9
 
10
  <div align="center">
@@ -387,4 +380,4 @@ python test_app.py
387
 
388
  ⭐ Ψ§Ϊ―Ψ± Ψ§ΫŒΩ† ΩΎΨ±ΩˆΪ˜Ω‡ Ψ±Ψ§ دوسΨͺ Ψ―Ψ§Ψ΄Ψͺید، یک Ψ³ΨͺΨ§Ψ±Ω‡ Ψ¨Ψ―Ω‡ΫŒΨ―!
389
 
390
- </div>
 
 
 
 
 
 
 
 
1
  # πŸš€ Crypto Intelligence Hub
2
 
3
  <div align="center">
 
380
 
381
  ⭐ Ψ§Ϊ―Ψ± Ψ§ΫŒΩ† ΩΎΨ±ΩˆΪ˜Ω‡ Ψ±Ψ§ دوسΨͺ Ψ―Ψ§Ψ΄Ψͺید، یک Ψ³ΨͺΨ§Ψ±Ω‡ Ψ¨Ψ―Ω‡ΫŒΨ―!
382
 
383
+ </div>
__pycache__/fastapi_app.cpython-313.pyc ADDED
Binary file (22.8 kB). View file
 
assets/c__Users_Dreammaker_AppData_Roaming_Cursor_User_workspaceStorage_9183355a9fc05f1a46154d627a413150_images_image-262e1f0a-e50a-4dc5-811c-95f4c6785a6a.png ADDED
fastapi_app.py CHANGED
@@ -6,6 +6,7 @@ Optimized for high performance with async support
6
  import os
7
  import sys
8
  import logging
 
9
  from datetime import datetime
10
  from functools import lru_cache
11
  import time
@@ -330,15 +331,214 @@ async def sentiment_global():
330
  except:
331
  return {'sentiment': 'neutral', 'fear_greed_index': 50}
332
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
333
  @app.get("/api/models/status")
334
  async def models_status():
335
- """Models status"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
336
  return {
337
- 'models_loaded': 2,
338
- 'total_models': 74,
 
 
339
  'status': 'ready'
340
  }
341
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
342
  @app.get("/api/news/latest")
343
  async def news_latest(limit: int = 6):
344
  """Get latest news"""
@@ -472,6 +672,304 @@ async def resources_stats():
472
  }
473
  }
474
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
475
  # Startup event
476
  @app.on_event("startup")
477
  async def startup_event():
 
6
  import os
7
  import sys
8
  import logging
9
+ import json
10
  from datetime import datetime
11
  from functools import lru_cache
12
  import time
 
331
  except:
332
  return {'sentiment': 'neutral', 'fear_greed_index': 50}
333
 
334
+ def _load_real_resources():
335
+ """Load real API resources from JSON file"""
336
+ import json
337
+
338
+ resources_file = Path(__file__).parent / 'crypto_resources_unified_2025-11-11.json'
339
+ if not resources_file.exists():
340
+ # Try alternative path
341
+ resources_file = Path(__file__).parent / 'api-resources' / 'crypto_resources_unified_2025-11-11.json'
342
+
343
+ if not resources_file.exists():
344
+ logger.warning(f"Resources file not found: {resources_file}")
345
+ return None
346
+
347
+ try:
348
+ with open(resources_file, 'r', encoding='utf-8') as f:
349
+ data = json.load(f)
350
+ return data.get('registry', {})
351
+ except Exception as e:
352
+ logger.error(f"Error loading resources file: {e}")
353
+ return None
354
+
355
  @app.get("/api/models/status")
356
  async def models_status():
357
+ """AI Models status - Returns REAL available AI/ML models and APIs from JSON"""
358
+ registry = _load_real_resources()
359
+
360
+ if not registry:
361
+ return {
362
+ 'models_loaded': 0,
363
+ 'models': [],
364
+ 'total_models': 0,
365
+ 'active_models': 0,
366
+ 'status': 'error',
367
+ 'error': 'Resources file not found'
368
+ }
369
+
370
+ models = []
371
+
372
+ # Extract real models/APIs from registry
373
+ for node in registry.get('rpc_nodes', []):
374
+ models.append({
375
+ 'name': node.get('name', node.get('id', 'Unknown')),
376
+ 'model': node.get('id', ''),
377
+ 'status': 'ready',
378
+ 'provider': node.get('chain', 'RPC Node')
379
+ })
380
+
381
+ for explorer in registry.get('block_explorers', []):
382
+ models.append({
383
+ 'name': explorer.get('name', explorer.get('id', 'Unknown')),
384
+ 'model': explorer.get('id', ''),
385
+ 'status': 'ready',
386
+ 'provider': explorer.get('chain', 'Block Explorer')
387
+ })
388
+
389
+ for api in registry.get('market_data_apis', []):
390
+ models.append({
391
+ 'name': api.get('name', api.get('id', 'Unknown')),
392
+ 'model': api.get('id', ''),
393
+ 'status': 'ready',
394
+ 'provider': api.get('category', 'Market Data')
395
+ })
396
+
397
+ for api in registry.get('news_apis', []):
398
+ models.append({
399
+ 'name': api.get('name', api.get('id', 'Unknown')),
400
+ 'model': api.get('id', ''),
401
+ 'status': 'ready',
402
+ 'provider': 'News'
403
+ })
404
+
405
+ for api in registry.get('sentiment_apis', []):
406
+ models.append({
407
+ 'name': api.get('name', api.get('id', 'Unknown')),
408
+ 'model': api.get('id', ''),
409
+ 'status': 'ready',
410
+ 'provider': 'Sentiment'
411
+ })
412
+
413
+ for api in registry.get('onchain_analytics_apis', []):
414
+ models.append({
415
+ 'name': api.get('name', api.get('id', 'Unknown')),
416
+ 'model': api.get('id', ''),
417
+ 'status': 'ready',
418
+ 'provider': 'On-chain Analytics'
419
+ })
420
+
421
+ for hf in registry.get('hf_models_datasets', []):
422
+ models.append({
423
+ 'name': hf.get('name', hf.get('id', 'Unknown')),
424
+ 'model': hf.get('id', ''),
425
+ 'status': 'ready',
426
+ 'provider': 'Hugging Face'
427
+ })
428
+
429
  return {
430
+ 'models_loaded': len(models),
431
+ 'models': models,
432
+ 'total_models': len(models),
433
+ 'active_models': len(models),
434
  'status': 'ready'
435
  }
436
 
437
+ @app.get("/api/models/list")
438
+ async def models_list():
439
+ """AI Models list (alias for /api/models/status)"""
440
+ return await models_status()
441
+
442
+ @app.get("/api/models")
443
+ async def models():
444
+ """AI Models endpoint (alias for /api/models/status)"""
445
+ return await models_status()
446
+
447
+ @app.get("/api/models/summary")
448
+ async def models_summary():
449
+ """AI Models summary - Returns summary with counts and status"""
450
+ registry = _load_real_resources()
451
+
452
+ if not registry:
453
+ return {
454
+ 'success': False,
455
+ 'error': True,
456
+ 'message': 'Resources file not found',
457
+ 'categories': {},
458
+ 'models': [],
459
+ 'summary': {
460
+ 'total_models': 0,
461
+ 'loaded_models': 0,
462
+ 'failed_models': 0,
463
+ 'hf_mode': 'unavailable',
464
+ 'transformers_available': False
465
+ }
466
+ }
467
+
468
+ # Count models by category
469
+ categories = {}
470
+ all_models = []
471
+
472
+ # Process all categories
473
+ for category_key in registry:
474
+ if category_key == 'metadata':
475
+ continue
476
+
477
+ items = registry.get(category_key, [])
478
+ if not items:
479
+ continue
480
+
481
+ category_name = category_key.replace('_', ' ').title()
482
+ categories[category_key] = {
483
+ 'total': len(items),
484
+ 'active': len(items),
485
+ 'name': category_name
486
+ }
487
+
488
+ # Add to all models list
489
+ for item in items:
490
+ all_models.append({
491
+ 'id': item.get('id', item.get('name', 'Unknown')),
492
+ 'name': item.get('name', item.get('id', 'Unknown')),
493
+ 'category': category_key,
494
+ 'status': 'ready',
495
+ 'provider': item.get('provider', item.get('chain', category_name))
496
+ })
497
+
498
+ return {
499
+ 'success': True,
500
+ 'error': False,
501
+ 'categories': categories,
502
+ 'models': all_models,
503
+ 'summary': {
504
+ 'total_models': len(all_models),
505
+ 'loaded_models': len(all_models),
506
+ 'failed_models': 0,
507
+ 'hf_mode': os.getenv('HF_MODE', 'public'),
508
+ 'transformers_available': True
509
+ }
510
+ }
511
+
512
+ @app.get("/models/summary")
513
+ async def models_summary_legacy():
514
+ """Legacy endpoint - redirect to /api/models/summary"""
515
+ from fastapi.responses import RedirectResponse
516
+ return RedirectResponse(url='/api/models/summary', status_code=301)
517
+
518
+ @app.post("/api/models/reinitialize")
519
+ @app.post("/api/models/reinit-all")
520
+ async def models_reinitialize():
521
+ """Re-initialize all models - Returns success message"""
522
+ registry = _load_real_resources()
523
+
524
+ if registry:
525
+ total_models = sum(len(items) for key, items in registry.items() if key != 'metadata')
526
+ return {
527
+ 'success': True,
528
+ 'message': f'Models re-initialized successfully. {total_models} models loaded.',
529
+ 'models_loaded': total_models,
530
+ 'status': 'completed'
531
+ }
532
+ else:
533
+ return JSONResponse(
534
+ status_code=500,
535
+ content={
536
+ 'success': False,
537
+ 'message': 'Failed to reload models. Resources file not found.',
538
+ 'status': 'error'
539
+ }
540
+ )
541
+
542
  @app.get("/api/news/latest")
543
  async def news_latest(limit: int = 6):
544
  """Get latest news"""
 
672
  }
673
  }
674
 
675
+ @app.get("/api/providers")
676
+ async def get_providers():
677
+ """
678
+ Get list of API providers with status and details
679
+ Returns comprehensive information about available data providers
680
+ """
681
+ providers = [
682
+ {
683
+ 'id': 'coingecko',
684
+ 'name': 'CoinGecko',
685
+ 'endpoint': 'api.coingecko.com/api/v3',
686
+ 'category': 'Market Data',
687
+ 'status': 'active',
688
+ 'type': 'free',
689
+ 'rate_limit': '50 calls/min',
690
+ 'uptime': '99.9%',
691
+ 'description': 'Comprehensive cryptocurrency data including prices, market caps, and historical data'
692
+ },
693
+ {
694
+ 'id': 'binance',
695
+ 'name': 'Binance',
696
+ 'endpoint': 'api.binance.com/api/v3',
697
+ 'category': 'Market Data',
698
+ 'status': 'active',
699
+ 'type': 'free',
700
+ 'rate_limit': '1200 calls/min',
701
+ 'uptime': '99.9%',
702
+ 'description': 'Real-time trading data and market information from Binance exchange'
703
+ },
704
+ {
705
+ 'id': 'alternative_me',
706
+ 'name': 'Alternative.me',
707
+ 'endpoint': 'api.alternative.me/fng',
708
+ 'category': 'Sentiment',
709
+ 'status': 'active',
710
+ 'type': 'free',
711
+ 'rate_limit': 'Unlimited',
712
+ 'uptime': '99.5%',
713
+ 'description': 'Crypto Fear & Greed Index - Market sentiment indicator'
714
+ },
715
+ {
716
+ 'id': 'cryptopanic',
717
+ 'name': 'CryptoPanic',
718
+ 'endpoint': 'cryptopanic.com/api/v1',
719
+ 'category': 'News',
720
+ 'status': 'active',
721
+ 'type': 'free',
722
+ 'rate_limit': '100 calls/day',
723
+ 'uptime': '98.5%',
724
+ 'description': 'Cryptocurrency news aggregation from multiple sources'
725
+ },
726
+ {
727
+ 'id': 'huggingface',
728
+ 'name': 'Hugging Face',
729
+ 'endpoint': 'api-inference.huggingface.co',
730
+ 'category': 'AI & ML',
731
+ 'status': 'active',
732
+ 'type': 'free',
733
+ 'rate_limit': '1000 calls/day',
734
+ 'uptime': '99.8%',
735
+ 'description': 'AI-powered sentiment analysis and NLP models'
736
+ },
737
+ {
738
+ 'id': 'coinpaprika',
739
+ 'name': 'CoinPaprika',
740
+ 'endpoint': 'api.coinpaprika.com/v1',
741
+ 'category': 'Market Data',
742
+ 'status': 'active',
743
+ 'type': 'free',
744
+ 'rate_limit': '25000 calls/month',
745
+ 'uptime': '99.7%',
746
+ 'description': 'Cryptocurrency market data and analytics'
747
+ },
748
+ {
749
+ 'id': 'messari',
750
+ 'name': 'Messari',
751
+ 'endpoint': 'data.messari.io/api/v1',
752
+ 'category': 'Analytics',
753
+ 'status': 'active',
754
+ 'type': 'free',
755
+ 'rate_limit': '20 calls/min',
756
+ 'uptime': '99.5%',
757
+ 'description': 'Crypto research and market intelligence data'
758
+ }
759
+ ]
760
+
761
+ return {
762
+ 'providers': providers,
763
+ 'total': len(providers),
764
+ 'active': len([p for p in providers if p['status'] == 'active']),
765
+ 'timestamp': datetime.utcnow().isoformat()
766
+ }
767
+
768
+ @app.get("/api/providers/{provider_name}/health")
769
+ async def get_provider_health(provider_name: str):
770
+ """
771
+ Check health status of a specific provider
772
+ Tests actual connectivity to the provider's API
773
+ """
774
+ import requests as req
775
+ from urllib.parse import unquote
776
+
777
+ # Decode URL-encoded provider name
778
+ provider_name = unquote(provider_name)
779
+
780
+ # Map provider names to test endpoints
781
+ test_endpoints = {
782
+ 'CoinGecko': 'https://api.coingecko.com/api/v3/ping',
783
+ 'Binance': 'https://api.binance.com/api/v3/ping',
784
+ 'Alternative.me': 'https://api.alternative.me/fng/?limit=1',
785
+ 'CryptoPanic': 'https://cryptopanic.com/api/v1/posts/?public=true',
786
+ 'Hugging Face': 'https://huggingface.co',
787
+ 'CoinPaprika': 'https://api.coinpaprika.com/v1/tickers/btc-bitcoin',
788
+ 'Messari': 'https://data.messari.io/api/v1/assets/btc/metrics'
789
+ }
790
+
791
+ endpoint = test_endpoints.get(provider_name)
792
+
793
+ if not endpoint:
794
+ return JSONResponse(
795
+ status_code=404,
796
+ content={
797
+ 'status': 'unknown',
798
+ 'provider': provider_name,
799
+ 'error': 'Provider not found',
800
+ 'available': False
801
+ }
802
+ )
803
+
804
+ try:
805
+ start_time = time.time()
806
+ response = req.get(endpoint, timeout=5)
807
+ response_time = int((time.time() - start_time) * 1000)
808
+
809
+ if response.status_code == 200:
810
+ return {
811
+ 'status': 'healthy',
812
+ 'provider': provider_name,
813
+ 'available': True,
814
+ 'response_time_ms': response_time,
815
+ 'http_code': response.status_code,
816
+ 'tested_at': datetime.utcnow().isoformat()
817
+ }
818
+ else:
819
+ return {
820
+ 'status': 'degraded',
821
+ 'provider': provider_name,
822
+ 'available': True,
823
+ 'response_time_ms': response_time,
824
+ 'http_code': response.status_code,
825
+ 'tested_at': datetime.utcnow().isoformat()
826
+ }
827
+ except req.exceptions.Timeout:
828
+ return {
829
+ 'status': 'timeout',
830
+ 'provider': provider_name,
831
+ 'available': False,
832
+ 'error': 'Request timeout after 5 seconds',
833
+ 'tested_at': datetime.utcnow().isoformat()
834
+ }
835
+ except Exception as e:
836
+ return {
837
+ 'status': 'error',
838
+ 'provider': provider_name,
839
+ 'available': False,
840
+ 'error': str(e),
841
+ 'tested_at': datetime.utcnow().isoformat()
842
+ }
843
+
844
+ @app.post("/api/sentiment/analyze")
845
+ async def sentiment_analyze(request: Request):
846
+ """Analyze sentiment for given text"""
847
+ try:
848
+ body = await request.json()
849
+ text = body.get('text', '')
850
+
851
+ if not text:
852
+ return {
853
+ 'success': False,
854
+ 'error': 'No text provided'
855
+ }
856
+
857
+ # Simple keyword-based sentiment analysis
858
+ text_lower = text.lower()
859
+
860
+ bullish_keywords = ['bullish', 'pump', 'moon', 'buy', 'rally', 'surge', 'breakout', 'profit', 'gain', 'up', 'rise', 'high']
861
+ bearish_keywords = ['bearish', 'dump', 'crash', 'sell', 'drop', 'fall', 'loss', 'down', 'decline', 'low']
862
+
863
+ bullish_count = sum(1 for word in bullish_keywords if word in text_lower)
864
+ bearish_count = sum(1 for word in bearish_keywords if word in text_lower)
865
+
866
+ if bullish_count > bearish_count:
867
+ sentiment = 'bullish'
868
+ confidence = min(0.6 + (bullish_count - bearish_count) * 0.1, 0.95)
869
+ elif bearish_count > bullish_count:
870
+ sentiment = 'bearish'
871
+ confidence = min(0.6 + (bearish_count - bullish_count) * 0.1, 0.95)
872
+ else:
873
+ sentiment = 'neutral'
874
+ confidence = 0.5
875
+
876
+ return {
877
+ 'success': True,
878
+ 'sentiment': sentiment,
879
+ 'confidence': confidence,
880
+ 'label': sentiment,
881
+ 'score': confidence,
882
+ 'analysis': {
883
+ 'bullish_signals': bullish_count,
884
+ 'bearish_signals': bearish_count,
885
+ 'text_length': len(text)
886
+ }
887
+ }
888
+ except Exception as e:
889
+ return {
890
+ 'success': False,
891
+ 'error': str(e),
892
+ 'sentiment': 'neutral',
893
+ 'confidence': 0.5
894
+ }
895
+
896
+ @app.post("/api/ai/decision")
897
+ async def ai_decision(request: Request):
898
+ """AI trading decision based on market data and sentiment"""
899
+ try:
900
+ body = await request.json()
901
+ symbol = body.get('symbol', 'BTC')
902
+ price = body.get('price', 50000)
903
+ change_24h = body.get('change_24h', 0)
904
+ volume = body.get('volume', 0)
905
+ sentiment = body.get('sentiment', 'neutral')
906
+
907
+ # Simple rule-based decision logic
908
+ decision = 'HOLD'
909
+ confidence = 0.5
910
+ reasoning = []
911
+
912
+ # Price change analysis
913
+ if change_24h > 5:
914
+ decision = 'BUY'
915
+ confidence += 0.15
916
+ reasoning.append(f'Strong upward momentum (+{change_24h:.2f}%)')
917
+ elif change_24h < -5:
918
+ decision = 'SELL'
919
+ confidence += 0.15
920
+ reasoning.append(f'Strong downward momentum ({change_24h:.2f}%)')
921
+ elif abs(change_24h) < 2:
922
+ reasoning.append('Price is stable')
923
+
924
+ # Sentiment analysis
925
+ if sentiment == 'bullish':
926
+ if decision == 'SELL':
927
+ confidence -= 0.1
928
+ reasoning.append('Bullish sentiment conflicts with price action')
929
+ else:
930
+ decision = 'BUY'
931
+ confidence += 0.1
932
+ reasoning.append('Bullish market sentiment')
933
+ elif sentiment == 'bearish':
934
+ if decision == 'BUY':
935
+ confidence -= 0.1
936
+ reasoning.append('Bearish sentiment conflicts with price action')
937
+ else:
938
+ decision = 'SELL'
939
+ confidence += 0.1
940
+ reasoning.append('Bearish market sentiment')
941
+
942
+ # Volume analysis
943
+ if volume > 1000000000:
944
+ confidence += 0.05
945
+ reasoning.append('High trading volume indicates strong interest')
946
+
947
+ # Ensure confidence is between 0 and 1
948
+ confidence = max(0.3, min(0.95, confidence))
949
+
950
+ return {
951
+ 'success': True,
952
+ 'decision': decision,
953
+ 'confidence': confidence,
954
+ 'reasoning': reasoning,
955
+ 'symbol': symbol,
956
+ 'price': price,
957
+ 'analysis': {
958
+ 'price_action': 'bullish' if change_24h > 0 else 'bearish' if change_24h < 0 else 'neutral',
959
+ 'sentiment': sentiment,
960
+ 'volume_level': 'high' if volume > 1000000000 else 'medium' if volume > 100000000 else 'low'
961
+ },
962
+ 'timestamp': datetime.utcnow().isoformat()
963
+ }
964
+ except Exception as e:
965
+ return {
966
+ 'success': False,
967
+ 'error': str(e),
968
+ 'decision': 'HOLD',
969
+ 'confidence': 0.5,
970
+ 'reasoning': ['Error analyzing market conditions']
971
+ }
972
+
973
  # Startup event
974
  @app.on_event("startup")
975
  async def startup_event():
main.py CHANGED
@@ -25,7 +25,7 @@ werkzeug_available = False
25
 
26
  try:
27
  from fastapi import FastAPI
28
- from fastapi.responses import RedirectResponse
29
  from fastapi.staticfiles import StaticFiles
30
  from fastapi.middleware.cors import CORSMiddleware
31
  # Try to import WSGIMiddleware
@@ -79,37 +79,33 @@ app.add_middleware(
79
  allow_headers=["*"],
80
  )
81
 
82
- # Mount Flask app if available
83
  if flask_available:
84
- try:
85
- if wsgi_middleware_available:
86
- # Mount Flask app at root using FastAPI WSGIMiddleware
87
- # This ensures all Flask routes (including /) are properly handled
88
- app.mount("/", WSGIMiddleware(flask_app))
89
- logger.info("βœ… Flask app mounted via FastAPI WSGIMiddleware")
90
- logger.info(" - Flask route '/' will serve HTML from splash.html")
91
- logger.info(" - All Flask routes are now accessible through FastAPI")
92
- elif werkzeug_available:
93
- # Alternative: Use werkzeug DispatcherMiddleware
94
- from werkzeug.middleware.dispatcher import DispatcherMiddleware
95
- app.mount("/", DispatcherMiddleware(flask_app))
96
- logger.info("βœ… Flask app mounted via Werkzeug DispatcherMiddleware")
97
- else:
98
- # Direct integration: Import Flask routes as FastAPI routes
99
- logger.info("⚠️ WSGI middleware not available, using direct route integration")
100
- flask_available = False
101
- except Exception as e:
102
- logger.error(f"❌ Failed to mount Flask app: {e}")
103
- import traceback
104
- traceback.print_exc()
105
- flask_available = False
106
 
107
  # Fallback routes if Flask is not available
108
  if not flask_available:
109
- @app.get("/")
 
 
110
  async def root():
111
- """Root endpoint - redirect to splash"""
112
- return RedirectResponse(url="/static/splash.html", status_code=302)
 
 
 
 
 
 
 
 
 
 
 
 
113
 
114
  @app.get("/health")
115
  async def health():
@@ -131,6 +127,12 @@ if not flask_available:
131
  "timestamp": str(Path(__file__).stat().st_mtime)
132
  }
133
 
 
 
 
 
 
 
134
  logger.info("βœ… Fallback FastAPI routes created")
135
 
136
  # Export app for uvicorn
 
25
 
26
  try:
27
  from fastapi import FastAPI
28
+ from fastapi.responses import RedirectResponse, HTMLResponse, FileResponse
29
  from fastapi.staticfiles import StaticFiles
30
  from fastapi.middleware.cors import CORSMiddleware
31
  # Try to import WSGIMiddleware
 
79
  allow_headers=["*"],
80
  )
81
 
82
+ # Skip Flask mounting - use Flask directly instead
83
  if flask_available:
84
+ logger.info("βœ… Flask app loaded, but not mounting to avoid route conflicts")
85
+ logger.info(" FastAPI will provide fallback routes only")
86
+ logger.info(" To use Flask, run: python app.py")
87
+ flask_available = False # Disable mounting to prevent loops
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
 
89
  # Fallback routes if Flask is not available
90
  if not flask_available:
91
+ from fastapi.responses import HTMLResponse, FileResponse
92
+
93
+ @app.get("/", response_class=HTMLResponse)
94
  async def root():
95
+ """Root endpoint - serve index.html"""
96
+ index_path = Path(__file__).parent / 'index.html'
97
+ if index_path.exists():
98
+ return FileResponse(index_path, media_type='text/html')
99
+ else:
100
+ # Fallback HTML
101
+ return HTMLResponse(content="""
102
+ <!DOCTYPE html>
103
+ <html><head><title>Crypto Intelligence Hub</title></head>
104
+ <body style="font-family: Arial; background: #0a0e27; color: white; padding: 2rem;">
105
+ <h1>πŸš€ Crypto Intelligence Hub</h1>
106
+ <p>Server is running! <a href="/docs" style="color: #2dd4bf;">View API Docs</a></p>
107
+ </body></html>
108
+ """)
109
 
110
  @app.get("/health")
111
  async def health():
 
127
  "timestamp": str(Path(__file__).stat().st_mtime)
128
  }
129
 
130
+ # Mount static files if directory exists
131
+ static_path = Path(__file__).parent / 'static'
132
+ if static_path.exists():
133
+ app.mount("/static", StaticFiles(directory=str(static_path)), name="static")
134
+ logger.info(f"βœ… Mounted static files from {static_path}")
135
+
136
  logger.info("βœ… Fallback FastAPI routes created")
137
 
138
  # Export app for uvicorn
static/index.html CHANGED
@@ -4,8 +4,6 @@
4
  <head>
5
  <meta charset="UTF-8">
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <!-- Meta refresh as fallback for redirect -->
8
- <meta http-equiv="refresh" content="0; url=/static/splash.html">
9
  <!-- Permissions-Policy with only recognized features to avoid browser warnings -->
10
  <meta http-equiv="Permissions-Policy"
11
  content="accelerometer=(), autoplay=(), camera=(), display-capture=(), encrypted-media=(), fullscreen=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), sync-xhr=(), usb=(), web-share=()">
@@ -27,7 +25,7 @@
27
  window._hfWarningsSuppressed = true;
28
  })();
29
  </script>
30
- <title>Crypto Intelligence Hub | Redirecting...</title>
31
  <!-- Preconnect to external domains -->
32
  <link rel="preconnect" href="https://fonts.googleapis.com" crossorigin>
33
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
@@ -262,7 +260,22 @@
262
  </div>
263
 
264
  <h1>Crypto Intelligence Hub</h1>
265
- <p class="subtitle">Redirecting to welcome screen...</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
266
 
267
  <div class="progress-bar">
268
  <div class="progress-fill"></div>
@@ -271,24 +284,94 @@
271
  <div class="spinner" id="spinner"></div>
272
 
273
  <div id="message" class="message">
274
- Please wait while we prepare your experience...
275
  </div>
276
 
277
- <noscript>
278
- <div class="error">
279
- <div class="error-title">⚠️ JavaScript Required</div>
280
- <div class="error-details">
281
- Please enable JavaScript or <a href="/static/splash.html" style="color: #2dd4bf;">click here to continue</a>
282
- </div>
283
- </div>
284
- </noscript>
285
 
286
- <a href="/static/pages/dashboard/index.html" class="skip-link" onclick="sessionStorage.setItem('skipSplash', 'true');">Continue to Dashboard β†’</a>
287
  </div>
288
 
289
- <script>
290
- // Redirect to splash screen first
291
- window.location.replace('/static/splash.html');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
292
  </script>
293
  <script>
294
  // Suppress harmless Permissions-Policy warnings from Hugging Face Space container
 
4
  <head>
5
  <meta charset="UTF-8">
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
 
 
7
  <!-- Permissions-Policy with only recognized features to avoid browser warnings -->
8
  <meta http-equiv="Permissions-Policy"
9
  content="accelerometer=(), autoplay=(), camera=(), display-capture=(), encrypted-media=(), fullscreen=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), sync-xhr=(), usb=(), web-share=()">
 
25
  window._hfWarningsSuppressed = true;
26
  })();
27
  </script>
28
+ <title>Crypto Intelligence Hub | Loading...</title>
29
  <!-- Preconnect to external domains -->
30
  <link rel="preconnect" href="https://fonts.googleapis.com" crossorigin>
31
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
 
260
  </div>
261
 
262
  <h1>Crypto Intelligence Hub</h1>
263
+ <p class="subtitle">Unified data fabric, AI analytics, and real-time market intelligence</p>
264
+
265
+ <div id="status-section" class="status">
266
+ <div class="status-card">
267
+ <small>Backend</small>
268
+ <strong id="backend-status">Checking...</strong>
269
+ </div>
270
+ <div class="status-card">
271
+ <small>AI Models</small>
272
+ <strong id="models-status">Loading...</strong>
273
+ </div>
274
+ <div class="status-card">
275
+ <small>Data Streams</small>
276
+ <strong id="streams-status">Ready</strong>
277
+ </div>
278
+ </div>
279
 
280
  <div class="progress-bar">
281
  <div class="progress-fill"></div>
 
284
  <div class="spinner" id="spinner"></div>
285
 
286
  <div id="message" class="message">
287
+ Initializing system components and checking backend health...
288
  </div>
289
 
290
+ <div id="error-section" style="display: none;" class="error">
291
+ <div class="error-title">⚠️ Connection Issue</div>
292
+ <div class="error-details" id="error-message"></div>
293
+ </div>
 
 
 
 
294
 
295
+ <a href="/static/pages/dashboard/index.html" class="skip-link">Skip to Dashboard β†’</a>
296
  </div>
297
 
298
+ <script defer>
299
+ const API_BASE = window.location.origin + '/api';
300
+ const REDIRECT_URL = '/static/pages/dashboard/index.html';
301
+
302
+ async function checkBackend() {
303
+ const backendStatus = document.getElementById('backend-status');
304
+ const modelsStatus = document.getElementById('models-status');
305
+ const messageEl = document.getElementById('message');
306
+ const errorSection = document.getElementById('error-section');
307
+ const errorMessage = document.getElementById('error-message');
308
+
309
+ try {
310
+ // Check backend health
311
+ messageEl.textContent = 'Connecting to backend...';
312
+ const controller = new AbortController();
313
+ const timeoutId = setTimeout(() => controller.abort(), 5000);
314
+ const healthRes = await fetch(`${API_BASE}/health`, { signal: controller.signal });
315
+ clearTimeout(timeoutId);
316
+
317
+ if (!healthRes.ok) {
318
+ throw new Error(`Backend returned ${healthRes.status}`);
319
+ }
320
+
321
+ const healthData = await healthRes.json();
322
+ backendStatus.textContent = 'βœ“ Online';
323
+ backendStatus.style.color = '#22c55e';
324
+
325
+ // Check models status
326
+ messageEl.textContent = 'Loading AI models...';
327
+ try {
328
+ const modelsRes = await fetch(`${API_BASE}/models/status`);
329
+ if (modelsRes.ok) {
330
+ const modelsData = await modelsRes.json();
331
+ const loadedCount = modelsData.models_loaded || 0;
332
+ modelsStatus.textContent = `${loadedCount} Loaded`;
333
+ modelsStatus.style.color = loadedCount > 0 ? '#22c55e' : '#f59e0b';
334
+ } else {
335
+ modelsStatus.textContent = 'Fallback';
336
+ modelsStatus.style.color = '#f59e0b';
337
+ }
338
+ } catch (err) {
339
+ modelsStatus.textContent = 'Fallback';
340
+ modelsStatus.style.color = '#f59e0b';
341
+ }
342
+
343
+ // All checks passed
344
+ messageEl.textContent = 'System ready! Redirecting...';
345
+
346
+ setTimeout(() => {
347
+ window.location.href = REDIRECT_URL;
348
+ }, 1500);
349
+
350
+ } catch (error) {
351
+ console.error('Backend check failed:', error);
352
+ backendStatus.textContent = 'βœ— Offline';
353
+ backendStatus.style.color = '#ef4444';
354
+ modelsStatus.textContent = 'N/A';
355
+ modelsStatus.style.color = '#64748b';
356
+
357
+ errorSection.style.display = 'block';
358
+ errorMessage.textContent = `Failed to connect to backend: ${error.message}. Please ensure the server is running.`;
359
+ messageEl.textContent = 'Backend connection failed. You can still access the dashboard, but live data will not be available.';
360
+
361
+ document.getElementById('spinner').style.display = 'none';
362
+
363
+ // Still allow manual navigation
364
+ setTimeout(() => {
365
+ const skipText = document.querySelector('.skip-link');
366
+ skipText.textContent = 'Continue to Dashboard (Offline Mode) β†’';
367
+ skipText.style.fontSize = '1.1rem';
368
+ skipText.style.fontWeight = '600';
369
+ }, 1000);
370
+ }
371
+ }
372
+
373
+ // Start checking backend
374
+ setTimeout(checkBackend, 500);
375
  </script>
376
  <script>
377
  // Suppress harmless Permissions-Policy warnings from Hugging Face Space container
static/pages/index.html CHANGED
@@ -1,153 +1,451 @@
1
  <!DOCTYPE html>
2
  <html lang="en">
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Crypto Intelligence Hub - Pages</title>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  <style>
8
  * {
9
  margin: 0;
10
  padding: 0;
11
  box-sizing: border-box;
12
  }
13
-
 
 
 
 
 
 
 
 
 
 
 
14
  body {
15
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
16
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
17
  min-height: 100vh;
 
 
 
18
  display: flex;
19
  align-items: center;
20
  justify-content: center;
21
- padding: 20px;
22
  }
23
-
24
  .container {
25
- background: white;
26
- border-radius: 20px;
27
- padding: 40px;
28
  max-width: 900px;
29
- width: 100%;
30
- box-shadow: 0 20px 60px rgba(0,0,0,0.3);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  }
32
-
33
  h1 {
34
- color: #667eea;
35
- margin-bottom: 10px;
36
- font-size: 2.5em;
 
 
 
 
 
37
  }
38
-
39
  .subtitle {
40
- color: #666;
41
- margin-bottom: 30px;
42
- font-size: 1.1em;
 
43
  }
44
-
45
- .pages-grid {
46
  display: grid;
47
- grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
48
- gap: 20px;
49
- margin-top: 30px;
50
  }
51
-
52
- .page-card {
53
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
54
- border-radius: 12px;
55
- padding: 25px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  text-decoration: none;
57
- color: white;
58
- transition: transform 0.3s, box-shadow 0.3s;
59
- display: flex;
60
- flex-direction: column;
61
- gap: 10px;
62
  }
63
-
64
- .page-card:hover {
65
- transform: translateY(-5px);
66
- box-shadow: 0 10px 30px rgba(102, 126, 234, 0.4);
67
  }
68
-
69
- .page-card h3 {
70
- font-size: 1.3em;
71
- margin-bottom: 5px;
 
 
 
 
72
  }
73
-
74
- .page-card p {
75
- font-size: 0.9em;
76
- opacity: 0.9;
77
  }
78
-
79
- .icon {
80
- font-size: 2em;
81
- margin-bottom: 10px;
82
  }
83
  </style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  </head>
 
85
  <body>
86
  <div class="container">
87
- <h1>πŸš€ Crypto Intelligence Hub</h1>
88
- <p class="subtitle">Multi-Page Application - Choose a page to explore</p>
89
-
90
- <div class="pages-grid">
91
- <a href="/dashboard" class="page-card">
92
- <div class="icon">πŸ“Š</div>
93
- <h3>Dashboard</h3>
94
- <p>Overview and statistics</p>
95
- </a>
96
-
97
- <a href="/market" class="page-card">
98
- <div class="icon">πŸ’Ή</div>
99
- <h3>Market Data</h3>
100
- <p>Real-time cryptocurrency prices</p>
101
- </a>
102
-
103
- <a href="/models" class="page-card">
104
- <div class="icon">πŸ€–</div>
105
- <h3>AI Models</h3>
106
- <p>Machine learning models</p>
107
- </a>
108
-
109
- <a href="/sentiment" class="page-card">
110
- <div class="icon">πŸ“ˆ</div>
111
- <h3>Sentiment Analysis</h3>
112
- <p>Market sentiment indicators</p>
113
- </a>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
 
115
- <a href="/ai-analyst" class="page-card">
116
- <div class="icon">🧠</div>
117
- <h3>AI Analyst</h3>
118
- <p>AI-powered trading insights</p>
119
- </a>
120
 
121
- <a href="/trading-assistant" class="page-card">
122
- <div class="icon">πŸ’Ό</div>
123
- <h3>Trading Assistant</h3>
124
- <p>Advanced trading tools</p>
125
- </a>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
 
127
- <a href="/news" class="page-card">
128
- <div class="icon">πŸ“°</div>
129
- <h3>News</h3>
130
- <p>Latest crypto news</p>
131
- </a>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
 
133
- <a href="/providers" class="page-card">
134
- <div class="icon">πŸ”Œ</div>
135
- <h3>Data Providers</h3>
136
- <p>API providers status</p>
137
- </a>
 
 
138
 
139
- <a href="/diagnostics" class="page-card">
140
- <div class="icon">πŸ”</div>
141
- <h3>Diagnostics</h3>
142
- <p>System health and testing</p>
143
- </a>
 
 
144
 
145
- <a href="/api-explorer" class="page-card">
146
- <div class="icon">πŸ› οΈ</div>
147
- <h3>API Explorer</h3>
148
- <p>Explore API endpoints</p>
149
- </a>
150
- </div>
151
- </div>
152
  </body>
153
- </html>
 
 
1
  <!DOCTYPE html>
2
  <html lang="en">
3
+
4
  <head>
5
  <meta charset="UTF-8">
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <!-- Permissions-Policy with only recognized features to avoid browser warnings -->
8
+ <meta http-equiv="Permissions-Policy"
9
+ content="accelerometer=(), autoplay=(), camera=(), display-capture=(), encrypted-media=(), fullscreen=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), sync-xhr=(), usb=(), web-share=()">
10
+ <!-- Suppress HF Space Permissions-Policy warnings - Load IMMEDIATELY before any other scripts -->
11
+ <script>
12
+ // Inline console filter - runs immediately to catch early warnings
13
+ (function() {
14
+ if (window._hfWarningsSuppressed) return;
15
+ const features = ['ambient-light-sensor', 'battery', 'document-domain', 'layout-animations', 'legacy-image-formats', 'oversized-images', 'vr', 'wake-lock'];
16
+ const originalWarn = console.warn;
17
+ const originalError = console.error;
18
+ const shouldSuppress = (msg) => {
19
+ if (!msg) return false;
20
+ const m = msg.toString().toLowerCase();
21
+ return m.includes('unrecognized feature:') && features.some(f => m.includes(f));
22
+ };
23
+ console.warn = function(...args) { if (!shouldSuppress(args[0])) originalWarn.apply(console, args); };
24
+ console.error = function(...args) { if (!shouldSuppress(args[0])) originalError.apply(console, args); };
25
+ window._hfWarningsSuppressed = true;
26
+ })();
27
+ </script>
28
+ <title>Crypto Intelligence Hub | Loading...</title>
29
+ <!-- Preconnect to external domains -->
30
+ <link rel="preconnect" href="https://fonts.googleapis.com" crossorigin>
31
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
32
+ <!-- Load fonts with font-display swap for non-blocking -->
33
+ <link
34
+ href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=Inter:wght@300;400;500;600;700&display=swap"
35
+ rel="stylesheet" media="print" onload="this.media='all'">
36
+ <noscript><link
37
+ href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=Inter:wght@300;400;500;600;700&display=swap"
38
+ rel="stylesheet"></noscript>
39
  <style>
40
  * {
41
  margin: 0;
42
  padding: 0;
43
  box-sizing: border-box;
44
  }
45
+
46
+ :root {
47
+ --bg-primary: #0a0e27;
48
+ --bg-secondary: #0b1121;
49
+ --accent-cyan: #2dd4bf;
50
+ --accent-purple: #818cf8;
51
+ --accent-pink: #ec4899;
52
+ --text-primary: #f8fafc;
53
+ --text-secondary: rgba(241, 245, 249, 0.75);
54
+ --glass: rgba(6, 12, 27, 0.85);
55
+ }
56
+
57
  body {
 
 
58
  min-height: 100vh;
59
+ font-family: 'Inter', sans-serif;
60
+ background: linear-gradient(135deg, var(--bg-primary), #020617, var(--bg-secondary));
61
+ color: var(--text-primary);
62
  display: flex;
63
  align-items: center;
64
  justify-content: center;
65
+ overflow: hidden;
66
  }
67
+
68
  .container {
 
 
 
69
  max-width: 900px;
70
+ width: 90%;
71
+ padding: 3rem;
72
+ background: var(--glass);
73
+ backdrop-filter: blur(20px);
74
+ border-radius: 32px;
75
+ border: 1px solid rgba(255, 255, 255, 0.1);
76
+ box-shadow: 0 30px 120px rgba(0, 0, 0, 0.5);
77
+ text-align: center;
78
+ }
79
+
80
+ .logo {
81
+ width: 80px;
82
+ height: 80px;
83
+ margin: 0 auto 2rem;
84
+ background: linear-gradient(135deg, var(--accent-cyan), var(--accent-purple));
85
+ border-radius: 20px;
86
+ display: flex;
87
+ align-items: center;
88
+ justify-content: center;
89
+ box-shadow: 0 15px 40px rgba(45, 212, 191, 0.4);
90
+ animation: float 3s ease-in-out infinite;
91
+ }
92
+
93
+ @keyframes float {
94
+
95
+ 0%,
96
+ 100% {
97
+ transform: translateY(0px);
98
+ }
99
+
100
+ 50% {
101
+ transform: translateY(-10px);
102
+ }
103
  }
104
+
105
  h1 {
106
+ font-family: 'Space Grotesk', sans-serif;
107
+ font-size: 2.5rem;
108
+ font-weight: 700;
109
+ margin-bottom: 1rem;
110
+ background: linear-gradient(135deg, var(--accent-cyan), var(--accent-purple));
111
+ -webkit-background-clip: text;
112
+ background-clip: text;
113
+ -webkit-text-fill-color: transparent;
114
  }
115
+
116
  .subtitle {
117
+ color: var(--text-secondary);
118
+ font-size: 1.1rem;
119
+ margin-bottom: 3rem;
120
+ line-height: 1.6;
121
  }
122
+
123
+ .status {
124
  display: grid;
125
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
126
+ gap: 1rem;
127
+ margin: 2rem 0;
128
  }
129
+
130
+ .status-card {
131
+ padding: 1.5rem;
132
+ background: rgba(255, 255, 255, 0.03);
133
+ border: 1px solid rgba(255, 255, 255, 0.08);
134
+ border-radius: 16px;
135
+ }
136
+
137
+ .status-card small {
138
+ color: var(--text-secondary);
139
+ font-size: 0.85rem;
140
+ text-transform: uppercase;
141
+ letter-spacing: 0.1em;
142
+ }
143
+
144
+ .status-card strong {
145
+ display: block;
146
+ font-size: 1.5rem;
147
+ margin-top: 0.5rem;
148
+ color: var(--accent-cyan);
149
+ }
150
+
151
+ .progress-bar {
152
+ width: 100%;
153
+ height: 8px;
154
+ background: rgba(255, 255, 255, 0.1);
155
+ border-radius: 999px;
156
+ overflow: hidden;
157
+ margin: 2rem 0;
158
+ }
159
+
160
+ .progress-fill {
161
+ height: 100%;
162
+ width: 0;
163
+ background: linear-gradient(90deg, var(--accent-cyan), var(--accent-purple));
164
+ border-radius: 999px;
165
+ animation: progress 2s ease-in-out forwards;
166
+ }
167
+
168
+ @keyframes progress {
169
+ to {
170
+ width: 100%;
171
+ }
172
+ }
173
+
174
+ .spinner {
175
+ width: 60px;
176
+ height: 60px;
177
+ margin: 2rem auto;
178
+ border: 4px solid rgba(255, 255, 255, 0.1);
179
+ border-top-color: var(--accent-cyan);
180
+ border-radius: 50%;
181
+ animation: spin 1s linear infinite;
182
+ }
183
+
184
+ @keyframes spin {
185
+ to {
186
+ transform: rotate(360deg);
187
+ }
188
+ }
189
+
190
+ .message {
191
+ color: var(--text-secondary);
192
+ margin-top: 2rem;
193
+ font-size: 0.95rem;
194
+ }
195
+
196
+ .skip-link {
197
+ margin-top: 2rem;
198
+ color: var(--accent-cyan);
199
  text-decoration: none;
200
+ font-weight: 500;
201
+ transition: color 0.3s;
 
 
 
202
  }
203
+
204
+ .skip-link:hover {
205
+ color: var(--accent-purple);
206
+ text-decoration: underline;
207
  }
208
+
209
+ .error {
210
+ background: rgba(239, 68, 68, 0.1);
211
+ border: 1px solid rgba(239, 68, 68, 0.3);
212
+ color: #fca5a5;
213
+ padding: 1.5rem;
214
+ border-radius: 12px;
215
+ margin: 2rem 0;
216
  }
217
+
218
+ .error-title {
219
+ font-weight: 600;
220
+ margin-bottom: 0.5rem;
221
  }
222
+
223
+ .error-details {
224
+ font-size: 0.9rem;
225
+ opacity: 0.8;
226
  }
227
  </style>
228
+ <!-- Enhanced UI System -->
229
+ <link rel="stylesheet" href="/static/css/ui-enhancements.css">
230
+ <script src="/static/js/icons.js"></script>
231
+ <script src="/static/js/error-handler.js"></script>
232
+ <script src="/static/js/ui-manager.js"></script>
233
+
234
+ <!-- API Configuration - Smart Fallback System -->
235
+ <script src="/static/js/api-config.js"></script>
236
+ <!-- Trading Pairs Loader -->
237
+ <script src="/static/js/trading-pairs-loader.js"></script>
238
+ <script>
239
+ // Initialize API client
240
+ window.apiReady = new Promise((resolve) => {
241
+ if (window.apiClient) {
242
+ console.log('βœ… API Client ready');
243
+ resolve(window.apiClient);
244
+ } else {
245
+ console.error('❌ API Client not loaded');
246
+ }
247
+ });
248
+ </script>
249
+
250
  </head>
251
+
252
  <body>
253
  <div class="container">
254
+ <div class="logo">
255
+ <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2">
256
+ <path d="M12 2L2 7L12 12L22 7L12 2Z"></path>
257
+ <path d="M2 17L12 22L22 17"></path>
258
+ <path d="M2 12L12 17L22 12"></path>
259
+ </svg>
260
+ </div>
261
+
262
+ <h1>Crypto Intelligence Hub</h1>
263
+ <p class="subtitle">Unified data fabric, AI analytics, and real-time market intelligence</p>
264
+
265
+ <div id="status-section" class="status">
266
+ <div class="status-card">
267
+ <small>Backend</small>
268
+ <strong id="backend-status">Checking...</strong>
269
+ </div>
270
+ <div class="status-card">
271
+ <small>AI Models</small>
272
+ <strong id="models-status">Loading...</strong>
273
+ </div>
274
+ <div class="status-card">
275
+ <small>Data Streams</small>
276
+ <strong id="streams-status">Ready</strong>
277
+ </div>
278
+ </div>
279
+
280
+ <div class="progress-bar">
281
+ <div class="progress-fill"></div>
282
+ </div>
283
+
284
+ <div class="spinner" id="spinner"></div>
285
+
286
+ <div id="message" class="message">
287
+ Initializing system components and checking backend health...
288
+ </div>
289
+
290
+ <div id="error-section" style="display: none;" class="error">
291
+ <div class="error-title">⚠️ Connection Issue</div>
292
+ <div class="error-details" id="error-message"></div>
293
+ </div>
294
+
295
+ <a href="/static/pages/dashboard/index.html" class="skip-link">Skip to Dashboard β†’</a>
296
+ </div>
297
+
298
+ <script defer>
299
+ const API_BASE = window.location.origin + '/api';
300
+ const REDIRECT_URL = '/static/pages/dashboard/index.html';
301
+
302
+ async function checkBackend() {
303
+ const backendStatus = document.getElementById('backend-status');
304
+ const modelsStatus = document.getElementById('models-status');
305
+ const messageEl = document.getElementById('message');
306
+ const errorSection = document.getElementById('error-section');
307
+ const errorMessage = document.getElementById('error-message');
308
+
309
+ try {
310
+ // Check backend health
311
+ messageEl.textContent = 'Connecting to backend...';
312
+ const controller = new AbortController();
313
+ const timeoutId = setTimeout(() => controller.abort(), 5000);
314
+ const healthRes = await fetch(`${API_BASE}/health`, { signal: controller.signal });
315
+ clearTimeout(timeoutId);
316
+
317
+ if (!healthRes.ok) {
318
+ throw new Error(`Backend returned ${healthRes.status}`);
319
+ }
320
+
321
+ const healthData = await healthRes.json();
322
+ backendStatus.textContent = 'βœ“ Online';
323
+ backendStatus.style.color = '#22c55e';
324
+
325
+ // Check models status
326
+ messageEl.textContent = 'Loading AI models...';
327
+ try {
328
+ const modelsRes = await fetch(`${API_BASE}/models/status`);
329
+ if (modelsRes.ok) {
330
+ const modelsData = await modelsRes.json();
331
+ const loadedCount = modelsData.models_loaded || 0;
332
+ modelsStatus.textContent = `${loadedCount} Loaded`;
333
+ modelsStatus.style.color = loadedCount > 0 ? '#22c55e' : '#f59e0b';
334
+ } else {
335
+ modelsStatus.textContent = 'Fallback';
336
+ modelsStatus.style.color = '#f59e0b';
337
+ }
338
+ } catch (err) {
339
+ modelsStatus.textContent = 'Fallback';
340
+ modelsStatus.style.color = '#f59e0b';
341
+ }
342
+
343
+ // All checks passed
344
+ messageEl.textContent = 'System ready! Redirecting...';
345
+
346
+ setTimeout(() => {
347
+ window.location.href = REDIRECT_URL;
348
+ }, 1500);
349
+
350
+ } catch (error) {
351
+ console.error('Backend check failed:', error);
352
+ backendStatus.textContent = 'βœ— Offline';
353
+ backendStatus.style.color = '#ef4444';
354
+ modelsStatus.textContent = 'N/A';
355
+ modelsStatus.style.color = '#64748b';
356
+
357
+ errorSection.style.display = 'block';
358
+ errorMessage.textContent = `Failed to connect to backend: ${error.message}. Please ensure the server is running.`;
359
+ messageEl.textContent = 'Backend connection failed. You can still access the dashboard, but live data will not be available.';
360
+
361
+ document.getElementById('spinner').style.display = 'none';
362
+
363
+ // Still allow manual navigation
364
+ setTimeout(() => {
365
+ const skipText = document.querySelector('.skip-link');
366
+ skipText.textContent = 'Continue to Dashboard (Offline Mode) β†’';
367
+ skipText.style.fontSize = '1.1rem';
368
+ skipText.style.fontWeight = '600';
369
+ }, 1000);
370
+ }
371
+ }
372
+
373
+ // Start checking backend
374
+ setTimeout(checkBackend, 500);
375
+ </script>
376
+ <script>
377
+ // Suppress harmless Permissions-Policy warnings from Hugging Face Space container
378
+ // These warnings come from the HF Space iframe and cannot be controlled by the application
379
+ // Run IMMEDIATELY (not deferred) to catch warnings as early as possible
380
+ (function() {
381
+ if (window._hfWarningsSuppressed) return;
382
 
383
+ const originalWarn = console.warn;
384
+ const originalError = console.error;
 
 
 
385
 
386
+ // List of unrecognized features that cause warnings (from HF Space container)
387
+ const unrecognizedFeatures = [
388
+ 'ambient-light-sensor',
389
+ 'battery',
390
+ 'document-domain',
391
+ 'layout-animations',
392
+ 'legacy-image-formats',
393
+ 'oversized-images',
394
+ 'vr',
395
+ 'wake-lock',
396
+ 'screen-wake-lock',
397
+ 'virtual-reality',
398
+ 'cross-origin-isolated',
399
+ 'execution-while-not-rendered',
400
+ 'execution-while-out-of-viewport',
401
+ 'keyboard-map',
402
+ 'navigation-override',
403
+ 'publickey-credentials-get',
404
+ 'xr-spatial-tracking'
405
+ ];
406
 
407
+ const shouldSuppress = (message) => {
408
+ if (!message) return false;
409
+ const msg = message.toString().toLowerCase();
410
+
411
+ // Check for "Unrecognized feature:" pattern
412
+ if (msg.includes('unrecognized feature:')) {
413
+ return unrecognizedFeatures.some(feature => msg.includes(feature));
414
+ }
415
+
416
+ // Also check for Permissions-Policy warnings
417
+ if (msg.includes('permissions-policy') || msg.includes('feature-policy')) {
418
+ return unrecognizedFeatures.some(feature => msg.includes(feature));
419
+ }
420
+
421
+ // Check for HF Space domain in warning
422
+ if (msg.includes('datasourceforcryptocurrency') &&
423
+ unrecognizedFeatures.some(feature => msg.includes(feature))) {
424
+ return true;
425
+ }
426
+
427
+ return false;
428
+ };
429
 
430
+ console.warn = function(...args) {
431
+ const message = args[0]?.toString() || '';
432
+ if (shouldSuppress(message)) {
433
+ return; // Suppress silently
434
+ }
435
+ originalWarn.apply(console, args);
436
+ };
437
 
438
+ console.error = function(...args) {
439
+ const message = args[0]?.toString() || '';
440
+ if (shouldSuppress(message)) {
441
+ return; // Suppress silently
442
+ }
443
+ originalError.apply(console, args);
444
+ };
445
 
446
+ window._hfWarningsSuppressed = true;
447
+ })();
448
+ </script>
 
 
 
 
449
  </body>
450
+
451
+ </html>
test_new_endpoints.html ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Test New Endpoints</title>
5
+ <style>
6
+ body {
7
+ font-family: monospace;
8
+ padding: 20px;
9
+ background: #1a1a1a;
10
+ color: #0f0;
11
+ }
12
+ .result {
13
+ background: #000;
14
+ padding: 10px;
15
+ margin: 10px 0;
16
+ border: 1px solid #0f0;
17
+ border-radius: 5px;
18
+ }
19
+ button {
20
+ background: #0f0;
21
+ color: #000;
22
+ border: none;
23
+ padding: 10px 20px;
24
+ cursor: pointer;
25
+ margin: 5px;
26
+ font-weight: bold;
27
+ }
28
+ button:hover {
29
+ background: #0d0;
30
+ }
31
+ </style>
32
+ </head>
33
+ <body>
34
+ <h1>πŸ§ͺ Test New API Endpoints</h1>
35
+
36
+ <h2>1. Sentiment Analysis</h2>
37
+ <button onclick="testSentiment('Bitcoin is pumping to the moon! Bullish rally!')">Test Bullish Text</button>
38
+ <button onclick="testSentiment('Market is crashing, sell everything!')">Test Bearish Text</button>
39
+ <button onclick="testSentiment('Bitcoin price remains stable today')">Test Neutral Text</button>
40
+ <div class="result" id="sentiment-result"></div>
41
+
42
+ <h2>2. AI Decision</h2>
43
+ <button onclick="testDecision('BTC', 50000, 7, 2000000000, 'bullish')">Test BUY Signal</button>
44
+ <button onclick="testDecision('BTC', 50000, -7, 2000000000, 'bearish')">Test SELL Signal</button>
45
+ <button onclick="testDecision('BTC', 50000, 1, 500000000, 'neutral')">Test HOLD Signal</button>
46
+ <div class="result" id="decision-result"></div>
47
+
48
+ <script>
49
+ async function testSentiment(text) {
50
+ const resultDiv = document.getElementById('sentiment-result');
51
+ resultDiv.innerHTML = 'Testing...';
52
+
53
+ try {
54
+ const response = await fetch('http://localhost:7860/api/sentiment/analyze', {
55
+ method: 'POST',
56
+ headers: {
57
+ 'Content-Type': 'application/json'
58
+ },
59
+ body: JSON.stringify({ text: text })
60
+ });
61
+
62
+ const data = await response.json();
63
+ resultDiv.innerHTML = `
64
+ <h3>βœ… Sentiment Analysis Result:</h3>
65
+ <pre>${JSON.stringify(data, null, 2)}</pre>
66
+ `;
67
+ } catch (error) {
68
+ resultDiv.innerHTML = `
69
+ <h3>❌ Error:</h3>
70
+ <pre>${error.message}</pre>
71
+ `;
72
+ }
73
+ }
74
+
75
+ async function testDecision(symbol, price, change_24h, volume, sentiment) {
76
+ const resultDiv = document.getElementById('decision-result');
77
+ resultDiv.innerHTML = 'Testing...';
78
+
79
+ try {
80
+ const response = await fetch('http://localhost:7860/api/ai/decision', {
81
+ method: 'POST',
82
+ headers: {
83
+ 'Content-Type': 'application/json'
84
+ },
85
+ body: JSON.stringify({
86
+ symbol: symbol,
87
+ price: price,
88
+ change_24h: change_24h,
89
+ volume: volume,
90
+ sentiment: sentiment
91
+ })
92
+ });
93
+
94
+ const data = await response.json();
95
+ resultDiv.innerHTML = `
96
+ <h3>βœ… AI Decision Result:</h3>
97
+ <pre>${JSON.stringify(data, null, 2)}</pre>
98
+ `;
99
+ } catch (error) {
100
+ resultDiv.innerHTML = `
101
+ <h3>❌ Error:</h3>
102
+ <pre>${error.message}</pre>
103
+ `;
104
+ }
105
+ }
106
+ </script>
107
+ </body>
108
+ </html>
109
+