From 23675b39b8055a8568cdcf71f66482b9d0cf90a9 Mon Sep 17 00:00:00 2001 From: Tyler Date: Sat, 28 Mar 2026 23:01:14 -0700 Subject: Initial commit — Prism financial analysis dashboard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Streamlit app with market bar, price chart, financial statements, DCF valuation engine, comparable companies, and news feed. Co-Authored-By: Claude Sonnet 4.6 --- app.py | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 app.py (limited to 'app.py') diff --git a/app.py b/app.py new file mode 100644 index 0000000..78b503f --- /dev/null +++ b/app.py @@ -0,0 +1,156 @@ +"""Prism — Financial Analysis Dashboard""" +import streamlit as st +from dotenv import load_dotenv + +load_dotenv() + +st.set_page_config( + page_title="Prism", + page_icon="🔷", + layout="wide", + initial_sidebar_state="expanded", +) + +# ── Global CSS ──────────────────────────────────────────────────────────────── +st.markdown(""" + +""", unsafe_allow_html=True) + +from components.market_bar import render_market_bar +from components.overview import render_overview +from components.financials import render_financials +from components.valuation import render_valuation +from components.news import render_news +from services.data_service import get_company_info, search_tickers + + +# ── Sidebar ────────────────────────────────────────────────────────────────── + +with st.sidebar: + st.markdown("### 🔷 Prism") + st.caption("Financial Analysis Dashboard") + st.divider() + + # Search input + query = st.text_input( + "Search company or ticker", + placeholder="e.g. Apple, AAPL, MSFT…", + key="search_query", + ).strip() + + # Autocomplete: show results if query looks like a search term (not a bare ticker) + selected_symbol = None + if query: + results = search_tickers(query) + if results: + options = {f"{r['symbol']} — {r['name']} ({r['exchange']})": r["symbol"] for r in results} + choice = st.selectbox( + "Select", + options=list(options.keys()), + label_visibility="collapsed", + ) + selected_symbol = options[choice] + else: + # Treat the raw input as a direct ticker + selected_symbol = query.upper() + + if st.button("Analyze", use_container_width=True, type="primary"): + if selected_symbol: + st.session_state["ticker"] = selected_symbol + + ticker = st.session_state.get("ticker", "AAPL") + + # Quick company info in sidebar + st.divider() + with st.spinner(""): + info = get_company_info(ticker) + if info: + st.caption(info.get("longName", ticker)) + st.caption(f"Exchange: {info.get('exchange', '—')}") + st.caption(f"Currency: {info.get('currency', 'USD')}") + st.caption(f"Sector: {info.get('sector', '—')}") + employees = info.get("fullTimeEmployees") + st.caption(f"Employees: {employees:,}" if isinstance(employees, int) else "Employees: —") + website = info.get("website") + if website: + st.markdown(f"[🌐 Website]({website})") + + +# ── Market Bar ──────────────────────────────────────────────────────────────── + +with st.container(): + render_market_bar() + +st.divider() + +# ── Main Content ────────────────────────────────────────────────────────────── + +tab_overview, tab_financials, tab_valuation, tab_news = st.tabs([ + "📈 Overview", + "📊 Financials", + "💰 Valuation", + "📰 News", +]) + +with tab_overview: + try: + render_overview(ticker) + except Exception as e: + st.error(f"Overview failed to load: {e}") + +with tab_financials: + try: + render_financials(ticker) + except Exception as e: + st.error(f"Financials failed to load: {e}") + +with tab_valuation: + try: + render_valuation(ticker) + except Exception as e: + st.error(f"Valuation failed to load: {e}") + +with tab_news: + try: + render_news(ticker) + except Exception as e: + st.error(f"News failed to load: {e}") -- cgit v1.3-2-g0d8e