import os import sys import tempfile import time import itertools import streamlit as st import pandas as pd import requests import openai from threading import Thread # Add 'src' to Python path 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") # === Tabs Setup === tab_report, tab_articles, tab_insights = st.tabs(["📝 Report", "📋 Articles", "📊 Insights"]) 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: # Reset old results articles_df = pd.DataFrame() insights_df = pd.DataFrame() html_paths = [] 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 spinner_box = st.empty() log_box = st.empty() 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 AI analysis...", "📊 Evaluating sentiment...", "📝 Generating report...", "💹 Finalizing insights..." ]) 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 try: client = openai.OpenAI(api_key=openai_api_key) client.models.list() log("✅ OpenAI API key is valid.") except Exception as e: log(f"❌ OpenAI API Key Error: {e}") rotating = False rotator_thread.join() st.stop() try: response = requests.post( "https://api.tavily.com/search", headers={"Authorization": f"Bearer {tavily_api_key}"}, json={"query": "test", "days": 1, "max_results": 1} ) if response.status_code == 200: log("✅ Tavily API key is valid.") else: log(f"❌ Tavily Key Error: {response.status_code} {response.text}") rotating = False rotator_thread.join() st.stop() except Exception as e: log(f"❌ Tavily API Key Error: {e}") rotating = False rotator_thread.join() st.stop() with st.spinner("⏳ Running analysis..."): html_paths, articles_df, insights_df = run_pipeline(csv_path, tavily_api_key, progress_callback=log) rotating = False rotator_thread.join() spinner_box.success("✅ Analysis complete!") # === Report Tab === with tab_report: st.subheader("📝 Latest Report") if html_paths: latest_report = html_paths[-1] with open(latest_report, 'r', encoding='utf-8') as f: html_content = f.read() # Download button for HTML report st.download_button( label="⬇️ Download Report (HTML)", data=html_content, file_name=os.path.basename(latest_report), mime="text/html" ) st.components.v1.html(html_content, height=600, scrolling=True) else: st.error("❌ No reports were generated.") # === Articles Tab === with tab_articles: st.subheader("📋 Articles Table") if not articles_df.empty: st.dataframe( articles_df[["Title", "URL", "Priority", "Sentiment", "Confidence", "Signal", "Date"]], use_container_width=True ) st.download_button( label="⬇️ Download Articles CSV", data=articles_df.to_csv(index=False).encode("utf-8"), file_name="articles.csv", mime="text/csv" ) else: st.info("No articles available.") # === Insights Tab === with tab_insights: st.subheader("📊 Investment Insights") if not insights_df.empty: st.dataframe(insights_df, use_container_width=True) st.download_button( label="⬇️ Download Insights CSV", data=insights_df.to_csv(index=False).encode("utf-8"), file_name="insights.csv", mime="text/csv" ) else: st.info("No insights available.") 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 streamlit as st # import pandas as pd # import requests # import openai # 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") # # === Tabs Setup === # tab_report, tab_articles, tab_insights, tab_debug = st.tabs(["📝 Report", "📋 Articles", "📊 Insights", "🛠 Debug"]) # 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: # articles_df = pd.DataFrame() # insights_df = pd.DataFrame() # html_paths = [] # 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 # spinner_box = st.empty() # log_box = st.empty() # logs = [] # def log(msg): # logs.append(msg) # log_box.code("\n".join(logs)) # try: # spinner_box.markdown("⏳ Checking API keys...") # # === Check OpenAI Key === # try: # client = openai.OpenAI(api_key=openai_api_key) # client.models.list() # log("✅ OpenAI API key is valid.") # except Exception as e: # log(f"❌ OpenAI API Key Error: {e}") # st.stop() # # === Check Tavily Key === # try: # response = requests.post( # "https://api.tavily.com/search", # headers={"Authorization": f"Bearer {tavily_api_key}"}, # json={"query": "test", "days": 1, "max_results": 1} # ) # if response.status_code == 200: # log("✅ Tavily API key is valid.") # else: # log(f"❌ Tavily Key Error: {response.status_code} {response.text}") # st.stop() # except Exception as e: # log(f"❌ Tavily API Key Error: {e}") # st.stop() # spinner_box.markdown("⏳ Running analysis pipeline...") # html_paths, articles_df, insights_df = run_pipeline(csv_path, tavily_api_key, progress_callback=log) # spinner_box.success("✅ Analysis complete!") # # === Report Tab === # with tab_report: # if html_paths: # for path in html_paths: # with open(path, 'r', encoding='utf-8') as f: # html_content = f.read() # st.components.v1.html(html_content, height=600, scrolling=True) # else: # st.error("❌ No reports were generated.") # # === Articles Tab === # with tab_articles: # st.subheader("📋 Articles Table") # if not articles_df.empty: # st.dataframe(articles_df[["Title", "URL", "Summary", "Priority", "Sentiment", "Confidence", "Signal", "Date"]], # use_container_width=True) # st.download_button( # label="⬇️ Download Articles CSV", # data=articles_df.to_csv(index=False).encode("utf-8"), # file_name="articles.csv", # mime="text/csv" # ) # else: # st.info("No articles available.") # # === Insights Tab === # with tab_insights: # st.subheader("📊 Top Investment Insights") # if not insights_df.empty: # st.dataframe(insights_df, use_container_width=True) # st.download_button( # label="⬇️ Download Insights CSV", # data=insights_df.to_csv(index=False).encode("utf-8"), # file_name="insights.csv", # mime="text/csv" # ) # else: # st.info("No insights available.") # # === Debug Tab === # with tab_debug: # st.subheader("🛠 Debug Log") # st.code("\n".join(logs) if logs else "No logs yet.") # except Exception as e: # spinner_box.error("❌ Failed.") # log_box.error(f"❌ Error: {e}")