File Upload & Attachments
When to Use
Use
imagesfor image upload/analysis. UsemixedFilesfor any file type (PDFs, docs). Always validate file types server-side.
Decision
| Feature | Use Case |
|---|---|
images |
Image upload/analysis |
camera |
Web camera capture |
audio |
Audio file upload |
microphone |
Voice recording |
mixedFiles |
Any file type (PDFs, docs) |
dragAndDrop |
Better UX for files |
Enable Image Upload
<DeepChat
images={true}
connect={{
url: '/api/chat',
method: 'POST',
}}
/>
Custom File Configuration
<DeepChat
images={{
files: {
maxNumberOfFiles: 5,
acceptedFormats: '.jpg,.png,.gif',
},
button: {
position: 'inside-left',
},
}}
/>
Mixed Files
<DeepChat
mixedFiles={{
files: {
maxNumberOfFiles: 3,
acceptedFormats: '.pdf,.docx,.txt',
infoModal: {
textMarkDown: 'Upload up to 3 files (PDF, DOCX, TXT)',
},
},
}}
/>
Drag and Drop
<DeepChat
images={true}
dragAndDrop={true}
/>
Request Format
When files are uploaded, DeepChat sends FormData instead of JSON:
FormData {
'message0': '{"role":"user","text":"Analyze this"}',
'files': File { name: 'image.jpg', ... },
'files': File { name: 'document.pdf', ... }
}
API Route Handler
export async function POST(request: NextRequest) {
const contentType = request.headers.get('content-type');
if (contentType?.includes('multipart/form-data')) {
// File upload
const formData = await request.formData();
const files = formData.getAll('files') as File[];
const message = JSON.parse(formData.get('message0') as string);
// Process files
const fileBuffers = await Promise.all(
files.map(async (file) => ({
name: file.name,
type: file.type,
buffer: Buffer.from(await file.arrayBuffer()),
}))
);
// Send to AI provider with files
const response = await processWithFiles(message.text, fileBuffers);
return NextResponse.json({ html: response });
} else {
// Text-only message
const body = await request.json();
// ...
}
}
Image Analysis (OpenAI Vision)
async function analyzeImage(text: string, imageBuffer: Buffer) {
const base64Image = imageBuffer.toString('base64');
const response = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: 'gpt-4-vision-preview',
messages: [
{
role: 'user',
content: [
{ type: 'text', text },
{
type: 'image_url',
image_url: {
url: `data:image/jpeg;base64,${base64Image}`,
},
},
],
},
],
max_tokens: 1000,
}),
});
const data = await response.json();
return data.choices[0].message.content;
}
Pattern
// Reusable file processor
async function processFiles(formData: FormData) {
const files = formData.getAll('files') as File[];
const message = JSON.parse(formData.get('message0') as string);
const processedFiles = await Promise.all(
files.map(async (file) => {
const buffer = Buffer.from(await file.arrayBuffer());
if (file.type.startsWith('image/')) {
return { type: 'image', buffer, name: file.name };
} else if (file.type === 'application/pdf') {
return { type: 'pdf', buffer, name: file.name };
} else {
return { type: 'other', buffer, name: file.name };
}
})
);
return { message, files: processedFiles };
}
Common Mistakes
- Wrong: Not checking
content-typeheader → Right: Check formultipart/form-databeforerequest.formData()to avoid parsing errors - Wrong: Using
request.json()on file upload → Right: Files are FormData, not JSON. This will throw an error - Wrong: Not converting File to Buffer → Right: AI APIs expect base64 or binary. Use
arrayBuffer()and Buffer - Wrong: Forgetting to limit file size → Right: Set
maxNumberOfFilesand validate size server-side - Wrong: Not validating file types → Right:
acceptedFormatsis client-side only. Validate MIME type server-side - Wrong: Sending large files to AI without compression → Right: Compress images before base64 encoding
See Also
- AI Provider Integration
- Security
- Reference: https://deepchat.dev/docs/files/