mgbam commited on
Commit
f611cc3
·
verified ·
1 Parent(s): 476cee0

Update app/sentiment.py

Browse files
Files changed (1) hide show
  1. app/sentiment.py +47 -67
app/sentiment.py CHANGED
@@ -1,70 +1,50 @@
1
  """
2
- Background price cache with multi-API fallback and rate-limit handling
3
  """
4
- import httpx
5
- import logging
6
-
7
- # Primary and secondary APIs for crypto prices
8
- COINGECKO_URL = (
9
- "https://api.coingecko.com/api/v3/simple/price"
10
- "?ids=bitcoin,ethereum,dogecoin&vs_currencies=usd"
11
- )
12
- COINCAP_URL = (
13
- "https://api.coincap.io/v2/assets?ids=bitcoin,ethereum,dogecoin"
14
- )
15
-
16
- # Shared price cache
17
- CURRENT_PRICES = {"bitcoin": "--", "ethereum": "--", "dogecoin": "--"}
18
-
19
- # How often to retry each API before falling back (seconds)
20
- RETRY_DELAY = 5
21
-
22
-
23
- def fetch_prices() -> None:
24
- """
25
- Try CoinGecko first; on 429 or error, fall back to CoinCap.
26
- Updates CURRENT_PRICES in-place.
27
- """
28
- global CURRENT_PRICES
29
- apis = [
30
- ("CoinGecko", COINGECKO_URL),
31
- ("CoinCap", COINCAP_URL)
32
- ]
33
 
34
- for name, url in apis:
35
- try:
36
- resp = httpx.get(url, timeout=10)
37
- # Handle CoinCap JSON structure separately
38
- if name == "CoinGecko":
39
- resp.raise_for_status()
40
- data = resp.json()
41
- prices = {
42
- "bitcoin": data["bitcoin"]["usd"],
43
- "ethereum": data["ethereum"]["usd"],
44
- "dogecoin": data["dogecoin"]["usd"]
45
- }
46
- else:
47
- resp.raise_for_status()
48
- data = resp.json().get("data", [])
49
- prices = {item["id"]: float(item["priceUsd"]) for item in data}
50
-
51
- CURRENT_PRICES.update(prices)
52
- logging.info("✅ [%s] prices updated: %s", name, prices)
53
- return
54
-
55
- except httpx.HTTPStatusError as e:
56
- status = e.response.status_code
57
- if status == 429:
58
- logging.warning("⚠️ [%s] rate limit (429). Retrying fallback.", name)
59
- else:
60
- logging.warning("⚠️ [%s] HTTP error %s: %s", name, status, e)
61
- except Exception as e:
62
- logging.warning("⚠️ [%s] fetch error: %s", name, e)
63
-
64
- # If we reach here, wait a bit before trying next API
65
- try:
66
- import time; time.sleep(RETRY_DELAY)
67
- except Exception:
68
- pass
69
-
70
- logging.error("❌ All price APIs failed. Keeping previous prices: %s", CURRENT_PRICES)
 
 
 
 
 
 
 
 
 
 
1
  """
2
+ Safe lazy-loading sentiment pipeline that works in Hugging Face Spaces (no /.cache error).
3
  """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
 
5
+ import os
6
+ import hashlib
7
+ import logging
8
+ from functools import lru_cache
9
+
10
+ # Redirect the HF model cache to a writable directory
11
+ os.environ["TRANSFORMERS_CACHE"] = "/tmp/huggingface"
12
+ os.makedirs("/tmp/huggingface", exist_ok=True)
13
+
14
+ from transformers import pipeline
15
+
16
+ class SentimentCache:
17
+ latest_id: int = 0
18
+ latest_result: dict = {}
19
+ _pipeline = None # Lazy init
20
+
21
+ @classmethod
22
+ def _get_pipeline(cls):
23
+ if cls._pipeline is None:
24
+ logging.info("🔄 Loading sentiment model…")
25
+ cls._pipeline = pipeline(
26
+ "sentiment-analysis",
27
+ model="distilbert-base-uncased-finetuned-sst-2-english"
28
+ )
29
+ return cls._pipeline
30
+
31
+ @classmethod
32
+ def _hash(cls, text: str) -> str:
33
+ return hashlib.sha256(text.encode()).hexdigest()
34
+
35
+ @classmethod
36
+ @lru_cache(maxsize=128)
37
+ def _analyze(cls, text: str):
38
+ pipe = cls._get_pipeline()
39
+ return pipe(text)[0]
40
+
41
+ @classmethod
42
+ def compute(cls, text: str):
43
+ res = cls._analyze(text)
44
+ cls.latest_id += 1
45
+ cls.latest_result = {
46
+ "text": text,
47
+ "label": res["label"],
48
+ "score": round(res["score"], 4)
49
+ }
50
+ logging.info("✅ Sentiment computed: %s", cls.latest_result)