mgbam commited on
Commit
01e217d
Β·
verified Β·
1 Parent(s): 669ca48

Update app/app.py

Browse files
Files changed (1) hide show
  1. app/app.py +10 -15
app/app.py CHANGED
@@ -18,11 +18,14 @@ from fastapi import FastAPI, Request
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
 
28
  # --- Application Lifespan for Resource Management ---
@@ -39,17 +42,15 @@ async def lifespan(app: FastAPI):
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,17 +87,13 @@ async def run_periodic_news_analysis(app: FastAPI, interval_seconds: int):
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}")
@@ -106,6 +103,7 @@ async def run_periodic_news_analysis(app: FastAPI, interval_seconds: int):
106
  # --- FastAPI App Initialization ---
107
 
108
  app = FastAPI(title="Sentinel TradeFlow Protocol", lifespan=lifespan)
 
109
  templates = Jinja2Templates(directory="templates")
110
 
111
  # --- HTML Rendering Helper ---
@@ -144,11 +142,8 @@ async def serve_dashboard(request: Request):
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)
 
18
  from fastapi.responses import HTMLResponse, StreamingResponse
19
  from fastapi.templating import Jinja2Templates
20
 
21
+ # ====================================================================
22
+ # FIX APPLIED HERE
23
+ # ====================================================================
24
+ # Use relative imports because these modules are in the same 'app' package.
25
+ from .price_fetcher import PriceFetcher
26
+ from .gemini_analyzer import GeminiAnalyzer
27
  from newsapi import NewsApiClient
28
+ # ====================================================================
29
 
30
 
31
  # --- Application Lifespan for Resource Management ---
 
42
  app.state.gemini_analyzer = GeminiAnalyzer(client=client)
43
  app.state.news_api = NewsApiClient(api_key=os.getenv("NEWS_API_KEY"))
44
 
45
+ # Create a queue for the real-time signal feed
 
46
  app.state.signal_queue: asyncio.Queue = asyncio.Queue()
 
47
 
48
  # Create cancellable background tasks for periodic updates.
49
  price_task = asyncio.create_task(
50
  run_periodic_updates(app.state.price_fetcher, interval_seconds=60)
51
  )
52
  news_task = asyncio.create_task(
53
+ run_periodic_news_analysis(app, interval_seconds=900) # Run every 15 minutes
54
  )
55
 
56
  print("πŸš€ Sentinel TradeFlow Protocol started successfully.")
 
87
  title = article.get('title')
88
  if title and "[Removed]" not in title:
89
  analysis = await analyzer.analyze_text(title)
 
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
  await app.state.signal_queue.put(analysis)
96
  print(f"βœ… Signal generated and queued for: {title}")
 
97
 
98
  except Exception as e:
99
  print(f"❌ Error during news fetching or analysis: {e}")
 
103
  # --- FastAPI App Initialization ---
104
 
105
  app = FastAPI(title="Sentinel TradeFlow Protocol", lifespan=lifespan)
106
+ # This path is relative to the root where the uvicorn command is run
107
  templates = Jinja2Templates(directory="templates")
108
 
109
  # --- HTML Rendering Helper ---
 
142
  @app.get("/api/signals/stream")
143
  async def signal_stream(request: Request):
144
  """SSE stream for the automated Signal Stream."""
 
145
  queue: asyncio.Queue = request.app.state.signal_queue
146
  async def event_generator():
 
 
147
  while True:
148
  payload = await queue.get()
149
  html = render_signal_card(payload)