| """FinChat - Streamlit chat UI. |
| |
| Run from the project root: |
| streamlit run app.py |
| """ |
| import streamlit as st |
|
|
| from src.rag import answer, available_companies, ensure_index |
|
|
| st.set_page_config( |
| page_title="FinChat", |
| page_icon="π¬", |
| layout="centered", |
| initial_sidebar_state="expanded", |
| ) |
|
|
| st.title("π¬ FinChat") |
| st.caption( |
| "Ask questions about companies' SEC 10-K filings. " |
| "Every answer is grounded in the filings, with sources you can inspect." |
| ) |
|
|
| |
| |
| with st.spinner("Preparing the knowledge base (first run only, please wait)β¦"): |
| ensure_index() |
|
|
| |
| with st.sidebar: |
| st.header("π Companies loaded") |
| for ticker, name in available_companies(): |
| st.markdown(f"- **{ticker}** β {name}") |
| st.caption("Source: recent SEC 10-K filings (FY2021β2023).") |
|
|
| |
| STARTER_QUESTIONS = [ |
| "What products does Apple sell?", |
| "What does NVIDIA design and sell?", |
| "What are Boeing's business segments?", |
| "What are the main risks AMD identifies?", |
| ] |
|
|
| |
| if "messages" not in st.session_state: |
| st.session_state.messages = [] |
|
|
| for msg in st.session_state.messages: |
| with st.chat_message(msg["role"]): |
| st.markdown(msg["content"]) |
|
|
| |
| if not st.session_state.messages and "pending" not in st.session_state: |
| st.markdown("**Try one of these to get started:**") |
| cols = st.columns(2) |
| for i, example in enumerate(STARTER_QUESTIONS): |
| if cols[i % 2].button(example, use_container_width=True): |
| st.session_state.pending = example |
| st.rerun() |
|
|
| |
| |
| prompt = st.chat_input("e.g. What were AMD's main risk factors?") or st.session_state.pop("pending", None) |
| if prompt: |
| st.session_state.messages.append({"role": "user", "content": prompt}) |
| with st.chat_message("user"): |
| st.markdown(prompt) |
|
|
| with st.chat_message("assistant"): |
| with st.spinner("Searching the filings..."): |
| result = answer(prompt) |
|
|
| st.markdown(result["answer"]) |
|
|
| if result["routed_to"]: |
| st.caption(f"π Routed retrieval to: **{result['routed_to']}**") |
|
|
| with st.expander(f"π Sources ({len(result['sources'])})"): |
| for i, doc in enumerate(result["sources"], 1): |
| st.markdown(f"**[{i}] {doc.metadata.get('source', '')}**") |
| st.write(doc.page_content[:500] + "β¦") |
|
|
| st.session_state.messages.append( |
| {"role": "assistant", "content": result["answer"]} |
| ) |
|
|