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