import { guarded, json } from "@/lib/api"; import { saveAttachment, extractText, allowedMime } from "@/lib/storage"; import { indexAttachment } from "@/lib/tools/documents"; import { env } from "@/lib/env"; export const maxDuration = 120; /** multipart/form-data: file (repeatable), conversationId?, projectId? */ export const POST = guarded(async (req) => { const form = await req.formData(); const conversationId = (form.get("conversationId") as string | null) || null; const projectId = (form.get("projectId") as string | null) || null; const files = form.getAll("file").filter((f): f is File => f instanceof File); if (!files.length) return json({ error: "Aucun fichier" }, { status: 400 }); const out = []; for (const f of files) { if (f.size > env.MAX_UPLOAD_MB * 1024 * 1024) return json({ error: `${f.name} dépasse ${env.MAX_UPLOAD_MB} Mo` }, { status: 413 }); let mime = f.type || "application/octet-stream"; if (mime === "application/octet-stream" || mime === "") { const ext = f.name.split(".").pop()?.toLowerCase(); mime = ({ md: "text/markdown", txt: "text/plain", csv: "text/csv", json: "application/json", pdf: "application/pdf", docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", png: "image/png", jpg: "image/jpeg", jpeg: "image/jpeg", webp: "image/webp", m4a: "audio/mp4", mp3: "audio/mpeg" } as Record)[ext ?? ""] ?? mime; } if (!allowedMime(mime)) return json({ error: `Type non pris en charge : ${mime}` }, { status: 415 }); const data = Buffer.from(await f.arrayBuffer()); const ext = mime.startsWith("image/") || mime.startsWith("audio/") ? { text: null as string | null } : await extractText(data, mime, f.name); const att = await saveAttachment({ data, filename: f.name, mime, conversationId, projectId, extractedText: ext.text, pageCount: "pages" in ext ? ext.pages ?? null : null }); if (ext.text && ext.text.length > 2000) void indexAttachment(att.id).catch(() => {}); out.push({ id: att.id, filename: att.filename, mime: att.mime, size: att.size_bytes, pages: att.page_count, chars: ext.text?.length ?? 0 }); } return json({ attachments: out }, { status: 201 }); });