# 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")