updated product launch intelligence agent with 3 diff agents

This commit is contained in:
Madhu 2025-06-03 00:52:40 +05:30
parent b7a21406b1
commit 415ad10f46

View file

@ -7,40 +7,32 @@ from datetime import datetime
from textwrap import dedent from textwrap import dedent
import os import os
# ---------------- Page Config & Styles ---------------- # ---------------- Page Config ----------------
st.set_page_config(page_title="Product Intelligence Agent", page_icon="🚀", layout="wide") st.set_page_config(
page_title="Product Intelligence Agent",
st.markdown( page_icon="🚀",
""" layout="wide",
<style> initial_sidebar_state="expanded"
/* Custom CSS for a sleek look */
.stButton>button {
border-radius: 5px;
height: 3em;
font-weight: 600;
}
.analysis-box {
padding: 1rem;
border-radius: 0.5rem;
background-color: #f9f9f9;
border: 1px solid #e1e1e1;
}
div[data-testid="stExpander"] div[role="button"] p {
font-size: 1.05rem;
font-weight: 600;
}
</style>
""",
unsafe_allow_html=True,
) )
# ---------------- Environment & Agent ---------------- # ---------------- Environment & Agent ----------------
load_dotenv() load_dotenv()
# Add API key inputs in sidebar # Add API key inputs in sidebar
with st.sidebar.expander("🔑 API Keys", expanded=True): st.sidebar.header("🔑 API Configuration")
openai_key = st.text_input("OpenAI API Key", type="password", value=os.getenv("OPENAI_API_KEY", "")) with st.sidebar.container():
firecrawl_key = st.text_input("Firecrawl API Key", type="password", value=os.getenv("FIRECRAWL_API_KEY", "")) openai_key = st.text_input(
"OpenAI API Key",
type="password",
value=os.getenv("OPENAI_API_KEY", ""),
help="Required for AI agent functionality"
)
firecrawl_key = st.text_input(
"Firecrawl API Key",
type="password",
value=os.getenv("FIRECRAWL_API_KEY", ""),
help="Required for web search and crawling"
)
# Set environment variables # Set environment variables
if openai_key: if openai_key:
@ -48,8 +40,9 @@ if openai_key:
if firecrawl_key: if firecrawl_key:
os.environ["FIRECRAWL_API_KEY"] = firecrawl_key os.environ["FIRECRAWL_API_KEY"] = firecrawl_key
# Initialize agent only if both keys are provided # Initialize agents only if both keys are provided
if openai_key and firecrawl_key: if openai_key and firecrawl_key:
# Agent 1: Competitor Launch Analyst
launch_analyst = Agent( launch_analyst = Agent(
name="Product Launch Analyst", name="Product Launch Analyst",
description=dedent(""" description=dedent("""
@ -60,9 +53,55 @@ if openai_key and firecrawl_key:
• Where execution fell short (weaknesses) • Where execution fell short (weaknesses)
• Actionable learnings competitors can leverage • Actionable learnings competitors can leverage
Always cite observable signals (messaging, pricing actions, channel mix, timing, engagement metrics). Maintain a crisp, executive tone and focus on strategic value. Always cite observable signals (messaging, pricing actions, channel mix, timing, engagement metrics). Maintain a crisp, executive tone and focus on strategic value.
IMPORTANT: Conclude your report with a 'Sources:' section, listing all URLs of websites you crawled or searched for this analysis.
"""), """),
model=OpenAIChat(id="gpt-4o"), model=OpenAIChat(id="gpt-4o"),
tools=[FirecrawlTools(search=True, crawl=True, limit=8, poll_interval=10)], tools=[FirecrawlTools(search=True, crawl=True, poll_interval=10)],
show_tool_calls=True,
markdown=True,
exponential_backoff=True,
delay_between_retries=2,
)
# Agent 2: Market Sentiment Specialist
sentiment_analyst = Agent(
name="Market Sentiment Specialist",
description=dedent("""
You are a market research expert specializing in sentiment analysis and consumer perception tracking.
Your expertise includes:
• Analyzing social media sentiment and customer feedback
• Identifying positive and negative sentiment drivers
• Tracking brand perception trends across platforms
• Monitoring customer satisfaction and review patterns
• Providing actionable insights on market reception
Focus on extracting sentiment signals from social platforms, review sites, forums, and customer feedback channels.
IMPORTANT: Conclude your report with a 'Sources:' section, listing all URLs of websites you crawled or searched for this analysis.
"""),
model=OpenAIChat(id="gpt-4o"),
tools=[FirecrawlTools(search=True, crawl=True, poll_interval=10)],
show_tool_calls=True,
markdown=True,
exponential_backoff=True,
delay_between_retries=2,
)
# Agent 3: Launch Metrics Specialist
metrics_analyst = Agent(
name="Launch Metrics Specialist",
description=dedent("""
You are a product launch performance analyst who specializes in tracking and analyzing launch KPIs.
Your focus areas include:
• User adoption and engagement metrics
• Revenue and business performance indicators
• Market penetration and growth rates
• Press coverage and media attention analysis
• Social media traction and viral coefficient tracking
• Competitive market share analysis
Always provide quantitative insights with context and benchmark against industry standards when possible.
IMPORTANT: Conclude your report with a 'Sources:' section, listing all URLs of websites you crawled or searched for this analysis.
"""),
model=OpenAIChat(id="gpt-4o"),
tools=[FirecrawlTools(search=True, crawl=True, poll_interval=10)],
show_tool_calls=True, show_tool_calls=True,
markdown=True, markdown=True,
exponential_backoff=True, exponential_backoff=True,
@ -70,6 +109,8 @@ if openai_key and firecrawl_key:
) )
else: else:
launch_analyst = None launch_analyst = None
sentiment_analyst = None
metrics_analyst = None
st.warning("⚠️ Please enter both API keys in the sidebar to use the application.") st.warning("⚠️ Please enter both API keys in the sidebar to use the application.")
# ---------------- Helper to display response ---------------- # ---------------- Helper to display response ----------------
@ -133,7 +174,7 @@ def expand_competitor_report(bullet_text: str, competitor: str) -> str:
# Helper to craft market sentiment report # Helper to craft market sentiment report
def expand_sentiment_report(bullet_text: str, product: str) -> str: def expand_sentiment_report(bullet_text: str, product: str) -> str:
if not launch_analyst: if not sentiment_analyst:
st.error("⚠️ Please enter both API keys in the sidebar first.") st.error("⚠️ Please enter both API keys in the sidebar first.")
return "" return ""
@ -147,12 +188,12 @@ def expand_sentiment_report(bullet_text: str, product: str) -> str:
f"Provide a short paragraph (≤120 words) summarising the overall sentiment balance and key drivers.\n\n" f"Provide a short paragraph (≤120 words) summarising the overall sentiment balance and key drivers.\n\n"
f"Tagged Bullets:\n{bullet_text}" f"Tagged Bullets:\n{bullet_text}"
) )
resp = launch_analyst.run(prompt) resp = sentiment_analyst.run(prompt)
return resp.content if hasattr(resp, "content") else str(resp) return resp.content if hasattr(resp, "content") else str(resp)
# Helper to craft launch metrics report # Helper to craft launch metrics report
def expand_metrics_report(bullet_text: str, launch: str) -> str: def expand_metrics_report(bullet_text: str, launch: str) -> str:
if not launch_analyst: if not metrics_analyst:
st.error("⚠️ Please enter both API keys in the sidebar first.") st.error("⚠️ Please enter both API keys in the sidebar first.")
return "" return ""
@ -168,137 +209,296 @@ def expand_metrics_report(bullet_text: str, launch: str) -> str:
f"Brief paragraph (≤120 words) highlighting what the metrics imply about launch success and next steps.\n\n" f"Brief paragraph (≤120 words) highlighting what the metrics imply about launch success and next steps.\n\n"
f"KPI Bullets:\n{bullet_text}" f"KPI Bullets:\n{bullet_text}"
) )
resp = launch_analyst.run(prompt) resp = metrics_analyst.run(prompt)
return resp.content if hasattr(resp, "content") else str(resp) return resp.content if hasattr(resp, "content") else str(resp)
# ---------------- UI ---------------- # ---------------- UI ----------------
st.title("🚀 Product Launch Intelligence Agent") st.title("🚀 Product Launch Intelligence Agent")
st.caption("AI Agent powered insights for GTM, Product Marketing & Growth Teams") st.markdown("*AI-powered insights for GTM, Product Marketing & Growth Teams*")
st.divider()
# Company input section
st.subheader("🏢 Company Analysis")
with st.container():
col1, col2 = st.columns([3, 1])
with col1:
company_name = st.text_input(
label="Company Name",
placeholder="Enter company name (e.g., OpenAI, Tesla, Spotify)",
help="This company will be analyzed by all three specialized agents",
label_visibility="collapsed"
)
with col2:
if company_name:
st.success(f"✓ Ready to analyze **{company_name}**")
st.divider()
# Create tabs for analysis types # Create tabs for analysis types
analysis_tabs = st.tabs(["Competitor Analysis", "Market Sentiment", "Launch Metrics"]) analysis_tabs = st.tabs([
"🔍 Competitor Analysis",
"💬 Market Sentiment",
"📈 Launch Metrics"
])
# Persistent storage for latest response # Persistent storage for latest response
if "analysis_response" not in st.session_state: if "analysis_response" not in st.session_state:
st.session_state.analysis_response = None st.session_state.analysis_response = None
st.session_state.analysis_meta = {} st.session_state.analysis_meta = {}
# Store separate responses for each agent
if "competitor_response" not in st.session_state:
st.session_state.competitor_response = None
if "sentiment_response" not in st.session_state:
st.session_state.sentiment_response = None
if "metrics_response" not in st.session_state:
st.session_state.metrics_response = None
# -------- Competitor Analysis Tab -------- # -------- Competitor Analysis Tab --------
with analysis_tabs[0]: with analysis_tabs[0]:
st.subheader("🔍 Competitor Launch Analysis") with st.container():
competitor_name = st.text_input("Competitor name", key="competitor_input") st.markdown("### 🔍 Competitor Launch Analysis")
cols = st.columns([2, 1]) with st.expander("ℹ️ About this Agent", expanded=False):
with cols[0]: st.markdown("""
if st.button("Analyze", key="competitor_btn") and competitor_name: **Product Launch Analyst** - Strategic GTM Expert
if not launch_analyst:
st.error("⚠️ Please enter both API keys in the sidebar first.") Specializes in:
else: - Competitive positioning analysis
with st.spinner("Gathering competitive insights..."): - Launch strategy evaluation
try: - Strengths & weaknesses identification
bullets = launch_analyst.run( - Strategic recommendations
f"Generate up to 16 evidence-based insight bullets about {competitor_name}'s most recent product launches.\n" """)
f"Format requirements:\n"
f"• Start every bullet with exactly one tag: Positioning | Strength | Weakness | Learning\n" if company_name:
f"• Follow the tag with a concise statement (max 30 words) referencing concrete observations: messaging, differentiation, pricing, channel selection, timing, engagement metrics, or customer feedback." col1, col2 = st.columns([2, 1])
)
long_text = expand_competitor_report( with col1:
bullets.content if hasattr(bullets, "content") else str(bullets), analyze_btn = st.button(
competitor_name "🚀 Analyze Competitor Strategy",
) key="competitor_btn",
st.session_state.analysis_response = long_text type="primary",
st.session_state.analysis_meta = { use_container_width=True
"type": "Competitor Analysis", )
"query": competitor_name,
"timestamp": datetime.utcnow().isoformat() with col2:
} if st.session_state.competitor_response:
st.success("✅ Analysis ready") st.success("✅ Analysis Complete")
except Exception as e: else:
st.error(f"❌ Error: {e}") st.info("⏳ Ready to analyze")
if st.session_state.analysis_response and st.session_state.analysis_meta.get("type") == "Competitor Analysis": if analyze_btn:
st.markdown("### 📊 Results") if not launch_analyst:
st.markdown(st.session_state.analysis_response) st.error("⚠️ Please enter both API keys in the sidebar first.")
else:
with st.spinner("🔍 Launch Analyst gathering competitive intelligence..."):
try:
bullets = launch_analyst.run(
f"Generate up to 16 evidence-based insight bullets about {company_name}'s most recent product launches.\n"
f"Format requirements:\n"
f"• Start every bullet with exactly one tag: Positioning | Strength | Weakness | Learning\n"
f"• Follow the tag with a concise statement (max 30 words) referencing concrete observations: messaging, differentiation, pricing, channel selection, timing, engagement metrics, or customer feedback."
)
long_text = expand_competitor_report(
bullets.content if hasattr(bullets, "content") else str(bullets),
company_name
)
st.session_state.competitor_response = long_text
st.success("✅ Competitor analysis ready")
st.rerun()
except Exception as e:
st.error(f"❌ Error: {e}")
# Display results
if st.session_state.competitor_response:
st.divider()
with st.container():
st.markdown("### 📊 Analysis Results")
st.markdown(st.session_state.competitor_response)
else:
st.info("👆 Please enter a company name above to start the analysis")
# -------- Market Sentiment Tab -------- # -------- Market Sentiment Tab --------
with analysis_tabs[1]: with analysis_tabs[1]:
st.subheader("💬 Market Sentiment Analysis") with st.container():
product_name = st.text_input("Product name", key="sentiment_input") st.markdown("### 💬 Market Sentiment Analysis")
cols = st.columns([2, 1]) with st.expander("ℹ️ About this Agent", expanded=False):
with cols[0]: st.markdown("""
if st.button("Analyze", key="sentiment_btn") and product_name: **Market Sentiment Specialist** - Consumer Perception Expert
if not launch_analyst:
st.error("⚠️ Please enter both API keys in the sidebar first.") Specializes in:
else: - Social media sentiment tracking
with st.spinner("Collecting market sentiment..."): - Customer feedback analysis
try: - Brand perception monitoring
bullets = launch_analyst.run( - Review pattern identification
f"Summarize market sentiment for {product_name} in <=10 bullets. " """)
f"Cover top positive & negative themes with source mentions (G2, Reddit, Twitter)."
) if company_name:
long_text = expand_sentiment_report( col1, col2 = st.columns([2, 1])
bullets.content if hasattr(bullets, "content") else str(bullets),
product_name with col1:
) sentiment_btn = st.button(
st.session_state.analysis_response = long_text "📊 Analyze Market Sentiment",
st.session_state.analysis_meta = { key="sentiment_btn",
"type": "Market Sentiment", type="primary",
"query": product_name, use_container_width=True
"timestamp": datetime.utcnow().isoformat() )
}
st.success("✅ Sentiment analysis ready") with col2:
except Exception as e: if st.session_state.sentiment_response:
st.error(f"❌ Error: {e}") st.success("✅ Analysis Complete")
else:
if st.session_state.analysis_response and st.session_state.analysis_meta.get("type") == "Market Sentiment": st.info("⏳ Ready to analyze")
st.markdown("### 📈 Sentiment Insights")
st.markdown(st.session_state.analysis_response) if sentiment_btn:
if not sentiment_analyst:
st.error("⚠️ Please enter both API keys in the sidebar first.")
else:
with st.spinner("💬 Sentiment Specialist analyzing market perception..."):
try:
bullets = sentiment_analyst.run(
f"Summarize market sentiment for {company_name} in <=10 bullets. "
f"Cover top positive & negative themes with source mentions (G2, Reddit, Twitter, customer reviews)."
)
long_text = expand_sentiment_report(
bullets.content if hasattr(bullets, "content") else str(bullets),
company_name
)
st.session_state.sentiment_response = long_text
st.success("✅ Sentiment analysis ready")
st.rerun()
except Exception as e:
st.error(f"❌ Error: {e}")
# Display results
if st.session_state.sentiment_response:
st.divider()
with st.container():
st.markdown("### 📈 Analysis Results")
st.markdown(st.session_state.sentiment_response)
else:
st.info("👆 Please enter a company name above to start the analysis")
# -------- Launch Metrics Tab -------- # -------- Launch Metrics Tab --------
with analysis_tabs[2]: with analysis_tabs[2]:
st.subheader("📈 Launch Performance Metrics") with st.container():
product_launch = st.text_input("Product name / Launch campaign", key="metrics_input") st.markdown("### 📈 Launch Performance Metrics")
cols = st.columns([2, 1]) with st.expander("ℹ️ About this Agent", expanded=False):
with cols[0]: st.markdown("""
if st.button("Analyze", key="metrics_btn") and product_launch: **Launch Metrics Specialist** - Performance Analytics Expert
if not launch_analyst:
st.error("⚠️ Please enter both API keys in the sidebar first.") Specializes in:
else: - User adoption metrics tracking
with st.spinner("Fetching launch performance data..."): - Revenue performance analysis
try: - Market penetration evaluation
bullets = launch_analyst.run( - Press coverage monitoring
f"List (max 10 bullets) the most important publicly available KPIs & qualitative signals for {product_launch}. " """)
f"Include engagement stats, press coverage and social traction if available."
) if company_name:
long_text = expand_metrics_report( col1, col2 = st.columns([2, 1])
bullets.content if hasattr(bullets, "content") else str(bullets),
product_launch with col1:
) metrics_btn = st.button(
st.session_state.analysis_response = long_text "📊 Analyze Launch Metrics",
st.session_state.analysis_meta = { key="metrics_btn",
"type": "Launch Metrics", type="primary",
"query": product_launch, use_container_width=True
"timestamp": datetime.utcnow().isoformat() )
}
st.success("✅ Metrics analysis ready") with col2:
except Exception as e: if st.session_state.metrics_response:
st.error(f"❌ Error: {e}") st.success("✅ Analysis Complete")
else:
if st.session_state.analysis_response and st.session_state.analysis_meta.get("type") == "Launch Metrics": st.info("⏳ Ready to analyze")
st.markdown("### 📊 Metric Highlights")
st.markdown(st.session_state.analysis_response) if metrics_btn:
if not metrics_analyst:
st.error("⚠️ Please enter both API keys in the sidebar first.")
else:
with st.spinner("📈 Metrics Specialist analyzing launch performance..."):
try:
bullets = metrics_analyst.run(
f"List (max 10 bullets) the most important publicly available KPIs & qualitative signals for {company_name}'s recent product launches. "
f"Include engagement stats, press coverage, adoption metrics, and market traction data if available."
)
long_text = expand_metrics_report(
bullets.content if hasattr(bullets, "content") else str(bullets),
company_name
)
st.session_state.metrics_response = long_text
st.success("✅ Metrics analysis ready")
st.rerun()
except Exception as e:
st.error(f"❌ Error: {e}")
# Display results
if st.session_state.metrics_response:
st.divider()
with st.container():
st.markdown("### 📊 Analysis Results")
st.markdown(st.session_state.metrics_response)
else:
st.info("👆 Please enter a company name above to start the analysis")
# ---------------- Sidebar ---------------- # ---------------- Sidebar ----------------
st.sidebar.header("ℹ️ About") # Agent status indicators
st.sidebar.markdown( with st.sidebar.container():
""" st.markdown("### 🤖 System Status")
**Product Launch Intelligence Agent** helps GTM teams quickly: if openai_key and firecrawl_key:
- Benchmark competitor launches st.success("✅ All agents ready")
- Monitor market sentiment pre/post-launch else:
- Track launch performance signals st.error("❌ API keys required")
st.sidebar.divider()
# Multi-agent system info
with st.sidebar.container():
st.markdown("### 🎯 Specialized Agents")
Built with **Agno** & **Firecrawl**. agents_info = [
""" ("🔍", "Product Launch Analyst", "Strategic GTM expert"),
) ("💬", "Market Sentiment Specialist", "Consumer perception expert"),
("📈", "Launch Metrics Specialist", "Performance analytics expert")
]
for icon, name, desc in agents_info:
with st.container():
st.markdown(f"**{icon} {name}**")
st.caption(desc)
st.sidebar.divider()
# Analysis status
if company_name:
with st.sidebar.container():
st.markdown("### 📊 Analysis Status")
st.markdown(f"**Company:** {company_name}")
status_items = [
("🔍", "Competitor Analysis", st.session_state.competitor_response),
("💬", "Sentiment Analysis", st.session_state.sentiment_response),
("📈", "Metrics Analysis", st.session_state.metrics_response)
]
for icon, name, status in status_items:
if status:
st.success(f"{icon} {name} ✓")
else:
st.info(f"{icon} {name} ⏳")
st.sidebar.divider()
# Quick actions
with st.sidebar.container():
st.markdown("### ⚡ Quick Actions")
if company_name:
st.markdown("""
**J** - Competitor analysis
**K** - Market sentiment
**L** - Launch metrics
""")
else:
st.info("Enter a company name to enable quick actions")