mgbam commited on
Commit
7ab0ea7
·
verified ·
1 Parent(s): 76f2683

Update app/app.py

Browse files
Files changed (1) hide show
  1. app/app.py +16 -9
app/app.py CHANGED
@@ -12,17 +12,18 @@ import json
12
  import httpx
13
  from fastapi import FastAPI, Request
14
  from fastapi.responses import HTMLResponse, StreamingResponse
15
- from fastapi.templating import Jinja2Templates
16
 
 
17
  from .price_fetcher import PriceFetcher
18
  from .arbitrage_analyzer import ArbitrageAnalyzer
19
  from .broker import signal_broker
20
 
21
- OPPORTUNITY_THRESHOLD = 0.0015 # 0.15% price difference to trigger a signal
22
 
23
  @asynccontextmanager
24
  async def lifespan(app: FastAPI):
25
- # This setup remains the same, but the logic it runs is now multi-asset.
26
  async with httpx.AsyncClient() as client:
27
  app.state.price_fetcher = PriceFetcher(client)
28
  app.state.arbitrage_analyzer = ArbitrageAnalyzer(client)
@@ -35,6 +36,7 @@ async def lifespan(app: FastAPI):
35
  except asyncio.CancelledError: print("Engine shut down.")
36
 
37
  async def run_arbitrage_detector(app: FastAPI):
 
38
  while True:
39
  await app.state.price_fetcher.update_prices_async()
40
  all_prices = app.state.price_fetcher.get_all_prices()
@@ -59,10 +61,12 @@ async def run_arbitrage_detector(app: FastAPI):
59
 
60
  await asyncio.sleep(15)
61
 
 
62
  app = FastAPI(title="Sentinel Arbitrage Engine", lifespan=lifespan)
63
- templates = Jinja2Templates(directory="templates")
64
 
 
65
  def render_signal_card(payload: dict) -> str:
 
66
  s = payload
67
  time_str = datetime.fromisoformat(s['timestamp']).strftime('%H:%M:%S UTC')
68
  pyth_class = "buy" if s['pyth_price'] < s['chainlink_price'] else "sell"
@@ -81,16 +85,19 @@ def render_signal_card(payload: dict) -> str:
81
  <div id="last-update-time" hx-swap-oob="true">{time_str}</div>
82
  """
83
 
84
- @app.get("/", response_class=HTMLResponse)
85
- async def serve_dashboard(request: Request):
86
- return templates.TemplateResponse("index.html", {"request": request})
87
-
88
  @app.get("/api/signals/stream")
89
  async def signal_stream(request: Request):
 
90
  async def event_generator():
91
  while True:
92
  payload = await signal_broker.queue.get()
93
  html_card = render_signal_card(payload)
94
  data_payload = html_card.replace('\n', ' ').strip()
95
  yield f"event: message\ndata: {data_payload}\n\n"
96
- return StreamingResponse(event_generator(), media_type="text/event-stream")
 
 
 
 
 
 
12
  import httpx
13
  from fastapi import FastAPI, Request
14
  from fastapi.responses import HTMLResponse, StreamingResponse
15
+ from fastapi.staticfiles import StaticFiles # <-- We use this instead of Jinja2
16
 
17
+ # Relative imports for package structure
18
  from .price_fetcher import PriceFetcher
19
  from .arbitrage_analyzer import ArbitrageAnalyzer
20
  from .broker import signal_broker
21
 
22
+ OPPORTUNITY_THRESHOLD = 0.0015 # 0.15% price difference
23
 
24
  @asynccontextmanager
25
  async def lifespan(app: FastAPI):
26
+ """Manages application startup and shutdown events."""
27
  async with httpx.AsyncClient() as client:
28
  app.state.price_fetcher = PriceFetcher(client)
29
  app.state.arbitrage_analyzer = ArbitrageAnalyzer(client)
 
36
  except asyncio.CancelledError: print("Engine shut down.")
37
 
38
  async def run_arbitrage_detector(app: FastAPI):
39
+ """The core engine loop. Checks for opportunities and queues them."""
40
  while True:
41
  await app.state.price_fetcher.update_prices_async()
42
  all_prices = app.state.price_fetcher.get_all_prices()
 
61
 
62
  await asyncio.sleep(15)
63
 
64
+ # --- FastAPI App Initialization ---
65
  app = FastAPI(title="Sentinel Arbitrage Engine", lifespan=lifespan)
 
66
 
67
+ # --- HTML Rendering Helper ---
68
  def render_signal_card(payload: dict) -> str:
69
+ """Renders a dictionary of analysis into a styled HTML table row."""
70
  s = payload
71
  time_str = datetime.fromisoformat(s['timestamp']).strftime('%H:%M:%S UTC')
72
  pyth_class = "buy" if s['pyth_price'] < s['chainlink_price'] else "sell"
 
85
  <div id="last-update-time" hx-swap-oob="true">{time_str}</div>
86
  """
87
 
88
+ # --- API Endpoints ---
 
 
 
89
  @app.get("/api/signals/stream")
90
  async def signal_stream(request: Request):
91
+ """SSE stream for the automated Signal Stream."""
92
  async def event_generator():
93
  while True:
94
  payload = await signal_broker.queue.get()
95
  html_card = render_signal_card(payload)
96
  data_payload = html_card.replace('\n', ' ').strip()
97
  yield f"event: message\ndata: {data_payload}\n\n"
98
+ return StreamingResponse(event_generator(), media_type="text/event-stream")
99
+
100
+ # --- Static File Server ---
101
+ # This single mount point serves index.html for the root path "/"
102
+ # and any other files like CSS or JS from the "static" directory.
103
+ app.mount("/", StaticFiles(directory="static", html=True), name="static")