ahmadsanafarooq commited on
Commit
c3dec5a
Β·
verified Β·
1 Parent(s): 3df036f

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +145 -0
app.py ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import sqlite3
3
+ import streamlit as st
4
+ from typing import List, TypedDict
5
+ from langchain_openai import ChatOpenAI
6
+ from langchain_community.tools.tavily_search import TavilySearchResults
7
+ from langgraph.graph import StateGraph, START, END
8
+ from langgraph.checkpoint.sqlite import SqliteSaver
9
+
10
+ # --- 1. PAGE SETUP & CUSTOM CSS ---
11
+ st.set_page_config(page_title="Strategic Intel-Agent", layout="wide", page_icon="πŸ›‘οΈ")
12
+
13
+ st.markdown("""
14
+ <style>
15
+ .main { background-color: #f8f9fa; }
16
+ .stButton>button { width: 100%; border-radius: 8px; height: 3em; font-weight: bold; transition: 0.3s; }
17
+ .stDownloadButton>button { background-color: #007bff; color: white; border-radius: 8px; }
18
+ .report-container { background-color: white; padding: 25px; border-radius: 12px; border: 1px solid #dee2e6; box-shadow: 0 4px 6px rgba(0,0,0,0.05); }
19
+ .tool-card { padding: 15px; border-radius: 10px; border-left: 5px solid #007bff; background: #ffffff; margin-bottom: 10px; }
20
+ </style>
21
+ """, unsafe_allow_html=True)
22
+
23
+ # --- 2. SIDEBAR (CONFIG) ---
24
+ with st.sidebar:
25
+ st.image("https://cdn-icons-png.flaticon.com/512/2103/2103633.png", width=80)
26
+ st.title("Settings")
27
+
28
+ with st.expander("πŸ”‘ API Credentials", expanded=True):
29
+ openai_key = st.text_input("OpenAI API Key", value=os.getenv("OPENAI_API_KEY", ""), type="password")
30
+ tavily_key = st.text_input("Tavily API Key", value=os.getenv("TAVILY_API_KEY", ""), type="password")
31
+
32
+ thread_id = st.text_input("Session ID", value="global_user_1")
33
+
34
+ os.environ["OPENAI_API_KEY"] = openai_key
35
+ os.environ["TAVILY_API_KEY"] = tavily_key
36
+
37
+ st.divider()
38
+ st.info("The agent will research and allow you to critique the data before generating a final report.")
39
+
40
+ # --- 3. AGENT LOGIC ---
41
+ DB_PATH = "/tmp/agent_memory.db"
42
+
43
+ class AgentState(TypedDict):
44
+ company_name: str
45
+ research_data: List[dict]
46
+ iteration: int
47
+ report: str
48
+
49
+ @st.cache_resource
50
+ def initialize_agent():
51
+ llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
52
+ search_tool = TavilySearchResults(max_results=3)
53
+
54
+ def researcher(state: AgentState):
55
+ iter_count = state.get("iteration", 0)
56
+ query = f"Financial SWOT and strategy for {state['company_name']} 2025"
57
+ if iter_count > 0:
58
+ query = f"Additional deep-dive business analysis for {state['company_name']} 2025"
59
+ results = search_tool.invoke({"query": query})
60
+ return {"research_data": results, "iteration": iter_count + 1}
61
+
62
+ def writer(state: AgentState):
63
+ context = "\n".join([f"Source: {r['url']}\nContent: {r['content']}" for r in state['research_data']])
64
+ prompt = f"Write a professional SWOT for {state['company_name']}. Cite [1][2].\n\nDATA:\n{context}"
65
+ response = llm.invoke(prompt)
66
+ return {"report": response.content}
67
+
68
+ builder = StateGraph(AgentState)
69
+ builder.add_node("researcher", researcher)
70
+ builder.add_node("writer", writer)
71
+ builder.add_edge(START, "researcher")
72
+ builder.add_edge("researcher", "writer")
73
+ builder.add_edge("writer", END)
74
+
75
+ conn = sqlite3.connect(DB_PATH, check_same_thread=False)
76
+ return builder.compile(checkpointer=SqliteSaver(conn), interrupt_before=["writer"])
77
+
78
+ # --- 4. UI STATE MANAGEMENT ---
79
+ if "report_output" not in st.session_state:
80
+ st.session_state.report_output = None
81
+
82
+ agent_app = initialize_agent()
83
+ config = {"configurable": {"thread_id": thread_id}}
84
+
85
+ # --- 5. MAIN GUI ---
86
+ st.title("πŸ›‘οΈ Strategic Intel-Agent")
87
+ st.caption("Agentic Intelligence: Research & SWOT Generation")
88
+
89
+ # Input Section
90
+ with st.container():
91
+ col_input, col_btn = st.columns([4, 1])
92
+ with col_input:
93
+ company = st.text_input("Target Company Name", placeholder="e.g. NVIDIA, Tesla, Microsoft", label_visibility="collapsed")
94
+ with col_btn:
95
+ if st.button("πŸ” Start Research"):
96
+ st.session_state.report_output = None
97
+ with st.status("Initializing Agent...", expanded=True) as status:
98
+ agent_app.invoke({"company_name": company, "iteration": 0}, config)
99
+ status.update(label="Research Phase Complete!", state="complete", expanded=False)
100
+ st.rerun()
101
+
102
+ current_state = agent_app.get_state(config)
103
+
104
+ if current_state.values.get("research_data"):
105
+ st.divider()
106
+
107
+ m1, m2 = st.columns([3, 1])
108
+ with m1:
109
+ st.subheader("πŸ“‹ Intelligence Briefing")
110
+ with m2:
111
+ st.metric("Web Search Cycles", current_state.values.get("iteration", 0))
112
+
113
+ with st.expander("πŸ“‚ View Raw Research Data", expanded=True):
114
+ for item in current_state.values["research_data"]:
115
+ st.markdown(f"**Source:** {item['url']}")
116
+ st.caption(item['content'])
117
+ st.divider()
118
+
119
+ c1, c2 = st.columns(2)
120
+ with c1:
121
+ if st.button("βœ… Approve & Generate SWOT", type="primary"):
122
+ with st.spinner("Synthesizing Report..."):
123
+ final_res = agent_app.invoke(None, config)
124
+ st.session_state.report_output = final_res.get("report")
125
+ st.rerun()
126
+ with c2:
127
+ if st.button("πŸ”„ Data Insufficient: Search Again"):
128
+ agent_app.update_state(config, {"research_data": []}, as_node="researcher")
129
+ with st.spinner("Refining search..."):
130
+ agent_app.invoke(None, config)
131
+ st.rerun()
132
+
133
+ # --- 6. REPORT SECTION ---
134
+ if st.session_state.report_output:
135
+ st.markdown("---")
136
+ st.markdown("### 🏁 Final SWOT Report")
137
+ st.markdown(f'<div class="report-container">{st.session_state.report_output}</div>', unsafe_allow_html=True)
138
+
139
+ st.divider()
140
+ st.download_button(
141
+ label="πŸ“„ Download Report (.md)",
142
+ data=st.session_state.report_output,
143
+ file_name=f"{company}_SWOT.md",
144
+ mime="text/markdown"
145
+ )