File size: 5,892 Bytes
c3dec5a 7f7b708 c3dec5a 7f7b708 c3dec5a 231a6dd c3dec5a 351a5f1 231a6dd c3dec5a 231a6dd c3dec5a 351a5f1 c3dec5a 351a5f1 5cdb4ed 7f7b708 aed3915 b5c0220 231a6dd e799cfb 351a5f1 c3dec5a 7f7b708 231a6dd 7f7b708 231a6dd 7f7b708 231a6dd 7f7b708 351a5f1 aed3915 7f7b708 231a6dd 7f7b708 351a5f1 231a6dd c3dec5a 7f7b708 c3dec5a 231a6dd 7f7b708 231a6dd c3dec5a 231a6dd c3dec5a 231a6dd c3dec5a aed3915 c3dec5a 231a6dd c3dec5a aed3915 231a6dd aed3915 c3dec5a 231a6dd c3dec5a 231a6dd 351a5f1 231a6dd 351a5f1 231a6dd aed3915 231a6dd | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | import os
import sqlite3
import smtplib
import streamlit as st
from typing import List, TypedDict
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
# LangChain & Graph Imports
from langchain_openai import ChatOpenAI
from langchain_community.tools.tavily_search import TavilySearchResults
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.sqlite import SqliteSaver
# --- 1. PAGE SETUP ---
st.set_page_config(page_title="Strategic Intel-Agent", layout="wide", page_icon="π‘οΈ")
st.markdown("""
<style>
.main { background-color: #f8f9fa; }
.stButton>button { width: 100%; border-radius: 8px; height: 3em; font-weight: bold; transition: 0.3s; }
.report-container { background-color: white; padding: 25px; border-radius: 12px; border: 1px solid #dee2e6; }
</style>
""", unsafe_allow_html=True)
# --- 2. SIDEBAR ---
with st.sidebar:
st.image("https://cdn-icons-png.flaticon.com/512/2103/2103633.png", width=80)
st.title("Settings & Tools")
with st.expander("π API Credentials", expanded=True):
openai_key = os.getenv("OPENAI_API_KEY")
tavily_key = os.getenv("TAVILY_API_KEY")
with st.expander("π§ Email Settings (SMTP)", expanded=True):
sender_email = st.text_input("Your Gmail Address", value="")
app_password = st.text_input("App Password", type="password")
thread_id = st.text_input("Session ID", value="global_user_1")
os.environ["OPENAI_API_KEY"] = openai_key
os.environ["TAVILY_API_KEY"] = tavily_key
# --- 3. EMAIL TOOL ---
def send_email_smtp(content, recipient, sender, password):
if not all([content, recipient, sender, password]): return False
msg = MIMEMultipart()
msg['From'], msg['To'], msg['Subject'] = sender, recipient, "Market Intelligence Report"
msg.attach(MIMEText(content, 'plain'))
try:
server = smtplib.SMTP('smtp.gmail.com', 587, timeout=10)
server.starttls()
server.login(sender, password)
server.sendmail(sender, recipient, msg.as_string())
server.quit()
return True
except Exception: return False
# --- 4. AGENT LOGIC ---
DB_PATH = "agent_memory.db"
class AgentState(TypedDict):
company_name: str
research_data: List[dict]
iteration: int
report: str
@st.cache_resource
def initialize_agent():
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
def researcher(state: AgentState):
# Initializing inside node to prevent the Tavily crash you saw earlier
search_tool = TavilySearchResults(max_results=3)
iter_count = state.get("iteration", 0)
query = f"Financial SWOT and strategy for {state['company_name']} 2025"
if iter_count > 0:
query = f"Deep-dive business analysis for {state['company_name']} 2025"
results = search_tool.invoke({"query": query})
return {"research_data": results, "iteration": iter_count + 1}
def writer(state: AgentState):
context = "\n".join([f"Source: {r['url']}\nContent: {r['content']}" for r in state['research_data']])
prompt = f"Write a professional SWOT for {state['company_name']}.\n\nDATA:\n{context}"
response = llm.invoke(prompt)
return {"report": response.content}
builder = StateGraph(AgentState)
builder.add_node("researcher", researcher)
builder.add_node("writer", writer)
builder.add_edge(START, "researcher")
builder.add_edge("researcher", "writer")
builder.add_edge("writer", END)
conn = sqlite3.connect(DB_PATH, check_same_thread=False)
return builder.compile(checkpointer=SqliteSaver(conn), interrupt_before=["writer"])
agent_app = initialize_agent()
config = {"configurable": {"thread_id": thread_id}}
# --- 5. MAIN GUI ---
st.title("π‘οΈ Strategic Intel-Agent")
if "report_output" not in st.session_state:
st.session_state.report_output = None
# Input Section
company = st.text_input("Target Company Name", placeholder="e.g. NVIDIA")
if st.button("π Start Research"):
st.session_state.report_output = None
agent_app.invoke({"company_name": company, "iteration": 0}, config)
st.rerun()
current_state = agent_app.get_state(config)
# --- SHOW RESEARCH AND THE TWO BUTTONS ---
if current_state.values.get("research_data"):
st.divider()
st.subheader("π Intelligence Briefing")
with st.expander("π View Raw Research Data", expanded=True):
for item in current_state.values["research_data"]:
st.markdown(f"**Source:** {item['url']}")
st.caption(item['content'])
st.divider()
# THE TWO OPTIONS YOU REQUESTED
c1, c2 = st.columns(2)
with c1:
if st.button("β
Approve & Generate SWOT", type="primary"):
final_res = agent_app.invoke(None, config)
st.session_state.report_output = final_res.get("report")
st.rerun()
with c2:
if st.button("π Data Insufficient: Search Again"):
agent_app.update_state(config, {"research_data": []}, as_node="researcher")
agent_app.invoke(None, config)
st.rerun()
# --- 6. REPORT & EMAIL CENTER ---
if st.session_state.report_output:
st.markdown("---")
res_col, tool_col = st.columns([2, 1])
with res_col:
st.markdown("### π Final SWOT Report")
st.markdown(f'<div class="report-container">{st.session_state.report_output}</div>', unsafe_allow_html=True)
with tool_col:
st.markdown("### π Email Delivery")
email_target = st.text_input("Recipient Email")
if st.button("π§ Send via Email"):
if send_email_smtp(st.session_state.report_output, email_target, sender_email, app_password):
st.success("Sent Successfully!")
else:
st.error("Check SMTP settings & App Password.") |