Generate Object with File Prompt through Form Submission

Learn how to generate object with file prompt through form submission using the AI TOOLKIT and Next.js

2 min readnextmulti-modalView source

This feature is limited to models/providers that support PDF inputs (Anthropic, OpenAI, Google Gemini, and Google Vertex). With select models, you can send PDFs (files) as part of your prompt. Let's create a simple Next.js application that allows a user to upload a PDF send it to an LLM for summarization.

Run it locally

$ npm install ai

Client

On the frontend, create a form that allows the user to upload a PDF. When the form is submitted, send the PDF to the /api/analyze route.

'use client';

import { useState } from 'react';

export default function Page() {

const [description, setDescription] = useState<string>();

const [loading, setLoading] = useState(false);

return (

<div>

<form

action={async formData => {

try {

setLoading(true);

const response = await fetch('/api/analyze', {

method: 'POST',

body: formData,

});

setLoading(false);

if (response.ok) {

setDescription(await response.text());

}

} catch (error) {

console.error('Analysis failed:', error);

}

}}

>

<div>

<label>Upload Image</label>

<input name="pdf" type="file" accept="application/pdf" />

</div>

<button type="submit" disabled={loading}>

Submit{loading && 'ing...'}

</button>

</form>

{description && (

<pre>{JSON.stringify(JSON.parse(description), null, 2)}</pre>

)}

</div>

);

}

app/page.tsx
tsx
  1. 1'use client';
  2. 2import { useState } from 'react';
  3. 3export default function Page() {
  4. 4 const [description, setDescription] = useState<string>();
  5. 5 const [loading, setLoading] = useState(false);
  6. 6 return (
  7. 7 <div>
  8. 8 <form
  9. 9 action={async formData => {
  10. 10 try {
  11. 11 setLoading(true);
  12. 12 const response = await fetch('/api/analyze', {
  13. 13 method: 'POST',
  14. 14 body: formData,
  15. 15 });
  16. 16 setLoading(false);
  17. 17 if (response.ok) {
  18. 18 setDescription(await response.text());
  19. 19 }
  20. 20 } catch (error) {
  21. 21 console.error('Analysis failed:', error);
  22. 22 }
  23. 23 }}
  24. 24 >
  25. 25 <div>
  26. 26 <label>Upload Image</label>
  27. 27 <input name="pdf" type="file" accept="application/pdf" />
  28. 28 </div>
  29. 29 <button type="submit" disabled={loading}>
  30. 30 Submit{loading && 'ing...'}
  31. 31 </button>
  32. 32 </form>
  33. 33 {description && (
  34. 34 <pre>{JSON.stringify(JSON.parse(description), null, 2)}</pre>
  35. 35 )}
  36. 36 </div>
  37. 37 );
  38. 38}

Server

On the server, create an API route that receives the PDF, sends it to the LLM, and returns the result. This example uses the `generateObject` function to generate the summary as part of a structured output.

import { generateObject } from 'ai-toolkit';

import { z } from 'zod';

export async function POST(request: Request) {

const formData = await request.formData();

const file = formData.get('pdf') as File;

// Convert the file's arrayBuffer to a Base64 data URL

const arrayBuffer = await file.arrayBuffer();

const uint8Array = new Uint8Array(arrayBuffer);

// Convert Uint8Array to an array of characters

const charArray = Array.from(uint8Array, byte => String.fromCharCode(byte));

const binaryString = charArray.join('');

const base64Data = btoa(binaryString);

const fileDataUrl = data:application/pdf;base64,${base64Data};

const result = await generateObject({

model: 'openai/gpt-4o',

messages: [

{

role: 'user',

content: [

{

type: 'text',

text: 'Analyze the following PDF and generate a summary.',

},

{

type: 'file',

data: fileDataUrl,

mediaType: 'application/pdf',

},

],

},

],

schema: z.object({

people: z

.object({

name: z.string().describe('The name of the person.'),

age: z.number().min(0).describe('The age of the person.'),

})

.array()

.describe('An array of people.'),

}),

});

return Response.json(result.object);

}

app/api/analyze/route.ts
typescript
  1. 1import { generateObject } from 'ai-toolkit';
  2. 2import { z } from 'zod';
  3. 3export async function POST(request: Request) {
  4. 4 const formData = await request.formData();
  5. 5 const file = formData.get('pdf') as File;
  6. 6 // Convert the file's arrayBuffer to a Base64 data URL
  7. 7 const arrayBuffer = await file.arrayBuffer();
  8. 8 const uint8Array = new Uint8Array(arrayBuffer);
  9. 9 // Convert Uint8Array to an array of characters
  10. 10 const charArray = Array.from(uint8Array, byte => String.fromCharCode(byte));
  11. 11 const binaryString = charArray.join('');
  12. 12 const base64Data = btoa(binaryString);
  13. 13 const fileDataUrl = `data:application/pdf;base64,${base64Data}`;
  14. 14 const result = await generateObject({
  15. 15 model: 'openai/gpt-4o',
  16. 16 messages: [
  17. 17 {
  18. 18 role: 'user',
  19. 19 content: [
  20. 20 {
  21. 21 type: 'text',
  22. 22 text: 'Analyze the following PDF and generate a summary.',
  23. 23 },
  24. 24 {
  25. 25 type: 'file',
  26. 26 data: fileDataUrl,
  27. 27 mediaType: 'application/pdf',
  28. 28 },
  29. 29 ],
  30. 30 },
  31. 31 ],
  32. 32 schema: z.object({
  33. 33 people: z
  34. 34 .object({
  35. 35 name: z.string().describe('The name of the person.'),
  36. 36 age: z.number().min(0).describe('The age of the person.'),
  37. 37 })
  38. 38 .array()
  39. 39 .describe('An array of people.'),
  40. 40 }),
  41. 41 });
  42. 42 return Response.json(result.object);
  43. 43}