mgbam commited on
Commit
cb01390
Β·
verified Β·
1 Parent(s): eaf2b94

Update app/main.py

Browse files
Files changed (1) hide show
  1. app/main.py +36 -35
app/main.py CHANGED
@@ -1,80 +1,81 @@
1
  """
2
- CryptoSentinel AI β€” FastAPI app entry point
3
  - Fetches live prices from CoinGecko
4
- - Provides real-time sentiment analysis using Hugging Face Transformers
5
- - Compatible with Hugging Face Spaces (safe caching)
6
  """
7
 
8
- import os
 
9
  from pathlib import Path
10
 
11
  from fastapi import FastAPI, Request, BackgroundTasks
12
  from fastapi.responses import HTMLResponse, JSONResponse, StreamingResponse
13
- from fastapi.staticfiles import StaticFiles
14
  from fastapi.templating import Jinja2Templates
15
  from apscheduler.schedulers.background import BackgroundScheduler
16
 
17
  from price_fetcher import fetch_prices, CURRENT_PRICES
18
  from sentiment import SentimentCache
19
- import json
20
- import asyncio
21
 
22
- # ──────────────────────────────────────────────────────────────────────────────
23
 
24
- # Define paths
25
  BASE_DIR = Path(__file__).parent
26
- TEMPLATES_DIR = BASE_DIR / "templates"
27
- STATIC_DIR = BASE_DIR / "static"
28
-
29
- # Create FastAPI app
30
- app = FastAPI(title="CryptoSentinel AI")
31
- templates = Jinja2Templates(directory=str(TEMPLATES_DIR))
32
- app.mount("/static", StaticFiles(directory=STATIC_DIR), name="static")
33
 
34
- # ──────────────────────────────────────────────────────────────────────────────
35
 
36
- # Start background job to update prices
37
  scheduler = BackgroundScheduler(daemon=True)
38
  scheduler.add_job(fetch_prices, trigger="interval", seconds=10)
39
  scheduler.start()
40
 
41
  @app.on_event("shutdown")
42
- def stop_scheduler():
43
  scheduler.shutdown(wait=False)
44
 
45
  @app.on_event("startup")
46
- def warm_up_model():
47
- # Pre-warm Hugging Face model on startup to avoid first-request latency
48
- SentimentCache.compute("The market is bullish today!")
49
 
50
- # ──────────────────────────────────────────────────────────────────────────────
51
- # ROUTES
52
 
53
  @app.get("/", response_class=HTMLResponse)
54
  async def index(request: Request):
 
 
 
 
55
  return templates.TemplateResponse("index.html", {"request": request})
56
 
57
  @app.get("/prices", response_class=JSONResponse)
58
- async def get_prices():
 
59
  return CURRENT_PRICES
60
 
61
  @app.post("/sentiment")
62
- async def analyze_sentiment(request: Request, background_tasks: BackgroundTasks):
 
 
 
 
63
  body = await request.json()
64
- text = body.get("text", "")
65
- background_tasks.add_task(SentimentCache.compute, text)
66
- return {"status": "processing"}
67
 
68
  @app.get("/sentiment/stream")
69
- async def stream_sentiment():
70
- """Server-Sent Events stream for pushing sentiment updates."""
71
- async def event_stream():
 
 
 
72
  last_id = 0
73
  while True:
74
  if SentimentCache.latest_id != last_id:
75
  last_id = SentimentCache.latest_id
76
- data = json.dumps(SentimentCache.latest_result)
77
- yield f"id:{last_id}\ndata:{data}\n\n"
78
  await asyncio.sleep(1)
79
 
80
- return StreamingResponse(event_stream(), media_type="text/event-stream")
 
1
  """
2
+ CryptoSentinel AI β€” FastAPI app entry point (no /static mount)
3
  - Fetches live prices from CoinGecko
4
+ - Provides real-time sentiment analysis via SSE
5
+ - Compatible with Hugging Face Spaces
6
  """
7
 
8
+ import json
9
+ import asyncio
10
  from pathlib import Path
11
 
12
  from fastapi import FastAPI, Request, BackgroundTasks
13
  from fastapi.responses import HTMLResponse, JSONResponse, StreamingResponse
 
14
  from fastapi.templating import Jinja2Templates
15
  from apscheduler.schedulers.background import BackgroundScheduler
16
 
17
  from price_fetcher import fetch_prices, CURRENT_PRICES
18
  from sentiment import SentimentCache
 
 
19
 
20
+ # ────── Setup ───────────────────────────────────────────────────────────────
21
 
 
22
  BASE_DIR = Path(__file__).parent
23
+ templates = Jinja2Templates(directory=str(BASE_DIR / "templates"))
 
 
 
 
 
 
24
 
25
+ app = FastAPI(title="CryptoSentinel AI (CDN-only static)")
26
 
27
+ # Start background job to refresh prices every 10s
28
  scheduler = BackgroundScheduler(daemon=True)
29
  scheduler.add_job(fetch_prices, trigger="interval", seconds=10)
30
  scheduler.start()
31
 
32
  @app.on_event("shutdown")
33
+ def shutdown():
34
  scheduler.shutdown(wait=False)
35
 
36
  @app.on_event("startup")
37
+ def warmup_model():
38
+ # Preload the sentiment model once on startup
39
+ SentimentCache.compute("The market is pumping πŸš€")
40
 
41
+ # ────── Routes ──────────────────────────────────────────────────────────────
 
42
 
43
  @app.get("/", response_class=HTMLResponse)
44
  async def index(request: Request):
45
+ """
46
+ Renders index.html which now should reference HTMX via CDN:
47
+ <script src="https://unpkg.com/[email protected]"></script>
48
+ """
49
  return templates.TemplateResponse("index.html", {"request": request})
50
 
51
  @app.get("/prices", response_class=JSONResponse)
52
+ async def prices():
53
+ """Return the latest cached crypto prices."""
54
  return CURRENT_PRICES
55
 
56
  @app.post("/sentiment")
57
+ async def sentiment(request: Request, background_tasks: BackgroundTasks):
58
+ """
59
+ Queue sentiment analysis for the given text.
60
+ Frontend will pick up results via SSE.
61
+ """
62
  body = await request.json()
63
+ background_tasks.add_task(SentimentCache.compute, body.get("text", ""))
64
+ return {"status": "queued"}
 
65
 
66
  @app.get("/sentiment/stream")
67
+ async def sentiment_stream():
68
+ """
69
+ Server-Sent Events endpoint that pushes new sentiment results
70
+ as they become available in SentimentCache.latest_result.
71
+ """
72
+ async def event_generator():
73
  last_id = 0
74
  while True:
75
  if SentimentCache.latest_id != last_id:
76
  last_id = SentimentCache.latest_id
77
+ payload = json.dumps(SentimentCache.latest_result)
78
+ yield f"id:{last_id}\ndata:{payload}\n\n"
79
  await asyncio.sleep(1)
80
 
81
+ return StreamingResponse(event_generator(), media_type="text/event-stream")