nexaapi-tutorial-2026 / journey_generator_app.py
nickyni's picture
Add AI User Journey Generator demo (Breadcrumb Product Hunt)
c0910f7 verified
import gradio as gr
import nexaapi
import requests
import json
from io import BytesIO
from PIL import Image
def generate_journey_diagram(
api_key: str,
journey_title: str,
steps_json: str,
model: str,
width: int,
height: int
):
"""
Generate a user journey diagram using NexaAPI.
Args:
api_key: NexaAPI key from nexa-api.com
journey_title: Title for the journey diagram
steps_json: JSON string with steps data
model: AI model to use
width: Image width
height: Image height
Returns:
PIL Image of the generated diagram
"""
if not api_key or api_key.strip() == "":
return None, "❌ Please enter your NexaAPI key. Get one free at https://nexa-api.com"
try:
steps = json.loads(steps_json)
except json.JSONDecodeError as e:
return None, f"❌ Invalid JSON format: {e}"
if not steps or len(steps) < 2:
return None, "❌ Please provide at least 2 journey steps"
# Build prompt
steps_desc = " β†’ ".join([
f"{s.get('name', 'Step')} ({s.get('users', 0):,} users)"
for s in steps
])
drop_offs = [
f"{s.get('name', 'Step')}: {int(s.get('drop_off', 0) * 100)}% drop-off"
for s in steps
if s.get("drop_off", 0) > 0
]
prompt = (
f"Professional user journey funnel diagram titled '{journey_title}'. "
f"Sequential steps: {steps_desc}. "
f"Drop-off rates: {', '.join(drop_offs) if drop_offs else 'not specified'}. "
"Clean modern flat design, gradient blue-to-green color scheme, "
"white background, clear typography, directional arrows, "
"user count labels, professional business style."
)
try:
client = nexaapi.Client(api_key=api_key.strip())
response = client.images.generate(
model=model,
prompt=prompt,
width=width,
height=height,
num_images=1
)
image_url = response.data[0].url
# Download image
img_response = requests.get(image_url, timeout=30)
img_response.raise_for_status()
image = Image.open(BytesIO(img_response.content))
return image, f"βœ… Generated successfully!\nπŸ”— URL: {image_url}"
except Exception as e:
return None, f"❌ Generation failed: {str(e)}\n\nMake sure your API key is valid at https://nexa-api.com"
# Example journey data
EXAMPLE_STEPS = json.dumps([
{"name": "Landing Page", "users": 10000, "drop_off": 0.35},
{"name": "Sign Up", "users": 6500, "drop_off": 0.20},
{"name": "Email Verified", "users": 5200, "drop_off": 0.15},
{"name": "First Action", "users": 4420, "drop_off": 0.10},
{"name": "Paid Conversion", "users": 3978, "drop_off": 0.00}
], indent=2)
ECOMMERCE_STEPS = json.dumps([
{"name": "Homepage", "users": 50000, "drop_off": 0.60},
{"name": "Product Page", "users": 20000, "drop_off": 0.40},
{"name": "Add to Cart", "users": 12000, "drop_off": 0.50},
{"name": "Checkout", "users": 6000, "drop_off": 0.30},
{"name": "Purchase", "users": 4200, "drop_off": 0.00}
], indent=2)
MOBILE_STEPS = json.dumps([
{"name": "App Install", "users": 5000, "drop_off": 0.20},
{"name": "Permissions", "users": 4000, "drop_off": 0.15},
{"name": "Account Setup","users": 3400, "drop_off": 0.10},
{"name": "Tutorial", "users": 3060, "drop_off": 0.08},
{"name": "First Use", "users": 2815, "drop_off": 0.00}
], indent=2)
# Build Gradio interface
with gr.Blocks(
title="AI User Journey Generator",
theme=gr.themes.Soft(),
css="""
.header { text-align: center; padding: 20px; }
.links { text-align: center; font-size: 14px; }
"""
) as demo:
gr.HTML("""
<div class="header">
<h1>πŸ—ΊοΈ AI User Journey Generator</h1>
<p>Generate beautiful user journey diagrams from your analytics data using AI</p>
<p>Inspired by <strong>Breadcrumb.ai</strong> on Product Hunt πŸš€</p>
</div>
""")
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("### βš™οΈ Configuration")
api_key = gr.Textbox(
label="NexaAPI Key",
placeholder="Enter your API key from nexa-api.com",
type="password",
info="Get a free key at https://nexa-api.com"
)
journey_title = gr.Textbox(
label="Journey Title",
value="SaaS Onboarding Funnel",
placeholder="e.g., SaaS Onboarding Funnel"
)
model = gr.Dropdown(
label="AI Model",
choices=["flux-schnell", "flux-dev", "sdxl", "dall-e-3"],
value="flux-schnell",
info="flux-schnell is fastest; flux-dev is highest quality"
)
with gr.Row():
width = gr.Slider(512, 1920, value=1200, step=64, label="Width")
height = gr.Slider(512, 1080, value=700, step=64, label="Height")
gr.Markdown("### πŸ“Š Journey Steps (JSON)")
gr.Markdown("Format: `[{\"name\": \"Step\", \"users\": 1000, \"drop_off\": 0.20}]`")
steps_json = gr.Code(
label="Steps Data",
value=EXAMPLE_STEPS,
language="json",
lines=12
)
with gr.Row():
gr.Button("πŸ“± Mobile Example", size="sm").click(
fn=lambda: ("Mobile App Onboarding", MOBILE_STEPS),
outputs=[journey_title, steps_json]
)
gr.Button("πŸ›’ E-commerce Example", size="sm").click(
fn=lambda: ("E-commerce Purchase Flow", ECOMMERCE_STEPS),
outputs=[journey_title, steps_json]
)
generate_btn = gr.Button(
"🎨 Generate Journey Diagram",
variant="primary",
size="lg"
)
with gr.Column(scale=1):
gr.Markdown("### πŸ–ΌοΈ Generated Diagram")
output_image = gr.Image(
label="User Journey Visualization",
type="pil",
height=500
)
status_text = gr.Textbox(
label="Status",
interactive=False,
lines=3
)
generate_btn.click(
fn=generate_journey_diagram,
inputs=[api_key, journey_title, steps_json, model, width, height],
outputs=[output_image, status_text]
)
gr.HTML("""
<div class="links">
<p>
🌐 <a href="https://nexa-api.com" target="_blank">nexa-api.com</a> &nbsp;|&nbsp;
πŸ“¦ <a href="https://pypi.org/project/nexaapi" target="_blank">PyPI</a> &nbsp;|&nbsp;
πŸ“¦ <a href="https://npmjs.com/package/nexaapi" target="_blank">npm</a> &nbsp;|&nbsp;
πŸ”— <a href="https://rapidapi.com/user/nexaquency" target="_blank">RapidAPI</a>
</p>
<p style="color: #666; font-size: 12px;">
Powered by NexaAPI β€” 38+ AI models, one API key
</p>
</div>
""")
if __name__ == "__main__":
demo.launch()