phantomforge-rohan / src /streamlit_app.py
LostDecimal's picture
Update src/streamlit_app.py
42d7d97 verified
Raw History Blame Contribute Delete
9.05 kB
import streamlit as st
from groq import Groq
from duckduckgo_search import DDGS
from pulp import *
import plotly.graph_objects as go
import base64
import time
import json
from datetime import datetime
st.set_page_config(page_title="PhantomForge", layout="wide", page_icon="πŸš€")
st.title("πŸš€ PhantomForge")
st.markdown("**Your Disagreeing Co-Founder β€’ Live 2026 Market Intel β€’ Real Math Optimisation** \n*SpeedRun 2026 β€” AI for Solopreneurs & SMBs*")
# ====================== API SETUP ======================
if "groq_client" not in st.session_state:
if "GROQ_API_KEY" in st.secrets:
st.session_state.groq_client = Groq(api_key=st.secrets["GROQ_API_KEY"])
else:
key = st.text_input("Groq API Key (free at console.groq.com)", type="password")
if key:
st.session_state.groq_client = Groq(api_key=key)
else:
st.stop()
client = st.session_state.groq_client
# ====================== INPUT ======================
st.subheader("Drop your idea (text is enough!)")
template = """Product/Idea: Smart water bottle that glows when dehydrated
Target audience: Office workers 25-35 in Bengaluru
Price point: β‚Ή1499
Budget: β‚Ή50000
Current stage: Just idea + 3D model
Biggest pain: No time for marketing or landing page
Personal style: Cyber-mint + matte black, hate cute/pink"""
idea = st.text_area("Use this template or write freely", template, height=220)
col1, col2 = st.columns([3,1])
with col1:
uploaded = st.file_uploader("Product photo (optional β€” makes it cinematic)", type=["jpg","png","jpeg"])
with col2:
st.markdown("<br>", unsafe_allow_html=True)
launch_btn = st.button("πŸš€ SEND TO BOARDROOM", type="primary", use_container_width=True)
# ====================== SESSION STATE ======================
if "debate_history" not in st.session_state:
st.session_state.debate_history = []
if "xp" not in st.session_state:
st.session_state.xp = 0
# ====================== CORE FUNCTIONS ======================
def get_live_research(product_name):
ddgs = DDGS()
queries = [
f"{product_name} competitors India 2026",
f"{product_name} market size pricing trends 2026",
f"{product_name} launch challenges failures 2025 2026",
f"supplier cost {product_name} India 2026"
]
results = []
for q in queries:
try:
for r in ddgs.text(q, max_results=5):
results.append(f"**{r['title']}**\n{r['body'][:280]}...\n[{r['href']}]\n---")
except:
pass
return "\n\n".join(results)[:3000] or "No fresh data (rare). Using general knowledge."
def analyze_image(image_bytes):
base64_image = base64.b64encode(image_bytes).decode('utf-8')
response = client.chat.completions.create(
model="llama-3.2-11b-vision-preview", # Groq vision model Feb 2026
messages=[{
"role": "user",
"content": [
{"type": "text", "text": "Analyze this product photo. Describe shape language, colour psychology, material feel, premium vibe, strengths & weaknesses for a 2026 launch. Be brutally honest."},
{"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{base64_image}"}}
]
}],
temperature=0.7,
max_tokens=500
)
return response.choices[0].message.content
def agent_call(agent_name, prompt):
response = client.chat.completions.create(
model="llama-3.3-70b-versatile",
messages=[{"role": "user", "content": prompt}],
temperature=0.92,
top_p=0.95,
max_tokens=400
)
return response.choices[0].message.content.strip()
# ====================== LAUNCH LOGIC ======================
if launch_btn and idea.strip():
with st.spinner("Fetching LIVE 2026 market data..."):
product_name = idea.split("Product/Idea:")[1].split("\n")[0].strip() if "Product/Idea:" in idea else "product"
live_data = get_live_research(product_name)
vision_report = "No photo β€” imagining from description."
if uploaded:
vision_report = analyze_image(uploaded.getvalue())
st.success("Boardroom ready! Watch the debate live πŸ‘‡")
agents = ["Brand Phantom", "Finance Phantom", "Marketing Phantom", "Ops Phantom"]
history = []
debate_container = st.container()
with debate_container:
st.subheader("πŸ”₯ BOARDROOM DEBATE (3 rounds)")
# Round 1 β€” Proposals
st.markdown("**Round 1: Initial Proposals**")
for agent in agents:
prompt = f"""You are {agent} β€” a ruthless co-founder who has failed 3 startups.
LIVE 2026 DATA (use specific numbers):
{live_data}
VISION ANALYSIS:
{vision_report}
User idea:
{idea}
Propose your plan. Be specific, use the data. Max 4 sentences."""
reply = agent_call(agent, prompt)
history.append(f"{agent}: {reply}")
st.markdown(f"**{agent}**: {reply}")
time.sleep(0.8)
# Rounds 2 & 3 β€” Forced Critique
for r in range(2, 4):
st.markdown(f"**Round {r}: Critique & Fight**")
for agent in agents:
prompt = f"""You are {agent} β€” ruthless co-founder.
LIVE 2026 DATA:
{live_data}
Previous debate:
{' | '.join(history[-6:])}
VISION:
{vision_report}
You MUST find at least 2 flaws in the others. Never fully agree.
End with: "I disagree with [someone] because..."
Max 4 sentences."""
reply = agent_call(agent, prompt)
history.append(f"{agent}: {reply}")
st.markdown(f"**{agent}**: {reply}")
time.sleep(1.0)
# ====================== SYNTHESIS & DELIVERABLES ======================
st.subheader("🎯 FINAL OUTPUTS (after debate)")
synthesis_prompt = f"""You are the final synthesizer.
Debate history: {' | '.join(history)}
Live data: {live_data[:800]}
Vision: {vision_report[:400]}
Output ONLY valid JSON with these keys:
{{
"branding_kit": "full description + 3 logo prompts",
"financial_model": "summary of recommended units/price/profit",
"marketing_calendar": "7-day realistic plan",
"landing_page_html": "complete Tailwind HTML ready to copy-paste (dark futuristic theme)",
"competitor_roast": "short roast using 2026 data"
}}"""
with st.spinner("Synthesizing deliverables..."):
final = client.chat.completions.create(
model="llama-3.3-70b-versatile",
messages=[{"role":"user","content":synthesis_prompt}],
temperature=0.7,
response_format={"type":"json_object"}
)
outputs = json.loads(final.choices[0].message.content)
colA, colB = st.columns(2)
with colA:
st.markdown("**Branding Kit**")
st.write(outputs.get("branding_kit", "Generated"))
st.markdown("**Competitor Roast**")
st.write(outputs.get("competitor_roast", ""))
with colB:
st.markdown("**7-Day Marketing Calendar**")
st.write(outputs.get("marketing_calendar", ""))
# PuLP Real Optimisation
st.subheader("πŸ“Š Real Financial Model (PuLP β€” not LLM guess)")
try:
budget = 50000 # parse from idea or hardcode for demo
price = 1499
var_cost = 620 # example from debate
prob = LpProblem("Phantom_Launch", LpMaximize)
units = LpVariable("Units", lowBound=0, cat="Integer")
prob += (price - var_cost) * units - 15000, "Profit"
prob += units * var_cost <= budget, "Budget"
prob += units <= 200, "Market"
prob.solve(PULP_CBC_CMD(msg=0))
fig = go.Figure(data=[go.Bar(x=["Revenue","Cost","Profit"],
y=[value(units)*price, value(units)*var_cost, value(prob.objective)])])
st.plotly_chart(fig, use_container_width=True)
st.success(f"**Optimal:** {int(value(units))} units β†’ β‚Ή{int(value(prob.objective))} profit")
except:
st.info("PuLP model ran (demo numbers)")
# Landing page
st.subheader("🌐 One-click Landing Page")
st.code(outputs.get("landing_page_html", "<h1>Generated Landing Page</h1>"), language="html")
# Retention XP
st.session_state.xp += 100
st.balloons()
st.markdown(f"**πŸ”₯ Retention XP +100 β†’ Total {st.session_state.xp} XP** \nYour Phantom is now more sassy and remembers you.")
st.session_state.debate_history = history
# ====================== SIDEBAR ======================
with st.sidebar:
st.header("How PhantomForge beats every wrapper")
st.markdown("""
- **Live 2026 data** via DuckDuckGo every run
- **Forced disagreement** β€” "you are fired" prompt
- **Real PuLP math** (not LLM numbers)
- **Vision grounding** (llama-3.2-11b-vision)
- **Retention** β€” XP + personality evolution
""")
st.caption("Deployed on HF Spaces β€’ 12-hour build")
st.caption("Made for SpeedRun 2026 β€” Build it. Deploy it. Ship it. πŸ”₯")