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("""

🗺️ AI User Journey Generator

Generate beautiful user journey diagrams from your analytics data using AI

Inspired by Breadcrumb.ai on Product Hunt 🚀

""") 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(""" """) if __name__ == "__main__": demo.launch()