mgbam commited on
Commit
669ca48
Β·
verified Β·
1 Parent(s): 24a8706

Update app/app.py

Browse files
Files changed (1) hide show
  1. app/app.py +22 -12
app/app.py CHANGED
@@ -18,9 +18,10 @@ from fastapi import FastAPI, Request
18
  from fastapi.responses import HTMLResponse, StreamingResponse
19
  from fastapi.templating import Jinja2Templates
20
 
21
- # Use relative imports because these modules are in the same 'app' package.
22
- from .price_fetcher import PriceFetcher
23
- from .gemini_analyzer import GeminiAnalyzer
 
24
  from newsapi import NewsApiClient
25
 
26
 
@@ -38,15 +39,17 @@ async def lifespan(app: FastAPI):
38
  app.state.gemini_analyzer = GeminiAnalyzer(client=client)
39
  app.state.news_api = NewsApiClient(api_key=os.getenv("NEWS_API_KEY"))
40
 
41
- # Create a queue for the real-time signal feed, attached to the app's state.
 
42
  app.state.signal_queue: asyncio.Queue = asyncio.Queue()
 
43
 
44
  # Create cancellable background tasks for periodic updates.
45
  price_task = asyncio.create_task(
46
  run_periodic_updates(app.state.price_fetcher, interval_seconds=60)
47
  )
48
  news_task = asyncio.create_task(
49
- run_periodic_news_analysis(app, interval_seconds=900) # Run every 15 minutes
50
  )
51
 
52
  print("πŸš€ Sentinel TradeFlow Protocol started successfully.")
@@ -83,8 +86,18 @@ async def run_periodic_news_analysis(app: FastAPI, interval_seconds: int):
83
  title = article.get('title')
84
  if title and "[Removed]" not in title:
85
  analysis = await analyzer.analyze_text(title)
 
 
 
 
 
86
  analysis['url'] = article.get('url')
 
 
87
  await app.state.signal_queue.put(analysis)
 
 
 
88
  except Exception as e:
89
  print(f"❌ Error during news fetching or analysis: {e}")
90
 
@@ -131,19 +144,16 @@ async def serve_dashboard(request: Request):
131
  @app.get("/api/signals/stream")
132
  async def signal_stream(request: Request):
133
  """SSE stream for the automated Signal Stream."""
134
- # ====================================================================
135
- # FIX APPLIED HERE
136
- # ====================================================================
137
- # Access the shared application state via `request.app.state`, not `request.state`.
138
  queue: asyncio.Queue = request.app.state.signal_queue
139
- # ====================================================================
140
-
141
  async def event_generator():
 
 
142
  while True:
143
  payload = await queue.get()
144
  html = render_signal_card(payload)
145
  data_payload = html.replace('\n', '')
146
- # Use a generic 'message' event, which HTMX listens to by default
147
  sse_message = f"event: message\ndata: {data_payload}\n\n"
148
  yield sse_message
 
149
  return StreamingResponse(event_generator(), media_type="text/event-stream")
 
18
  from fastapi.responses import HTMLResponse, StreamingResponse
19
  from fastapi.templating import Jinja2Templates
20
 
21
+ # Use relative imports if your files are in an 'app' package,
22
+ # or direct imports if they are at the root. Assuming root for simplicity now.
23
+ from price_fetcher import PriceFetcher
24
+ from gemini_analyzer import GeminiAnalyzer
25
  from newsapi import NewsApiClient
26
 
27
 
 
39
  app.state.gemini_analyzer = GeminiAnalyzer(client=client)
40
  app.state.news_api = NewsApiClient(api_key=os.getenv("NEWS_API_KEY"))
41
 
42
+ # =================== FIX APPLIED HERE (1/2) ===================
43
+ # We only need ONE queue for the autonomous signal stream.
44
  app.state.signal_queue: asyncio.Queue = asyncio.Queue()
45
+ # =============================================================
46
 
47
  # Create cancellable background tasks for periodic updates.
48
  price_task = asyncio.create_task(
49
  run_periodic_updates(app.state.price_fetcher, interval_seconds=60)
50
  )
51
  news_task = asyncio.create_task(
52
+ run_periodic_news_analysis(app, interval_seconds=900) # Check news every 15 minutes
53
  )
54
 
55
  print("πŸš€ Sentinel TradeFlow Protocol started successfully.")
 
86
  title = article.get('title')
87
  if title and "[Removed]" not in title:
88
  analysis = await analyzer.analyze_text(title)
89
+ # Don't proceed if Gemini returned an error
90
+ if analysis.get("error"):
91
+ print(f"Skipping article due to Gemini error: {analysis['reason']}")
92
+ continue
93
+
94
  analysis['url'] = article.get('url')
95
+ # =================== FIX APPLIED HERE (2/2) ===================
96
+ # Ensure the result is put into the one and only signal_queue.
97
  await app.state.signal_queue.put(analysis)
98
+ print(f"βœ… Signal generated and queued for: {title}")
99
+ # =============================================================
100
+
101
  except Exception as e:
102
  print(f"❌ Error during news fetching or analysis: {e}")
103
 
 
144
  @app.get("/api/signals/stream")
145
  async def signal_stream(request: Request):
146
  """SSE stream for the automated Signal Stream."""
147
+ # This was already correct from the last fix, but we confirm it points to signal_queue.
 
 
 
148
  queue: asyncio.Queue = request.app.state.signal_queue
 
 
149
  async def event_generator():
150
+ # Let's send a confirmation that the stream is connected and ready
151
+ yield f"event: message\ndata: <div hx-swap-oob='innerHTML' id='signal-stream-container'><p>Status: ONLINE - Listening for new market signals...</p></div>\n\n"
152
  while True:
153
  payload = await queue.get()
154
  html = render_signal_card(payload)
155
  data_payload = html.replace('\n', '')
 
156
  sse_message = f"event: message\ndata: {data_payload}\n\n"
157
  yield sse_message
158
+
159
  return StreamingResponse(event_generator(), media_type="text/event-stream")