Spaces:
Runtime error
Runtime error
| import json | |
| import gradio as gr | |
| TITLE = "AppDraft" | |
| STACKS = [ | |
| "Next.js + TypeScript", | |
| "React + Vite", | |
| "FastAPI + React", | |
| "Flask + HTMX", | |
| "Electron + React", | |
| "React Native + Expo", | |
| "Vue 3 + TypeScript", | |
| "SvelteKit", | |
| ] | |
| PLATFORMS = [ | |
| "Web app", | |
| "Mobile app", | |
| "Desktop app", | |
| "Marketplace", | |
| "SaaS dashboard", | |
| "Landing page + app", | |
| "Browser extension", | |
| "CLI tool", | |
| ] | |
| STYLES = [ | |
| "Minimal modern", | |
| "Dark SaaS", | |
| "Bold startup", | |
| "Playful consumer", | |
| "Enterprise clean", | |
| "Mobile-first utility", | |
| "Glassmorphism", | |
| "Retro terminal", | |
| ] | |
| AUTHS = ["Email + password", "Magic link", "OAuth (Google/GitHub)", "No auth"] | |
| DATABASES = ["PostgreSQL", "Supabase", "SQLite", "MongoDB", "Firebase", "PlanetScale", "Turso"] | |
| EXTRAS = ["Payments", "Notifications", "Admin panel", "AI features", "File uploads", "Realtime", "Search", "Analytics"] | |
| def slugify(value: str) -> str: | |
| value = (value or "my-app").strip().lower() | |
| out = [] | |
| for ch in value: | |
| if ch.isalnum(): | |
| out.append(ch) | |
| elif ch in {" ", "_", ".", "/", "-"}: | |
| out.append("-") | |
| slug = "".join(out) | |
| while "--" in slug: | |
| slug = slug.replace("--", "-") | |
| return slug.strip("-") or "my-app" | |
| def build_pack(app_idea, stack, platform, style, auth, database, extras): | |
| if not app_idea or not app_idea.strip(): | |
| return ( | |
| "## No input\n\nPlease describe your app idea in the box above.", | |
| "", "", "", "", "", "", "" | |
| ) | |
| app_name = app_idea.strip().split("\n")[0][:60] or "My App" | |
| slug = slugify(app_name) | |
| extras = extras or [] | |
| feature_pool = [ | |
| "Authentication and user onboarding" if auth != "No auth" else "Guest-friendly onboarding and local session flow", | |
| "Dashboard or home view with quick actions", | |
| "Create, edit, and delete core records", | |
| "Search, filter, and sort data", | |
| "Responsive mobile-friendly UI", | |
| "Error, loading, and empty states throughout", | |
| "Activity history and analytics", | |
| ] | |
| if "Payments" in extras: | |
| feature_pool.append("Subscriptions, billing, and checkout flow") | |
| if "Notifications" in extras: | |
| feature_pool.append("Email and in-app notification system") | |
| if "Admin panel" in extras: | |
| feature_pool.append("Role-based admin panel and moderation tools") | |
| if "AI features" in extras: | |
| feature_pool.append("AI-powered generation, summarization, or recommendations") | |
| if "File uploads" in extras: | |
| feature_pool.append("Secure file upload and storage pipeline") | |
| if "Realtime" in extras: | |
| feature_pool.append("Realtime collaboration or live activity updates") | |
| if "Search" in extras: | |
| feature_pool.append("Full-text search with filters and indexing") | |
| if "Analytics" in extras: | |
| feature_pool.append("Usage analytics dashboard and event tracking") | |
| pages = [ | |
| "Landing / marketing page", | |
| "Sign in / sign up" if auth != "No auth" else "Welcome / guest entry", | |
| "Main dashboard", | |
| "List view with filters", | |
| "Detail / single record view", | |
| "Create and edit form", | |
| "User settings and profile", | |
| ] | |
| if "Admin panel" in extras: | |
| pages.append("Admin dashboard and user management") | |
| if "Payments" in extras: | |
| pages.append("Billing and subscription management") | |
| if "Analytics" in extras: | |
| pages.append("Analytics and reporting dashboard") | |
| components = [ | |
| "Navbar and app shell", | |
| "Sidebar or tab navigation", | |
| "Hero or empty state block", | |
| "Data cards and tables", | |
| "Modal and drawer for quick actions", | |
| "Toast and alert notification system", | |
| "Form inputs with validation feedback", | |
| "Loading skeletons and spinners", | |
| "Confirmation dialogs", | |
| ] | |
| tables = [ | |
| { | |
| "table": "users", | |
| "fields": ["id", "email", "password_hash", "role", "created_at"] | |
| if auth != "No auth" | |
| else ["id", "device_id", "display_name", "created_at"], | |
| }, | |
| { | |
| "table": "projects", | |
| "fields": ["id", "owner_id", "title", "description", "status", "created_at", "updated_at"], | |
| }, | |
| { | |
| "table": "items", | |
| "fields": ["id", "project_id", "title", "content", "type", "order", "created_at", "updated_at"], | |
| }, | |
| { | |
| "table": "activity_logs", | |
| "fields": ["id", "user_id", "action", "entity_type", "entity_id", "metadata", "created_at"], | |
| }, | |
| ] | |
| if "Payments" in extras: | |
| tables.append({"table": "subscriptions", "fields": ["id", "user_id", "plan", "status", "provider_customer_id", "renewal_date"]}) | |
| if "Notifications" in extras: | |
| tables.append({"table": "notifications", "fields": ["id", "user_id", "type", "title", "body", "read_at", "created_at"]}) | |
| if "File uploads" in extras: | |
| tables.append({"table": "files", "fields": ["id", "owner_id", "entity_id", "filename", "mime_type", "storage_url", "size_bytes", "created_at"]}) | |
| if "Analytics" in extras: | |
| tables.append({"table": "events", "fields": ["id", "user_id", "event_name", "properties", "session_id", "created_at"]}) | |
| endpoints = [ | |
| "POST /api/auth/register" if auth != "No auth" else "POST /api/session/start", | |
| "POST /api/auth/login" if auth != "No auth" else "GET /api/session", | |
| "POST /api/auth/logout" if auth != "No auth" else "", | |
| "GET /api/projects", | |
| "POST /api/projects", | |
| "GET /api/projects/:id", | |
| "PUT /api/projects/:id", | |
| "DELETE /api/projects/:id", | |
| "GET /api/items?projectId=:id", | |
| "POST /api/items", | |
| "PUT /api/items/:id", | |
| "DELETE /api/items/:id", | |
| ] | |
| endpoints = [e for e in endpoints if e] | |
| if "Payments" in extras: | |
| endpoints += ["POST /api/billing/checkout", "GET /api/billing/subscription", "POST /api/billing/cancel"] | |
| if "Notifications" in extras: | |
| endpoints += ["GET /api/notifications", "POST /api/notifications/mark-read"] | |
| if "File uploads" in extras: | |
| endpoints += ["POST /api/files/upload", "GET /api/files", "DELETE /api/files/:id"] | |
| if "Search" in extras: | |
| endpoints += ["GET /api/search?q=:query"] | |
| folder_tree = f"""{slug}/ | |
| ├── app/ | |
| │ ├── components/ | |
| │ │ ├── ui/ | |
| │ │ ├── forms/ | |
| │ │ └── layout/ | |
| │ ├── pages/ | |
| │ ├── hooks/ | |
| │ ├── services/ | |
| │ ├── lib/ | |
| │ └── styles/ | |
| ├── server/ | |
| │ ├── routes/ | |
| │ ├── controllers/ | |
| │ ├── middleware/ | |
| │ └── models/ | |
| ├── database/ | |
| │ ├── schema.sql | |
| │ ├── migrations/ | |
| │ └── seed.sql | |
| ├── public/ | |
| │ └── assets/ | |
| ├── tests/ | |
| │ ├── unit/ | |
| │ └── integration/ | |
| ├── .env.example | |
| ├── .gitignore | |
| ├── README.md | |
| └── package.json""" | |
| starter_code = f"""# {app_name} - Starter Code | |
| ## Stack | |
| - Frontend: {stack} | |
| - Platform: {platform} | |
| - UI Style: {style} | |
| - Auth: {auth} | |
| - Database: {database} | |
| - Extras: {', '.join(extras) if extras else 'None'} | |
| --- | |
| ## App Shell | |
| ```tsx | |
| // app/layout.tsx | |
| export default function RootLayout({{ children }}: {{ children: React.ReactNode }}) {{ | |
| return ( | |
| <html lang="en"> | |
| <body> | |
| <nav className="navbar"> | |
| <h1>{app_name}</h1> | |
| </nav> | |
| <main className="main-content"> | |
| {{children}} | |
| </main> | |
| </body> | |
| </html> | |
| ); | |
| }} | |
| ``` | |
| ## API Service | |
| ```ts | |
| // app/services/api.ts | |
| const BASE = '/api'; | |
| export async function fetchProjects() {{ | |
| const res = await fetch(`${{BASE}}/projects`); | |
| if (!res.ok) throw new Error('Failed to load projects'); | |
| return res.json(); | |
| }} | |
| export async function createProject(data: {{ title: string; description: string }}) {{ | |
| const res = await fetch(`${{BASE}}/projects`, {{ | |
| method: 'POST', | |
| headers: {{ 'Content-Type': 'application/json' }}, | |
| body: JSON.stringify(data), | |
| }}); | |
| if (!res.ok) throw new Error('Failed to create project'); | |
| return res.json(); | |
| }} | |
| ``` | |
| ## Database Schema | |
| ```sql | |
| -- database/schema.sql | |
| CREATE TABLE projects ( | |
| id UUID PRIMARY KEY DEFAULT gen_random_uuid(), | |
| owner_id UUID NOT NULL, | |
| title TEXT NOT NULL, | |
| description TEXT, | |
| status TEXT DEFAULT 'draft', | |
| created_at TIMESTAMP DEFAULT NOW(), | |
| updated_at TIMESTAMP DEFAULT NOW() | |
| ); | |
| CREATE TABLE items ( | |
| id UUID PRIMARY KEY DEFAULT gen_random_uuid(), | |
| project_id UUID REFERENCES projects(id) ON DELETE CASCADE, | |
| title TEXT NOT NULL, | |
| content TEXT, | |
| type TEXT DEFAULT 'default', | |
| "order" INT DEFAULT 0, | |
| created_at TIMESTAMP DEFAULT NOW(), | |
| updated_at TIMESTAMP DEFAULT NOW() | |
| ); | |
| ``` | |
| ## Environment Variables | |
| ```env | |
| # .env.example | |
| DATABASE_URL= | |
| NEXT_PUBLIC_API_URL= | |
| JWT_SECRET= | |
| NODE_ENV=development | |
| ``` | |
| """ | |
| prd = f"""# Product Requirements Document | |
| ## App Name | |
| **{app_name}** | |
| ## Idea | |
| {app_idea} | |
| --- | |
| ## Target Platform | |
| {platform} | |
| ## Tech Stack | |
| {stack} | |
| ## Design Style | |
| {style} | |
| ## Auth Strategy | |
| {auth} | |
| ## Database | |
| {database} | |
| ## Extra Features | |
| {', '.join(extras) if extras else 'None selected'} | |
| --- | |
| ## Experience Goal | |
| Build a {style.lower()} {platform.lower()} that feels fast and intuitive. | |
| Users should be able to get value within 60 seconds of opening the app. | |
| --- | |
| ## Core Features | |
| """ + "\n".join(f"- {item}" for item in feature_pool) | |
| ui_plan = f"""# UI Plan | |
| ## Pages ({len(pages)} total) | |
| """ + "\n".join(f"- {p}" for p in pages) + f""" | |
| --- | |
| ## Components ({len(components)} total) | |
| """ + "\n".join(f"- {c}" for c in components) + """ | |
| --- | |
| ## Design Tokens | |
| - Use a consistent spacing scale: 4, 8, 12, 16, 24, 32, 48px | |
| - Font sizes: 12, 14, 16, 20, 24, 32px | |
| - Border radius: 4px (inputs), 8px (cards), 16px (modals) | |
| - Transitions: 150ms ease for hover, 250ms ease for modals | |
| ## Accessibility | |
| - All interactive elements must be keyboard navigable | |
| - ARIA labels on icon-only buttons | |
| - Color contrast ratio minimum 4.5:1 | |
| - Focus indicators on all inputs | |
| """ | |
| db_plan = "# Database Plan\n\n" + "\n\n".join( | |
| f"## Table: `{t['table']}`\n" + "\n".join(f"- `{field}`" for field in t["fields"]) | |
| for t in tables | |
| ) + """ | |
| --- | |
| ## Indexes to add | |
| - Index on `owner_id` for all user-owned tables | |
| - Index on `created_at` for time-sorted queries | |
| - Index on `status` for filtered list views | |
| ## Relationships | |
| - projects.owner_id -> users.id | |
| - items.project_id -> projects.id (CASCADE DELETE) | |
| - activity_logs.user_id -> users.id | |
| """ | |
| api_plan = "# API Routes\n\n" + "\n".join(f"- `{route}`" for route in endpoints) + """ | |
| --- | |
| ## Auth headers | |
| All protected routes require: | |
| ``` | |
| Authorization: Bearer <token> | |
| ``` | |
| ## Error format | |
| ```json | |
| { | |
| "error": true, | |
| "message": "Human readable message", | |
| "code": "ERROR_CODE" | |
| } | |
| ``` | |
| ## Success format | |
| ```json | |
| { | |
| "data": {}, | |
| "meta": { "total": 0, "page": 1 } | |
| } | |
| ``` | |
| """ | |
| system_prompt = f"""You are a senior full-stack engineer and product architect. | |
| Build a complete, production-ready application based on the following spec: | |
| APP IDEA: {app_idea} | |
| STACK: | |
| - Framework: {stack} | |
| - Platform: {platform} | |
| - Design style: {style} | |
| - Auth: {auth} | |
| - Database: {database} | |
| - Extra features: {', '.join(extras) if extras else 'None'} | |
| DELIVER THE FOLLOWING IN ORDER: | |
| 1. Folder structure with all files listed | |
| 2. package.json / requirements.txt with all dependencies | |
| 3. Database schema (full SQL or ORM models) | |
| 4. Auth implementation | |
| 5. Core API routes with full handler code | |
| 6. Frontend pages: layout, dashboard, list, detail, form | |
| 7. Reusable UI components | |
| 8. Environment variable template | |
| 9. README with setup instructions | |
| RULES: | |
| - Write real, working code. No placeholders. | |
| - Use TypeScript where applicable. | |
| - Follow the {style.lower()} design system. | |
| - All code must be copy-paste ready into an IDE. | |
| - Keep files under 200 lines each.""" | |
| json_export = json.dumps( | |
| { | |
| "name": app_name, | |
| "slug": slug, | |
| "stack": stack, | |
| "platform": platform, | |
| "style": style, | |
| "auth": auth, | |
| "database": database, | |
| "extras": extras, | |
| "features": feature_pool, | |
| "pages": pages, | |
| "components": components, | |
| "tables": [{"table": t["table"], "fields": t["fields"]} for t in tables], | |
| "endpoints": endpoints, | |
| "folder_tree": folder_tree, | |
| }, | |
| indent=2, | |
| ) | |
| return prd, ui_plan, db_plan, api_plan, folder_tree, starter_code, system_prompt, json_export | |
| WELCOME = """ | |
| # AppDraft | |
| Describe your app idea below, pick your stack and options, then hit **Generate**. | |
| You'll get a full build pack across 8 tabs that you can copy straight into your IDE. | |
| | Tab | What you get | | |
| |---|---| | |
| | PRD | Product requirements, goals, and feature list | | |
| | UI | Pages, components, and design tokens | | |
| | Database | Tables, fields, indexes, and relationships | | |
| | API | All routes with auth and error format | | |
| | Structure | Full folder and file tree | | |
| | Starter code | App shell, services, schema, env template | | |
| | Prompt | Paste this into any AI to generate the full app | | |
| | JSON | Machine-readable export of the entire spec | | |
| """ | |
| with gr.Blocks(title=TITLE) as demo: | |
| gr.Markdown(WELCOME) | |
| with gr.Row(equal_height=False): | |
| with gr.Column(scale=1): | |
| gr.Markdown("### Describe your app") | |
| app_idea = gr.Textbox( | |
| label="App idea", | |
| lines=6, | |
| placeholder="Example: A habit tracker for developers with streaks, GitHub integration, daily standups, and a public profile page.", | |
| show_label=False, | |
| ) | |
| gr.Markdown("### Stack and options") | |
| stack = gr.Dropdown(STACKS, value="Next.js + TypeScript", label="Target stack") | |
| platform = gr.Dropdown(PLATFORMS, value="Web app", label="Platform") | |
| style = gr.Dropdown(STYLES, value="Dark SaaS", label="Design style") | |
| auth = gr.Dropdown(AUTHS, value="Email + password", label="Auth") | |
| database = gr.Dropdown(DATABASES, value="PostgreSQL", label="Database") | |
| gr.Markdown("### Extra features") | |
| extras = gr.CheckboxGroup(EXTRAS, label="", value=[]) | |
| generate = gr.Button("Generate build pack", variant="primary", size="lg") | |
| with gr.Column(scale=2): | |
| gr.Markdown("### Your build pack") | |
| with gr.Tabs(): | |
| with gr.Tab("PRD"): | |
| prd_out = gr.Markdown(value="*Fill in the form and click Generate to build your pack.*") | |
| with gr.Tab("UI"): | |
| ui_out = gr.Markdown() | |
| with gr.Tab("Database"): | |
| db_out = gr.Markdown() | |
| with gr.Tab("API"): | |
| api_out = gr.Markdown() | |
| with gr.Tab("Structure"): | |
| tree_out = gr.Textbox(lines=20, label="Folder tree", show_copy_button=True) | |
| with gr.Tab("Starter code"): | |
| starter_out = gr.Markdown() | |
| with gr.Tab("Prompt"): | |
| prompt_out = gr.Code(language="markdown", label="Copy this prompt into any AI") | |
| with gr.Tab("JSON"): | |
| json_out = gr.Code(language="json", label="Full spec export") | |
| generate.click( | |
| fn=build_pack, | |
| inputs=[app_idea, stack, platform, style, auth, database, extras], | |
| outputs=[prd_out, ui_out, db_out, api_out, tree_out, starter_out, prompt_out, json_out], | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() | |