# import os
# import sys
# import tempfile
# import time
# import itertools
# import streamlit as st
# import pandas as pd
# from threading import Thread
# from io import StringIO
# # Add 'src' to Python path so we can import main.py
# sys.path.append(os.path.join(os.path.dirname(__file__), 'src'))
# from main import run_pipeline
# st.set_page_config(page_title="đ° AI News Analyzer", layout="wide")
# st.title("đ§ AI-Powered Investing News Analyzer")
# # === API Key Input ===
# st.subheader("đ API Keys")
# openai_api_key = st.text_input("OpenAI API Key", type="password").strip()
# tavily_api_key = st.text_input("Tavily API Key", type="password").strip()
# # === Topic Input ===
# st.subheader("đ Topics of Interest")
# topics_data = []
# with st.form("topics_form"):
# topic_count = st.number_input("How many topics?", min_value=1, max_value=10, value=1, step=1)
# for i in range(topic_count):
# col1, col2 = st.columns(2)
# with col1:
# topic = st.text_input(f"Topic {i+1}", key=f"topic_{i}")
# with col2:
# days = st.number_input(f"Timespan (days)", min_value=1, max_value=30, value=7, key=f"days_{i}")
# topics_data.append({"topic": topic, "timespan_days": days})
# submitted = st.form_submit_button("Run Analysis")
# # === Submission logic ===
# if submitted:
# if not openai_api_key or not tavily_api_key or not all([td['topic'] for td in topics_data]):
# st.warning("Please fill in all fields.")
# else:
# os.environ["OPENAI_API_KEY"] = openai_api_key
# os.environ["TAVILY_API_KEY"] = tavily_api_key
# df = pd.DataFrame(topics_data)
# with tempfile.NamedTemporaryFile(delete=False, suffix=".csv") as tmp_csv:
# df.to_csv(tmp_csv.name, index=False)
# csv_path = tmp_csv.name
# # === UI Elements ===
# spinner_box = st.empty() # For rotating messages
# log_box = st.empty() # For logs
# logs = []
# rotating = True
# def log(msg):
# logs.append(msg)
# log_box.code("\n".join(logs))
# # === Rotating UI Messages ===
# def rotating_messages():
# messages = itertools.cycle([
# "đ Searching financial news...",
# "đ§ Running language models...",
# "đ Analyzing investor sentiment...",
# "đ Summarizing key takeaways...",
# "đš Building markdown reports..."
# ])
# while rotating:
# spinner_box.markdown(f"âŗ {next(messages)}")
# time.sleep(1.5)
# rotator_thread = Thread(target=rotating_messages)
# rotator_thread.start()
# try:
# # Check API Keys
# import openai
# openai.OpenAI(api_key=openai_api_key).models.list()
# log("â
OpenAI API key is valid.")
# import requests
# tavily_test = requests.post(
# "https://api.tavily.com/search",
# headers={"Authorization": f"Bearer {tavily_api_key}"},
# json={"query": "test", "days": 1, "max_results": 1}
# )
# if tavily_test.status_code == 200:
# log("â
Tavily API key is valid.")
# else:
# raise ValueError(f"Tavily error: {tavily_test.status_code} - {tavily_test.text}")
# # Run the full pipeline
# log("đ Running analysis pipeline...")
# output_path = run_pipeline(csv_path, tavily_api_key, progress_callback=log)
# rotating = False
# rotator_thread.join()
# spinner_box.success("â
Analysis complete!")
# if output_path and isinstance(output_path, list):
# for path in output_path:
# if os.path.exists(path):
# with open(path, 'r', encoding='utf-8') as file:
# html_content = file.read()
# filename = os.path.basename(path)
# st.download_button(
# label=f"đĨ Download {filename}",
# data=html_content,
# file_name=filename,
# mime="text/html"
# )
# st.components.v1.html(html_content, height=600, scrolling=True)
# else:
# st.error("â No reports were generated.")
# except Exception as e:
# rotating = False
# rotator_thread.join()
# spinner_box.error("â Failed.")
# log_box.error(f"â Error: {e}")
##################################################################################################
##################################################################################################
import os
import sys
import tempfile
import time
import itertools
import streamlit as st
import pandas as pd
from threading import Thread
from io import StringIO
# Add 'src' to Python path so we can import main.py
sys.path.append(os.path.join(os.path.dirname(__file__), 'src'))
from main import run_pipeline
st.set_page_config(page_title="đ° AI News Analyzer", layout="wide")
st.title("đ§ AI-Powered Investing News Analyzer")
# === State control ===
if "running" not in st.session_state:
st.session_state.running = False
if "stop_requested" not in st.session_state:
st.session_state.stop_requested = False
# === Tabs ===
tabs = st.tabs(["đĨ Input", "đ¤ Results", "đĒĩ Logs"])
input_tab, result_tab, log_tab = tabs
# === Input Tab ===
with input_tab:
st.subheader("đ API Keys")
openai_api_key = st.text_input("OpenAI API Key", type="password").strip()
tavily_api_key = st.text_input("Tavily API Key", type="password").strip()
st.subheader("đ Topics of Interest")
topics_data = []
with st.form("topics_form"):
topic_count = st.number_input("How many topics?", min_value=1, max_value=10, value=1, step=1)
for i in range(topic_count):
col1, col2 = st.columns(2)
with col1:
topic = st.text_input(f"Topic {i+1}", key=f"topic_{i}")
with col2:
days = st.number_input(f"Timespan (days)", min_value=1, max_value=30, value=7, key=f"days_{i}")
topics_data.append({"topic": topic, "timespan_days": days})
run_btn = st.form_submit_button(
"Run Analysis" if not st.session_state.running else "Running...", disabled=st.session_state.running
)
# === Output placeholders ===
with result_tab:
spinner_box = st.empty()
download_box = st.empty()
with log_tab:
log_box = st.empty()
stop_btn = st.button("đ Stop Analysis", disabled=not st.session_state.running)
# === Run if submitted ===
if run_btn and not st.session_state.running:
if not openai_api_key or not tavily_api_key or not all([td['topic'] for td in topics_data]):
st.warning("Please fill in all fields.")
else:
os.environ["OPENAI_API_KEY"] = openai_api_key
os.environ["TAVILY_API_KEY"] = tavily_api_key
st.session_state.running = True
st.session_state.stop_requested = False
logs = []
df = pd.DataFrame(topics_data)
with tempfile.NamedTemporaryFile(delete=False, suffix=".csv") as tmp_csv:
df.to_csv(tmp_csv.name, index=False)
csv_path = tmp_csv.name
def log(msg, level="info"):
emoji = {"info": "âšī¸", "warning": "â ī¸", "error": "â"}.get(level, "")
logs.append(f"{emoji} {msg}")
colors = {"info": "blue", "warning": "orange", "error": "red"}
styled = [f'{emoji} {msg}' for msg in logs]
log_box.markdown("
".join(styled), unsafe_allow_html=True)
# Rotating status messages
def rotating_messages():
phrases = itertools.cycle([
"đ Searching financial news...",
"đ§ Running language models...",
"đ Analyzing investor sentiment...",
"đ Summarizing insights...",
"đĄ Generating markdown reports..."
])
while st.session_state.running and not st.session_state.stop_requested:
spinner_box.markdown(f"âŗ {next(phrases)}")
time.sleep(1.5)
rotator = Thread(target=rotating_messages)
rotator.start()
try:
import openai
openai.OpenAI(api_key=openai_api_key).models.list()
log("OpenAI API key validated.", "info")
import requests
test = requests.post(
"https://api.tavily.com/search",
headers={"Authorization": f"Bearer {tavily_api_key}"},
json={"query": "test", "days": 1, "max_results": 1}
)
if test.status_code == 200:
log("Tavily API key validated.", "info")
else:
raise ValueError(f"Tavily key rejected: {test.status_code} {test.text}")
# Run the pipeline
def progress_callback(msg):
if st.session_state.stop_requested:
raise Exception("â Analysis stopped by user.")
log(msg, "info")
log("Starting pipeline...", "info")
output_path = run_pipeline(csv_path, tavily_api_key, progress_callback=progress_callback)
st.session_state.running = False
rotator.join()
spinner_box.success("â
Analysis complete!")
if output_path:
for path in output_path:
if os.path.exists(path):
with open(path, "r", encoding="utf-8") as file:
html_content = file.read()
filename = os.path.basename(path)
download_box.download_button(
f"đĨ Download {filename}", html_content, filename=filename, mime="text/html"
)
download_box.components.v1.html(html_content, height=600, scrolling=True)
else:
log("No reports were generated.", "warning")
spinner_box.error("â No reports were generated.")
except Exception as e:
st.session_state.running = False
rotator.join()
spinner_box.error(f"â Error: {e}")
log(str(e), "error")
# === Handle manual stop ===
if stop_btn and st.session_state.running:
st.session_state.stop_requested = True
log("đ Stop requested by user...", "warning")