# app_command_center.py import streamlit as st import sys import os import httpx import time import json from datetime import datetime # --- Path Setup --- sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '.'))) from agents.orchestrator_v3 import SentinelOrchestratorV3 # --- Configuration --- WATCHLIST_FILE = "watchlist.json" ALERTS_FILE = "alerts.json" # --- Page Configuration --- st.set_page_config( page_title="Aegis Digital Briefing", page_icon="🛡️", layout="wide" ) # --- Custom CSS for the Briefing Room Theme --- st.markdown(""" """, unsafe_allow_html=True) # --- Helper Functions & State --- @st.cache_data(ttl=60) def check_server_status(): urls = {"Gateway": "http://127.0.0.1:8000/", "Tavily": "http://127.0.0.1:8001/", "Alpha Vantage": "http://127.0.0.1:8002/", "Private DB": "http://127.0.0.1:8003/"} statuses = {} with httpx.Client(timeout=2.0) as client: for name, url in urls.items(): try: response = client.get(url) statuses[name] = "✅ Online" if response.status_code == 200 else "⚠️ Error" except: statuses[name] = "❌ Offline" return statuses def load_watchlist(): if not os.path.exists(WATCHLIST_FILE): return [] try: with open(WATCHLIST_FILE, 'r') as f: return json.load(f) except: return [] def save_watchlist(watchlist): with open(WATCHLIST_FILE, 'w') as f: json.dump(watchlist, f) def load_alerts(): if not os.path.exists(ALERTS_FILE): return [] try: with open(ALERTS_FILE, 'r') as f: return json.load(f) except: return [] if 'final_state' not in st.session_state: st.session_state.final_state = None # --- UI Rendering --- # Header st.markdown('
Automated Intelligence Reports for Modern Finance
', unsafe_allow_html=True) # --- SIDEBAR: Watchlist & Notes --- sidebar = st.sidebar sidebar.title("🛡️ Command Center") # 1. Watchlist Manager sidebar.subheader("Active Watchlist") watchlist = load_watchlist() new_symbol = sidebar.text_input("Add Symbol:", placeholder="e.g. MSFT").upper() if sidebar.button("Add to Watchlist"): if new_symbol and new_symbol not in watchlist: watchlist.append(new_symbol) save_watchlist(watchlist) st.rerun() symbol_to_remove = sidebar.selectbox("Remove Symbol:", ["Select..."] + watchlist) if symbol_to_remove != "Select..." and sidebar.button("Remove"): watchlist.remove(symbol_to_remove) save_watchlist(watchlist) st.rerun() sidebar.markdown("---") # 2. Analyst Notes sidebar.title("👨💼 Analyst's Live Notes") notes_placeholder = sidebar.empty() notes_placeholder.info("Awaiting new directive...") # --- MAIN CONTENT --- main_col, alerts_col = st.columns([3, 1]) with main_col: # Main container for Research main_container = st.container(border=True) # Input Form with main_container: st.subheader("🚀 Launch On-Demand Analysis") with st.form("research_form"): task_input = st.text_input("", placeholder="Enter your directive, e.g., 'Analyze market reaction to the latest Apple ($AAPL) product launch'", label_visibility="collapsed") submitted = st.form_submit_button("Generate Briefing", use_container_width=True) # --- Main Logic --- if submitted and task_input: server_statuses = check_server_status() if not all(s == "✅ Online" for s in server_statuses.values()): main_container.error("Analysis cannot proceed. One or more backend services are offline. Please check the status.") else: # main_container.empty() # Don't clear, just show results below final_state_result = {} analyst_notes = [] try: with st.spinner("Your AI Analyst is compiling the briefing... This may take a moment."): for event in SentinelOrchestratorV3.stream({"task": task_input}): node_name = list(event.keys())[0] final_state_result.update(event[node_name]) # --- Generate and Display Live Analyst Notes --- note = "" if node_name == "extract_symbol": note = f"Identified target entity: **{event[node_name].get('symbol', 'N/A')}**" elif node_name == "web_researcher": note = "Sourced initial open-source intelligence from the web." elif node_name == "market_data_analyst": note = "Retrieved latest intraday market performance data." elif node_name == "data_analyzer": note = "Commenced deep-dive quantitative analysis of time-series data." elif node_name == "report_synthesizer": note = "Synthesizing all findings into the final executive briefing." if note: analyst_notes.append(f'No visualizations were generated for this briefing.