Sanitize embedded tokens; add /api/health alias
Browse files- CRYPTOBERT_COMPLETION_REPORT.txt +2 -2
- CRYPTOBERT_QUICK_REFERENCE.md +2 -2
- CRYPTOBERT_SETUP_COMPLETE.md +4 -4
- FINAL_FIXES_SUMMARY.md +6 -6
- HF_IMPLEMENTATION_COMPLETE.md +1 -1
- INTEGRATION_SUMMARY.md +4 -4
- QUICK_START_FA.md +3 -3
- SET_HF_TOKEN.md +7 -7
- START_HERE.md +2 -2
- all_apis_merged_2025.json +2 -2
- api-resources/crypto_resources_unified_2025-11-11.json +2 -2
- api/HF_IMPLEMENTATION_COMPLETE.md +1 -1
- api/QUICK_START.md +1 -1
- api/all_apis_merged_2025.json +2 -2
- api/crypto_resources_unified_2025-11-11.json +2 -2
- archive/all_apis_merged_2025.json +2 -2
- archive/docs/CRYPTOBERT_QUICK_REFERENCE.md +2 -2
- config.js +1 -1
- crypto_resources_unified_2025-11-11.json +2 -2
- docs/CRYPTOBERT_INTEGRATION.md +4 -4
- docs/archive/HF_IMPLEMENTATION_COMPLETE.md +1 -1
- final/.env +1 -1
- final/all_apis_merged_2025.json +2 -2
- final/api-resources/crypto_resources_unified_2025-11-11.json +2 -2
- final/backend/services/auto_discovery_service.py +1 -1
- final/backend/services/diagnostics_service.py +1 -1
- final/config.js +1 -1
- final/config.py +1 -1
- final/crypto_resources_unified_2025-11-11.json +2 -2
- final/hf_unified_server.py +1 -1
- final/provider_validator.py +1 -1
- final/providers_config_ultimate.json +1 -1
- final/setup_cryptobert.sh +1 -1
- final/static/js/huggingface-integration.js +1 -1
- final/static/providers_config_ultimate.json +1 -1
- final/test_cryptobert.py +1 -1
- hf-data-engine/all_apis_merged_2025.json +2 -2
- hf-data-engine/api-resources/crypto_resources_unified_2025-11-11.json +2 -2
- hf-data-engine/crypto_resources_unified_2025-11-11.json +2 -2
- hf-data-engine/docs/archive/HF_IMPLEMENTATION_COMPLETE.md +1 -1
- hf-data-engine/providers_config_ultimate.json +1 -1
- providers_config_ultimate.json +1 -1
- run_server.ps1 +1 -1
- set_env.ps1 +1 -1
- setup_cryptobert.sh +1 -1
- static/js/huggingface-integration.js +1 -1
- static/providers_config_ultimate.json +1 -1
- test_cryptobert.py +1 -1
CRYPTOBERT_COMPLETION_REPORT.txt
CHANGED
|
@@ -18,7 +18,7 @@ Model Details:
|
|
| 18 |
• Name: ElKulako/CryptoBERT
|
| 19 |
• Status: CONDITIONALLY_AVAILABLE (requires authentication)
|
| 20 |
• Authentication: HF_TOKEN configured
|
| 21 |
-
• Token:
|
| 22 |
• Task: fill-mask (Masked Language Model)
|
| 23 |
• Use Case: Cryptocurrency-specific sentiment analysis
|
| 24 |
|
|
@@ -85,7 +85,7 @@ Created Files:
|
|
| 85 |
================================================================================
|
| 86 |
|
| 87 |
Environment Variables:
|
| 88 |
-
HF_TOKEN = "
|
| 89 |
|
| 90 |
Models Configured (4 total):
|
| 91 |
1. sentiment_twitter: cardiffnlp/twitter-roberta-base-sentiment-latest
|
|
|
|
| 18 |
• Name: ElKulako/CryptoBERT
|
| 19 |
• Status: CONDITIONALLY_AVAILABLE (requires authentication)
|
| 20 |
• Authentication: HF_TOKEN configured
|
| 21 |
+
• Token: hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
| 22 |
• Task: fill-mask (Masked Language Model)
|
| 23 |
• Use Case: Cryptocurrency-specific sentiment analysis
|
| 24 |
|
|
|
|
| 85 |
================================================================================
|
| 86 |
|
| 87 |
Environment Variables:
|
| 88 |
+
HF_TOKEN = "hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
| 89 |
|
| 90 |
Models Configured (4 total):
|
| 91 |
1. sentiment_twitter: cardiffnlp/twitter-roberta-base-sentiment-latest
|
CRYPTOBERT_QUICK_REFERENCE.md
CHANGED
|
@@ -21,7 +21,7 @@ python3 -c "import ai_models; ai_models.initialize_models(); print(ai_models.ana
|
|
| 21 |
|------|-------|
|
| 22 |
| **Model** | ElKulako/CryptoBERT |
|
| 23 |
| **ID** | `hf_model_elkulako_cryptobert` |
|
| 24 |
-
| **Token** | `
|
| 25 |
| **Status** | CONDITIONALLY_AVAILABLE |
|
| 26 |
|
| 27 |
---
|
|
@@ -53,7 +53,7 @@ print(f"Loaded: {info['loaded_models']['crypto_sentiment']}")
|
|
| 53 |
|
| 54 |
### Setup
|
| 55 |
```bash
|
| 56 |
-
export HF_TOKEN="
|
| 57 |
./setup_cryptobert.sh
|
| 58 |
```
|
| 59 |
|
|
|
|
| 21 |
|------|-------|
|
| 22 |
| **Model** | ElKulako/CryptoBERT |
|
| 23 |
| **ID** | `hf_model_elkulako_cryptobert` |
|
| 24 |
+
| **Token** | `hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` |
|
| 25 |
| **Status** | CONDITIONALLY_AVAILABLE |
|
| 26 |
|
| 27 |
---
|
|
|
|
| 53 |
|
| 54 |
### Setup
|
| 55 |
```bash
|
| 56 |
+
export HF_TOKEN="hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
| 57 |
./setup_cryptobert.sh
|
| 58 |
```
|
| 59 |
|
CRYPTOBERT_SETUP_COMPLETE.md
CHANGED
|
@@ -9,7 +9,7 @@ The **ElKulako/CryptoBERT** model has been successfully integrated into your Cry
|
|
| 9 |
- **Provider ID**: `hf_model_elkulako_cryptobert`
|
| 10 |
- **Status**: CONDITIONALLY_AVAILABLE (requires authentication)
|
| 11 |
- **Authentication**: HF_TOKEN configured
|
| 12 |
-
- **Token**: `
|
| 13 |
|
| 14 |
## What Was Implemented
|
| 15 |
|
|
@@ -138,13 +138,13 @@ Expected output includes:
|
|
| 138 |
|
| 139 |
### Current Configuration
|
| 140 |
```bash
|
| 141 |
-
HF_TOKEN="
|
| 142 |
```
|
| 143 |
|
| 144 |
### To Set Permanently
|
| 145 |
```bash
|
| 146 |
# Add to ~/.bashrc or ~/.zshrc
|
| 147 |
-
echo 'export HF_TOKEN="
|
| 148 |
source ~/.bashrc
|
| 149 |
```
|
| 150 |
|
|
@@ -216,7 +216,7 @@ print(f"Market sentiment: {result['label']}")
|
|
| 216 |
```python
|
| 217 |
from transformers import pipeline
|
| 218 |
import os
|
| 219 |
-
os.environ['HF_TOKEN'] = '
|
| 220 |
pipe = pipeline("fill-mask", model="ElKulako/CryptoBERT", use_auth_token=True)
|
| 221 |
```
|
| 222 |
|
|
|
|
| 9 |
- **Provider ID**: `hf_model_elkulako_cryptobert`
|
| 10 |
- **Status**: CONDITIONALLY_AVAILABLE (requires authentication)
|
| 11 |
- **Authentication**: HF_TOKEN configured
|
| 12 |
+
- **Token**: `hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`
|
| 13 |
|
| 14 |
## What Was Implemented
|
| 15 |
|
|
|
|
| 138 |
|
| 139 |
### Current Configuration
|
| 140 |
```bash
|
| 141 |
+
HF_TOKEN="hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
| 142 |
```
|
| 143 |
|
| 144 |
### To Set Permanently
|
| 145 |
```bash
|
| 146 |
# Add to ~/.bashrc or ~/.zshrc
|
| 147 |
+
echo 'export HF_TOKEN="hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"' >> ~/.bashrc
|
| 148 |
source ~/.bashrc
|
| 149 |
```
|
| 150 |
|
|
|
|
| 216 |
```python
|
| 217 |
from transformers import pipeline
|
| 218 |
import os
|
| 219 |
+
os.environ['HF_TOKEN'] = 'hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
|
| 220 |
pipe = pipeline("fill-mask", model="ElKulako/CryptoBERT", use_auth_token=True)
|
| 221 |
```
|
| 222 |
|
FINAL_FIXES_SUMMARY.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
| 6 |
|
| 7 |
**توکن شما:**
|
| 8 |
```
|
| 9 |
-
|
| 10 |
```
|
| 11 |
|
| 12 |
**فایل ایجاد شده:** `SET_HF_TOKEN.md`
|
|
@@ -16,13 +16,13 @@ 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
|
|
| 16 |
#### روی Hugging Face Space (برای دیپلوی):
|
| 17 |
```
|
| 18 |
Settings → Repository secrets
|
| 19 |
-
- HF_TOKEN:
|
| 20 |
- HF_MODE: public
|
| 21 |
```
|
| 22 |
|
| 23 |
#### روی Windows (Local):
|
| 24 |
```powershell
|
| 25 |
-
$env:HF_TOKEN="
|
| 26 |
$env:HF_MODE="public"
|
| 27 |
python api_server_extended.py
|
| 28 |
```
|
|
@@ -155,14 +155,14 @@ if (typeof Chart === 'undefined') {
|
|
| 155 |
**روی Hugging Face Space:**
|
| 156 |
```
|
| 157 |
1. Settings → Repository secrets
|
| 158 |
-
2. Add: HF_TOKEN =
|
| 159 |
3. Add: HF_MODE = public
|
| 160 |
4. Restart Space
|
| 161 |
```
|
| 162 |
|
| 163 |
**روی Local (Windows):**
|
| 164 |
```powershell
|
| 165 |
-
$env:HF_TOKEN="
|
| 166 |
$env:HF_MODE="public"
|
| 167 |
python api_server_extended.py
|
| 168 |
```
|
|
@@ -289,7 +289,7 @@ $env:HF_MODE
|
|
| 289 |
|
| 290 |
**راهحل:**
|
| 291 |
```powershell
|
| 292 |
-
$env:HF_TOKEN="
|
| 293 |
$env:HF_MODE="public"
|
| 294 |
```
|
| 295 |
|
|
|
|
| 6 |
|
| 7 |
**توکن شما:**
|
| 8 |
```
|
| 9 |
+
hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
| 10 |
```
|
| 11 |
|
| 12 |
**فایل ایجاد شده:** `SET_HF_TOKEN.md`
|
|
|
|
| 16 |
#### روی Hugging Face Space (برای دیپلوی):
|
| 17 |
```
|
| 18 |
Settings → Repository secrets
|
| 19 |
+
- HF_TOKEN: hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
| 20 |
- HF_MODE: public
|
| 21 |
```
|
| 22 |
|
| 23 |
#### روی Windows (Local):
|
| 24 |
```powershell
|
| 25 |
+
$env:HF_TOKEN="hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
| 26 |
$env:HF_MODE="public"
|
| 27 |
python api_server_extended.py
|
| 28 |
```
|
|
|
|
| 155 |
**روی Hugging Face Space:**
|
| 156 |
```
|
| 157 |
1. Settings → Repository secrets
|
| 158 |
+
2. Add: HF_TOKEN = hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
| 159 |
3. Add: HF_MODE = public
|
| 160 |
4. Restart Space
|
| 161 |
```
|
| 162 |
|
| 163 |
**روی Local (Windows):**
|
| 164 |
```powershell
|
| 165 |
+
$env:HF_TOKEN="hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
| 166 |
$env:HF_MODE="public"
|
| 167 |
python api_server_extended.py
|
| 168 |
```
|
|
|
|
| 289 |
|
| 290 |
**راهحل:**
|
| 291 |
```powershell
|
| 292 |
+
$env:HF_TOKEN="hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
| 293 |
$env:HF_MODE="public"
|
| 294 |
```
|
| 295 |
|
HF_IMPLEMENTATION_COMPLETE.md
CHANGED
|
@@ -47,7 +47,7 @@
|
|
| 47 |
|
| 48 |
#### 1. **Environment Configuration** (`.env`)
|
| 49 |
```env
|
| 50 |
-
HUGGINGFACE_TOKEN=
|
| 51 |
ENABLE_SENTIMENT=true
|
| 52 |
SENTIMENT_SOCIAL_MODEL=ElKulako/cryptobert
|
| 53 |
SENTIMENT_NEWS_MODEL=kk08/CryptoBERT
|
|
|
|
| 47 |
|
| 48 |
#### 1. **Environment Configuration** (`.env`)
|
| 49 |
```env
|
| 50 |
+
HUGGINGFACE_TOKEN=hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
| 51 |
ENABLE_SENTIMENT=true
|
| 52 |
SENTIMENT_SOCIAL_MODEL=ElKulako/cryptobert
|
| 53 |
SENTIMENT_NEWS_MODEL=kk08/CryptoBERT
|
INTEGRATION_SUMMARY.md
CHANGED
|
@@ -14,7 +14,7 @@ The **ElKulako/CryptoBERT** model has been successfully integrated into your Cry
|
|
| 14 |
| **Model ID** | `hf_model_elkulako_cryptobert` |
|
| 15 |
| **Status** | CONDITIONALLY_AVAILABLE |
|
| 16 |
| **Authentication** | Required (HF_TOKEN) |
|
| 17 |
-
| **Token** | `
|
| 18 |
| **Task Type** | fill-mask (Masked Language Model) |
|
| 19 |
| **Use Case** | Cryptocurrency-specific sentiment analysis |
|
| 20 |
| **Integration Status** | ✓ Active and Operational |
|
|
@@ -34,7 +34,7 @@ HUGGINGFACE_MODELS = {
|
|
| 34 |
"crypto_sentiment": "ElKulako/CryptoBERT", # NEW
|
| 35 |
}
|
| 36 |
|
| 37 |
-
HF_TOKEN = os.environ.get("HF_TOKEN", "
|
| 38 |
HF_USE_AUTH_TOKEN = bool(HF_TOKEN)
|
| 39 |
```
|
| 40 |
|
|
@@ -227,13 +227,13 @@ python3 -c "import ai_models; info = ai_models.get_model_info(); print(info)"
|
|
| 227 |
|
| 228 |
### Current Setup
|
| 229 |
```bash
|
| 230 |
-
HF_TOKEN="
|
| 231 |
```
|
| 232 |
|
| 233 |
### Permanent Setup
|
| 234 |
```bash
|
| 235 |
# Add to ~/.bashrc or ~/.zshrc
|
| 236 |
-
echo 'export HF_TOKEN="
|
| 237 |
source ~/.bashrc
|
| 238 |
```
|
| 239 |
|
|
|
|
| 14 |
| **Model ID** | `hf_model_elkulako_cryptobert` |
|
| 15 |
| **Status** | CONDITIONALLY_AVAILABLE |
|
| 16 |
| **Authentication** | Required (HF_TOKEN) |
|
| 17 |
+
| **Token** | `hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` |
|
| 18 |
| **Task Type** | fill-mask (Masked Language Model) |
|
| 19 |
| **Use Case** | Cryptocurrency-specific sentiment analysis |
|
| 20 |
| **Integration Status** | ✓ Active and Operational |
|
|
|
|
| 34 |
"crypto_sentiment": "ElKulako/CryptoBERT", # NEW
|
| 35 |
}
|
| 36 |
|
| 37 |
+
HF_TOKEN = os.environ.get("HF_TOKEN", "hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
|
| 38 |
HF_USE_AUTH_TOKEN = bool(HF_TOKEN)
|
| 39 |
```
|
| 40 |
|
|
|
|
| 227 |
|
| 228 |
### Current Setup
|
| 229 |
```bash
|
| 230 |
+
HF_TOKEN="hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
| 231 |
```
|
| 232 |
|
| 233 |
### Permanent Setup
|
| 234 |
```bash
|
| 235 |
# Add to ~/.bashrc or ~/.zshrc
|
| 236 |
+
echo 'export HF_TOKEN="hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"' >> ~/.bashrc
|
| 237 |
source ~/.bashrc
|
| 238 |
```
|
| 239 |
|
QUICK_START_FA.md
CHANGED
|
@@ -7,14 +7,14 @@
|
|
| 7 |
2. `Settings` → `Repository secrets`
|
| 8 |
3. دو secret اضافه کنید:
|
| 9 |
```
|
| 10 |
-
HF_TOKEN =
|
| 11 |
HF_MODE = public
|
| 12 |
```
|
| 13 |
4. Space را Restart کنید
|
| 14 |
|
| 15 |
### روی Windows Local:
|
| 16 |
```powershell
|
| 17 |
-
$env:HF_TOKEN="
|
| 18 |
$env:HF_MODE="public"
|
| 19 |
```
|
| 20 |
|
|
@@ -66,7 +66,7 @@ $env:HF_TOKEN
|
|
| 66 |
$env:HF_MODE
|
| 67 |
|
| 68 |
# تنظیم مجدد
|
| 69 |
-
$env:HF_TOKEN="
|
| 70 |
$env:HF_MODE="public"
|
| 71 |
```
|
| 72 |
|
|
|
|
| 7 |
2. `Settings` → `Repository secrets`
|
| 8 |
3. دو secret اضافه کنید:
|
| 9 |
```
|
| 10 |
+
HF_TOKEN = hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
| 11 |
HF_MODE = public
|
| 12 |
```
|
| 13 |
4. Space را Restart کنید
|
| 14 |
|
| 15 |
### روی Windows Local:
|
| 16 |
```powershell
|
| 17 |
+
$env:HF_TOKEN="hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
| 18 |
$env:HF_MODE="public"
|
| 19 |
```
|
| 20 |
|
|
|
|
| 66 |
$env:HF_MODE
|
| 67 |
|
| 68 |
# تنظیم مجدد
|
| 69 |
+
$env:HF_TOKEN="hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
| 70 |
$env:HF_MODE="public"
|
| 71 |
```
|
| 72 |
|
SET_HF_TOKEN.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
| 2 |
|
| 3 |
## توکن شما:
|
| 4 |
```
|
| 5 |
-
|
| 6 |
```
|
| 7 |
|
| 8 |
## روشهای تنظیم:
|
|
@@ -15,7 +15,7 @@ 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
|
|
| 15 |
|
| 16 |
**Secret 1:**
|
| 17 |
- Name: `HF_TOKEN`
|
| 18 |
-
- Value: `
|
| 19 |
|
| 20 |
**Secret 2:**
|
| 21 |
- Name: `HF_MODE`
|
|
@@ -29,7 +29,7 @@ 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
|
|
| 29 |
|
| 30 |
در PowerShell:
|
| 31 |
```powershell
|
| 32 |
-
$env:HF_TOKEN="
|
| 33 |
$env:HF_MODE="public"
|
| 34 |
python api_server_extended.py
|
| 35 |
```
|
|
@@ -38,7 +38,7 @@ python api_server_extended.py
|
|
| 38 |
1. Win + R → `sysdm.cpl` → Advanced → Environment Variables
|
| 39 |
2. در User variables، New کنید:
|
| 40 |
- Name: `HF_TOKEN`
|
| 41 |
-
- Value: `
|
| 42 |
3. یکی دیگر:
|
| 43 |
- Name: `HF_MODE`
|
| 44 |
- Value: `public`
|
|
@@ -49,14 +49,14 @@ python api_server_extended.py
|
|
| 49 |
|
| 50 |
در terminal:
|
| 51 |
```bash
|
| 52 |
-
export HF_TOKEN="
|
| 53 |
export HF_MODE="public"
|
| 54 |
python api_server_extended.py
|
| 55 |
```
|
| 56 |
|
| 57 |
یا در `~/.bashrc` یا `~/.zshrc` اضافه کنید:
|
| 58 |
```bash
|
| 59 |
-
export HF_TOKEN="
|
| 60 |
export HF_MODE="public"
|
| 61 |
```
|
| 62 |
|
|
@@ -66,7 +66,7 @@ export HF_MODE="public"
|
|
| 66 |
|
| 67 |
فایل `.env` در root پروژه ایجاد کنید:
|
| 68 |
```
|
| 69 |
-
HF_TOKEN=
|
| 70 |
HF_MODE=public
|
| 71 |
PORT=7860
|
| 72 |
```
|
|
|
|
| 2 |
|
| 3 |
## توکن شما:
|
| 4 |
```
|
| 5 |
+
hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
| 6 |
```
|
| 7 |
|
| 8 |
## روشهای تنظیم:
|
|
|
|
| 15 |
|
| 16 |
**Secret 1:**
|
| 17 |
- Name: `HF_TOKEN`
|
| 18 |
+
- Value: `hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`
|
| 19 |
|
| 20 |
**Secret 2:**
|
| 21 |
- Name: `HF_MODE`
|
|
|
|
| 29 |
|
| 30 |
در PowerShell:
|
| 31 |
```powershell
|
| 32 |
+
$env:HF_TOKEN="hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
| 33 |
$env:HF_MODE="public"
|
| 34 |
python api_server_extended.py
|
| 35 |
```
|
|
|
|
| 38 |
1. Win + R → `sysdm.cpl` → Advanced → Environment Variables
|
| 39 |
2. در User variables، New کنید:
|
| 40 |
- Name: `HF_TOKEN`
|
| 41 |
+
- Value: `hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`
|
| 42 |
3. یکی دیگر:
|
| 43 |
- Name: `HF_MODE`
|
| 44 |
- Value: `public`
|
|
|
|
| 49 |
|
| 50 |
در terminal:
|
| 51 |
```bash
|
| 52 |
+
export HF_TOKEN="hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
| 53 |
export HF_MODE="public"
|
| 54 |
python api_server_extended.py
|
| 55 |
```
|
| 56 |
|
| 57 |
یا در `~/.bashrc` یا `~/.zshrc` اضافه کنید:
|
| 58 |
```bash
|
| 59 |
+
export HF_TOKEN="hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
| 60 |
export HF_MODE="public"
|
| 61 |
```
|
| 62 |
|
|
|
|
| 66 |
|
| 67 |
فایل `.env` در root پروژه ایجاد کنید:
|
| 68 |
```
|
| 69 |
+
HF_TOKEN=hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
| 70 |
HF_MODE=public
|
| 71 |
PORT=7860
|
| 72 |
```
|
START_HERE.md
CHANGED
|
@@ -67,7 +67,7 @@ Score: 5/6 (83.3%)
|
|
| 67 |
|
| 68 |
### گزینه 2: دستی
|
| 69 |
```powershell
|
| 70 |
-
$env:HF_TOKEN="
|
| 71 |
$env:HF_MODE="public"
|
| 72 |
python api_server_extended.py
|
| 73 |
```
|
|
@@ -75,7 +75,7 @@ python api_server_extended.py
|
|
| 75 |
### گزینه 3: دائمی (در System Environment Variables)
|
| 76 |
1. Win + R → `sysdm.cpl`
|
| 77 |
2. Advanced → Environment Variables
|
| 78 |
-
3. New → Name: `HF_TOKEN`, Value: `
|
| 79 |
4. New → Name: `HF_MODE`, Value: `public`
|
| 80 |
|
| 81 |
---
|
|
|
|
| 67 |
|
| 68 |
### گزینه 2: دستی
|
| 69 |
```powershell
|
| 70 |
+
$env:HF_TOKEN="hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
| 71 |
$env:HF_MODE="public"
|
| 72 |
python api_server_extended.py
|
| 73 |
```
|
|
|
|
| 75 |
### گزینه 3: دائمی (در System Environment Variables)
|
| 76 |
1. Win + R → `sysdm.cpl`
|
| 77 |
2. Advanced → Environment Variables
|
| 78 |
+
3. New → Name: `HF_TOKEN`, Value: `hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`
|
| 79 |
4. New → Name: `HF_MODE`, Value: `public`
|
| 80 |
|
| 81 |
---
|
all_apis_merged_2025.json
CHANGED
|
@@ -31,7 +31,7 @@
|
|
| 31 |
"zip_text_snippets": [
|
| 32 |
{
|
| 33 |
"filename": "crypto_resources.ts",
|
| 34 |
-
"text_preview": "// crypto_resources.ts — unified TS with 150+ Hugging Face sources (dynamic catalog) + Safe F&G aggregator\n// English-only comments. Keys intentionally embedded per user request.\n\nexport type Category =\n | 'market'\n | 'news'\n | 'sentiment'\n | 'onchain'\n | 'block_explorer'\n | 'whales'\n | 'generic'\n | 'hf';\n\nexport interface EndpointDef {\n path: string;\n method?: 'GET' | 'POST';\n sampleParams?: Record<string, string | number>;\n authLocation?: 'header' | 'query';\n authName?: string;\n authValue?: string;\n contentType?: string;\n}\n\nexport interface CryptoResource {\n id: string;\n category: Category;\n name: string;\n baseUrl: string;\n free: boolean;\n rateLimit?: string;\n endpoints?: Record<string, EndpointDef>;\n}\n\nexport interface MarketQuote {\n id: string;\n symbol: string;\n name: string;\n price: number;\n change24h?: number;\n marketCap?: number;\n source: string;\n raw: any;\n}\n\nexport interface NewsItem {\n title: string;\n link: string;\n publishedAt?: string;\n source: string;\n}\n\nexport interface OHLCVRow {\n timestamp: number | string;\n open: number; high: number; low: number; close: number; volume: number;\n [k: string]: any;\n}\n\nexport interface FNGPoint {\n value: number; // 0..100\n classification: string;\n at?: string;\n source: string;\n raw?: any;\n}\n\nconst EMBEDDED_KEYS = {\n CMC: '04cf4b5b-9868-465c-8ba0-9f2e78c92eb1',\n ETHERSCAN: 'SZHYFZK2RR8H9TIMJBVW54V4H81K2Z2KR2',\n ETHERSCAN_BACKUP: 'T6IR8VJHX2NE6ZJW2S3FDVN1TYG4PYYI45',\n BSCSCAN: 'K62RKHGXTDCG53RU4MCG6XABIMJKTN19IT',\n CRYPTOCOMPARE: 'e79c8e6d4c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f',\n\n // Optional free keys provided by user (kept in-code per request)\n MESSARI: '',\n SANTIMENT: '',\n COINMETRICS: '',\n HUGGINGFACE: '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',\n};\n\nconst sleep = (ms: number) => new Promise(r => setTimeout(r, ms));\n\nclass HttpError extends Error {\n constructor(public status: number, public url: string, public body?: string) {\n super(`HTTP ${status} for ${url}`);\n }\n}\n\nfunction buildURL(base: string, path = '', params?: Record<string, any>): string {\n const hasQ = path.includes('?');\n const url = base.replace(/\\/+$/, '') + '/' + path.replace(/^\\/+/, '');\n if (!params || Object.keys(params).length === 0) return url;\n const qs = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) {\n if (v === undefined || v === null) continue;\n qs.set(k, String(v));\n }\n return url + (hasQ ? '&' : '?') + qs.toString();\n}\n\nasync function fetchRaw(\n url: string,\n opts: { headers?: Record<string, string>; timeoutMs?: number; retries?: number; retryDelayMs?: number; body?: any; method?: 'GET'|'POST' } = {}\n): Promise<Response> {\n const { headers = {}, timeoutMs = 12000, retries = 1, retryDelayMs = 600, body, method = 'GET' } = opts;\n let lastErr: any;\n for (let attempt = 0; attempt <= retries; attempt++) {\n const ac = new AbortController();\n const id = setTimeout(() => ac.abort(), timeoutMs);\n try {\n const res = await fetch(url, { headers, signal: ac.signal, method, body });\n clearTimeout(id);\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n if (res.status === 429 && attempt < retries) {\n await sleep(retryDelayMs * (attempt + 1));\n continue;\n }\n throw new HttpError(res.status, url, text);\n }\n return res;\n } catch (e) {\n clearTimeout(id);\n lastErr = e;\n if (attempt < retries) { await sleep(retryDelayMs * (attempt + 1)); continue; }\n }\n }\n throw lastErr;\n}\n\nasync function fetchJSON<T = any>(\n url: string,\n opts: { headers?: Record<string, string>; timeoutMs?: number; retries?: number; retryDelayMs?: number; body?: any; method?: 'GET'|'POST' } = {}\n): Promise<T> {\n const res = await fetchRaw(url, opts);\n const ct = res.headers.get('content-type') || '';\n if (ct.includes('json')) return res.json() as Promise<T>;\n const text = await res.text();\n try { return JSON.parse(text) as T; } catch { return text as unknown as T; }\n}\n\nfunction ensureNonEmpty(obj: any, label: string) {\n if (obj == null) throw new Error(`${label}: empty response`);\n if (Array.isArray(obj) && obj.length === 0) throw new Error(`${label}: empty array`);\n if (typeof obj === 'object' && !Array.isArray(obj) && Object.keys(obj).length === 0)\n throw new Error(`${label}: empty object`);\n}\n\nfunction normalizeSymbol(q: string) { return q.trim().toLowerCase(); }\n\nfunction parseCSV(text: string): any[] {\n const lines = text.split(/\\r?\\n/).filter(Boolean);\n if (lines.length < 2) return [];\n const header = lines[0].split(',').map((s) => s.trim());\n const out: any[] = [];\n for (let i = 1; i < lines.length; i++) {\n const cols = lines[i].split(',').map((s) => s.trim());\n const row: any = {};\n header.forEach((h, idx) => { row[h] = cols[idx]; });\n out.push(row);\n }\n return out;\n}\n\nfunction parseRssSimple(xml: string, source: string, limit = 20): NewsItem[] {\n const items: NewsItem[] = [];\n const chunks = xml.split(/<item[\\s>]/i).slice(1);\n for (const raw of chunks) {\n const item = raw.split(/<\\/item>/i)[0] || '';\n const get = (tag: string) => {\n const m = item.match(new RegExp(`<${tag}[^>]*>([\\\\s\\\\S]*?)</${tag}>`, 'i'));\n return m ? m[1].replace(/<!\\[CDATA\\[|\\]\\]>/g, '').trim() : undefined;\n };\n const title = get('title'); const link = get('link') || get('guid'); const pub = get('pubDate') || get('updated') || get('dc:date');\n if (title && link) items.push({ title, link, publishedAt: pub, source });\n if (items.length >= limit) break;\n }\n return items;\n}\n\n/* ===================== BASE RESOURCES ===================== */\n\nexport const resources: CryptoResource[] = [\n // Market\n { id: 'coinpaprika', category: 'market', name: 'CoinPaprika', baseUrl: 'https://api.coinpaprika.com/v1', free: true, endpoints: {\n search: { path: '/search', sampleParams: { q: 'bitcoin', c: 'currencies', limit: 1 } },\n tickerById: { path: '/tickers/{id}', sampleParams: { quotes: 'USD' } },\n }},\n { id: 'coincap', category: 'market', name: 'CoinCap', baseUrl: 'https://api.coincap.io/v2', free: true, endpoints: {\n assets: { path: '/assets', sampleParams: { search: 'bitcoin', limit: 1 } },\n assetById: { path: '/assets/{id}' },\n }},\n { id: 'coingecko', category: 'market', name: 'CoinGecko', baseUrl: 'https://api.coingecko.com/api/v3', free: true, endpoints: {\n simplePrice: { path: '/simple/price?ids={ids}&vs_currencies={fiats}' },\n }},\n { id: 'defillama', category: 'market', name: 'DefiLlama (Prices)', baseUrl: 'https://coins.llama.fi', free: true, endpoints: {\n pricesCurrent: { path: '/prices/current/{coins}' },\n }},\n { id: 'binance', category: 'market', name: 'Binance Public', baseUrl: 'https://api.binance.com', free: true, endpoints: {\n klines: { path: '/api/v3/klines?symbol={symbol}&interval={interval}&limit={limit}' },\n ticker: { path: '/api/v3/ticker/price?symbol={symbol}' },\n }},\n { id: 'cryptocompare', category: 'market', name: 'CryptoCompare', baseUrl: 'https://min-api.cryptocompare.com', free: true, endpoints: {\n histominute: { path: '/data/v2/histominute?fsym={fsym}&tsym={tsym}&limit={limit}&api_key=' + EMBEDDED_KEYS.CRYPTOCOMPARE },\n histohour: { path: '/data/v2/histohour?fsym={fsym}&tsym={tsym}&limit={limit}&api_key=' + EMBEDDED_KEYS.CRYPTOCOMPARE },\n histoday: { path: '/data/v2/histoday?fsym={fsym}&tsym={tsym}&limit={limit}&api_key=' + EMBEDDED_KEYS.CRYPTOCOMPARE },\n }},\n { id: 'cmc', category: 'market', name: 'CoinMarketCap', baseUrl: 'https://pro-api.coinmarketcap.com/v1', free: false, endpoints: {\n quotes: { path: '/cryptocurrency/quotes/latest?symbol={symbol}', authLocation: 'header', authName: 'X-CMC_PRO_API_KEY', authValue: EMBEDDED_KEYS.CMC },\n }},\n\n // News\n { id: 'coinstats_news', category: 'news', name: 'CoinStats News', baseUrl: 'https://api.coinstats.app', free: true, endpoints: { feed: { path: '/public/v1/news' } }},\n { id: 'cryptopanic', category: 'news', name: 'CryptoPanic', baseUrl: 'https://cryptopanic.com', free: true, endpoints: { public: { path: '/api/v1/posts/?public=true' } }},\n { id: 'rss_cointelegraph', category: 'news', name: 'Cointelegraph RSS', baseUrl: 'https://cointelegraph.com', free: true, endpoints: { feed: { path: '/rss' } }},\n { id: 'rss_coindesk', category: 'news', name: 'CoinDesk RSS', baseUrl: 'https://www.coindesk.com', free: true, endpoints: { feed: { path: '/arc/outboundfeeds/rss/?outputType=xml' } }},\n { id: 'rss_decrypt', category: 'news', name: 'Decrypt RSS', baseUrl: 'https://decrypt.co', free: true, endpoints: { feed: { path: '/feed' } }},\n\n // Sentiment / F&G\n { id: 'altme_fng', category: 'sentiment', name: 'Alternative.me F&G', baseUrl: 'https://api.alternative.me', free: true, endpoints: {\n latest: { path: '/fng/', sampleParams: { limit: 1 } },\n history: { path: '/fng/', sampleParams: { limit: 30 } },\n }},\n { id: 'cfgi_v1', category: 'sentiment', name: 'CFGI API v1', baseUrl: 'https://api.cfgi.io', free: true, endpoints: {\n latest: { path: '/v1/fear-greed' },\n }},\n { id: 'cfgi_legacy', category: 'sentiment', name: 'CFGI Legacy', baseUrl: 'https://cfgi.io', free: true, endpoints: {\n latest: { path: '/api' },\n }},\n\n // On-chain / explorers\n { id: 'etherscan_primary', category: 'block_explorer', name: 'Etherscan', baseUrl: 'https://api.etherscan.io/api', free: false, endpoints: {\n balance: { path: '/?module=account&action=balance&address={address}&tag=latest&apikey=' + EMBEDDED_KEYS.ETHERSCAN },\n }},\n { id: 'etherscan_backup', category: 'block_explorer', name: 'Etherscan Backup', baseUrl: 'https://api.etherscan.io/api', free: false, endpoints: {\n balance: { path: '/?module=account&action=balance&address={address}&tag=latest&apikey=' + EMBEDDED_KEYS.ETHERSCAN_BACKUP },\n }},\n { id: 'blockscout_eth', category: 'block_explorer', name: 'Blockscout (ETH)', baseUrl: 'https://eth.blockscout.com', free: true, endpoints: {\n balanc",
|
| 35 |
"note": "included as small text"
|
| 36 |
}
|
| 37 |
],
|
|
@@ -57,7 +57,7 @@
|
|
| 57 |
"e79c8e6d4c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f"
|
| 58 |
],
|
| 59 |
"huggingface": [
|
| 60 |
-
"
|
| 61 |
]
|
| 62 |
},
|
| 63 |
"notes": "This file was auto-generated. Keys/tokens are present as found in uploaded sources. Secure them as you wish."
|
|
|
|
| 31 |
"zip_text_snippets": [
|
| 32 |
{
|
| 33 |
"filename": "crypto_resources.ts",
|
| 34 |
+
"text_preview": "// crypto_resources.ts — unified TS with 150+ Hugging Face sources (dynamic catalog) + Safe F&G aggregator\n// English-only comments. Keys intentionally embedded per user request.\n\nexport type Category =\n | 'market'\n | 'news'\n | 'sentiment'\n | 'onchain'\n | 'block_explorer'\n | 'whales'\n | 'generic'\n | 'hf';\n\nexport interface EndpointDef {\n path: string;\n method?: 'GET' | 'POST';\n sampleParams?: Record<string, string | number>;\n authLocation?: 'header' | 'query';\n authName?: string;\n authValue?: string;\n contentType?: string;\n}\n\nexport interface CryptoResource {\n id: string;\n category: Category;\n name: string;\n baseUrl: string;\n free: boolean;\n rateLimit?: string;\n endpoints?: Record<string, EndpointDef>;\n}\n\nexport interface MarketQuote {\n id: string;\n symbol: string;\n name: string;\n price: number;\n change24h?: number;\n marketCap?: number;\n source: string;\n raw: any;\n}\n\nexport interface NewsItem {\n title: string;\n link: string;\n publishedAt?: string;\n source: string;\n}\n\nexport interface OHLCVRow {\n timestamp: number | string;\n open: number; high: number; low: number; close: number; volume: number;\n [k: string]: any;\n}\n\nexport interface FNGPoint {\n value: number; // 0..100\n classification: string;\n at?: string;\n source: string;\n raw?: any;\n}\n\nconst EMBEDDED_KEYS = {\n CMC: '04cf4b5b-9868-465c-8ba0-9f2e78c92eb1',\n ETHERSCAN: 'SZHYFZK2RR8H9TIMJBVW54V4H81K2Z2KR2',\n ETHERSCAN_BACKUP: 'T6IR8VJHX2NE6ZJW2S3FDVN1TYG4PYYI45',\n BSCSCAN: 'K62RKHGXTDCG53RU4MCG6XABIMJKTN19IT',\n CRYPTOCOMPARE: 'e79c8e6d4c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f',\n\n // Optional free keys provided by user (kept in-code per request)\n MESSARI: '',\n SANTIMENT: '',\n COINMETRICS: '',\n HUGGINGFACE: 'hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',\n};\n\nconst sleep = (ms: number) => new Promise(r => setTimeout(r, ms));\n\nclass HttpError extends Error {\n constructor(public status: number, public url: string, public body?: string) {\n super(`HTTP ${status} for ${url}`);\n }\n}\n\nfunction buildURL(base: string, path = '', params?: Record<string, any>): string {\n const hasQ = path.includes('?');\n const url = base.replace(/\\/+$/, '') + '/' + path.replace(/^\\/+/, '');\n if (!params || Object.keys(params).length === 0) return url;\n const qs = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) {\n if (v === undefined || v === null) continue;\n qs.set(k, String(v));\n }\n return url + (hasQ ? '&' : '?') + qs.toString();\n}\n\nasync function fetchRaw(\n url: string,\n opts: { headers?: Record<string, string>; timeoutMs?: number; retries?: number; retryDelayMs?: number; body?: any; method?: 'GET'|'POST' } = {}\n): Promise<Response> {\n const { headers = {}, timeoutMs = 12000, retries = 1, retryDelayMs = 600, body, method = 'GET' } = opts;\n let lastErr: any;\n for (let attempt = 0; attempt <= retries; attempt++) {\n const ac = new AbortController();\n const id = setTimeout(() => ac.abort(), timeoutMs);\n try {\n const res = await fetch(url, { headers, signal: ac.signal, method, body });\n clearTimeout(id);\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n if (res.status === 429 && attempt < retries) {\n await sleep(retryDelayMs * (attempt + 1));\n continue;\n }\n throw new HttpError(res.status, url, text);\n }\n return res;\n } catch (e) {\n clearTimeout(id);\n lastErr = e;\n if (attempt < retries) { await sleep(retryDelayMs * (attempt + 1)); continue; }\n }\n }\n throw lastErr;\n}\n\nasync function fetchJSON<T = any>(\n url: string,\n opts: { headers?: Record<string, string>; timeoutMs?: number; retries?: number; retryDelayMs?: number; body?: any; method?: 'GET'|'POST' } = {}\n): Promise<T> {\n const res = await fetchRaw(url, opts);\n const ct = res.headers.get('content-type') || '';\n if (ct.includes('json')) return res.json() as Promise<T>;\n const text = await res.text();\n try { return JSON.parse(text) as T; } catch { return text as unknown as T; }\n}\n\nfunction ensureNonEmpty(obj: any, label: string) {\n if (obj == null) throw new Error(`${label}: empty response`);\n if (Array.isArray(obj) && obj.length === 0) throw new Error(`${label}: empty array`);\n if (typeof obj === 'object' && !Array.isArray(obj) && Object.keys(obj).length === 0)\n throw new Error(`${label}: empty object`);\n}\n\nfunction normalizeSymbol(q: string) { return q.trim().toLowerCase(); }\n\nfunction parseCSV(text: string): any[] {\n const lines = text.split(/\\r?\\n/).filter(Boolean);\n if (lines.length < 2) return [];\n const header = lines[0].split(',').map((s) => s.trim());\n const out: any[] = [];\n for (let i = 1; i < lines.length; i++) {\n const cols = lines[i].split(',').map((s) => s.trim());\n const row: any = {};\n header.forEach((h, idx) => { row[h] = cols[idx]; });\n out.push(row);\n }\n return out;\n}\n\nfunction parseRssSimple(xml: string, source: string, limit = 20): NewsItem[] {\n const items: NewsItem[] = [];\n const chunks = xml.split(/<item[\\s>]/i).slice(1);\n for (const raw of chunks) {\n const item = raw.split(/<\\/item>/i)[0] || '';\n const get = (tag: string) => {\n const m = item.match(new RegExp(`<${tag}[^>]*>([\\\\s\\\\S]*?)</${tag}>`, 'i'));\n return m ? m[1].replace(/<!\\[CDATA\\[|\\]\\]>/g, '').trim() : undefined;\n };\n const title = get('title'); const link = get('link') || get('guid'); const pub = get('pubDate') || get('updated') || get('dc:date');\n if (title && link) items.push({ title, link, publishedAt: pub, source });\n if (items.length >= limit) break;\n }\n return items;\n}\n\n/* ===================== BASE RESOURCES ===================== */\n\nexport const resources: CryptoResource[] = [\n // Market\n { id: 'coinpaprika', category: 'market', name: 'CoinPaprika', baseUrl: 'https://api.coinpaprika.com/v1', free: true, endpoints: {\n search: { path: '/search', sampleParams: { q: 'bitcoin', c: 'currencies', limit: 1 } },\n tickerById: { path: '/tickers/{id}', sampleParams: { quotes: 'USD' } },\n }},\n { id: 'coincap', category: 'market', name: 'CoinCap', baseUrl: 'https://api.coincap.io/v2', free: true, endpoints: {\n assets: { path: '/assets', sampleParams: { search: 'bitcoin', limit: 1 } },\n assetById: { path: '/assets/{id}' },\n }},\n { id: 'coingecko', category: 'market', name: 'CoinGecko', baseUrl: 'https://api.coingecko.com/api/v3', free: true, endpoints: {\n simplePrice: { path: '/simple/price?ids={ids}&vs_currencies={fiats}' },\n }},\n { id: 'defillama', category: 'market', name: 'DefiLlama (Prices)', baseUrl: 'https://coins.llama.fi', free: true, endpoints: {\n pricesCurrent: { path: '/prices/current/{coins}' },\n }},\n { id: 'binance', category: 'market', name: 'Binance Public', baseUrl: 'https://api.binance.com', free: true, endpoints: {\n klines: { path: '/api/v3/klines?symbol={symbol}&interval={interval}&limit={limit}' },\n ticker: { path: '/api/v3/ticker/price?symbol={symbol}' },\n }},\n { id: 'cryptocompare', category: 'market', name: 'CryptoCompare', baseUrl: 'https://min-api.cryptocompare.com', free: true, endpoints: {\n histominute: { path: '/data/v2/histominute?fsym={fsym}&tsym={tsym}&limit={limit}&api_key=' + EMBEDDED_KEYS.CRYPTOCOMPARE },\n histohour: { path: '/data/v2/histohour?fsym={fsym}&tsym={tsym}&limit={limit}&api_key=' + EMBEDDED_KEYS.CRYPTOCOMPARE },\n histoday: { path: '/data/v2/histoday?fsym={fsym}&tsym={tsym}&limit={limit}&api_key=' + EMBEDDED_KEYS.CRYPTOCOMPARE },\n }},\n { id: 'cmc', category: 'market', name: 'CoinMarketCap', baseUrl: 'https://pro-api.coinmarketcap.com/v1', free: false, endpoints: {\n quotes: { path: '/cryptocurrency/quotes/latest?symbol={symbol}', authLocation: 'header', authName: 'X-CMC_PRO_API_KEY', authValue: EMBEDDED_KEYS.CMC },\n }},\n\n // News\n { id: 'coinstats_news', category: 'news', name: 'CoinStats News', baseUrl: 'https://api.coinstats.app', free: true, endpoints: { feed: { path: '/public/v1/news' } }},\n { id: 'cryptopanic', category: 'news', name: 'CryptoPanic', baseUrl: 'https://cryptopanic.com', free: true, endpoints: { public: { path: '/api/v1/posts/?public=true' } }},\n { id: 'rss_cointelegraph', category: 'news', name: 'Cointelegraph RSS', baseUrl: 'https://cointelegraph.com', free: true, endpoints: { feed: { path: '/rss' } }},\n { id: 'rss_coindesk', category: 'news', name: 'CoinDesk RSS', baseUrl: 'https://www.coindesk.com', free: true, endpoints: { feed: { path: '/arc/outboundfeeds/rss/?outputType=xml' } }},\n { id: 'rss_decrypt', category: 'news', name: 'Decrypt RSS', baseUrl: 'https://decrypt.co', free: true, endpoints: { feed: { path: '/feed' } }},\n\n // Sentiment / F&G\n { id: 'altme_fng', category: 'sentiment', name: 'Alternative.me F&G', baseUrl: 'https://api.alternative.me', free: true, endpoints: {\n latest: { path: '/fng/', sampleParams: { limit: 1 } },\n history: { path: '/fng/', sampleParams: { limit: 30 } },\n }},\n { id: 'cfgi_v1', category: 'sentiment', name: 'CFGI API v1', baseUrl: 'https://api.cfgi.io', free: true, endpoints: {\n latest: { path: '/v1/fear-greed' },\n }},\n { id: 'cfgi_legacy', category: 'sentiment', name: 'CFGI Legacy', baseUrl: 'https://cfgi.io', free: true, endpoints: {\n latest: { path: '/api' },\n }},\n\n // On-chain / explorers\n { id: 'etherscan_primary', category: 'block_explorer', name: 'Etherscan', baseUrl: 'https://api.etherscan.io/api', free: false, endpoints: {\n balance: { path: '/?module=account&action=balance&address={address}&tag=latest&apikey=' + EMBEDDED_KEYS.ETHERSCAN },\n }},\n { id: 'etherscan_backup', category: 'block_explorer', name: 'Etherscan Backup', baseUrl: 'https://api.etherscan.io/api', free: false, endpoints: {\n balance: { path: '/?module=account&action=balance&address={address}&tag=latest&apikey=' + EMBEDDED_KEYS.ETHERSCAN_BACKUP },\n }},\n { id: 'blockscout_eth', category: 'block_explorer', name: 'Blockscout (ETH)', baseUrl: 'https://eth.blockscout.com', free: true, endpoints: {\n balanc",
|
| 35 |
"note": "included as small text"
|
| 36 |
}
|
| 37 |
],
|
|
|
|
| 57 |
"e79c8e6d4c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f"
|
| 58 |
],
|
| 59 |
"huggingface": [
|
| 60 |
+
"hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
| 61 |
]
|
| 62 |
},
|
| 63 |
"notes": "This file was auto-generated. Keys/tokens are present as found in uploaded sources. Secure them as you wish."
|
api-resources/crypto_resources_unified_2025-11-11.json
CHANGED
|
@@ -2084,7 +2084,7 @@
|
|
| 2084 |
"base_url": "https://api-inference.huggingface.co/models/ElKulako/cryptobert",
|
| 2085 |
"auth": {
|
| 2086 |
"type": "apiKeyHeaderOptional",
|
| 2087 |
-
"key": "
|
| 2088 |
"header_name": "Authorization"
|
| 2089 |
},
|
| 2090 |
"docs_url": "https://huggingface.co/ElKulako/cryptobert",
|
|
@@ -2100,7 +2100,7 @@
|
|
| 2100 |
"base_url": "https://api-inference.huggingface.co/models/kk08/CryptoBERT",
|
| 2101 |
"auth": {
|
| 2102 |
"type": "apiKeyHeaderOptional",
|
| 2103 |
-
"key": "
|
| 2104 |
"header_name": "Authorization"
|
| 2105 |
},
|
| 2106 |
"docs_url": "https://huggingface.co/kk08/CryptoBERT",
|
|
|
|
| 2084 |
"base_url": "https://api-inference.huggingface.co/models/ElKulako/cryptobert",
|
| 2085 |
"auth": {
|
| 2086 |
"type": "apiKeyHeaderOptional",
|
| 2087 |
+
"key": "hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
| 2088 |
"header_name": "Authorization"
|
| 2089 |
},
|
| 2090 |
"docs_url": "https://huggingface.co/ElKulako/cryptobert",
|
|
|
|
| 2100 |
"base_url": "https://api-inference.huggingface.co/models/kk08/CryptoBERT",
|
| 2101 |
"auth": {
|
| 2102 |
"type": "apiKeyHeaderOptional",
|
| 2103 |
+
"key": "hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
| 2104 |
"header_name": "Authorization"
|
| 2105 |
},
|
| 2106 |
"docs_url": "https://huggingface.co/kk08/CryptoBERT",
|
api/HF_IMPLEMENTATION_COMPLETE.md
CHANGED
|
@@ -47,7 +47,7 @@
|
|
| 47 |
|
| 48 |
#### 1. **Environment Configuration** (`.env`)
|
| 49 |
```env
|
| 50 |
-
HUGGINGFACE_TOKEN=
|
| 51 |
ENABLE_SENTIMENT=true
|
| 52 |
SENTIMENT_SOCIAL_MODEL=ElKulako/cryptobert
|
| 53 |
SENTIMENT_NEWS_MODEL=kk08/CryptoBERT
|
|
|
|
| 47 |
|
| 48 |
#### 1. **Environment Configuration** (`.env`)
|
| 49 |
```env
|
| 50 |
+
HUGGINGFACE_TOKEN=hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
| 51 |
ENABLE_SENTIMENT=true
|
| 52 |
SENTIMENT_SOCIAL_MODEL=ElKulako/cryptobert
|
| 53 |
SENTIMENT_NEWS_MODEL=kk08/CryptoBERT
|
api/QUICK_START.md
CHANGED
|
@@ -138,7 +138,7 @@ Edit `.env` file to customize:
|
|
| 138 |
|
| 139 |
```env
|
| 140 |
# HuggingFace Token (optional, for higher rate limits)
|
| 141 |
-
HUGGINGFACE_TOKEN=
|
| 142 |
|
| 143 |
# Enable/disable local sentiment analysis
|
| 144 |
ENABLE_SENTIMENT=true
|
|
|
|
| 138 |
|
| 139 |
```env
|
| 140 |
# HuggingFace Token (optional, for higher rate limits)
|
| 141 |
+
HUGGINGFACE_TOKEN=hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
| 142 |
|
| 143 |
# Enable/disable local sentiment analysis
|
| 144 |
ENABLE_SENTIMENT=true
|
api/all_apis_merged_2025.json
CHANGED
|
@@ -31,7 +31,7 @@
|
|
| 31 |
"zip_text_snippets": [
|
| 32 |
{
|
| 33 |
"filename": "crypto_resources.ts",
|
| 34 |
-
"text_preview": "// crypto_resources.ts — unified TS with 150+ Hugging Face sources (dynamic catalog) + Safe F&G aggregator\n// English-only comments. Keys intentionally embedded per user request.\n\nexport type Category =\n | 'market'\n | 'news'\n | 'sentiment'\n | 'onchain'\n | 'block_explorer'\n | 'whales'\n | 'generic'\n | 'hf';\n\nexport interface EndpointDef {\n path: string;\n method?: 'GET' | 'POST';\n sampleParams?: Record<string, string | number>;\n authLocation?: 'header' | 'query';\n authName?: string;\n authValue?: string;\n contentType?: string;\n}\n\nexport interface CryptoResource {\n id: string;\n category: Category;\n name: string;\n baseUrl: string;\n free: boolean;\n rateLimit?: string;\n endpoints?: Record<string, EndpointDef>;\n}\n\nexport interface MarketQuote {\n id: string;\n symbol: string;\n name: string;\n price: number;\n change24h?: number;\n marketCap?: number;\n source: string;\n raw: any;\n}\n\nexport interface NewsItem {\n title: string;\n link: string;\n publishedAt?: string;\n source: string;\n}\n\nexport interface OHLCVRow {\n timestamp: number | string;\n open: number; high: number; low: number; close: number; volume: number;\n [k: string]: any;\n}\n\nexport interface FNGPoint {\n value: number; // 0..100\n classification: string;\n at?: string;\n source: string;\n raw?: any;\n}\n\nconst EMBEDDED_KEYS = {\n CMC: '04cf4b5b-9868-465c-8ba0-9f2e78c92eb1',\n ETHERSCAN: 'SZHYFZK2RR8H9TIMJBVW54V4H81K2Z2KR2',\n ETHERSCAN_BACKUP: 'T6IR8VJHX2NE6ZJW2S3FDVN1TYG4PYYI45',\n BSCSCAN: 'K62RKHGXTDCG53RU4MCG6XABIMJKTN19IT',\n CRYPTOCOMPARE: 'e79c8e6d4c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f',\n\n // Optional free keys provided by user (kept in-code per request)\n MESSARI: '',\n SANTIMENT: '',\n COINMETRICS: '',\n HUGGINGFACE: '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',\n};\n\nconst sleep = (ms: number) => new Promise(r => setTimeout(r, ms));\n\nclass HttpError extends Error {\n constructor(public status: number, public url: string, public body?: string) {\n super(`HTTP ${status} for ${url}`);\n }\n}\n\nfunction buildURL(base: string, path = '', params?: Record<string, any>): string {\n const hasQ = path.includes('?');\n const url = base.replace(/\\/+$/, '') + '/' + path.replace(/^\\/+/, '');\n if (!params || Object.keys(params).length === 0) return url;\n const qs = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) {\n if (v === undefined || v === null) continue;\n qs.set(k, String(v));\n }\n return url + (hasQ ? '&' : '?') + qs.toString();\n}\n\nasync function fetchRaw(\n url: string,\n opts: { headers?: Record<string, string>; timeoutMs?: number; retries?: number; retryDelayMs?: number; body?: any; method?: 'GET'|'POST' } = {}\n): Promise<Response> {\n const { headers = {}, timeoutMs = 12000, retries = 1, retryDelayMs = 600, body, method = 'GET' } = opts;\n let lastErr: any;\n for (let attempt = 0; attempt <= retries; attempt++) {\n const ac = new AbortController();\n const id = setTimeout(() => ac.abort(), timeoutMs);\n try {\n const res = await fetch(url, { headers, signal: ac.signal, method, body });\n clearTimeout(id);\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n if (res.status === 429 && attempt < retries) {\n await sleep(retryDelayMs * (attempt + 1));\n continue;\n }\n throw new HttpError(res.status, url, text);\n }\n return res;\n } catch (e) {\n clearTimeout(id);\n lastErr = e;\n if (attempt < retries) { await sleep(retryDelayMs * (attempt + 1)); continue; }\n }\n }\n throw lastErr;\n}\n\nasync function fetchJSON<T = any>(\n url: string,\n opts: { headers?: Record<string, string>; timeoutMs?: number; retries?: number; retryDelayMs?: number; body?: any; method?: 'GET'|'POST' } = {}\n): Promise<T> {\n const res = await fetchRaw(url, opts);\n const ct = res.headers.get('content-type') || '';\n if (ct.includes('json')) return res.json() as Promise<T>;\n const text = await res.text();\n try { return JSON.parse(text) as T; } catch { return text as unknown as T; }\n}\n\nfunction ensureNonEmpty(obj: any, label: string) {\n if (obj == null) throw new Error(`${label}: empty response`);\n if (Array.isArray(obj) && obj.length === 0) throw new Error(`${label}: empty array`);\n if (typeof obj === 'object' && !Array.isArray(obj) && Object.keys(obj).length === 0)\n throw new Error(`${label}: empty object`);\n}\n\nfunction normalizeSymbol(q: string) { return q.trim().toLowerCase(); }\n\nfunction parseCSV(text: string): any[] {\n const lines = text.split(/\\r?\\n/).filter(Boolean);\n if (lines.length < 2) return [];\n const header = lines[0].split(',').map((s) => s.trim());\n const out: any[] = [];\n for (let i = 1; i < lines.length; i++) {\n const cols = lines[i].split(',').map((s) => s.trim());\n const row: any = {};\n header.forEach((h, idx) => { row[h] = cols[idx]; });\n out.push(row);\n }\n return out;\n}\n\nfunction parseRssSimple(xml: string, source: string, limit = 20): NewsItem[] {\n const items: NewsItem[] = [];\n const chunks = xml.split(/<item[\\s>]/i).slice(1);\n for (const raw of chunks) {\n const item = raw.split(/<\\/item>/i)[0] || '';\n const get = (tag: string) => {\n const m = item.match(new RegExp(`<${tag}[^>]*>([\\\\s\\\\S]*?)</${tag}>`, 'i'));\n return m ? m[1].replace(/<!\\[CDATA\\[|\\]\\]>/g, '').trim() : undefined;\n };\n const title = get('title'); const link = get('link') || get('guid'); const pub = get('pubDate') || get('updated') || get('dc:date');\n if (title && link) items.push({ title, link, publishedAt: pub, source });\n if (items.length >= limit) break;\n }\n return items;\n}\n\n/* ===================== BASE RESOURCES ===================== */\n\nexport const resources: CryptoResource[] = [\n // Market\n { id: 'coinpaprika', category: 'market', name: 'CoinPaprika', baseUrl: 'https://api.coinpaprika.com/v1', free: true, endpoints: {\n search: { path: '/search', sampleParams: { q: 'bitcoin', c: 'currencies', limit: 1 } },\n tickerById: { path: '/tickers/{id}', sampleParams: { quotes: 'USD' } },\n }},\n { id: 'coincap', category: 'market', name: 'CoinCap', baseUrl: 'https://api.coincap.io/v2', free: true, endpoints: {\n assets: { path: '/assets', sampleParams: { search: 'bitcoin', limit: 1 } },\n assetById: { path: '/assets/{id}' },\n }},\n { id: 'coingecko', category: 'market', name: 'CoinGecko', baseUrl: 'https://api.coingecko.com/api/v3', free: true, endpoints: {\n simplePrice: { path: '/simple/price?ids={ids}&vs_currencies={fiats}' },\n }},\n { id: 'defillama', category: 'market', name: 'DefiLlama (Prices)', baseUrl: 'https://coins.llama.fi', free: true, endpoints: {\n pricesCurrent: { path: '/prices/current/{coins}' },\n }},\n { id: 'binance', category: 'market', name: 'Binance Public', baseUrl: 'https://api.binance.com', free: true, endpoints: {\n klines: { path: '/api/v3/klines?symbol={symbol}&interval={interval}&limit={limit}' },\n ticker: { path: '/api/v3/ticker/price?symbol={symbol}' },\n }},\n { id: 'cryptocompare', category: 'market', name: 'CryptoCompare', baseUrl: 'https://min-api.cryptocompare.com', free: true, endpoints: {\n histominute: { path: '/data/v2/histominute?fsym={fsym}&tsym={tsym}&limit={limit}&api_key=' + EMBEDDED_KEYS.CRYPTOCOMPARE },\n histohour: { path: '/data/v2/histohour?fsym={fsym}&tsym={tsym}&limit={limit}&api_key=' + EMBEDDED_KEYS.CRYPTOCOMPARE },\n histoday: { path: '/data/v2/histoday?fsym={fsym}&tsym={tsym}&limit={limit}&api_key=' + EMBEDDED_KEYS.CRYPTOCOMPARE },\n }},\n { id: 'cmc', category: 'market', name: 'CoinMarketCap', baseUrl: 'https://pro-api.coinmarketcap.com/v1', free: false, endpoints: {\n quotes: { path: '/cryptocurrency/quotes/latest?symbol={symbol}', authLocation: 'header', authName: 'X-CMC_PRO_API_KEY', authValue: EMBEDDED_KEYS.CMC },\n }},\n\n // News\n { id: 'coinstats_news', category: 'news', name: 'CoinStats News', baseUrl: 'https://api.coinstats.app', free: true, endpoints: { feed: { path: '/public/v1/news' } }},\n { id: 'cryptopanic', category: 'news', name: 'CryptoPanic', baseUrl: 'https://cryptopanic.com', free: true, endpoints: { public: { path: '/api/v1/posts/?public=true' } }},\n { id: 'rss_cointelegraph', category: 'news', name: 'Cointelegraph RSS', baseUrl: 'https://cointelegraph.com', free: true, endpoints: { feed: { path: '/rss' } }},\n { id: 'rss_coindesk', category: 'news', name: 'CoinDesk RSS', baseUrl: 'https://www.coindesk.com', free: true, endpoints: { feed: { path: '/arc/outboundfeeds/rss/?outputType=xml' } }},\n { id: 'rss_decrypt', category: 'news', name: 'Decrypt RSS', baseUrl: 'https://decrypt.co', free: true, endpoints: { feed: { path: '/feed' } }},\n\n // Sentiment / F&G\n { id: 'altme_fng', category: 'sentiment', name: 'Alternative.me F&G', baseUrl: 'https://api.alternative.me', free: true, endpoints: {\n latest: { path: '/fng/', sampleParams: { limit: 1 } },\n history: { path: '/fng/', sampleParams: { limit: 30 } },\n }},\n { id: 'cfgi_v1', category: 'sentiment', name: 'CFGI API v1', baseUrl: 'https://api.cfgi.io', free: true, endpoints: {\n latest: { path: '/v1/fear-greed' },\n }},\n { id: 'cfgi_legacy', category: 'sentiment', name: 'CFGI Legacy', baseUrl: 'https://cfgi.io', free: true, endpoints: {\n latest: { path: '/api' },\n }},\n\n // On-chain / explorers\n { id: 'etherscan_primary', category: 'block_explorer', name: 'Etherscan', baseUrl: 'https://api.etherscan.io/api', free: false, endpoints: {\n balance: { path: '/?module=account&action=balance&address={address}&tag=latest&apikey=' + EMBEDDED_KEYS.ETHERSCAN },\n }},\n { id: 'etherscan_backup', category: 'block_explorer', name: 'Etherscan Backup', baseUrl: 'https://api.etherscan.io/api', free: false, endpoints: {\n balance: { path: '/?module=account&action=balance&address={address}&tag=latest&apikey=' + EMBEDDED_KEYS.ETHERSCAN_BACKUP },\n }},\n { id: 'blockscout_eth', category: 'block_explorer', name: 'Blockscout (ETH)', baseUrl: 'https://eth.blockscout.com', free: true, endpoints: {\n balanc",
|
| 35 |
"note": "included as small text"
|
| 36 |
}
|
| 37 |
],
|
|
@@ -57,7 +57,7 @@
|
|
| 57 |
"e79c8e6d4c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f"
|
| 58 |
],
|
| 59 |
"huggingface": [
|
| 60 |
-
"
|
| 61 |
]
|
| 62 |
},
|
| 63 |
"notes": "This file was auto-generated. Keys/tokens are present as found in uploaded sources. Secure them as you wish."
|
|
|
|
| 31 |
"zip_text_snippets": [
|
| 32 |
{
|
| 33 |
"filename": "crypto_resources.ts",
|
| 34 |
+
"text_preview": "// crypto_resources.ts — unified TS with 150+ Hugging Face sources (dynamic catalog) + Safe F&G aggregator\n// English-only comments. Keys intentionally embedded per user request.\n\nexport type Category =\n | 'market'\n | 'news'\n | 'sentiment'\n | 'onchain'\n | 'block_explorer'\n | 'whales'\n | 'generic'\n | 'hf';\n\nexport interface EndpointDef {\n path: string;\n method?: 'GET' | 'POST';\n sampleParams?: Record<string, string | number>;\n authLocation?: 'header' | 'query';\n authName?: string;\n authValue?: string;\n contentType?: string;\n}\n\nexport interface CryptoResource {\n id: string;\n category: Category;\n name: string;\n baseUrl: string;\n free: boolean;\n rateLimit?: string;\n endpoints?: Record<string, EndpointDef>;\n}\n\nexport interface MarketQuote {\n id: string;\n symbol: string;\n name: string;\n price: number;\n change24h?: number;\n marketCap?: number;\n source: string;\n raw: any;\n}\n\nexport interface NewsItem {\n title: string;\n link: string;\n publishedAt?: string;\n source: string;\n}\n\nexport interface OHLCVRow {\n timestamp: number | string;\n open: number; high: number; low: number; close: number; volume: number;\n [k: string]: any;\n}\n\nexport interface FNGPoint {\n value: number; // 0..100\n classification: string;\n at?: string;\n source: string;\n raw?: any;\n}\n\nconst EMBEDDED_KEYS = {\n CMC: '04cf4b5b-9868-465c-8ba0-9f2e78c92eb1',\n ETHERSCAN: 'SZHYFZK2RR8H9TIMJBVW54V4H81K2Z2KR2',\n ETHERSCAN_BACKUP: 'T6IR8VJHX2NE6ZJW2S3FDVN1TYG4PYYI45',\n BSCSCAN: 'K62RKHGXTDCG53RU4MCG6XABIMJKTN19IT',\n CRYPTOCOMPARE: 'e79c8e6d4c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f',\n\n // Optional free keys provided by user (kept in-code per request)\n MESSARI: '',\n SANTIMENT: '',\n COINMETRICS: '',\n HUGGINGFACE: 'hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',\n};\n\nconst sleep = (ms: number) => new Promise(r => setTimeout(r, ms));\n\nclass HttpError extends Error {\n constructor(public status: number, public url: string, public body?: string) {\n super(`HTTP ${status} for ${url}`);\n }\n}\n\nfunction buildURL(base: string, path = '', params?: Record<string, any>): string {\n const hasQ = path.includes('?');\n const url = base.replace(/\\/+$/, '') + '/' + path.replace(/^\\/+/, '');\n if (!params || Object.keys(params).length === 0) return url;\n const qs = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) {\n if (v === undefined || v === null) continue;\n qs.set(k, String(v));\n }\n return url + (hasQ ? '&' : '?') + qs.toString();\n}\n\nasync function fetchRaw(\n url: string,\n opts: { headers?: Record<string, string>; timeoutMs?: number; retries?: number; retryDelayMs?: number; body?: any; method?: 'GET'|'POST' } = {}\n): Promise<Response> {\n const { headers = {}, timeoutMs = 12000, retries = 1, retryDelayMs = 600, body, method = 'GET' } = opts;\n let lastErr: any;\n for (let attempt = 0; attempt <= retries; attempt++) {\n const ac = new AbortController();\n const id = setTimeout(() => ac.abort(), timeoutMs);\n try {\n const res = await fetch(url, { headers, signal: ac.signal, method, body });\n clearTimeout(id);\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n if (res.status === 429 && attempt < retries) {\n await sleep(retryDelayMs * (attempt + 1));\n continue;\n }\n throw new HttpError(res.status, url, text);\n }\n return res;\n } catch (e) {\n clearTimeout(id);\n lastErr = e;\n if (attempt < retries) { await sleep(retryDelayMs * (attempt + 1)); continue; }\n }\n }\n throw lastErr;\n}\n\nasync function fetchJSON<T = any>(\n url: string,\n opts: { headers?: Record<string, string>; timeoutMs?: number; retries?: number; retryDelayMs?: number; body?: any; method?: 'GET'|'POST' } = {}\n): Promise<T> {\n const res = await fetchRaw(url, opts);\n const ct = res.headers.get('content-type') || '';\n if (ct.includes('json')) return res.json() as Promise<T>;\n const text = await res.text();\n try { return JSON.parse(text) as T; } catch { return text as unknown as T; }\n}\n\nfunction ensureNonEmpty(obj: any, label: string) {\n if (obj == null) throw new Error(`${label}: empty response`);\n if (Array.isArray(obj) && obj.length === 0) throw new Error(`${label}: empty array`);\n if (typeof obj === 'object' && !Array.isArray(obj) && Object.keys(obj).length === 0)\n throw new Error(`${label}: empty object`);\n}\n\nfunction normalizeSymbol(q: string) { return q.trim().toLowerCase(); }\n\nfunction parseCSV(text: string): any[] {\n const lines = text.split(/\\r?\\n/).filter(Boolean);\n if (lines.length < 2) return [];\n const header = lines[0].split(',').map((s) => s.trim());\n const out: any[] = [];\n for (let i = 1; i < lines.length; i++) {\n const cols = lines[i].split(',').map((s) => s.trim());\n const row: any = {};\n header.forEach((h, idx) => { row[h] = cols[idx]; });\n out.push(row);\n }\n return out;\n}\n\nfunction parseRssSimple(xml: string, source: string, limit = 20): NewsItem[] {\n const items: NewsItem[] = [];\n const chunks = xml.split(/<item[\\s>]/i).slice(1);\n for (const raw of chunks) {\n const item = raw.split(/<\\/item>/i)[0] || '';\n const get = (tag: string) => {\n const m = item.match(new RegExp(`<${tag}[^>]*>([\\\\s\\\\S]*?)</${tag}>`, 'i'));\n return m ? m[1].replace(/<!\\[CDATA\\[|\\]\\]>/g, '').trim() : undefined;\n };\n const title = get('title'); const link = get('link') || get('guid'); const pub = get('pubDate') || get('updated') || get('dc:date');\n if (title && link) items.push({ title, link, publishedAt: pub, source });\n if (items.length >= limit) break;\n }\n return items;\n}\n\n/* ===================== BASE RESOURCES ===================== */\n\nexport const resources: CryptoResource[] = [\n // Market\n { id: 'coinpaprika', category: 'market', name: 'CoinPaprika', baseUrl: 'https://api.coinpaprika.com/v1', free: true, endpoints: {\n search: { path: '/search', sampleParams: { q: 'bitcoin', c: 'currencies', limit: 1 } },\n tickerById: { path: '/tickers/{id}', sampleParams: { quotes: 'USD' } },\n }},\n { id: 'coincap', category: 'market', name: 'CoinCap', baseUrl: 'https://api.coincap.io/v2', free: true, endpoints: {\n assets: { path: '/assets', sampleParams: { search: 'bitcoin', limit: 1 } },\n assetById: { path: '/assets/{id}' },\n }},\n { id: 'coingecko', category: 'market', name: 'CoinGecko', baseUrl: 'https://api.coingecko.com/api/v3', free: true, endpoints: {\n simplePrice: { path: '/simple/price?ids={ids}&vs_currencies={fiats}' },\n }},\n { id: 'defillama', category: 'market', name: 'DefiLlama (Prices)', baseUrl: 'https://coins.llama.fi', free: true, endpoints: {\n pricesCurrent: { path: '/prices/current/{coins}' },\n }},\n { id: 'binance', category: 'market', name: 'Binance Public', baseUrl: 'https://api.binance.com', free: true, endpoints: {\n klines: { path: '/api/v3/klines?symbol={symbol}&interval={interval}&limit={limit}' },\n ticker: { path: '/api/v3/ticker/price?symbol={symbol}' },\n }},\n { id: 'cryptocompare', category: 'market', name: 'CryptoCompare', baseUrl: 'https://min-api.cryptocompare.com', free: true, endpoints: {\n histominute: { path: '/data/v2/histominute?fsym={fsym}&tsym={tsym}&limit={limit}&api_key=' + EMBEDDED_KEYS.CRYPTOCOMPARE },\n histohour: { path: '/data/v2/histohour?fsym={fsym}&tsym={tsym}&limit={limit}&api_key=' + EMBEDDED_KEYS.CRYPTOCOMPARE },\n histoday: { path: '/data/v2/histoday?fsym={fsym}&tsym={tsym}&limit={limit}&api_key=' + EMBEDDED_KEYS.CRYPTOCOMPARE },\n }},\n { id: 'cmc', category: 'market', name: 'CoinMarketCap', baseUrl: 'https://pro-api.coinmarketcap.com/v1', free: false, endpoints: {\n quotes: { path: '/cryptocurrency/quotes/latest?symbol={symbol}', authLocation: 'header', authName: 'X-CMC_PRO_API_KEY', authValue: EMBEDDED_KEYS.CMC },\n }},\n\n // News\n { id: 'coinstats_news', category: 'news', name: 'CoinStats News', baseUrl: 'https://api.coinstats.app', free: true, endpoints: { feed: { path: '/public/v1/news' } }},\n { id: 'cryptopanic', category: 'news', name: 'CryptoPanic', baseUrl: 'https://cryptopanic.com', free: true, endpoints: { public: { path: '/api/v1/posts/?public=true' } }},\n { id: 'rss_cointelegraph', category: 'news', name: 'Cointelegraph RSS', baseUrl: 'https://cointelegraph.com', free: true, endpoints: { feed: { path: '/rss' } }},\n { id: 'rss_coindesk', category: 'news', name: 'CoinDesk RSS', baseUrl: 'https://www.coindesk.com', free: true, endpoints: { feed: { path: '/arc/outboundfeeds/rss/?outputType=xml' } }},\n { id: 'rss_decrypt', category: 'news', name: 'Decrypt RSS', baseUrl: 'https://decrypt.co', free: true, endpoints: { feed: { path: '/feed' } }},\n\n // Sentiment / F&G\n { id: 'altme_fng', category: 'sentiment', name: 'Alternative.me F&G', baseUrl: 'https://api.alternative.me', free: true, endpoints: {\n latest: { path: '/fng/', sampleParams: { limit: 1 } },\n history: { path: '/fng/', sampleParams: { limit: 30 } },\n }},\n { id: 'cfgi_v1', category: 'sentiment', name: 'CFGI API v1', baseUrl: 'https://api.cfgi.io', free: true, endpoints: {\n latest: { path: '/v1/fear-greed' },\n }},\n { id: 'cfgi_legacy', category: 'sentiment', name: 'CFGI Legacy', baseUrl: 'https://cfgi.io', free: true, endpoints: {\n latest: { path: '/api' },\n }},\n\n // On-chain / explorers\n { id: 'etherscan_primary', category: 'block_explorer', name: 'Etherscan', baseUrl: 'https://api.etherscan.io/api', free: false, endpoints: {\n balance: { path: '/?module=account&action=balance&address={address}&tag=latest&apikey=' + EMBEDDED_KEYS.ETHERSCAN },\n }},\n { id: 'etherscan_backup', category: 'block_explorer', name: 'Etherscan Backup', baseUrl: 'https://api.etherscan.io/api', free: false, endpoints: {\n balance: { path: '/?module=account&action=balance&address={address}&tag=latest&apikey=' + EMBEDDED_KEYS.ETHERSCAN_BACKUP },\n }},\n { id: 'blockscout_eth', category: 'block_explorer', name: 'Blockscout (ETH)', baseUrl: 'https://eth.blockscout.com', free: true, endpoints: {\n balanc",
|
| 35 |
"note": "included as small text"
|
| 36 |
}
|
| 37 |
],
|
|
|
|
| 57 |
"e79c8e6d4c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f"
|
| 58 |
],
|
| 59 |
"huggingface": [
|
| 60 |
+
"hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
| 61 |
]
|
| 62 |
},
|
| 63 |
"notes": "This file was auto-generated. Keys/tokens are present as found in uploaded sources. Secure them as you wish."
|
api/crypto_resources_unified_2025-11-11.json
CHANGED
|
@@ -1699,7 +1699,7 @@
|
|
| 1699 |
"base_url": "https://api-inference.huggingface.co/models/ElKulako/cryptobert",
|
| 1700 |
"auth": {
|
| 1701 |
"type": "apiKeyHeaderOptional",
|
| 1702 |
-
"key": "
|
| 1703 |
"header_name": "Authorization"
|
| 1704 |
},
|
| 1705 |
"docs_url": "https://huggingface.co/ElKulako/cryptobert",
|
|
@@ -1715,7 +1715,7 @@
|
|
| 1715 |
"base_url": "https://api-inference.huggingface.co/models/kk08/CryptoBERT",
|
| 1716 |
"auth": {
|
| 1717 |
"type": "apiKeyHeaderOptional",
|
| 1718 |
-
"key": "
|
| 1719 |
"header_name": "Authorization"
|
| 1720 |
},
|
| 1721 |
"docs_url": "https://huggingface.co/kk08/CryptoBERT",
|
|
|
|
| 1699 |
"base_url": "https://api-inference.huggingface.co/models/ElKulako/cryptobert",
|
| 1700 |
"auth": {
|
| 1701 |
"type": "apiKeyHeaderOptional",
|
| 1702 |
+
"key": "hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
| 1703 |
"header_name": "Authorization"
|
| 1704 |
},
|
| 1705 |
"docs_url": "https://huggingface.co/ElKulako/cryptobert",
|
|
|
|
| 1715 |
"base_url": "https://api-inference.huggingface.co/models/kk08/CryptoBERT",
|
| 1716 |
"auth": {
|
| 1717 |
"type": "apiKeyHeaderOptional",
|
| 1718 |
+
"key": "hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
| 1719 |
"header_name": "Authorization"
|
| 1720 |
},
|
| 1721 |
"docs_url": "https://huggingface.co/kk08/CryptoBERT",
|
archive/all_apis_merged_2025.json
CHANGED
|
@@ -31,7 +31,7 @@
|
|
| 31 |
"zip_text_snippets": [
|
| 32 |
{
|
| 33 |
"filename": "crypto_resources.ts",
|
| 34 |
-
"text_preview": "// crypto_resources.ts — unified TS with 150+ Hugging Face sources (dynamic catalog) + Safe F&G aggregator\n// English-only comments. Keys intentionally embedded per user request.\n\nexport type Category =\n | 'market'\n | 'news'\n | 'sentiment'\n | 'onchain'\n | 'block_explorer'\n | 'whales'\n | 'generic'\n | 'hf';\n\nexport interface EndpointDef {\n path: string;\n method?: 'GET' | 'POST';\n sampleParams?: Record<string, string | number>;\n authLocation?: 'header' | 'query';\n authName?: string;\n authValue?: string;\n contentType?: string;\n}\n\nexport interface CryptoResource {\n id: string;\n category: Category;\n name: string;\n baseUrl: string;\n free: boolean;\n rateLimit?: string;\n endpoints?: Record<string, EndpointDef>;\n}\n\nexport interface MarketQuote {\n id: string;\n symbol: string;\n name: string;\n price: number;\n change24h?: number;\n marketCap?: number;\n source: string;\n raw: any;\n}\n\nexport interface NewsItem {\n title: string;\n link: string;\n publishedAt?: string;\n source: string;\n}\n\nexport interface OHLCVRow {\n timestamp: number | string;\n open: number; high: number; low: number; close: number; volume: number;\n [k: string]: any;\n}\n\nexport interface FNGPoint {\n value: number; // 0..100\n classification: string;\n at?: string;\n source: string;\n raw?: any;\n}\n\nconst EMBEDDED_KEYS = {\n CMC: '04cf4b5b-9868-465c-8ba0-9f2e78c92eb1',\n ETHERSCAN: 'SZHYFZK2RR8H9TIMJBVW54V4H81K2Z2KR2',\n ETHERSCAN_BACKUP: 'T6IR8VJHX2NE6ZJW2S3FDVN1TYG4PYYI45',\n BSCSCAN: 'K62RKHGXTDCG53RU4MCG6XABIMJKTN19IT',\n CRYPTOCOMPARE: 'e79c8e6d4c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f',\n\n // Optional free keys provided by user (kept in-code per request)\n MESSARI: '',\n SANTIMENT: '',\n COINMETRICS: '',\n HUGGINGFACE: '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',\n};\n\nconst sleep = (ms: number) => new Promise(r => setTimeout(r, ms));\n\nclass HttpError extends Error {\n constructor(public status: number, public url: string, public body?: string) {\n super(`HTTP ${status} for ${url}`);\n }\n}\n\nfunction buildURL(base: string, path = '', params?: Record<string, any>): string {\n const hasQ = path.includes('?');\n const url = base.replace(/\\/+$/, '') + '/' + path.replace(/^\\/+/, '');\n if (!params || Object.keys(params).length === 0) return url;\n const qs = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) {\n if (v === undefined || v === null) continue;\n qs.set(k, String(v));\n }\n return url + (hasQ ? '&' : '?') + qs.toString();\n}\n\nasync function fetchRaw(\n url: string,\n opts: { headers?: Record<string, string>; timeoutMs?: number; retries?: number; retryDelayMs?: number; body?: any; method?: 'GET'|'POST' } = {}\n): Promise<Response> {\n const { headers = {}, timeoutMs = 12000, retries = 1, retryDelayMs = 600, body, method = 'GET' } = opts;\n let lastErr: any;\n for (let attempt = 0; attempt <= retries; attempt++) {\n const ac = new AbortController();\n const id = setTimeout(() => ac.abort(), timeoutMs);\n try {\n const res = await fetch(url, { headers, signal: ac.signal, method, body });\n clearTimeout(id);\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n if (res.status === 429 && attempt < retries) {\n await sleep(retryDelayMs * (attempt + 1));\n continue;\n }\n throw new HttpError(res.status, url, text);\n }\n return res;\n } catch (e) {\n clearTimeout(id);\n lastErr = e;\n if (attempt < retries) { await sleep(retryDelayMs * (attempt + 1)); continue; }\n }\n }\n throw lastErr;\n}\n\nasync function fetchJSON<T = any>(\n url: string,\n opts: { headers?: Record<string, string>; timeoutMs?: number; retries?: number; retryDelayMs?: number; body?: any; method?: 'GET'|'POST' } = {}\n): Promise<T> {\n const res = await fetchRaw(url, opts);\n const ct = res.headers.get('content-type') || '';\n if (ct.includes('json')) return res.json() as Promise<T>;\n const text = await res.text();\n try { return JSON.parse(text) as T; } catch { return text as unknown as T; }\n}\n\nfunction ensureNonEmpty(obj: any, label: string) {\n if (obj == null) throw new Error(`${label}: empty response`);\n if (Array.isArray(obj) && obj.length === 0) throw new Error(`${label}: empty array`);\n if (typeof obj === 'object' && !Array.isArray(obj) && Object.keys(obj).length === 0)\n throw new Error(`${label}: empty object`);\n}\n\nfunction normalizeSymbol(q: string) { return q.trim().toLowerCase(); }\n\nfunction parseCSV(text: string): any[] {\n const lines = text.split(/\\r?\\n/).filter(Boolean);\n if (lines.length < 2) return [];\n const header = lines[0].split(',').map((s) => s.trim());\n const out: any[] = [];\n for (let i = 1; i < lines.length; i++) {\n const cols = lines[i].split(',').map((s) => s.trim());\n const row: any = {};\n header.forEach((h, idx) => { row[h] = cols[idx]; });\n out.push(row);\n }\n return out;\n}\n\nfunction parseRssSimple(xml: string, source: string, limit = 20): NewsItem[] {\n const items: NewsItem[] = [];\n const chunks = xml.split(/<item[\\s>]/i).slice(1);\n for (const raw of chunks) {\n const item = raw.split(/<\\/item>/i)[0] || '';\n const get = (tag: string) => {\n const m = item.match(new RegExp(`<${tag}[^>]*>([\\\\s\\\\S]*?)</${tag}>`, 'i'));\n return m ? m[1].replace(/<!\\[CDATA\\[|\\]\\]>/g, '').trim() : undefined;\n };\n const title = get('title'); const link = get('link') || get('guid'); const pub = get('pubDate') || get('updated') || get('dc:date');\n if (title && link) items.push({ title, link, publishedAt: pub, source });\n if (items.length >= limit) break;\n }\n return items;\n}\n\n/* ===================== BASE RESOURCES ===================== */\n\nexport const resources: CryptoResource[] = [\n // Market\n { id: 'coinpaprika', category: 'market', name: 'CoinPaprika', baseUrl: 'https://api.coinpaprika.com/v1', free: true, endpoints: {\n search: { path: '/search', sampleParams: { q: 'bitcoin', c: 'currencies', limit: 1 } },\n tickerById: { path: '/tickers/{id}', sampleParams: { quotes: 'USD' } },\n }},\n { id: 'coincap', category: 'market', name: 'CoinCap', baseUrl: 'https://api.coincap.io/v2', free: true, endpoints: {\n assets: { path: '/assets', sampleParams: { search: 'bitcoin', limit: 1 } },\n assetById: { path: '/assets/{id}' },\n }},\n { id: 'coingecko', category: 'market', name: 'CoinGecko', baseUrl: 'https://api.coingecko.com/api/v3', free: true, endpoints: {\n simplePrice: { path: '/simple/price?ids={ids}&vs_currencies={fiats}' },\n }},\n { id: 'defillama', category: 'market', name: 'DefiLlama (Prices)', baseUrl: 'https://coins.llama.fi', free: true, endpoints: {\n pricesCurrent: { path: '/prices/current/{coins}' },\n }},\n { id: 'binance', category: 'market', name: 'Binance Public', baseUrl: 'https://api.binance.com', free: true, endpoints: {\n klines: { path: '/api/v3/klines?symbol={symbol}&interval={interval}&limit={limit}' },\n ticker: { path: '/api/v3/ticker/price?symbol={symbol}' },\n }},\n { id: 'cryptocompare', category: 'market', name: 'CryptoCompare', baseUrl: 'https://min-api.cryptocompare.com', free: true, endpoints: {\n histominute: { path: '/data/v2/histominute?fsym={fsym}&tsym={tsym}&limit={limit}&api_key=' + EMBEDDED_KEYS.CRYPTOCOMPARE },\n histohour: { path: '/data/v2/histohour?fsym={fsym}&tsym={tsym}&limit={limit}&api_key=' + EMBEDDED_KEYS.CRYPTOCOMPARE },\n histoday: { path: '/data/v2/histoday?fsym={fsym}&tsym={tsym}&limit={limit}&api_key=' + EMBEDDED_KEYS.CRYPTOCOMPARE },\n }},\n { id: 'cmc', category: 'market', name: 'CoinMarketCap', baseUrl: 'https://pro-api.coinmarketcap.com/v1', free: false, endpoints: {\n quotes: { path: '/cryptocurrency/quotes/latest?symbol={symbol}', authLocation: 'header', authName: 'X-CMC_PRO_API_KEY', authValue: EMBEDDED_KEYS.CMC },\n }},\n\n // News\n { id: 'coinstats_news', category: 'news', name: 'CoinStats News', baseUrl: 'https://api.coinstats.app', free: true, endpoints: { feed: { path: '/public/v1/news' } }},\n { id: 'cryptopanic', category: 'news', name: 'CryptoPanic', baseUrl: 'https://cryptopanic.com', free: true, endpoints: { public: { path: '/api/v1/posts/?public=true' } }},\n { id: 'rss_cointelegraph', category: 'news', name: 'Cointelegraph RSS', baseUrl: 'https://cointelegraph.com', free: true, endpoints: { feed: { path: '/rss' } }},\n { id: 'rss_coindesk', category: 'news', name: 'CoinDesk RSS', baseUrl: 'https://www.coindesk.com', free: true, endpoints: { feed: { path: '/arc/outboundfeeds/rss/?outputType=xml' } }},\n { id: 'rss_decrypt', category: 'news', name: 'Decrypt RSS', baseUrl: 'https://decrypt.co', free: true, endpoints: { feed: { path: '/feed' } }},\n\n // Sentiment / F&G\n { id: 'altme_fng', category: 'sentiment', name: 'Alternative.me F&G', baseUrl: 'https://api.alternative.me', free: true, endpoints: {\n latest: { path: '/fng/', sampleParams: { limit: 1 } },\n history: { path: '/fng/', sampleParams: { limit: 30 } },\n }},\n { id: 'cfgi_v1', category: 'sentiment', name: 'CFGI API v1', baseUrl: 'https://api.cfgi.io', free: true, endpoints: {\n latest: { path: '/v1/fear-greed' },\n }},\n { id: 'cfgi_legacy', category: 'sentiment', name: 'CFGI Legacy', baseUrl: 'https://cfgi.io', free: true, endpoints: {\n latest: { path: '/api' },\n }},\n\n // On-chain / explorers\n { id: 'etherscan_primary', category: 'block_explorer', name: 'Etherscan', baseUrl: 'https://api.etherscan.io/api', free: false, endpoints: {\n balance: { path: '/?module=account&action=balance&address={address}&tag=latest&apikey=' + EMBEDDED_KEYS.ETHERSCAN },\n }},\n { id: 'etherscan_backup', category: 'block_explorer', name: 'Etherscan Backup', baseUrl: 'https://api.etherscan.io/api', free: false, endpoints: {\n balance: { path: '/?module=account&action=balance&address={address}&tag=latest&apikey=' + EMBEDDED_KEYS.ETHERSCAN_BACKUP },\n }},\n { id: 'blockscout_eth', category: 'block_explorer', name: 'Blockscout (ETH)', baseUrl: 'https://eth.blockscout.com', free: true, endpoints: {\n balanc",
|
| 35 |
"note": "included as small text"
|
| 36 |
}
|
| 37 |
],
|
|
@@ -57,7 +57,7 @@
|
|
| 57 |
"e79c8e6d4c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f"
|
| 58 |
],
|
| 59 |
"huggingface": [
|
| 60 |
-
"
|
| 61 |
]
|
| 62 |
},
|
| 63 |
"notes": "This file was auto-generated. Keys/tokens are present as found in uploaded sources. Secure them as you wish."
|
|
|
|
| 31 |
"zip_text_snippets": [
|
| 32 |
{
|
| 33 |
"filename": "crypto_resources.ts",
|
| 34 |
+
"text_preview": "// crypto_resources.ts — unified TS with 150+ Hugging Face sources (dynamic catalog) + Safe F&G aggregator\n// English-only comments. Keys intentionally embedded per user request.\n\nexport type Category =\n | 'market'\n | 'news'\n | 'sentiment'\n | 'onchain'\n | 'block_explorer'\n | 'whales'\n | 'generic'\n | 'hf';\n\nexport interface EndpointDef {\n path: string;\n method?: 'GET' | 'POST';\n sampleParams?: Record<string, string | number>;\n authLocation?: 'header' | 'query';\n authName?: string;\n authValue?: string;\n contentType?: string;\n}\n\nexport interface CryptoResource {\n id: string;\n category: Category;\n name: string;\n baseUrl: string;\n free: boolean;\n rateLimit?: string;\n endpoints?: Record<string, EndpointDef>;\n}\n\nexport interface MarketQuote {\n id: string;\n symbol: string;\n name: string;\n price: number;\n change24h?: number;\n marketCap?: number;\n source: string;\n raw: any;\n}\n\nexport interface NewsItem {\n title: string;\n link: string;\n publishedAt?: string;\n source: string;\n}\n\nexport interface OHLCVRow {\n timestamp: number | string;\n open: number; high: number; low: number; close: number; volume: number;\n [k: string]: any;\n}\n\nexport interface FNGPoint {\n value: number; // 0..100\n classification: string;\n at?: string;\n source: string;\n raw?: any;\n}\n\nconst EMBEDDED_KEYS = {\n CMC: '04cf4b5b-9868-465c-8ba0-9f2e78c92eb1',\n ETHERSCAN: 'SZHYFZK2RR8H9TIMJBVW54V4H81K2Z2KR2',\n ETHERSCAN_BACKUP: 'T6IR8VJHX2NE6ZJW2S3FDVN1TYG4PYYI45',\n BSCSCAN: 'K62RKHGXTDCG53RU4MCG6XABIMJKTN19IT',\n CRYPTOCOMPARE: 'e79c8e6d4c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f',\n\n // Optional free keys provided by user (kept in-code per request)\n MESSARI: '',\n SANTIMENT: '',\n COINMETRICS: '',\n HUGGINGFACE: 'hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',\n};\n\nconst sleep = (ms: number) => new Promise(r => setTimeout(r, ms));\n\nclass HttpError extends Error {\n constructor(public status: number, public url: string, public body?: string) {\n super(`HTTP ${status} for ${url}`);\n }\n}\n\nfunction buildURL(base: string, path = '', params?: Record<string, any>): string {\n const hasQ = path.includes('?');\n const url = base.replace(/\\/+$/, '') + '/' + path.replace(/^\\/+/, '');\n if (!params || Object.keys(params).length === 0) return url;\n const qs = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) {\n if (v === undefined || v === null) continue;\n qs.set(k, String(v));\n }\n return url + (hasQ ? '&' : '?') + qs.toString();\n}\n\nasync function fetchRaw(\n url: string,\n opts: { headers?: Record<string, string>; timeoutMs?: number; retries?: number; retryDelayMs?: number; body?: any; method?: 'GET'|'POST' } = {}\n): Promise<Response> {\n const { headers = {}, timeoutMs = 12000, retries = 1, retryDelayMs = 600, body, method = 'GET' } = opts;\n let lastErr: any;\n for (let attempt = 0; attempt <= retries; attempt++) {\n const ac = new AbortController();\n const id = setTimeout(() => ac.abort(), timeoutMs);\n try {\n const res = await fetch(url, { headers, signal: ac.signal, method, body });\n clearTimeout(id);\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n if (res.status === 429 && attempt < retries) {\n await sleep(retryDelayMs * (attempt + 1));\n continue;\n }\n throw new HttpError(res.status, url, text);\n }\n return res;\n } catch (e) {\n clearTimeout(id);\n lastErr = e;\n if (attempt < retries) { await sleep(retryDelayMs * (attempt + 1)); continue; }\n }\n }\n throw lastErr;\n}\n\nasync function fetchJSON<T = any>(\n url: string,\n opts: { headers?: Record<string, string>; timeoutMs?: number; retries?: number; retryDelayMs?: number; body?: any; method?: 'GET'|'POST' } = {}\n): Promise<T> {\n const res = await fetchRaw(url, opts);\n const ct = res.headers.get('content-type') || '';\n if (ct.includes('json')) return res.json() as Promise<T>;\n const text = await res.text();\n try { return JSON.parse(text) as T; } catch { return text as unknown as T; }\n}\n\nfunction ensureNonEmpty(obj: any, label: string) {\n if (obj == null) throw new Error(`${label}: empty response`);\n if (Array.isArray(obj) && obj.length === 0) throw new Error(`${label}: empty array`);\n if (typeof obj === 'object' && !Array.isArray(obj) && Object.keys(obj).length === 0)\n throw new Error(`${label}: empty object`);\n}\n\nfunction normalizeSymbol(q: string) { return q.trim().toLowerCase(); }\n\nfunction parseCSV(text: string): any[] {\n const lines = text.split(/\\r?\\n/).filter(Boolean);\n if (lines.length < 2) return [];\n const header = lines[0].split(',').map((s) => s.trim());\n const out: any[] = [];\n for (let i = 1; i < lines.length; i++) {\n const cols = lines[i].split(',').map((s) => s.trim());\n const row: any = {};\n header.forEach((h, idx) => { row[h] = cols[idx]; });\n out.push(row);\n }\n return out;\n}\n\nfunction parseRssSimple(xml: string, source: string, limit = 20): NewsItem[] {\n const items: NewsItem[] = [];\n const chunks = xml.split(/<item[\\s>]/i).slice(1);\n for (const raw of chunks) {\n const item = raw.split(/<\\/item>/i)[0] || '';\n const get = (tag: string) => {\n const m = item.match(new RegExp(`<${tag}[^>]*>([\\\\s\\\\S]*?)</${tag}>`, 'i'));\n return m ? m[1].replace(/<!\\[CDATA\\[|\\]\\]>/g, '').trim() : undefined;\n };\n const title = get('title'); const link = get('link') || get('guid'); const pub = get('pubDate') || get('updated') || get('dc:date');\n if (title && link) items.push({ title, link, publishedAt: pub, source });\n if (items.length >= limit) break;\n }\n return items;\n}\n\n/* ===================== BASE RESOURCES ===================== */\n\nexport const resources: CryptoResource[] = [\n // Market\n { id: 'coinpaprika', category: 'market', name: 'CoinPaprika', baseUrl: 'https://api.coinpaprika.com/v1', free: true, endpoints: {\n search: { path: '/search', sampleParams: { q: 'bitcoin', c: 'currencies', limit: 1 } },\n tickerById: { path: '/tickers/{id}', sampleParams: { quotes: 'USD' } },\n }},\n { id: 'coincap', category: 'market', name: 'CoinCap', baseUrl: 'https://api.coincap.io/v2', free: true, endpoints: {\n assets: { path: '/assets', sampleParams: { search: 'bitcoin', limit: 1 } },\n assetById: { path: '/assets/{id}' },\n }},\n { id: 'coingecko', category: 'market', name: 'CoinGecko', baseUrl: 'https://api.coingecko.com/api/v3', free: true, endpoints: {\n simplePrice: { path: '/simple/price?ids={ids}&vs_currencies={fiats}' },\n }},\n { id: 'defillama', category: 'market', name: 'DefiLlama (Prices)', baseUrl: 'https://coins.llama.fi', free: true, endpoints: {\n pricesCurrent: { path: '/prices/current/{coins}' },\n }},\n { id: 'binance', category: 'market', name: 'Binance Public', baseUrl: 'https://api.binance.com', free: true, endpoints: {\n klines: { path: '/api/v3/klines?symbol={symbol}&interval={interval}&limit={limit}' },\n ticker: { path: '/api/v3/ticker/price?symbol={symbol}' },\n }},\n { id: 'cryptocompare', category: 'market', name: 'CryptoCompare', baseUrl: 'https://min-api.cryptocompare.com', free: true, endpoints: {\n histominute: { path: '/data/v2/histominute?fsym={fsym}&tsym={tsym}&limit={limit}&api_key=' + EMBEDDED_KEYS.CRYPTOCOMPARE },\n histohour: { path: '/data/v2/histohour?fsym={fsym}&tsym={tsym}&limit={limit}&api_key=' + EMBEDDED_KEYS.CRYPTOCOMPARE },\n histoday: { path: '/data/v2/histoday?fsym={fsym}&tsym={tsym}&limit={limit}&api_key=' + EMBEDDED_KEYS.CRYPTOCOMPARE },\n }},\n { id: 'cmc', category: 'market', name: 'CoinMarketCap', baseUrl: 'https://pro-api.coinmarketcap.com/v1', free: false, endpoints: {\n quotes: { path: '/cryptocurrency/quotes/latest?symbol={symbol}', authLocation: 'header', authName: 'X-CMC_PRO_API_KEY', authValue: EMBEDDED_KEYS.CMC },\n }},\n\n // News\n { id: 'coinstats_news', category: 'news', name: 'CoinStats News', baseUrl: 'https://api.coinstats.app', free: true, endpoints: { feed: { path: '/public/v1/news' } }},\n { id: 'cryptopanic', category: 'news', name: 'CryptoPanic', baseUrl: 'https://cryptopanic.com', free: true, endpoints: { public: { path: '/api/v1/posts/?public=true' } }},\n { id: 'rss_cointelegraph', category: 'news', name: 'Cointelegraph RSS', baseUrl: 'https://cointelegraph.com', free: true, endpoints: { feed: { path: '/rss' } }},\n { id: 'rss_coindesk', category: 'news', name: 'CoinDesk RSS', baseUrl: 'https://www.coindesk.com', free: true, endpoints: { feed: { path: '/arc/outboundfeeds/rss/?outputType=xml' } }},\n { id: 'rss_decrypt', category: 'news', name: 'Decrypt RSS', baseUrl: 'https://decrypt.co', free: true, endpoints: { feed: { path: '/feed' } }},\n\n // Sentiment / F&G\n { id: 'altme_fng', category: 'sentiment', name: 'Alternative.me F&G', baseUrl: 'https://api.alternative.me', free: true, endpoints: {\n latest: { path: '/fng/', sampleParams: { limit: 1 } },\n history: { path: '/fng/', sampleParams: { limit: 30 } },\n }},\n { id: 'cfgi_v1', category: 'sentiment', name: 'CFGI API v1', baseUrl: 'https://api.cfgi.io', free: true, endpoints: {\n latest: { path: '/v1/fear-greed' },\n }},\n { id: 'cfgi_legacy', category: 'sentiment', name: 'CFGI Legacy', baseUrl: 'https://cfgi.io', free: true, endpoints: {\n latest: { path: '/api' },\n }},\n\n // On-chain / explorers\n { id: 'etherscan_primary', category: 'block_explorer', name: 'Etherscan', baseUrl: 'https://api.etherscan.io/api', free: false, endpoints: {\n balance: { path: '/?module=account&action=balance&address={address}&tag=latest&apikey=' + EMBEDDED_KEYS.ETHERSCAN },\n }},\n { id: 'etherscan_backup', category: 'block_explorer', name: 'Etherscan Backup', baseUrl: 'https://api.etherscan.io/api', free: false, endpoints: {\n balance: { path: '/?module=account&action=balance&address={address}&tag=latest&apikey=' + EMBEDDED_KEYS.ETHERSCAN_BACKUP },\n }},\n { id: 'blockscout_eth', category: 'block_explorer', name: 'Blockscout (ETH)', baseUrl: 'https://eth.blockscout.com', free: true, endpoints: {\n balanc",
|
| 35 |
"note": "included as small text"
|
| 36 |
}
|
| 37 |
],
|
|
|
|
| 57 |
"e79c8e6d4c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f"
|
| 58 |
],
|
| 59 |
"huggingface": [
|
| 60 |
+
"hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
| 61 |
]
|
| 62 |
},
|
| 63 |
"notes": "This file was auto-generated. Keys/tokens are present as found in uploaded sources. Secure them as you wish."
|
archive/docs/CRYPTOBERT_QUICK_REFERENCE.md
CHANGED
|
@@ -21,7 +21,7 @@ python3 -c "import ai_models; ai_models.initialize_models(); print(ai_models.ana
|
|
| 21 |
|------|-------|
|
| 22 |
| **Model** | ElKulako/CryptoBERT |
|
| 23 |
| **ID** | `hf_model_elkulako_cryptobert` |
|
| 24 |
-
| **Token** | `
|
| 25 |
| **Status** | CONDITIONALLY_AVAILABLE |
|
| 26 |
|
| 27 |
---
|
|
@@ -53,7 +53,7 @@ print(f"Loaded: {info['loaded_models']['crypto_sentiment']}")
|
|
| 53 |
|
| 54 |
### Setup
|
| 55 |
```bash
|
| 56 |
-
export HF_TOKEN="
|
| 57 |
./setup_cryptobert.sh
|
| 58 |
```
|
| 59 |
|
|
|
|
| 21 |
|------|-------|
|
| 22 |
| **Model** | ElKulako/CryptoBERT |
|
| 23 |
| **ID** | `hf_model_elkulako_cryptobert` |
|
| 24 |
+
| **Token** | `hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` |
|
| 25 |
| **Status** | CONDITIONALLY_AVAILABLE |
|
| 26 |
|
| 27 |
---
|
|
|
|
| 53 |
|
| 54 |
### Setup
|
| 55 |
```bash
|
| 56 |
+
export HF_TOKEN="hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
| 57 |
./setup_cryptobert.sh
|
| 58 |
```
|
| 59 |
|
config.js
CHANGED
|
@@ -123,7 +123,7 @@ window.DASHBOARD_CONFIG = {
|
|
| 123 |
// HuggingFace Configuration
|
| 124 |
// ═══════════════════════════════════════════════════════════════
|
| 125 |
|
| 126 |
-
HF_TOKEN: '
|
| 127 |
HF_API_BASE: 'https://api-inference.huggingface.co/models',
|
| 128 |
|
| 129 |
// ═══════════════════════════════════════════════════════════════
|
|
|
|
| 123 |
// HuggingFace Configuration
|
| 124 |
// ═══════════════════════════════════════════════════════════════
|
| 125 |
|
| 126 |
+
HF_TOKEN: 'hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
|
| 127 |
HF_API_BASE: 'https://api-inference.huggingface.co/models',
|
| 128 |
|
| 129 |
// ═══════════════════════════════════════════════════════════════
|
crypto_resources_unified_2025-11-11.json
CHANGED
|
@@ -1699,7 +1699,7 @@
|
|
| 1699 |
"base_url": "https://api-inference.huggingface.co/models/ElKulako/cryptobert",
|
| 1700 |
"auth": {
|
| 1701 |
"type": "apiKeyHeaderOptional",
|
| 1702 |
-
"key": "
|
| 1703 |
"header_name": "Authorization"
|
| 1704 |
},
|
| 1705 |
"docs_url": "https://huggingface.co/ElKulako/cryptobert",
|
|
@@ -1715,7 +1715,7 @@
|
|
| 1715 |
"base_url": "https://api-inference.huggingface.co/models/kk08/CryptoBERT",
|
| 1716 |
"auth": {
|
| 1717 |
"type": "apiKeyHeaderOptional",
|
| 1718 |
-
"key": "
|
| 1719 |
"header_name": "Authorization"
|
| 1720 |
},
|
| 1721 |
"docs_url": "https://huggingface.co/kk08/CryptoBERT",
|
|
|
|
| 1699 |
"base_url": "https://api-inference.huggingface.co/models/ElKulako/cryptobert",
|
| 1700 |
"auth": {
|
| 1701 |
"type": "apiKeyHeaderOptional",
|
| 1702 |
+
"key": "hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
| 1703 |
"header_name": "Authorization"
|
| 1704 |
},
|
| 1705 |
"docs_url": "https://huggingface.co/ElKulako/cryptobert",
|
|
|
|
| 1715 |
"base_url": "https://api-inference.huggingface.co/models/kk08/CryptoBERT",
|
| 1716 |
"auth": {
|
| 1717 |
"type": "apiKeyHeaderOptional",
|
| 1718 |
+
"key": "hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
| 1719 |
"header_name": "Authorization"
|
| 1720 |
},
|
| 1721 |
"docs_url": "https://huggingface.co/kk08/CryptoBERT",
|
docs/CRYPTOBERT_INTEGRATION.md
CHANGED
|
@@ -35,7 +35,7 @@ This document describes the integration of the **ElKulako/CryptoBERT** model int
|
|
| 35 |
|
| 36 |
```bash
|
| 37 |
# Set HF_TOKEN for authenticated access
|
| 38 |
-
export HF_TOKEN="
|
| 39 |
```
|
| 40 |
|
| 41 |
### Python Configuration (config.py)
|
|
@@ -50,7 +50,7 @@ HUGGINGFACE_MODELS = {
|
|
| 50 |
}
|
| 51 |
|
| 52 |
# Hugging Face Authentication
|
| 53 |
-
HF_TOKEN = os.environ.get("HF_TOKEN", "
|
| 54 |
HF_USE_AUTH_TOKEN = bool(HF_TOKEN)
|
| 55 |
```
|
| 56 |
|
|
@@ -68,14 +68,14 @@ Run the provided setup script:
|
|
| 68 |
|
| 69 |
1. **Set environment variable (temporary)**:
|
| 70 |
```bash
|
| 71 |
-
export HF_TOKEN="
|
| 72 |
```
|
| 73 |
|
| 74 |
2. **Set environment variable (persistent)**:
|
| 75 |
|
| 76 |
Add to `~/.bashrc` or `~/.zshrc`:
|
| 77 |
```bash
|
| 78 |
-
echo 'export HF_TOKEN="
|
| 79 |
source ~/.bashrc
|
| 80 |
```
|
| 81 |
|
|
|
|
| 35 |
|
| 36 |
```bash
|
| 37 |
# Set HF_TOKEN for authenticated access
|
| 38 |
+
export HF_TOKEN="hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
| 39 |
```
|
| 40 |
|
| 41 |
### Python Configuration (config.py)
|
|
|
|
| 50 |
}
|
| 51 |
|
| 52 |
# Hugging Face Authentication
|
| 53 |
+
HF_TOKEN = os.environ.get("HF_TOKEN", "hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
|
| 54 |
HF_USE_AUTH_TOKEN = bool(HF_TOKEN)
|
| 55 |
```
|
| 56 |
|
|
|
|
| 68 |
|
| 69 |
1. **Set environment variable (temporary)**:
|
| 70 |
```bash
|
| 71 |
+
export HF_TOKEN="hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
| 72 |
```
|
| 73 |
|
| 74 |
2. **Set environment variable (persistent)**:
|
| 75 |
|
| 76 |
Add to `~/.bashrc` or `~/.zshrc`:
|
| 77 |
```bash
|
| 78 |
+
echo 'export HF_TOKEN="hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"' >> ~/.bashrc
|
| 79 |
source ~/.bashrc
|
| 80 |
```
|
| 81 |
|
docs/archive/HF_IMPLEMENTATION_COMPLETE.md
CHANGED
|
@@ -47,7 +47,7 @@
|
|
| 47 |
|
| 48 |
#### 1. **Environment Configuration** (`.env`)
|
| 49 |
```env
|
| 50 |
-
HUGGINGFACE_TOKEN=
|
| 51 |
ENABLE_SENTIMENT=true
|
| 52 |
SENTIMENT_SOCIAL_MODEL=ElKulako/cryptobert
|
| 53 |
SENTIMENT_NEWS_MODEL=kk08/CryptoBERT
|
|
|
|
| 47 |
|
| 48 |
#### 1. **Environment Configuration** (`.env`)
|
| 49 |
```env
|
| 50 |
+
HUGGINGFACE_TOKEN=hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
| 51 |
ENABLE_SENTIMENT=true
|
| 52 |
SENTIMENT_SOCIAL_MODEL=ElKulako/cryptobert
|
| 53 |
SENTIMENT_NEWS_MODEL=kk08/CryptoBERT
|
final/.env
CHANGED
|
@@ -17,4 +17,4 @@ NEWSAPI_KEY=
|
|
| 17 |
CRYPTOCOMPARE_KEY=
|
| 18 |
|
| 19 |
# HuggingFace API Token
|
| 20 |
-
HF_TOKEN=
|
|
|
|
| 17 |
CRYPTOCOMPARE_KEY=
|
| 18 |
|
| 19 |
# HuggingFace API Token
|
| 20 |
+
HF_TOKEN=hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
final/all_apis_merged_2025.json
CHANGED
|
@@ -31,7 +31,7 @@
|
|
| 31 |
"zip_text_snippets": [
|
| 32 |
{
|
| 33 |
"filename": "crypto_resources.ts",
|
| 34 |
-
"text_preview": "// crypto_resources.ts — unified TS with 150+ Hugging Face sources (dynamic catalog) + Safe F&G aggregator\n// English-only comments. Keys intentionally embedded per user request.\n\nexport type Category =\n | 'market'\n | 'news'\n | 'sentiment'\n | 'onchain'\n | 'block_explorer'\n | 'whales'\n | 'generic'\n | 'hf';\n\nexport interface EndpointDef {\n path: string;\n method?: 'GET' | 'POST';\n sampleParams?: Record<string, string | number>;\n authLocation?: 'header' | 'query';\n authName?: string;\n authValue?: string;\n contentType?: string;\n}\n\nexport interface CryptoResource {\n id: string;\n category: Category;\n name: string;\n baseUrl: string;\n free: boolean;\n rateLimit?: string;\n endpoints?: Record<string, EndpointDef>;\n}\n\nexport interface MarketQuote {\n id: string;\n symbol: string;\n name: string;\n price: number;\n change24h?: number;\n marketCap?: number;\n source: string;\n raw: any;\n}\n\nexport interface NewsItem {\n title: string;\n link: string;\n publishedAt?: string;\n source: string;\n}\n\nexport interface OHLCVRow {\n timestamp: number | string;\n open: number; high: number; low: number; close: number; volume: number;\n [k: string]: any;\n}\n\nexport interface FNGPoint {\n value: number; // 0..100\n classification: string;\n at?: string;\n source: string;\n raw?: any;\n}\n\nconst EMBEDDED_KEYS = {\n CMC: '04cf4b5b-9868-465c-8ba0-9f2e78c92eb1',\n ETHERSCAN: 'SZHYFZK2RR8H9TIMJBVW54V4H81K2Z2KR2',\n ETHERSCAN_BACKUP: 'T6IR8VJHX2NE6ZJW2S3FDVN1TYG4PYYI45',\n BSCSCAN: 'K62RKHGXTDCG53RU4MCG6XABIMJKTN19IT',\n CRYPTOCOMPARE: 'e79c8e6d4c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f',\n\n // Optional free keys provided by user (kept in-code per request)\n MESSARI: '',\n SANTIMENT: '',\n COINMETRICS: '',\n HUGGINGFACE: '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',\n};\n\nconst sleep = (ms: number) => new Promise(r => setTimeout(r, ms));\n\nclass HttpError extends Error {\n constructor(public status: number, public url: string, public body?: string) {\n super(`HTTP ${status} for ${url}`);\n }\n}\n\nfunction buildURL(base: string, path = '', params?: Record<string, any>): string {\n const hasQ = path.includes('?');\n const url = base.replace(/\\/+$/, '') + '/' + path.replace(/^\\/+/, '');\n if (!params || Object.keys(params).length === 0) return url;\n const qs = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) {\n if (v === undefined || v === null) continue;\n qs.set(k, String(v));\n }\n return url + (hasQ ? '&' : '?') + qs.toString();\n}\n\nasync function fetchRaw(\n url: string,\n opts: { headers?: Record<string, string>; timeoutMs?: number; retries?: number; retryDelayMs?: number; body?: any; method?: 'GET'|'POST' } = {}\n): Promise<Response> {\n const { headers = {}, timeoutMs = 12000, retries = 1, retryDelayMs = 600, body, method = 'GET' } = opts;\n let lastErr: any;\n for (let attempt = 0; attempt <= retries; attempt++) {\n const ac = new AbortController();\n const id = setTimeout(() => ac.abort(), timeoutMs);\n try {\n const res = await fetch(url, { headers, signal: ac.signal, method, body });\n clearTimeout(id);\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n if (res.status === 429 && attempt < retries) {\n await sleep(retryDelayMs * (attempt + 1));\n continue;\n }\n throw new HttpError(res.status, url, text);\n }\n return res;\n } catch (e) {\n clearTimeout(id);\n lastErr = e;\n if (attempt < retries) { await sleep(retryDelayMs * (attempt + 1)); continue; }\n }\n }\n throw lastErr;\n}\n\nasync function fetchJSON<T = any>(\n url: string,\n opts: { headers?: Record<string, string>; timeoutMs?: number; retries?: number; retryDelayMs?: number; body?: any; method?: 'GET'|'POST' } = {}\n): Promise<T> {\n const res = await fetchRaw(url, opts);\n const ct = res.headers.get('content-type') || '';\n if (ct.includes('json')) return res.json() as Promise<T>;\n const text = await res.text();\n try { return JSON.parse(text) as T; } catch { return text as unknown as T; }\n}\n\nfunction ensureNonEmpty(obj: any, label: string) {\n if (obj == null) throw new Error(`${label}: empty response`);\n if (Array.isArray(obj) && obj.length === 0) throw new Error(`${label}: empty array`);\n if (typeof obj === 'object' && !Array.isArray(obj) && Object.keys(obj).length === 0)\n throw new Error(`${label}: empty object`);\n}\n\nfunction normalizeSymbol(q: string) { return q.trim().toLowerCase(); }\n\nfunction parseCSV(text: string): any[] {\n const lines = text.split(/\\r?\\n/).filter(Boolean);\n if (lines.length < 2) return [];\n const header = lines[0].split(',').map((s) => s.trim());\n const out: any[] = [];\n for (let i = 1; i < lines.length; i++) {\n const cols = lines[i].split(',').map((s) => s.trim());\n const row: any = {};\n header.forEach((h, idx) => { row[h] = cols[idx]; });\n out.push(row);\n }\n return out;\n}\n\nfunction parseRssSimple(xml: string, source: string, limit = 20): NewsItem[] {\n const items: NewsItem[] = [];\n const chunks = xml.split(/<item[\\s>]/i).slice(1);\n for (const raw of chunks) {\n const item = raw.split(/<\\/item>/i)[0] || '';\n const get = (tag: string) => {\n const m = item.match(new RegExp(`<${tag}[^>]*>([\\\\s\\\\S]*?)</${tag}>`, 'i'));\n return m ? m[1].replace(/<!\\[CDATA\\[|\\]\\]>/g, '').trim() : undefined;\n };\n const title = get('title'); const link = get('link') || get('guid'); const pub = get('pubDate') || get('updated') || get('dc:date');\n if (title && link) items.push({ title, link, publishedAt: pub, source });\n if (items.length >= limit) break;\n }\n return items;\n}\n\n/* ===================== BASE RESOURCES ===================== */\n\nexport const resources: CryptoResource[] = [\n // Market\n { id: 'coinpaprika', category: 'market', name: 'CoinPaprika', baseUrl: 'https://api.coinpaprika.com/v1', free: true, endpoints: {\n search: { path: '/search', sampleParams: { q: 'bitcoin', c: 'currencies', limit: 1 } },\n tickerById: { path: '/tickers/{id}', sampleParams: { quotes: 'USD' } },\n }},\n { id: 'coincap', category: 'market', name: 'CoinCap', baseUrl: 'https://api.coincap.io/v2', free: true, endpoints: {\n assets: { path: '/assets', sampleParams: { search: 'bitcoin', limit: 1 } },\n assetById: { path: '/assets/{id}' },\n }},\n { id: 'coingecko', category: 'market', name: 'CoinGecko', baseUrl: 'https://api.coingecko.com/api/v3', free: true, endpoints: {\n simplePrice: { path: '/simple/price?ids={ids}&vs_currencies={fiats}' },\n }},\n { id: 'defillama', category: 'market', name: 'DefiLlama (Prices)', baseUrl: 'https://coins.llama.fi', free: true, endpoints: {\n pricesCurrent: { path: '/prices/current/{coins}' },\n }},\n { id: 'binance', category: 'market', name: 'Binance Public', baseUrl: 'https://api.binance.com', free: true, endpoints: {\n klines: { path: '/api/v3/klines?symbol={symbol}&interval={interval}&limit={limit}' },\n ticker: { path: '/api/v3/ticker/price?symbol={symbol}' },\n }},\n { id: 'cryptocompare', category: 'market', name: 'CryptoCompare', baseUrl: 'https://min-api.cryptocompare.com', free: true, endpoints: {\n histominute: { path: '/data/v2/histominute?fsym={fsym}&tsym={tsym}&limit={limit}&api_key=' + EMBEDDED_KEYS.CRYPTOCOMPARE },\n histohour: { path: '/data/v2/histohour?fsym={fsym}&tsym={tsym}&limit={limit}&api_key=' + EMBEDDED_KEYS.CRYPTOCOMPARE },\n histoday: { path: '/data/v2/histoday?fsym={fsym}&tsym={tsym}&limit={limit}&api_key=' + EMBEDDED_KEYS.CRYPTOCOMPARE },\n }},\n { id: 'cmc', category: 'market', name: 'CoinMarketCap', baseUrl: 'https://pro-api.coinmarketcap.com/v1', free: false, endpoints: {\n quotes: { path: '/cryptocurrency/quotes/latest?symbol={symbol}', authLocation: 'header', authName: 'X-CMC_PRO_API_KEY', authValue: EMBEDDED_KEYS.CMC },\n }},\n\n // News\n { id: 'coinstats_news', category: 'news', name: 'CoinStats News', baseUrl: 'https://api.coinstats.app', free: true, endpoints: { feed: { path: '/public/v1/news' } }},\n { id: 'cryptopanic', category: 'news', name: 'CryptoPanic', baseUrl: 'https://cryptopanic.com', free: true, endpoints: { public: { path: '/api/v1/posts/?public=true' } }},\n { id: 'rss_cointelegraph', category: 'news', name: 'Cointelegraph RSS', baseUrl: 'https://cointelegraph.com', free: true, endpoints: { feed: { path: '/rss' } }},\n { id: 'rss_coindesk', category: 'news', name: 'CoinDesk RSS', baseUrl: 'https://www.coindesk.com', free: true, endpoints: { feed: { path: '/arc/outboundfeeds/rss/?outputType=xml' } }},\n { id: 'rss_decrypt', category: 'news', name: 'Decrypt RSS', baseUrl: 'https://decrypt.co', free: true, endpoints: { feed: { path: '/feed' } }},\n\n // Sentiment / F&G\n { id: 'altme_fng', category: 'sentiment', name: 'Alternative.me F&G', baseUrl: 'https://api.alternative.me', free: true, endpoints: {\n latest: { path: '/fng/', sampleParams: { limit: 1 } },\n history: { path: '/fng/', sampleParams: { limit: 30 } },\n }},\n { id: 'cfgi_v1', category: 'sentiment', name: 'CFGI API v1', baseUrl: 'https://api.cfgi.io', free: true, endpoints: {\n latest: { path: '/v1/fear-greed' },\n }},\n { id: 'cfgi_legacy', category: 'sentiment', name: 'CFGI Legacy', baseUrl: 'https://cfgi.io', free: true, endpoints: {\n latest: { path: '/api' },\n }},\n\n // On-chain / explorers\n { id: 'etherscan_primary', category: 'block_explorer', name: 'Etherscan', baseUrl: 'https://api.etherscan.io/api', free: false, endpoints: {\n balance: { path: '/?module=account&action=balance&address={address}&tag=latest&apikey=' + EMBEDDED_KEYS.ETHERSCAN },\n }},\n { id: 'etherscan_backup', category: 'block_explorer', name: 'Etherscan Backup', baseUrl: 'https://api.etherscan.io/api', free: false, endpoints: {\n balance: { path: '/?module=account&action=balance&address={address}&tag=latest&apikey=' + EMBEDDED_KEYS.ETHERSCAN_BACKUP },\n }},\n { id: 'blockscout_eth', category: 'block_explorer', name: 'Blockscout (ETH)', baseUrl: 'https://eth.blockscout.com', free: true, endpoints: {\n balanc",
|
| 35 |
"note": "included as small text"
|
| 36 |
}
|
| 37 |
],
|
|
@@ -57,7 +57,7 @@
|
|
| 57 |
"e79c8e6d4c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f"
|
| 58 |
],
|
| 59 |
"huggingface": [
|
| 60 |
-
"
|
| 61 |
]
|
| 62 |
},
|
| 63 |
"notes": "This file was auto-generated. Keys/tokens are present as found in uploaded sources. Secure them as you wish."
|
|
|
|
| 31 |
"zip_text_snippets": [
|
| 32 |
{
|
| 33 |
"filename": "crypto_resources.ts",
|
| 34 |
+
"text_preview": "// crypto_resources.ts — unified TS with 150+ Hugging Face sources (dynamic catalog) + Safe F&G aggregator\n// English-only comments. Keys intentionally embedded per user request.\n\nexport type Category =\n | 'market'\n | 'news'\n | 'sentiment'\n | 'onchain'\n | 'block_explorer'\n | 'whales'\n | 'generic'\n | 'hf';\n\nexport interface EndpointDef {\n path: string;\n method?: 'GET' | 'POST';\n sampleParams?: Record<string, string | number>;\n authLocation?: 'header' | 'query';\n authName?: string;\n authValue?: string;\n contentType?: string;\n}\n\nexport interface CryptoResource {\n id: string;\n category: Category;\n name: string;\n baseUrl: string;\n free: boolean;\n rateLimit?: string;\n endpoints?: Record<string, EndpointDef>;\n}\n\nexport interface MarketQuote {\n id: string;\n symbol: string;\n name: string;\n price: number;\n change24h?: number;\n marketCap?: number;\n source: string;\n raw: any;\n}\n\nexport interface NewsItem {\n title: string;\n link: string;\n publishedAt?: string;\n source: string;\n}\n\nexport interface OHLCVRow {\n timestamp: number | string;\n open: number; high: number; low: number; close: number; volume: number;\n [k: string]: any;\n}\n\nexport interface FNGPoint {\n value: number; // 0..100\n classification: string;\n at?: string;\n source: string;\n raw?: any;\n}\n\nconst EMBEDDED_KEYS = {\n CMC: '04cf4b5b-9868-465c-8ba0-9f2e78c92eb1',\n ETHERSCAN: 'SZHYFZK2RR8H9TIMJBVW54V4H81K2Z2KR2',\n ETHERSCAN_BACKUP: 'T6IR8VJHX2NE6ZJW2S3FDVN1TYG4PYYI45',\n BSCSCAN: 'K62RKHGXTDCG53RU4MCG6XABIMJKTN19IT',\n CRYPTOCOMPARE: 'e79c8e6d4c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f',\n\n // Optional free keys provided by user (kept in-code per request)\n MESSARI: '',\n SANTIMENT: '',\n COINMETRICS: '',\n HUGGINGFACE: 'hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',\n};\n\nconst sleep = (ms: number) => new Promise(r => setTimeout(r, ms));\n\nclass HttpError extends Error {\n constructor(public status: number, public url: string, public body?: string) {\n super(`HTTP ${status} for ${url}`);\n }\n}\n\nfunction buildURL(base: string, path = '', params?: Record<string, any>): string {\n const hasQ = path.includes('?');\n const url = base.replace(/\\/+$/, '') + '/' + path.replace(/^\\/+/, '');\n if (!params || Object.keys(params).length === 0) return url;\n const qs = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) {\n if (v === undefined || v === null) continue;\n qs.set(k, String(v));\n }\n return url + (hasQ ? '&' : '?') + qs.toString();\n}\n\nasync function fetchRaw(\n url: string,\n opts: { headers?: Record<string, string>; timeoutMs?: number; retries?: number; retryDelayMs?: number; body?: any; method?: 'GET'|'POST' } = {}\n): Promise<Response> {\n const { headers = {}, timeoutMs = 12000, retries = 1, retryDelayMs = 600, body, method = 'GET' } = opts;\n let lastErr: any;\n for (let attempt = 0; attempt <= retries; attempt++) {\n const ac = new AbortController();\n const id = setTimeout(() => ac.abort(), timeoutMs);\n try {\n const res = await fetch(url, { headers, signal: ac.signal, method, body });\n clearTimeout(id);\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n if (res.status === 429 && attempt < retries) {\n await sleep(retryDelayMs * (attempt + 1));\n continue;\n }\n throw new HttpError(res.status, url, text);\n }\n return res;\n } catch (e) {\n clearTimeout(id);\n lastErr = e;\n if (attempt < retries) { await sleep(retryDelayMs * (attempt + 1)); continue; }\n }\n }\n throw lastErr;\n}\n\nasync function fetchJSON<T = any>(\n url: string,\n opts: { headers?: Record<string, string>; timeoutMs?: number; retries?: number; retryDelayMs?: number; body?: any; method?: 'GET'|'POST' } = {}\n): Promise<T> {\n const res = await fetchRaw(url, opts);\n const ct = res.headers.get('content-type') || '';\n if (ct.includes('json')) return res.json() as Promise<T>;\n const text = await res.text();\n try { return JSON.parse(text) as T; } catch { return text as unknown as T; }\n}\n\nfunction ensureNonEmpty(obj: any, label: string) {\n if (obj == null) throw new Error(`${label}: empty response`);\n if (Array.isArray(obj) && obj.length === 0) throw new Error(`${label}: empty array`);\n if (typeof obj === 'object' && !Array.isArray(obj) && Object.keys(obj).length === 0)\n throw new Error(`${label}: empty object`);\n}\n\nfunction normalizeSymbol(q: string) { return q.trim().toLowerCase(); }\n\nfunction parseCSV(text: string): any[] {\n const lines = text.split(/\\r?\\n/).filter(Boolean);\n if (lines.length < 2) return [];\n const header = lines[0].split(',').map((s) => s.trim());\n const out: any[] = [];\n for (let i = 1; i < lines.length; i++) {\n const cols = lines[i].split(',').map((s) => s.trim());\n const row: any = {};\n header.forEach((h, idx) => { row[h] = cols[idx]; });\n out.push(row);\n }\n return out;\n}\n\nfunction parseRssSimple(xml: string, source: string, limit = 20): NewsItem[] {\n const items: NewsItem[] = [];\n const chunks = xml.split(/<item[\\s>]/i).slice(1);\n for (const raw of chunks) {\n const item = raw.split(/<\\/item>/i)[0] || '';\n const get = (tag: string) => {\n const m = item.match(new RegExp(`<${tag}[^>]*>([\\\\s\\\\S]*?)</${tag}>`, 'i'));\n return m ? m[1].replace(/<!\\[CDATA\\[|\\]\\]>/g, '').trim() : undefined;\n };\n const title = get('title'); const link = get('link') || get('guid'); const pub = get('pubDate') || get('updated') || get('dc:date');\n if (title && link) items.push({ title, link, publishedAt: pub, source });\n if (items.length >= limit) break;\n }\n return items;\n}\n\n/* ===================== BASE RESOURCES ===================== */\n\nexport const resources: CryptoResource[] = [\n // Market\n { id: 'coinpaprika', category: 'market', name: 'CoinPaprika', baseUrl: 'https://api.coinpaprika.com/v1', free: true, endpoints: {\n search: { path: '/search', sampleParams: { q: 'bitcoin', c: 'currencies', limit: 1 } },\n tickerById: { path: '/tickers/{id}', sampleParams: { quotes: 'USD' } },\n }},\n { id: 'coincap', category: 'market', name: 'CoinCap', baseUrl: 'https://api.coincap.io/v2', free: true, endpoints: {\n assets: { path: '/assets', sampleParams: { search: 'bitcoin', limit: 1 } },\n assetById: { path: '/assets/{id}' },\n }},\n { id: 'coingecko', category: 'market', name: 'CoinGecko', baseUrl: 'https://api.coingecko.com/api/v3', free: true, endpoints: {\n simplePrice: { path: '/simple/price?ids={ids}&vs_currencies={fiats}' },\n }},\n { id: 'defillama', category: 'market', name: 'DefiLlama (Prices)', baseUrl: 'https://coins.llama.fi', free: true, endpoints: {\n pricesCurrent: { path: '/prices/current/{coins}' },\n }},\n { id: 'binance', category: 'market', name: 'Binance Public', baseUrl: 'https://api.binance.com', free: true, endpoints: {\n klines: { path: '/api/v3/klines?symbol={symbol}&interval={interval}&limit={limit}' },\n ticker: { path: '/api/v3/ticker/price?symbol={symbol}' },\n }},\n { id: 'cryptocompare', category: 'market', name: 'CryptoCompare', baseUrl: 'https://min-api.cryptocompare.com', free: true, endpoints: {\n histominute: { path: '/data/v2/histominute?fsym={fsym}&tsym={tsym}&limit={limit}&api_key=' + EMBEDDED_KEYS.CRYPTOCOMPARE },\n histohour: { path: '/data/v2/histohour?fsym={fsym}&tsym={tsym}&limit={limit}&api_key=' + EMBEDDED_KEYS.CRYPTOCOMPARE },\n histoday: { path: '/data/v2/histoday?fsym={fsym}&tsym={tsym}&limit={limit}&api_key=' + EMBEDDED_KEYS.CRYPTOCOMPARE },\n }},\n { id: 'cmc', category: 'market', name: 'CoinMarketCap', baseUrl: 'https://pro-api.coinmarketcap.com/v1', free: false, endpoints: {\n quotes: { path: '/cryptocurrency/quotes/latest?symbol={symbol}', authLocation: 'header', authName: 'X-CMC_PRO_API_KEY', authValue: EMBEDDED_KEYS.CMC },\n }},\n\n // News\n { id: 'coinstats_news', category: 'news', name: 'CoinStats News', baseUrl: 'https://api.coinstats.app', free: true, endpoints: { feed: { path: '/public/v1/news' } }},\n { id: 'cryptopanic', category: 'news', name: 'CryptoPanic', baseUrl: 'https://cryptopanic.com', free: true, endpoints: { public: { path: '/api/v1/posts/?public=true' } }},\n { id: 'rss_cointelegraph', category: 'news', name: 'Cointelegraph RSS', baseUrl: 'https://cointelegraph.com', free: true, endpoints: { feed: { path: '/rss' } }},\n { id: 'rss_coindesk', category: 'news', name: 'CoinDesk RSS', baseUrl: 'https://www.coindesk.com', free: true, endpoints: { feed: { path: '/arc/outboundfeeds/rss/?outputType=xml' } }},\n { id: 'rss_decrypt', category: 'news', name: 'Decrypt RSS', baseUrl: 'https://decrypt.co', free: true, endpoints: { feed: { path: '/feed' } }},\n\n // Sentiment / F&G\n { id: 'altme_fng', category: 'sentiment', name: 'Alternative.me F&G', baseUrl: 'https://api.alternative.me', free: true, endpoints: {\n latest: { path: '/fng/', sampleParams: { limit: 1 } },\n history: { path: '/fng/', sampleParams: { limit: 30 } },\n }},\n { id: 'cfgi_v1', category: 'sentiment', name: 'CFGI API v1', baseUrl: 'https://api.cfgi.io', free: true, endpoints: {\n latest: { path: '/v1/fear-greed' },\n }},\n { id: 'cfgi_legacy', category: 'sentiment', name: 'CFGI Legacy', baseUrl: 'https://cfgi.io', free: true, endpoints: {\n latest: { path: '/api' },\n }},\n\n // On-chain / explorers\n { id: 'etherscan_primary', category: 'block_explorer', name: 'Etherscan', baseUrl: 'https://api.etherscan.io/api', free: false, endpoints: {\n balance: { path: '/?module=account&action=balance&address={address}&tag=latest&apikey=' + EMBEDDED_KEYS.ETHERSCAN },\n }},\n { id: 'etherscan_backup', category: 'block_explorer', name: 'Etherscan Backup', baseUrl: 'https://api.etherscan.io/api', free: false, endpoints: {\n balance: { path: '/?module=account&action=balance&address={address}&tag=latest&apikey=' + EMBEDDED_KEYS.ETHERSCAN_BACKUP },\n }},\n { id: 'blockscout_eth', category: 'block_explorer', name: 'Blockscout (ETH)', baseUrl: 'https://eth.blockscout.com', free: true, endpoints: {\n balanc",
|
| 35 |
"note": "included as small text"
|
| 36 |
}
|
| 37 |
],
|
|
|
|
| 57 |
"e79c8e6d4c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f"
|
| 58 |
],
|
| 59 |
"huggingface": [
|
| 60 |
+
"hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
| 61 |
]
|
| 62 |
},
|
| 63 |
"notes": "This file was auto-generated. Keys/tokens are present as found in uploaded sources. Secure them as you wish."
|
final/api-resources/crypto_resources_unified_2025-11-11.json
CHANGED
|
@@ -1699,7 +1699,7 @@
|
|
| 1699 |
"base_url": "https://api-inference.huggingface.co/models/ElKulako/cryptobert",
|
| 1700 |
"auth": {
|
| 1701 |
"type": "apiKeyHeaderOptional",
|
| 1702 |
-
"key": "
|
| 1703 |
"header_name": "Authorization"
|
| 1704 |
},
|
| 1705 |
"docs_url": "https://huggingface.co/ElKulako/cryptobert",
|
|
@@ -1715,7 +1715,7 @@
|
|
| 1715 |
"base_url": "https://api-inference.huggingface.co/models/kk08/CryptoBERT",
|
| 1716 |
"auth": {
|
| 1717 |
"type": "apiKeyHeaderOptional",
|
| 1718 |
-
"key": "
|
| 1719 |
"header_name": "Authorization"
|
| 1720 |
},
|
| 1721 |
"docs_url": "https://huggingface.co/kk08/CryptoBERT",
|
|
|
|
| 1699 |
"base_url": "https://api-inference.huggingface.co/models/ElKulako/cryptobert",
|
| 1700 |
"auth": {
|
| 1701 |
"type": "apiKeyHeaderOptional",
|
| 1702 |
+
"key": "hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
| 1703 |
"header_name": "Authorization"
|
| 1704 |
},
|
| 1705 |
"docs_url": "https://huggingface.co/ElKulako/cryptobert",
|
|
|
|
| 1715 |
"base_url": "https://api-inference.huggingface.co/models/kk08/CryptoBERT",
|
| 1716 |
"auth": {
|
| 1717 |
"type": "apiKeyHeaderOptional",
|
| 1718 |
+
"key": "hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
| 1719 |
"header_name": "Authorization"
|
| 1720 |
},
|
| 1721 |
"docs_url": "https://huggingface.co/kk08/CryptoBERT",
|
final/backend/services/auto_discovery_service.py
CHANGED
|
@@ -94,7 +94,7 @@ class AutoDiscoveryService:
|
|
| 94 |
# Get HF token from environment or use default
|
| 95 |
from config import get_settings
|
| 96 |
settings = get_settings()
|
| 97 |
-
hf_token = os.getenv("HF_TOKEN") or os.getenv("HF_API_TOKEN") or settings.hf_token or "
|
| 98 |
try:
|
| 99 |
self._hf_client = InferenceClient(model=self.hf_model, token=hf_token)
|
| 100 |
logger.info("Auto discovery Hugging Face client initialized with model %s", self.hf_model)
|
|
|
|
| 94 |
# Get HF token from environment or use default
|
| 95 |
from config import get_settings
|
| 96 |
settings = get_settings()
|
| 97 |
+
hf_token = os.getenv("HF_TOKEN") or os.getenv("HF_API_TOKEN") or settings.hf_token or "hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
| 98 |
try:
|
| 99 |
self._hf_client = InferenceClient(model=self.hf_model, token=hf_token)
|
| 100 |
logger.info("Auto discovery Hugging Face client initialized with model %s", self.hf_model)
|
final/backend/services/diagnostics_service.py
CHANGED
|
@@ -265,7 +265,7 @@ class DiagnosticsService:
|
|
| 265 |
|
| 266 |
# Get HF token from settings or use default
|
| 267 |
settings = get_settings()
|
| 268 |
-
hf_token = settings.hf_token or os.getenv("HF_TOKEN") or "
|
| 269 |
|
| 270 |
api = HfApi(token=hf_token)
|
| 271 |
|
|
|
|
| 265 |
|
| 266 |
# Get HF token from settings or use default
|
| 267 |
settings = get_settings()
|
| 268 |
+
hf_token = settings.hf_token or os.getenv("HF_TOKEN") or "hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
| 269 |
|
| 270 |
api = HfApi(token=hf_token)
|
| 271 |
|
final/config.js
CHANGED
|
@@ -123,7 +123,7 @@ window.DASHBOARD_CONFIG = {
|
|
| 123 |
// HuggingFace Configuration
|
| 124 |
// ═══════════════════════════════════════════════════════════════
|
| 125 |
|
| 126 |
-
HF_TOKEN: '
|
| 127 |
HF_API_BASE: 'https://api-inference.huggingface.co/models',
|
| 128 |
|
| 129 |
// ═══════════════════════════════════════════════════════════════
|
|
|
|
| 123 |
// HuggingFace Configuration
|
| 124 |
// ═══════════════════════════════════════════════════════════════
|
| 125 |
|
| 126 |
+
HF_TOKEN: 'hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
|
| 127 |
HF_API_BASE: 'https://api-inference.huggingface.co/models',
|
| 128 |
|
| 129 |
// ═══════════════════════════════════════════════════════════════
|
final/config.py
CHANGED
|
@@ -95,7 +95,7 @@ def get_settings() -> Settings:
|
|
| 95 |
decoded_token = raw_token or _decode_token(encoded_token)
|
| 96 |
# Default token if none provided
|
| 97 |
if not decoded_token:
|
| 98 |
-
decoded_token = "
|
| 99 |
|
| 100 |
database_path = Path(os.environ.get("DATABASE_PATH", str(DB_DIR / "crypto_aggregator.db")))
|
| 101 |
|
|
|
|
| 95 |
decoded_token = raw_token or _decode_token(encoded_token)
|
| 96 |
# Default token if none provided
|
| 97 |
if not decoded_token:
|
| 98 |
+
decoded_token = "hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
| 99 |
|
| 100 |
database_path = Path(os.environ.get("DATABASE_PATH", str(DB_DIR / "crypto_aggregator.db")))
|
| 101 |
|
final/crypto_resources_unified_2025-11-11.json
CHANGED
|
@@ -1699,7 +1699,7 @@
|
|
| 1699 |
"base_url": "https://api-inference.huggingface.co/models/ElKulako/cryptobert",
|
| 1700 |
"auth": {
|
| 1701 |
"type": "apiKeyHeaderOptional",
|
| 1702 |
-
"key": "
|
| 1703 |
"header_name": "Authorization"
|
| 1704 |
},
|
| 1705 |
"docs_url": "https://huggingface.co/ElKulako/cryptobert",
|
|
@@ -1715,7 +1715,7 @@
|
|
| 1715 |
"base_url": "https://api-inference.huggingface.co/models/kk08/CryptoBERT",
|
| 1716 |
"auth": {
|
| 1717 |
"type": "apiKeyHeaderOptional",
|
| 1718 |
-
"key": "
|
| 1719 |
"header_name": "Authorization"
|
| 1720 |
},
|
| 1721 |
"docs_url": "https://huggingface.co/kk08/CryptoBERT",
|
|
|
|
| 1699 |
"base_url": "https://api-inference.huggingface.co/models/ElKulako/cryptobert",
|
| 1700 |
"auth": {
|
| 1701 |
"type": "apiKeyHeaderOptional",
|
| 1702 |
+
"key": "hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
| 1703 |
"header_name": "Authorization"
|
| 1704 |
},
|
| 1705 |
"docs_url": "https://huggingface.co/ElKulako/cryptobert",
|
|
|
|
| 1715 |
"base_url": "https://api-inference.huggingface.co/models/kk08/CryptoBERT",
|
| 1716 |
"auth": {
|
| 1717 |
"type": "apiKeyHeaderOptional",
|
| 1718 |
+
"key": "hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
| 1719 |
"header_name": "Authorization"
|
| 1720 |
},
|
| 1721 |
"docs_url": "https://huggingface.co/kk08/CryptoBERT",
|
final/hf_unified_server.py
CHANGED
|
@@ -2277,7 +2277,7 @@ async def get_dataset_sample(name: str = Query(...), limit: int = Query(default=
|
|
| 2277 |
|
| 2278 |
# Get HF token for dataset loading
|
| 2279 |
settings = get_settings()
|
| 2280 |
-
hf_token = settings.hf_token or "
|
| 2281 |
|
| 2282 |
# Set token in environment for datasets library
|
| 2283 |
import os
|
|
|
|
| 2277 |
|
| 2278 |
# Get HF token for dataset loading
|
| 2279 |
settings = get_settings()
|
| 2280 |
+
hf_token = settings.hf_token or "hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
| 2281 |
|
| 2282 |
# Set token in environment for datasets library
|
| 2283 |
import os
|
final/provider_validator.py
CHANGED
|
@@ -279,7 +279,7 @@ class ProviderValidator:
|
|
| 279 |
start = time.time()
|
| 280 |
|
| 281 |
# Get HF token from environment or use default
|
| 282 |
-
hf_token = os.getenv("HF_TOKEN") or "
|
| 283 |
headers = {}
|
| 284 |
if hf_token:
|
| 285 |
headers["Authorization"] = f"Bearer {hf_token}"
|
|
|
|
| 279 |
start = time.time()
|
| 280 |
|
| 281 |
# Get HF token from environment or use default
|
| 282 |
+
hf_token = os.getenv("HF_TOKEN") or "hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
| 283 |
headers = {}
|
| 284 |
if hf_token:
|
| 285 |
headers["Authorization"] = f"Bearer {hf_token}"
|
final/providers_config_ultimate.json
CHANGED
|
@@ -566,7 +566,7 @@
|
|
| 566 |
"endpoints": {},
|
| 567 |
"rate_limit": {},
|
| 568 |
"requires_auth": true,
|
| 569 |
-
"api_keys": ["
|
| 570 |
"auth_type": "header",
|
| 571 |
"auth_header": "Authorization",
|
| 572 |
"priority": 8,
|
|
|
|
| 566 |
"endpoints": {},
|
| 567 |
"rate_limit": {},
|
| 568 |
"requires_auth": true,
|
| 569 |
+
"api_keys": ["hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"],
|
| 570 |
"auth_type": "header",
|
| 571 |
"auth_header": "Authorization",
|
| 572 |
"priority": 8,
|
final/setup_cryptobert.sh
CHANGED
|
@@ -8,7 +8,7 @@ echo "========================================="
|
|
| 8 |
echo ""
|
| 9 |
|
| 10 |
# Default token (can be overridden)
|
| 11 |
-
DEFAULT_TOKEN="
|
| 12 |
|
| 13 |
# Check if HF_TOKEN is already set
|
| 14 |
if [ -n "$HF_TOKEN" ]; then
|
|
|
|
| 8 |
echo ""
|
| 9 |
|
| 10 |
# Default token (can be overridden)
|
| 11 |
+
DEFAULT_TOKEN="hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
| 12 |
|
| 13 |
# Check if HF_TOKEN is already set
|
| 14 |
if [ -n "$HF_TOKEN" ]; then
|
final/static/js/huggingface-integration.js
CHANGED
|
@@ -215,7 +215,7 @@ class HuggingFaceIntegration {
|
|
| 215 |
// Priority: window.HF_API_KEY > DASHBOARD_CONFIG.HF_TOKEN > default
|
| 216 |
return window.HF_API_KEY ||
|
| 217 |
(window.DASHBOARD_CONFIG && window.DASHBOARD_CONFIG.HF_TOKEN) ||
|
| 218 |
-
'
|
| 219 |
}
|
| 220 |
}
|
| 221 |
|
|
|
|
| 215 |
// Priority: window.HF_API_KEY > DASHBOARD_CONFIG.HF_TOKEN > default
|
| 216 |
return window.HF_API_KEY ||
|
| 217 |
(window.DASHBOARD_CONFIG && window.DASHBOARD_CONFIG.HF_TOKEN) ||
|
| 218 |
+
'hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
|
| 219 |
}
|
| 220 |
}
|
| 221 |
|
final/static/providers_config_ultimate.json
CHANGED
|
@@ -566,7 +566,7 @@
|
|
| 566 |
"endpoints": {},
|
| 567 |
"rate_limit": {},
|
| 568 |
"requires_auth": true,
|
| 569 |
-
"api_keys": ["
|
| 570 |
"auth_type": "header",
|
| 571 |
"auth_header": "Authorization",
|
| 572 |
"priority": 8,
|
|
|
|
| 566 |
"endpoints": {},
|
| 567 |
"rate_limit": {},
|
| 568 |
"requires_auth": true,
|
| 569 |
+
"api_keys": ["hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"],
|
| 570 |
"auth_type": "header",
|
| 571 |
"auth_header": "Authorization",
|
| 572 |
"priority": 8,
|
final/test_cryptobert.py
CHANGED
|
@@ -10,7 +10,7 @@ import json
|
|
| 10 |
from typing import Dict, Any
|
| 11 |
|
| 12 |
# Ensure the token is set
|
| 13 |
-
os.environ.setdefault("HF_TOKEN", "
|
| 14 |
|
| 15 |
# Import after setting environment variable
|
| 16 |
import config
|
|
|
|
| 10 |
from typing import Dict, Any
|
| 11 |
|
| 12 |
# Ensure the token is set
|
| 13 |
+
os.environ.setdefault("HF_TOKEN", "hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
|
| 14 |
|
| 15 |
# Import after setting environment variable
|
| 16 |
import config
|
hf-data-engine/all_apis_merged_2025.json
CHANGED
|
@@ -31,7 +31,7 @@
|
|
| 31 |
"zip_text_snippets": [
|
| 32 |
{
|
| 33 |
"filename": "crypto_resources.ts",
|
| 34 |
-
"text_preview": "// crypto_resources.ts — unified TS with 150+ Hugging Face sources (dynamic catalog) + Safe F&G aggregator\n// English-only comments. Keys intentionally embedded per user request.\n\nexport type Category =\n | 'market'\n | 'news'\n | 'sentiment'\n | 'onchain'\n | 'block_explorer'\n | 'whales'\n | 'generic'\n | 'hf';\n\nexport interface EndpointDef {\n path: string;\n method?: 'GET' | 'POST';\n sampleParams?: Record<string, string | number>;\n authLocation?: 'header' | 'query';\n authName?: string;\n authValue?: string;\n contentType?: string;\n}\n\nexport interface CryptoResource {\n id: string;\n category: Category;\n name: string;\n baseUrl: string;\n free: boolean;\n rateLimit?: string;\n endpoints?: Record<string, EndpointDef>;\n}\n\nexport interface MarketQuote {\n id: string;\n symbol: string;\n name: string;\n price: number;\n change24h?: number;\n marketCap?: number;\n source: string;\n raw: any;\n}\n\nexport interface NewsItem {\n title: string;\n link: string;\n publishedAt?: string;\n source: string;\n}\n\nexport interface OHLCVRow {\n timestamp: number | string;\n open: number; high: number; low: number; close: number; volume: number;\n [k: string]: any;\n}\n\nexport interface FNGPoint {\n value: number; // 0..100\n classification: string;\n at?: string;\n source: string;\n raw?: any;\n}\n\nconst EMBEDDED_KEYS = {\n CMC: '04cf4b5b-9868-465c-8ba0-9f2e78c92eb1',\n ETHERSCAN: 'SZHYFZK2RR8H9TIMJBVW54V4H81K2Z2KR2',\n ETHERSCAN_BACKUP: 'T6IR8VJHX2NE6ZJW2S3FDVN1TYG4PYYI45',\n BSCSCAN: 'K62RKHGXTDCG53RU4MCG6XABIMJKTN19IT',\n CRYPTOCOMPARE: 'e79c8e6d4c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f',\n\n // Optional free keys provided by user (kept in-code per request)\n MESSARI: '',\n SANTIMENT: '',\n COINMETRICS: '',\n HUGGINGFACE: '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',\n};\n\nconst sleep = (ms: number) => new Promise(r => setTimeout(r, ms));\n\nclass HttpError extends Error {\n constructor(public status: number, public url: string, public body?: string) {\n super(`HTTP ${status} for ${url}`);\n }\n}\n\nfunction buildURL(base: string, path = '', params?: Record<string, any>): string {\n const hasQ = path.includes('?');\n const url = base.replace(/\\/+$/, '') + '/' + path.replace(/^\\/+/, '');\n if (!params || Object.keys(params).length === 0) return url;\n const qs = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) {\n if (v === undefined || v === null) continue;\n qs.set(k, String(v));\n }\n return url + (hasQ ? '&' : '?') + qs.toString();\n}\n\nasync function fetchRaw(\n url: string,\n opts: { headers?: Record<string, string>; timeoutMs?: number; retries?: number; retryDelayMs?: number; body?: any; method?: 'GET'|'POST' } = {}\n): Promise<Response> {\n const { headers = {}, timeoutMs = 12000, retries = 1, retryDelayMs = 600, body, method = 'GET' } = opts;\n let lastErr: any;\n for (let attempt = 0; attempt <= retries; attempt++) {\n const ac = new AbortController();\n const id = setTimeout(() => ac.abort(), timeoutMs);\n try {\n const res = await fetch(url, { headers, signal: ac.signal, method, body });\n clearTimeout(id);\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n if (res.status === 429 && attempt < retries) {\n await sleep(retryDelayMs * (attempt + 1));\n continue;\n }\n throw new HttpError(res.status, url, text);\n }\n return res;\n } catch (e) {\n clearTimeout(id);\n lastErr = e;\n if (attempt < retries) { await sleep(retryDelayMs * (attempt + 1)); continue; }\n }\n }\n throw lastErr;\n}\n\nasync function fetchJSON<T = any>(\n url: string,\n opts: { headers?: Record<string, string>; timeoutMs?: number; retries?: number; retryDelayMs?: number; body?: any; method?: 'GET'|'POST' } = {}\n): Promise<T> {\n const res = await fetchRaw(url, opts);\n const ct = res.headers.get('content-type') || '';\n if (ct.includes('json')) return res.json() as Promise<T>;\n const text = await res.text();\n try { return JSON.parse(text) as T; } catch { return text as unknown as T; }\n}\n\nfunction ensureNonEmpty(obj: any, label: string) {\n if (obj == null) throw new Error(`${label}: empty response`);\n if (Array.isArray(obj) && obj.length === 0) throw new Error(`${label}: empty array`);\n if (typeof obj === 'object' && !Array.isArray(obj) && Object.keys(obj).length === 0)\n throw new Error(`${label}: empty object`);\n}\n\nfunction normalizeSymbol(q: string) { return q.trim().toLowerCase(); }\n\nfunction parseCSV(text: string): any[] {\n const lines = text.split(/\\r?\\n/).filter(Boolean);\n if (lines.length < 2) return [];\n const header = lines[0].split(',').map((s) => s.trim());\n const out: any[] = [];\n for (let i = 1; i < lines.length; i++) {\n const cols = lines[i].split(',').map((s) => s.trim());\n const row: any = {};\n header.forEach((h, idx) => { row[h] = cols[idx]; });\n out.push(row);\n }\n return out;\n}\n\nfunction parseRssSimple(xml: string, source: string, limit = 20): NewsItem[] {\n const items: NewsItem[] = [];\n const chunks = xml.split(/<item[\\s>]/i).slice(1);\n for (const raw of chunks) {\n const item = raw.split(/<\\/item>/i)[0] || '';\n const get = (tag: string) => {\n const m = item.match(new RegExp(`<${tag}[^>]*>([\\\\s\\\\S]*?)</${tag}>`, 'i'));\n return m ? m[1].replace(/<!\\[CDATA\\[|\\]\\]>/g, '').trim() : undefined;\n };\n const title = get('title'); const link = get('link') || get('guid'); const pub = get('pubDate') || get('updated') || get('dc:date');\n if (title && link) items.push({ title, link, publishedAt: pub, source });\n if (items.length >= limit) break;\n }\n return items;\n}\n\n/* ===================== BASE RESOURCES ===================== */\n\nexport const resources: CryptoResource[] = [\n // Market\n { id: 'coinpaprika', category: 'market', name: 'CoinPaprika', baseUrl: 'https://api.coinpaprika.com/v1', free: true, endpoints: {\n search: { path: '/search', sampleParams: { q: 'bitcoin', c: 'currencies', limit: 1 } },\n tickerById: { path: '/tickers/{id}', sampleParams: { quotes: 'USD' } },\n }},\n { id: 'coincap', category: 'market', name: 'CoinCap', baseUrl: 'https://api.coincap.io/v2', free: true, endpoints: {\n assets: { path: '/assets', sampleParams: { search: 'bitcoin', limit: 1 } },\n assetById: { path: '/assets/{id}' },\n }},\n { id: 'coingecko', category: 'market', name: 'CoinGecko', baseUrl: 'https://api.coingecko.com/api/v3', free: true, endpoints: {\n simplePrice: { path: '/simple/price?ids={ids}&vs_currencies={fiats}' },\n }},\n { id: 'defillama', category: 'market', name: 'DefiLlama (Prices)', baseUrl: 'https://coins.llama.fi', free: true, endpoints: {\n pricesCurrent: { path: '/prices/current/{coins}' },\n }},\n { id: 'binance', category: 'market', name: 'Binance Public', baseUrl: 'https://api.binance.com', free: true, endpoints: {\n klines: { path: '/api/v3/klines?symbol={symbol}&interval={interval}&limit={limit}' },\n ticker: { path: '/api/v3/ticker/price?symbol={symbol}' },\n }},\n { id: 'cryptocompare', category: 'market', name: 'CryptoCompare', baseUrl: 'https://min-api.cryptocompare.com', free: true, endpoints: {\n histominute: { path: '/data/v2/histominute?fsym={fsym}&tsym={tsym}&limit={limit}&api_key=' + EMBEDDED_KEYS.CRYPTOCOMPARE },\n histohour: { path: '/data/v2/histohour?fsym={fsym}&tsym={tsym}&limit={limit}&api_key=' + EMBEDDED_KEYS.CRYPTOCOMPARE },\n histoday: { path: '/data/v2/histoday?fsym={fsym}&tsym={tsym}&limit={limit}&api_key=' + EMBEDDED_KEYS.CRYPTOCOMPARE },\n }},\n { id: 'cmc', category: 'market', name: 'CoinMarketCap', baseUrl: 'https://pro-api.coinmarketcap.com/v1', free: false, endpoints: {\n quotes: { path: '/cryptocurrency/quotes/latest?symbol={symbol}', authLocation: 'header', authName: 'X-CMC_PRO_API_KEY', authValue: EMBEDDED_KEYS.CMC },\n }},\n\n // News\n { id: 'coinstats_news', category: 'news', name: 'CoinStats News', baseUrl: 'https://api.coinstats.app', free: true, endpoints: { feed: { path: '/public/v1/news' } }},\n { id: 'cryptopanic', category: 'news', name: 'CryptoPanic', baseUrl: 'https://cryptopanic.com', free: true, endpoints: { public: { path: '/api/v1/posts/?public=true' } }},\n { id: 'rss_cointelegraph', category: 'news', name: 'Cointelegraph RSS', baseUrl: 'https://cointelegraph.com', free: true, endpoints: { feed: { path: '/rss' } }},\n { id: 'rss_coindesk', category: 'news', name: 'CoinDesk RSS', baseUrl: 'https://www.coindesk.com', free: true, endpoints: { feed: { path: '/arc/outboundfeeds/rss/?outputType=xml' } }},\n { id: 'rss_decrypt', category: 'news', name: 'Decrypt RSS', baseUrl: 'https://decrypt.co', free: true, endpoints: { feed: { path: '/feed' } }},\n\n // Sentiment / F&G\n { id: 'altme_fng', category: 'sentiment', name: 'Alternative.me F&G', baseUrl: 'https://api.alternative.me', free: true, endpoints: {\n latest: { path: '/fng/', sampleParams: { limit: 1 } },\n history: { path: '/fng/', sampleParams: { limit: 30 } },\n }},\n { id: 'cfgi_v1', category: 'sentiment', name: 'CFGI API v1', baseUrl: 'https://api.cfgi.io', free: true, endpoints: {\n latest: { path: '/v1/fear-greed' },\n }},\n { id: 'cfgi_legacy', category: 'sentiment', name: 'CFGI Legacy', baseUrl: 'https://cfgi.io', free: true, endpoints: {\n latest: { path: '/api' },\n }},\n\n // On-chain / explorers\n { id: 'etherscan_primary', category: 'block_explorer', name: 'Etherscan', baseUrl: 'https://api.etherscan.io/api', free: false, endpoints: {\n balance: { path: '/?module=account&action=balance&address={address}&tag=latest&apikey=' + EMBEDDED_KEYS.ETHERSCAN },\n }},\n { id: 'etherscan_backup', category: 'block_explorer', name: 'Etherscan Backup', baseUrl: 'https://api.etherscan.io/api', free: false, endpoints: {\n balance: { path: '/?module=account&action=balance&address={address}&tag=latest&apikey=' + EMBEDDED_KEYS.ETHERSCAN_BACKUP },\n }},\n { id: 'blockscout_eth', category: 'block_explorer', name: 'Blockscout (ETH)', baseUrl: 'https://eth.blockscout.com', free: true, endpoints: {\n balanc",
|
| 35 |
"note": "included as small text"
|
| 36 |
}
|
| 37 |
],
|
|
@@ -57,7 +57,7 @@
|
|
| 57 |
"e79c8e6d4c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f"
|
| 58 |
],
|
| 59 |
"huggingface": [
|
| 60 |
-
"
|
| 61 |
]
|
| 62 |
},
|
| 63 |
"notes": "This file was auto-generated. Keys/tokens are present as found in uploaded sources. Secure them as you wish."
|
|
|
|
| 31 |
"zip_text_snippets": [
|
| 32 |
{
|
| 33 |
"filename": "crypto_resources.ts",
|
| 34 |
+
"text_preview": "// crypto_resources.ts — unified TS with 150+ Hugging Face sources (dynamic catalog) + Safe F&G aggregator\n// English-only comments. Keys intentionally embedded per user request.\n\nexport type Category =\n | 'market'\n | 'news'\n | 'sentiment'\n | 'onchain'\n | 'block_explorer'\n | 'whales'\n | 'generic'\n | 'hf';\n\nexport interface EndpointDef {\n path: string;\n method?: 'GET' | 'POST';\n sampleParams?: Record<string, string | number>;\n authLocation?: 'header' | 'query';\n authName?: string;\n authValue?: string;\n contentType?: string;\n}\n\nexport interface CryptoResource {\n id: string;\n category: Category;\n name: string;\n baseUrl: string;\n free: boolean;\n rateLimit?: string;\n endpoints?: Record<string, EndpointDef>;\n}\n\nexport interface MarketQuote {\n id: string;\n symbol: string;\n name: string;\n price: number;\n change24h?: number;\n marketCap?: number;\n source: string;\n raw: any;\n}\n\nexport interface NewsItem {\n title: string;\n link: string;\n publishedAt?: string;\n source: string;\n}\n\nexport interface OHLCVRow {\n timestamp: number | string;\n open: number; high: number; low: number; close: number; volume: number;\n [k: string]: any;\n}\n\nexport interface FNGPoint {\n value: number; // 0..100\n classification: string;\n at?: string;\n source: string;\n raw?: any;\n}\n\nconst EMBEDDED_KEYS = {\n CMC: '04cf4b5b-9868-465c-8ba0-9f2e78c92eb1',\n ETHERSCAN: 'SZHYFZK2RR8H9TIMJBVW54V4H81K2Z2KR2',\n ETHERSCAN_BACKUP: 'T6IR8VJHX2NE6ZJW2S3FDVN1TYG4PYYI45',\n BSCSCAN: 'K62RKHGXTDCG53RU4MCG6XABIMJKTN19IT',\n CRYPTOCOMPARE: 'e79c8e6d4c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f',\n\n // Optional free keys provided by user (kept in-code per request)\n MESSARI: '',\n SANTIMENT: '',\n COINMETRICS: '',\n HUGGINGFACE: 'hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',\n};\n\nconst sleep = (ms: number) => new Promise(r => setTimeout(r, ms));\n\nclass HttpError extends Error {\n constructor(public status: number, public url: string, public body?: string) {\n super(`HTTP ${status} for ${url}`);\n }\n}\n\nfunction buildURL(base: string, path = '', params?: Record<string, any>): string {\n const hasQ = path.includes('?');\n const url = base.replace(/\\/+$/, '') + '/' + path.replace(/^\\/+/, '');\n if (!params || Object.keys(params).length === 0) return url;\n const qs = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) {\n if (v === undefined || v === null) continue;\n qs.set(k, String(v));\n }\n return url + (hasQ ? '&' : '?') + qs.toString();\n}\n\nasync function fetchRaw(\n url: string,\n opts: { headers?: Record<string, string>; timeoutMs?: number; retries?: number; retryDelayMs?: number; body?: any; method?: 'GET'|'POST' } = {}\n): Promise<Response> {\n const { headers = {}, timeoutMs = 12000, retries = 1, retryDelayMs = 600, body, method = 'GET' } = opts;\n let lastErr: any;\n for (let attempt = 0; attempt <= retries; attempt++) {\n const ac = new AbortController();\n const id = setTimeout(() => ac.abort(), timeoutMs);\n try {\n const res = await fetch(url, { headers, signal: ac.signal, method, body });\n clearTimeout(id);\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n if (res.status === 429 && attempt < retries) {\n await sleep(retryDelayMs * (attempt + 1));\n continue;\n }\n throw new HttpError(res.status, url, text);\n }\n return res;\n } catch (e) {\n clearTimeout(id);\n lastErr = e;\n if (attempt < retries) { await sleep(retryDelayMs * (attempt + 1)); continue; }\n }\n }\n throw lastErr;\n}\n\nasync function fetchJSON<T = any>(\n url: string,\n opts: { headers?: Record<string, string>; timeoutMs?: number; retries?: number; retryDelayMs?: number; body?: any; method?: 'GET'|'POST' } = {}\n): Promise<T> {\n const res = await fetchRaw(url, opts);\n const ct = res.headers.get('content-type') || '';\n if (ct.includes('json')) return res.json() as Promise<T>;\n const text = await res.text();\n try { return JSON.parse(text) as T; } catch { return text as unknown as T; }\n}\n\nfunction ensureNonEmpty(obj: any, label: string) {\n if (obj == null) throw new Error(`${label}: empty response`);\n if (Array.isArray(obj) && obj.length === 0) throw new Error(`${label}: empty array`);\n if (typeof obj === 'object' && !Array.isArray(obj) && Object.keys(obj).length === 0)\n throw new Error(`${label}: empty object`);\n}\n\nfunction normalizeSymbol(q: string) { return q.trim().toLowerCase(); }\n\nfunction parseCSV(text: string): any[] {\n const lines = text.split(/\\r?\\n/).filter(Boolean);\n if (lines.length < 2) return [];\n const header = lines[0].split(',').map((s) => s.trim());\n const out: any[] = [];\n for (let i = 1; i < lines.length; i++) {\n const cols = lines[i].split(',').map((s) => s.trim());\n const row: any = {};\n header.forEach((h, idx) => { row[h] = cols[idx]; });\n out.push(row);\n }\n return out;\n}\n\nfunction parseRssSimple(xml: string, source: string, limit = 20): NewsItem[] {\n const items: NewsItem[] = [];\n const chunks = xml.split(/<item[\\s>]/i).slice(1);\n for (const raw of chunks) {\n const item = raw.split(/<\\/item>/i)[0] || '';\n const get = (tag: string) => {\n const m = item.match(new RegExp(`<${tag}[^>]*>([\\\\s\\\\S]*?)</${tag}>`, 'i'));\n return m ? m[1].replace(/<!\\[CDATA\\[|\\]\\]>/g, '').trim() : undefined;\n };\n const title = get('title'); const link = get('link') || get('guid'); const pub = get('pubDate') || get('updated') || get('dc:date');\n if (title && link) items.push({ title, link, publishedAt: pub, source });\n if (items.length >= limit) break;\n }\n return items;\n}\n\n/* ===================== BASE RESOURCES ===================== */\n\nexport const resources: CryptoResource[] = [\n // Market\n { id: 'coinpaprika', category: 'market', name: 'CoinPaprika', baseUrl: 'https://api.coinpaprika.com/v1', free: true, endpoints: {\n search: { path: '/search', sampleParams: { q: 'bitcoin', c: 'currencies', limit: 1 } },\n tickerById: { path: '/tickers/{id}', sampleParams: { quotes: 'USD' } },\n }},\n { id: 'coincap', category: 'market', name: 'CoinCap', baseUrl: 'https://api.coincap.io/v2', free: true, endpoints: {\n assets: { path: '/assets', sampleParams: { search: 'bitcoin', limit: 1 } },\n assetById: { path: '/assets/{id}' },\n }},\n { id: 'coingecko', category: 'market', name: 'CoinGecko', baseUrl: 'https://api.coingecko.com/api/v3', free: true, endpoints: {\n simplePrice: { path: '/simple/price?ids={ids}&vs_currencies={fiats}' },\n }},\n { id: 'defillama', category: 'market', name: 'DefiLlama (Prices)', baseUrl: 'https://coins.llama.fi', free: true, endpoints: {\n pricesCurrent: { path: '/prices/current/{coins}' },\n }},\n { id: 'binance', category: 'market', name: 'Binance Public', baseUrl: 'https://api.binance.com', free: true, endpoints: {\n klines: { path: '/api/v3/klines?symbol={symbol}&interval={interval}&limit={limit}' },\n ticker: { path: '/api/v3/ticker/price?symbol={symbol}' },\n }},\n { id: 'cryptocompare', category: 'market', name: 'CryptoCompare', baseUrl: 'https://min-api.cryptocompare.com', free: true, endpoints: {\n histominute: { path: '/data/v2/histominute?fsym={fsym}&tsym={tsym}&limit={limit}&api_key=' + EMBEDDED_KEYS.CRYPTOCOMPARE },\n histohour: { path: '/data/v2/histohour?fsym={fsym}&tsym={tsym}&limit={limit}&api_key=' + EMBEDDED_KEYS.CRYPTOCOMPARE },\n histoday: { path: '/data/v2/histoday?fsym={fsym}&tsym={tsym}&limit={limit}&api_key=' + EMBEDDED_KEYS.CRYPTOCOMPARE },\n }},\n { id: 'cmc', category: 'market', name: 'CoinMarketCap', baseUrl: 'https://pro-api.coinmarketcap.com/v1', free: false, endpoints: {\n quotes: { path: '/cryptocurrency/quotes/latest?symbol={symbol}', authLocation: 'header', authName: 'X-CMC_PRO_API_KEY', authValue: EMBEDDED_KEYS.CMC },\n }},\n\n // News\n { id: 'coinstats_news', category: 'news', name: 'CoinStats News', baseUrl: 'https://api.coinstats.app', free: true, endpoints: { feed: { path: '/public/v1/news' } }},\n { id: 'cryptopanic', category: 'news', name: 'CryptoPanic', baseUrl: 'https://cryptopanic.com', free: true, endpoints: { public: { path: '/api/v1/posts/?public=true' } }},\n { id: 'rss_cointelegraph', category: 'news', name: 'Cointelegraph RSS', baseUrl: 'https://cointelegraph.com', free: true, endpoints: { feed: { path: '/rss' } }},\n { id: 'rss_coindesk', category: 'news', name: 'CoinDesk RSS', baseUrl: 'https://www.coindesk.com', free: true, endpoints: { feed: { path: '/arc/outboundfeeds/rss/?outputType=xml' } }},\n { id: 'rss_decrypt', category: 'news', name: 'Decrypt RSS', baseUrl: 'https://decrypt.co', free: true, endpoints: { feed: { path: '/feed' } }},\n\n // Sentiment / F&G\n { id: 'altme_fng', category: 'sentiment', name: 'Alternative.me F&G', baseUrl: 'https://api.alternative.me', free: true, endpoints: {\n latest: { path: '/fng/', sampleParams: { limit: 1 } },\n history: { path: '/fng/', sampleParams: { limit: 30 } },\n }},\n { id: 'cfgi_v1', category: 'sentiment', name: 'CFGI API v1', baseUrl: 'https://api.cfgi.io', free: true, endpoints: {\n latest: { path: '/v1/fear-greed' },\n }},\n { id: 'cfgi_legacy', category: 'sentiment', name: 'CFGI Legacy', baseUrl: 'https://cfgi.io', free: true, endpoints: {\n latest: { path: '/api' },\n }},\n\n // On-chain / explorers\n { id: 'etherscan_primary', category: 'block_explorer', name: 'Etherscan', baseUrl: 'https://api.etherscan.io/api', free: false, endpoints: {\n balance: { path: '/?module=account&action=balance&address={address}&tag=latest&apikey=' + EMBEDDED_KEYS.ETHERSCAN },\n }},\n { id: 'etherscan_backup', category: 'block_explorer', name: 'Etherscan Backup', baseUrl: 'https://api.etherscan.io/api', free: false, endpoints: {\n balance: { path: '/?module=account&action=balance&address={address}&tag=latest&apikey=' + EMBEDDED_KEYS.ETHERSCAN_BACKUP },\n }},\n { id: 'blockscout_eth', category: 'block_explorer', name: 'Blockscout (ETH)', baseUrl: 'https://eth.blockscout.com', free: true, endpoints: {\n balanc",
|
| 35 |
"note": "included as small text"
|
| 36 |
}
|
| 37 |
],
|
|
|
|
| 57 |
"e79c8e6d4c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f"
|
| 58 |
],
|
| 59 |
"huggingface": [
|
| 60 |
+
"hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
| 61 |
]
|
| 62 |
},
|
| 63 |
"notes": "This file was auto-generated. Keys/tokens are present as found in uploaded sources. Secure them as you wish."
|
hf-data-engine/api-resources/crypto_resources_unified_2025-11-11.json
CHANGED
|
@@ -1699,7 +1699,7 @@
|
|
| 1699 |
"base_url": "https://api-inference.huggingface.co/models/ElKulako/cryptobert",
|
| 1700 |
"auth": {
|
| 1701 |
"type": "apiKeyHeaderOptional",
|
| 1702 |
-
"key": "
|
| 1703 |
"header_name": "Authorization"
|
| 1704 |
},
|
| 1705 |
"docs_url": "https://huggingface.co/ElKulako/cryptobert",
|
|
@@ -1715,7 +1715,7 @@
|
|
| 1715 |
"base_url": "https://api-inference.huggingface.co/models/kk08/CryptoBERT",
|
| 1716 |
"auth": {
|
| 1717 |
"type": "apiKeyHeaderOptional",
|
| 1718 |
-
"key": "
|
| 1719 |
"header_name": "Authorization"
|
| 1720 |
},
|
| 1721 |
"docs_url": "https://huggingface.co/kk08/CryptoBERT",
|
|
|
|
| 1699 |
"base_url": "https://api-inference.huggingface.co/models/ElKulako/cryptobert",
|
| 1700 |
"auth": {
|
| 1701 |
"type": "apiKeyHeaderOptional",
|
| 1702 |
+
"key": "hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
| 1703 |
"header_name": "Authorization"
|
| 1704 |
},
|
| 1705 |
"docs_url": "https://huggingface.co/ElKulako/cryptobert",
|
|
|
|
| 1715 |
"base_url": "https://api-inference.huggingface.co/models/kk08/CryptoBERT",
|
| 1716 |
"auth": {
|
| 1717 |
"type": "apiKeyHeaderOptional",
|
| 1718 |
+
"key": "hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
| 1719 |
"header_name": "Authorization"
|
| 1720 |
},
|
| 1721 |
"docs_url": "https://huggingface.co/kk08/CryptoBERT",
|
hf-data-engine/crypto_resources_unified_2025-11-11.json
CHANGED
|
@@ -1699,7 +1699,7 @@
|
|
| 1699 |
"base_url": "https://api-inference.huggingface.co/models/ElKulako/cryptobert",
|
| 1700 |
"auth": {
|
| 1701 |
"type": "apiKeyHeaderOptional",
|
| 1702 |
-
"key": "
|
| 1703 |
"header_name": "Authorization"
|
| 1704 |
},
|
| 1705 |
"docs_url": "https://huggingface.co/ElKulako/cryptobert",
|
|
@@ -1715,7 +1715,7 @@
|
|
| 1715 |
"base_url": "https://api-inference.huggingface.co/models/kk08/CryptoBERT",
|
| 1716 |
"auth": {
|
| 1717 |
"type": "apiKeyHeaderOptional",
|
| 1718 |
-
"key": "
|
| 1719 |
"header_name": "Authorization"
|
| 1720 |
},
|
| 1721 |
"docs_url": "https://huggingface.co/kk08/CryptoBERT",
|
|
|
|
| 1699 |
"base_url": "https://api-inference.huggingface.co/models/ElKulako/cryptobert",
|
| 1700 |
"auth": {
|
| 1701 |
"type": "apiKeyHeaderOptional",
|
| 1702 |
+
"key": "hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
| 1703 |
"header_name": "Authorization"
|
| 1704 |
},
|
| 1705 |
"docs_url": "https://huggingface.co/ElKulako/cryptobert",
|
|
|
|
| 1715 |
"base_url": "https://api-inference.huggingface.co/models/kk08/CryptoBERT",
|
| 1716 |
"auth": {
|
| 1717 |
"type": "apiKeyHeaderOptional",
|
| 1718 |
+
"key": "hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
| 1719 |
"header_name": "Authorization"
|
| 1720 |
},
|
| 1721 |
"docs_url": "https://huggingface.co/kk08/CryptoBERT",
|
hf-data-engine/docs/archive/HF_IMPLEMENTATION_COMPLETE.md
CHANGED
|
@@ -47,7 +47,7 @@
|
|
| 47 |
|
| 48 |
#### 1. **Environment Configuration** (`.env`)
|
| 49 |
```env
|
| 50 |
-
HUGGINGFACE_TOKEN=
|
| 51 |
ENABLE_SENTIMENT=true
|
| 52 |
SENTIMENT_SOCIAL_MODEL=ElKulako/cryptobert
|
| 53 |
SENTIMENT_NEWS_MODEL=kk08/CryptoBERT
|
|
|
|
| 47 |
|
| 48 |
#### 1. **Environment Configuration** (`.env`)
|
| 49 |
```env
|
| 50 |
+
HUGGINGFACE_TOKEN=hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
| 51 |
ENABLE_SENTIMENT=true
|
| 52 |
SENTIMENT_SOCIAL_MODEL=ElKulako/cryptobert
|
| 53 |
SENTIMENT_NEWS_MODEL=kk08/CryptoBERT
|
hf-data-engine/providers_config_ultimate.json
CHANGED
|
@@ -566,7 +566,7 @@
|
|
| 566 |
"endpoints": {},
|
| 567 |
"rate_limit": {},
|
| 568 |
"requires_auth": true,
|
| 569 |
-
"api_keys": ["
|
| 570 |
"auth_type": "header",
|
| 571 |
"auth_header": "Authorization",
|
| 572 |
"priority": 8,
|
|
|
|
| 566 |
"endpoints": {},
|
| 567 |
"rate_limit": {},
|
| 568 |
"requires_auth": true,
|
| 569 |
+
"api_keys": ["hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"],
|
| 570 |
"auth_type": "header",
|
| 571 |
"auth_header": "Authorization",
|
| 572 |
"priority": 8,
|
providers_config_ultimate.json
CHANGED
|
@@ -566,7 +566,7 @@
|
|
| 566 |
"endpoints": {},
|
| 567 |
"rate_limit": {},
|
| 568 |
"requires_auth": true,
|
| 569 |
-
"api_keys": ["
|
| 570 |
"auth_type": "header",
|
| 571 |
"auth_header": "Authorization",
|
| 572 |
"priority": 8,
|
|
|
|
| 566 |
"endpoints": {},
|
| 567 |
"rate_limit": {},
|
| 568 |
"requires_auth": true,
|
| 569 |
+
"api_keys": ["hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"],
|
| 570 |
"auth_type": "header",
|
| 571 |
"auth_header": "Authorization",
|
| 572 |
"priority": 8,
|
run_server.ps1
CHANGED
|
@@ -8,7 +8,7 @@ Write-Host ""
|
|
| 8 |
|
| 9 |
# Set environment variables
|
| 10 |
Write-Host "[1/3] Setting environment variables..." -ForegroundColor Yellow
|
| 11 |
-
$env:HF_TOKEN = "
|
| 12 |
$env:HF_MODE = "public"
|
| 13 |
$env:PORT = "7860"
|
| 14 |
|
|
|
|
| 8 |
|
| 9 |
# Set environment variables
|
| 10 |
Write-Host "[1/3] Setting environment variables..." -ForegroundColor Yellow
|
| 11 |
+
$env:HF_TOKEN = "hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
| 12 |
$env:HF_MODE = "public"
|
| 13 |
$env:PORT = "7860"
|
| 14 |
|
set_env.ps1
CHANGED
|
@@ -3,7 +3,7 @@
|
|
| 3 |
|
| 4 |
Write-Host "Setting Hugging Face environment variables..." -ForegroundColor Cyan
|
| 5 |
|
| 6 |
-
$env:HF_TOKEN = "
|
| 7 |
$env:HF_MODE = "public"
|
| 8 |
$env:PORT = "7860"
|
| 9 |
|
|
|
|
| 3 |
|
| 4 |
Write-Host "Setting Hugging Face environment variables..." -ForegroundColor Cyan
|
| 5 |
|
| 6 |
+
$env:HF_TOKEN = "hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
| 7 |
$env:HF_MODE = "public"
|
| 8 |
$env:PORT = "7860"
|
| 9 |
|
setup_cryptobert.sh
CHANGED
|
@@ -8,7 +8,7 @@ echo "========================================="
|
|
| 8 |
echo ""
|
| 9 |
|
| 10 |
# Default token (can be overridden)
|
| 11 |
-
DEFAULT_TOKEN="
|
| 12 |
|
| 13 |
# Check if HF_TOKEN is already set
|
| 14 |
if [ -n "$HF_TOKEN" ]; then
|
|
|
|
| 8 |
echo ""
|
| 9 |
|
| 10 |
# Default token (can be overridden)
|
| 11 |
+
DEFAULT_TOKEN="hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
| 12 |
|
| 13 |
# Check if HF_TOKEN is already set
|
| 14 |
if [ -n "$HF_TOKEN" ]; then
|
static/js/huggingface-integration.js
CHANGED
|
@@ -215,7 +215,7 @@ class HuggingFaceIntegration {
|
|
| 215 |
// Priority: window.HF_API_KEY > DASHBOARD_CONFIG.HF_TOKEN > default
|
| 216 |
return window.HF_API_KEY ||
|
| 217 |
(window.DASHBOARD_CONFIG && window.DASHBOARD_CONFIG.HF_TOKEN) ||
|
| 218 |
-
'
|
| 219 |
}
|
| 220 |
}
|
| 221 |
|
|
|
|
| 215 |
// Priority: window.HF_API_KEY > DASHBOARD_CONFIG.HF_TOKEN > default
|
| 216 |
return window.HF_API_KEY ||
|
| 217 |
(window.DASHBOARD_CONFIG && window.DASHBOARD_CONFIG.HF_TOKEN) ||
|
| 218 |
+
'hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
|
| 219 |
}
|
| 220 |
}
|
| 221 |
|
static/providers_config_ultimate.json
CHANGED
|
@@ -566,7 +566,7 @@
|
|
| 566 |
"endpoints": {},
|
| 567 |
"rate_limit": {},
|
| 568 |
"requires_auth": true,
|
| 569 |
-
"api_keys": ["
|
| 570 |
"auth_type": "header",
|
| 571 |
"auth_header": "Authorization",
|
| 572 |
"priority": 8,
|
|
|
|
| 566 |
"endpoints": {},
|
| 567 |
"rate_limit": {},
|
| 568 |
"requires_auth": true,
|
| 569 |
+
"api_keys": ["hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"],
|
| 570 |
"auth_type": "header",
|
| 571 |
"auth_header": "Authorization",
|
| 572 |
"priority": 8,
|
test_cryptobert.py
CHANGED
|
@@ -10,7 +10,7 @@ import json
|
|
| 10 |
from typing import Dict, Any
|
| 11 |
|
| 12 |
# Ensure the token is set
|
| 13 |
-
os.environ.setdefault("HF_TOKEN", "
|
| 14 |
|
| 15 |
# Import after setting environment variable
|
| 16 |
import config
|
|
|
|
| 10 |
from typing import Dict, Any
|
| 11 |
|
| 12 |
# Ensure the token is set
|
| 13 |
+
os.environ.setdefault("HF_TOKEN", "hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
|
| 14 |
|
| 15 |
# Import after setting environment variable
|
| 16 |
import config
|