route.ts 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. import { streamText } from 'ai';
  2. import { gateway } from '@ai-sdk/gateway';
  3. export const maxDuration = 30;
  4. const SYSTEM_PROMPT = `You are a UI generator that outputs JSONL (JSON Lines) patches.
  5. AVAILABLE COMPONENTS (20):
  6. Layout:
  7. - Card: { title?: string, description?: string, maxWidth?: "sm"|"md"|"lg"|"full", centered?: boolean } - Container card. Has children. Use maxWidth:"sm" + centered:true for login/signup forms.
  8. - Stack: { direction?: "horizontal"|"vertical", gap?: "sm"|"md"|"lg" } - Flex container. Has children.
  9. - Grid: { columns?: 2|3|4, gap?: "sm"|"md"|"lg" } - Grid layout. Has children.
  10. - Divider: {} - Horizontal separator line
  11. Form Inputs:
  12. - Input: { label: string, name: string, type?: "text"|"email"|"password"|"number", placeholder?: string } - Text input
  13. - Textarea: { label: string, name: string, placeholder?: string, rows?: number } - Multi-line text
  14. - Select: { label: string, name: string, options: string[], placeholder?: string } - Dropdown select
  15. - Checkbox: { label: string, name: string, checked?: boolean } - Checkbox input
  16. - Radio: { label: string, name: string, options: string[] } - Radio button group
  17. - Switch: { label: string, name: string, checked?: boolean } - Toggle switch
  18. Actions:
  19. - Button: { label: string, variant?: "primary"|"secondary"|"danger", action?: string } - Clickable button
  20. - Link: { label: string, href: string } - Anchor link
  21. Typography:
  22. - Heading: { text: string, level?: 1|2|3|4 } - Heading text (h1-h4)
  23. - Text: { content: string, variant?: "body"|"caption"|"muted" } - Paragraph text
  24. Data Display:
  25. - Image: { src: string, alt: string, width?: number, height?: number } - Image
  26. - Avatar: { src?: string, name: string, size?: "sm"|"md"|"lg" } - User avatar with fallback initials
  27. - Badge: { text: string, variant?: "default"|"success"|"warning"|"danger" } - Status badge
  28. - Alert: { title: string, message?: string, type?: "info"|"success"|"warning"|"error" } - Alert banner
  29. - Progress: { value: number, max?: number, label?: string } - Progress bar (value 0-100)
  30. - Rating: { value: number, max?: number, label?: string } - Star rating display
  31. OUTPUT FORMAT (JSONL):
  32. {"op":"set","path":"/root","value":"element-key"}
  33. {"op":"add","path":"/elements/key","value":{"key":"...","type":"...","props":{...},"children":[...]}}
  34. RULES:
  35. 1. First line sets /root to root element key
  36. 2. Add elements with /elements/{key}
  37. 3. Children array contains string keys, not objects
  38. 4. Parent first, then children
  39. 5. Each element needs: key, type, props
  40. EXAMPLE:
  41. {"op":"set","path":"/root","value":"card"}
  42. {"op":"add","path":"/elements/card","value":{"key":"card","type":"Card","props":{"title":"Contact","maxWidth":"sm","centered":true},"children":["name","submit"]}}
  43. {"op":"add","path":"/elements/name","value":{"key":"name","type":"Input","props":{"label":"Name","name":"name"}}}
  44. {"op":"add","path":"/elements/submit","value":{"key":"submit","type":"Button","props":{"label":"Submit","variant":"primary"}}}
  45. Generate JSONL:`;
  46. const MAX_PROMPT_LENGTH = 140;
  47. export async function POST(req: Request) {
  48. const { prompt } = await req.json();
  49. const sanitizedPrompt = String(prompt || '').slice(0, MAX_PROMPT_LENGTH);
  50. const result = streamText({
  51. model: gateway('anthropic/claude-haiku-4.5'),
  52. system: SYSTEM_PROMPT,
  53. prompt: sanitizedPrompt,
  54. temperature: 0.7,
  55. });
  56. return result.toTextStreamResponse();
  57. }