page.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. import Link from "next/link";
  2. import { Code } from "@/components/code";
  3. export const metadata = {
  4. title: "AI SDK Integration | json-render",
  5. };
  6. export default function AiSdkPage() {
  7. return (
  8. <article>
  9. <h1 className="text-3xl font-bold mb-4">AI SDK Integration</h1>
  10. <p className="text-muted-foreground mb-8">
  11. Use json-render with the Vercel AI SDK for seamless streaming.
  12. </p>
  13. <h2 className="text-xl font-semibold mt-12 mb-4">Installation</h2>
  14. <Code lang="bash">npm install ai</Code>
  15. <h2 className="text-xl font-semibold mt-12 mb-4">API Route Setup</h2>
  16. <Code lang="typescript">{`// app/api/generate/route.ts
  17. import { streamText } from 'ai';
  18. import { catalog } from '@/lib/catalog';
  19. export async function POST(req: Request) {
  20. const { prompt, currentTree } = await req.json();
  21. // Generate system prompt from catalog
  22. const systemPrompt = catalog.prompt();
  23. // Optionally include current UI state for context
  24. const contextPrompt = currentTree
  25. ? \`\\n\\nCurrent UI state:\\n\${JSON.stringify(currentTree, null, 2)}\`
  26. : '';
  27. const result = streamText({
  28. model: 'anthropic/claude-haiku-4.5',
  29. system: systemPrompt + contextPrompt,
  30. prompt,
  31. });
  32. return result.toTextStreamResponse();
  33. }`}</Code>
  34. <h2 className="text-xl font-semibold mt-12 mb-4">Client-Side Hook</h2>
  35. <p className="text-sm text-muted-foreground mb-4">
  36. Use <code className="text-foreground">useUIStream</code> on the client:
  37. </p>
  38. <Code lang="tsx">{`'use client';
  39. import { useUIStream, Renderer } from '@json-render/react';
  40. function GenerativeUI() {
  41. const { spec, isStreaming, error, send } = useUIStream({
  42. api: '/api/generate',
  43. });
  44. return (
  45. <div>
  46. <button
  47. onClick={() => send('Create a dashboard with metrics')}
  48. disabled={isStreaming}
  49. >
  50. {isStreaming ? 'Generating...' : 'Generate'}
  51. </button>
  52. {error && <p className="text-red-500">{error.message}</p>}
  53. <Renderer spec={spec} registry={registry} loading={isStreaming} />
  54. </div>
  55. );
  56. }`}</Code>
  57. <h2 className="text-xl font-semibold mt-12 mb-4">Prompt Engineering</h2>
  58. <p className="text-sm text-muted-foreground mb-4">
  59. The <code className="text-foreground">catalog.prompt()</code> method
  60. creates an optimized system prompt that:
  61. </p>
  62. <ul className="list-disc list-inside text-sm text-muted-foreground space-y-1 mb-4">
  63. <li>Lists all available components and their props</li>
  64. <li>Describes available actions</li>
  65. <li>Specifies the expected JSON output format</li>
  66. <li>Includes examples for better generation</li>
  67. </ul>
  68. <h2 className="text-xl font-semibold mt-12 mb-4">
  69. Custom System Prompts
  70. </h2>
  71. <p className="text-sm text-muted-foreground mb-4">
  72. Pass custom rules to tailor AI behavior:
  73. </p>
  74. <Code lang="typescript">{`const systemPrompt = catalog.prompt({
  75. customRules: [
  76. 'Always use Card components for grouping related content',
  77. 'Prefer horizontal layouts (Row) for metrics',
  78. 'Use consistent spacing with padding="md"',
  79. ],
  80. });`}</Code>
  81. <h2 className="text-xl font-semibold mt-12 mb-4">Next</h2>
  82. <p className="text-sm text-muted-foreground">
  83. Learn about{" "}
  84. <Link
  85. href="/docs/streaming"
  86. className="text-foreground hover:underline"
  87. >
  88. progressive streaming
  89. </Link>
  90. .
  91. </p>
  92. </article>
  93. );
  94. }