feat(frontend): POST for images
This commit is contained in:
@@ -2,6 +2,22 @@ import { api } from '$lib/convex/_generated/api';
|
|||||||
import { error } from '@sveltejs/kit';
|
import { error } from '@sveltejs/kit';
|
||||||
import type { RequestHandler } from './$types';
|
import type { RequestHandler } from './$types';
|
||||||
|
|
||||||
|
function detectImageType(bytes: Uint8Array): string | null {
|
||||||
|
if (bytes[0] === 0xff && bytes[1] === 0xd8 && bytes[2] === 0xff) {
|
||||||
|
return 'image/jpeg';
|
||||||
|
}
|
||||||
|
if (bytes[0] === 0x89 && bytes[1] === 0x50 && bytes[2] === 0x4e && bytes[3] === 0x47) {
|
||||||
|
return 'image/png';
|
||||||
|
}
|
||||||
|
if (bytes[0] === 0x47 && bytes[1] === 0x49 && bytes[2] === 0x46) {
|
||||||
|
return 'image/gif';
|
||||||
|
}
|
||||||
|
if (bytes[0] === 0x52 && bytes[1] === 0x49 && bytes[2] === 0x46 && bytes[3] === 0x46) {
|
||||||
|
return 'image/webp';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
export const POST: RequestHandler = async ({ params, request, locals }) => {
|
export const POST: RequestHandler = async ({ params, request, locals }) => {
|
||||||
const mnemonic = params.mnemonic;
|
const mnemonic = params.mnemonic;
|
||||||
|
|
||||||
@@ -10,22 +26,54 @@ export const POST: RequestHandler = async ({ params, request, locals }) => {
|
|||||||
throw error(404, 'Chat not found');
|
throw error(404, 'Chat not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
const contentType = request.headers.get('content-type') || 'image/jpeg';
|
const rawContentType = request.headers.get('content-type') || '';
|
||||||
const buffer = await request.arrayBuffer();
|
|
||||||
const base64 = Buffer.from(buffer).toString('base64');
|
|
||||||
|
|
||||||
const caption = request.headers.get('x-caption') || '';
|
const caption = request.headers.get('x-caption') || '';
|
||||||
|
|
||||||
|
console.log('[POST /{mnemonic}] headers:', Object.fromEntries(request.headers.entries()));
|
||||||
|
console.log('[POST /{mnemonic}] content-type:', rawContentType);
|
||||||
|
|
||||||
|
let base64: string;
|
||||||
|
let mediaType: string;
|
||||||
|
|
||||||
|
if (rawContentType.includes('multipart/form-data')) {
|
||||||
|
const formData = await request.formData();
|
||||||
|
console.log('[POST /{mnemonic}] formData keys:', [...formData.keys()]);
|
||||||
|
|
||||||
|
const file = formData.get('file') || formData.get('image') || formData.values().next().value;
|
||||||
|
if (!(file instanceof File)) {
|
||||||
|
throw error(400, 'No file found in form data');
|
||||||
|
}
|
||||||
|
|
||||||
|
const buffer = await file.arrayBuffer();
|
||||||
|
const bytes = new Uint8Array(buffer);
|
||||||
|
base64 = Buffer.from(buffer).toString('base64');
|
||||||
|
mediaType = detectImageType(bytes) || file.type || 'image/jpeg';
|
||||||
|
|
||||||
|
console.log('[POST /{mnemonic}] file:', file.name, file.type, 'size:', buffer.byteLength);
|
||||||
|
} else {
|
||||||
|
const buffer = await request.arrayBuffer();
|
||||||
|
const bytes = new Uint8Array(buffer);
|
||||||
|
base64 = Buffer.from(buffer).toString('base64');
|
||||||
|
mediaType = detectImageType(bytes) || rawContentType || 'image/jpeg';
|
||||||
|
|
||||||
|
console.log('[POST /{mnemonic}] raw bytes size:', buffer.byteLength);
|
||||||
|
console.log('[POST /{mnemonic}] detected type:', mediaType);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!base64 || base64.length === 0) {
|
||||||
|
throw error(400, 'Empty image data');
|
||||||
|
}
|
||||||
|
|
||||||
await locals.convex.mutation(api.messages.create, {
|
await locals.convex.mutation(api.messages.create, {
|
||||||
chatId: chatData._id,
|
chatId: chatData._id,
|
||||||
role: 'user',
|
role: 'user',
|
||||||
content: caption,
|
content: caption,
|
||||||
source: 'web',
|
source: 'web',
|
||||||
imageBase64: base64,
|
imageBase64: base64,
|
||||||
imageMediaType: contentType
|
imageMediaType: mediaType
|
||||||
});
|
});
|
||||||
|
|
||||||
return new Response(JSON.stringify({ ok: true }), {
|
return new Response(JSON.stringify({ ok: true, mediaType, size: base64.length }), {
|
||||||
headers: { 'Content-Type': 'application/json' }
|
headers: { 'Content-Type': 'application/json' }
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user