import os, requests, time
DC_TOKEN = os.environ["DISCORD_BOT_TOKEN"]
DC_BASE = "https://discord.com/api/v10"
DC_H = {"Authorization": f"Bot {DC_TOKEN}"}
MV = os.environ["MAVERA_API_KEY"]
MV_BASE = "https://app.mavera.io/api/v1"
MV_H = {"Authorization": f"Bearer {MV}", "Content-Type": "application/json"}
FEATURE_CHANNEL = "CHANNEL_ID_FEATURES"
# 1. Fetch feature request messages
msgs = []
after = "0"
while len(msgs) < 300:
r = requests.get(f"{DC_BASE}/channels/{FEATURE_CHANNEL}/messages", headers=DC_H,
params={"limit": 100, "after": after})
if r.status_code == 429:
time.sleep(r.json().get("retry_after", 1))
continue
if not r.ok:
break
batch = r.json()
if not batch:
break
for m in batch:
if not m.get("author",{}).get("bot",False) and len(m.get("content","")) > 15:
reactions = sum(r.get("count",0) for r in m.get("reactions", []))
msgs.append({"text": m["content"][:400], "reactions": reactions,
"author_roles": [r.get("name","") for r in m.get("member",{}).get("roles",[])]})
after = batch[0]["id"]
time.sleep(0.5)
print(f"Feature requests: {len(msgs)}")
# 2. Cluster via Mave
corpus = "\n".join(
f"- (reactions: {m['reactions']}) {m['text'][:250]}"
for m in sorted(msgs, key=lambda x: -x["reactions"])[:80]
)
clustering = requests.post(f"{MV_BASE}/mave/chat", headers=MV_H, json={
"message": f"Product analyst. Cluster {len(msgs)} Discord feature requests into top 8 themes.\n\n"
f"{corpus[:6000]}\n\n"
"For each:\n- Feature name (3-5 words)\n- Request count\n- Total reactions (proxy for community votes)\n"
"- Representative request (exact quote)\n- Complexity estimate (low/medium/high)\n"
"Rank by reactions × frequency."
}).json()
clusters = clustering.get("content", "")
print(f"\nClusters:\n{clusters[:1200]}")
# 3. Create community-segment personas
SEGMENTS = [
{"name": "Free Tier Power User", "desc": "Uses daily, hits limits constantly. Won't pay but evangelizes to others. Cares about functionality over polish."},
{"name": "Pro Subscriber", "desc": "Paying $15/month. Expects reliability and premium features. Compares to competitors. Values ROI."},
{"name": "Community Moderator", "desc": "Manages a 500+ member server using the product. Cares about admin tools, permissions, analytics. Loyal but demanding."},
{"name": "Developer / API User", "desc": "Builds integrations. Cares about API quality, documentation, rate limits, webhooks. Will leave for better DX."},
]
persona_ids = []
for seg in SEGMENTS:
p = requests.post(f"{MV_BASE}/personas", headers=MV_H, json={
"name": f"Discord: {seg['name']}", "description": seg["desc"],
}).json()
persona_ids.append(p["id"])
time.sleep(0.3)
# 4. Focus Group
fg = requests.post(f"{MV_BASE}/focus-groups", headers=MV_H, json={
"name": "Discord Feature Request Validation",
"persona_ids": persona_ids,
"questions": [
f"Here are the top community feature requests:\n{clusters[:2000]}\n\nRank your top 3 and explain why.",
"Which feature would make you upgrade (or stay on your current plan)?",
"Is there a request NOT on this list that matters more to you?",
"If we shipped your #1 request but it was behind a paywall, would you pay?",
],
"responses_per_persona": 2,
}).json()
for _ in range(25):
time.sleep(5)
data = requests.get(f"{MV_BASE}/focus-groups/{fg['id']}", headers=MV_H).json()
if data.get("status") == "completed":
break
print(f"\n{'='*60}\nFEATURE REQUEST FOCUS GROUP\n{'='*60}")
for resp in data.get("responses", []):
idx = persona_ids.index(resp.get("persona_id")) if resp.get("persona_id") in persona_ids else -1
name = SEGMENTS[idx]["name"] if 0 <= idx < len(SEGMENTS) else "Unknown"
print(f"\n[{name}] Q: {resp.get('question','')[:80]}")
print(f" A: {resp.get('answer','')[:350]}")