import os, requests, time
from collections import defaultdict
G2 = os.environ["G2_API_KEY"]
MV = os.environ["MAVERA_API_KEY"]
G2_BASE = "https://data.g2.com/api/v1"
MV_BASE = "https://app.mavera.io/api/v1"
G2_H = {"Authorization": f"Token token={G2}", "Content-Type": "application/vnd.api+json"}
MV_H = {"Authorization": f"Bearer {MV}", "Content-Type": "application/json"}
# 1. Pull reviews
reviews = []
page = 1
while len(reviews) < 300:
r = requests.get(f"{G2_BASE}/survey-responses",
headers=G2_H,
params={"page[size]": 50, "page[number]": page})
if r.status_code == 429:
time.sleep(1)
continue
r.raise_for_status()
data = r.json().get("data", [])
if not data:
break
reviews.extend(data)
page += 1
time.sleep(0.1)
# 2. Group by reviewer role
role_groups = defaultdict(list)
for rev in reviews:
attrs = rev.get("attributes", {})
role = attrs.get("title", "Unknown Role")
industry = attrs.get("industry", "Unknown")
star = attrs.get("star_rating", 0)
love = ""
hate = ""
for ans in attrs.get("comment_answers", {}).values():
text = ans if isinstance(ans, str) else ans.get("text", "")
if "love" in str(ans).lower() or "best" in str(ans).lower():
love = text[:300]
elif "dislike" in str(ans).lower() or "hate" in str(ans).lower():
hate = text[:300]
role_bucket = role.split(",")[0].strip() if role else "Unknown"
role_groups[role_bucket].append({
"star": star, "industry": industry,
"love": love, "hate": hate,
})
# 3. Create personas per role
persona_map = []
for role, revs in sorted(role_groups.items(), key=lambda x: -len(x[1]))[:6]:
if len(revs) < 3:
continue
avg_star = sum(r["star"] for r in revs) / len(revs)
industries = list({r["industry"] for r in revs if r["industry"] != "Unknown"})[:3]
love_samples = [r["love"] for r in revs if r["love"]][:3]
hate_samples = [r["hate"] for r in revs if r["hate"]][:3]
p = requests.post(f"{MV_BASE}/personas", headers=MV_H, json={
"name": f"G2 Reviewer: {role}",
"description": (
f"G2 reviewer with role '{role}'. N={len(revs)}. Avg rating: {avg_star:.1f}/5. "
f"Industries: {', '.join(industries)}. "
f"What they love: {'; '.join(love_samples[:2])}. "
f"What they dislike: {'; '.join(hate_samples[:2])}."
),
"demographic": {"job_titles": [role], "industries": industries},
"psychographic": {
"product_sentiment": "positive" if avg_star >= 4 else "mixed" if avg_star >= 3 else "negative",
"avg_rating": avg_star,
},
}).json()
persona_map.append({"id": p["id"], "role": role, "n": len(revs), "avg": avg_star})
print(f"Persona: {p['id']} — {role} ({len(revs)} reviews, avg {avg_star:.1f})")
time.sleep(0.3)
# 4. Generate role-targeted content
for pm in persona_map:
gen = requests.post(f"{MV_BASE}/generations", headers=MV_H, json={
"persona_id": pm["id"],
"prompt": (
f"Generate a 150-word marketing paragraph targeting {pm['role']}s. "
f"This segment gave us {pm['avg']:.1f}/5 on G2. "
f"Use language that resonates with their specific concerns and value drivers. "
f"Include a CTA appropriate for their role."
),
}).json()
content = gen.get("output", gen.get("content", gen.get("text", "")))
print(f"\n--- Content for {pm['role']} ---")
print(content[:400])
time.sleep(0.5)
comment_answersfield structure varies by survey version. Some are flat strings, others are{text, id}objects. The code handles both formats.