Spaces:
Running
Running
| 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> | | |
| π¦ <a href="https://pypi.org/project/nexaapi" target="_blank">PyPI</a> | | |
| π¦ <a href="https://npmjs.com/package/nexaapi" target="_blank">npm</a> | | |
| π <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() | |