apix/app/api/references/upload/route.ts
Khoa.vo 8741e3b89f
Some checks are pending
CI / build (18.x) (push) Waiting to run
CI / build (20.x) (push) Waiting to run
feat: Initial commit with multi-provider image generation
2026-01-05 13:50:35 +07:00

99 lines
4.3 KiB
TypeScript

import { NextResponse } from 'next/server';
import { WhiskClient } from '@/lib/whisk-client';
export async function POST(req: Request) {
try {
const { imageBase64, mimeType, category, cookies } = await req.json();
if (!imageBase64 || !mimeType || !category || !cookies) {
const missing = [];
if (!imageBase64) missing.push('imageBase64');
if (!mimeType) missing.push('mimeType');
if (!category) missing.push('category');
if (!cookies) missing.push('cookies');
return NextResponse.json({ error: `Missing required fields: ${missing.join(', ')}` }, { status: 400 });
}
// 1. Validate MIME Type
const allowedTypes = ['image/jpeg', 'image/png', 'image/webp', 'image/gif'];
if (!allowedTypes.includes(mimeType)) {
return NextResponse.json({ error: `Unsupported file type: ${mimeType}. Please use JPG, PNG, or WEBP.` }, { status: 400 });
}
// 2. Normalize and Validate Cookies
let validCookies = cookies.trim();
let isJson = false;
let parsedCookies = "";
// Auto-fix: Handle JSON array (e.g. from Cookie-Editor export)
if (validCookies.startsWith('[') || validCookies.startsWith('{')) {
isJson = true;
try {
const cookieArray = JSON.parse(validCookies);
if (Array.isArray(cookieArray)) {
// Convert ALL cookies to a string, not just 1PSID
parsedCookies = cookieArray
.map((c: any) => `${c.name}=${c.value}`)
.join('; ');
console.log(`[API] Successfully parsed ${cookieArray.length} cookies from JSON.`);
validCookies = parsedCookies;
} else if (cookieArray.name && cookieArray.value) {
validCookies = `${cookieArray.name}=${cookieArray.value}`;
}
} catch (e) {
console.warn("[API] Failed to parse cookie JSON, falling back to raw value:", e);
// If parsing fails, just use the raw string, maybe it's not JSON after all.
}
}
// Auto-fix: If user pasted just a raw value (heuristic)
if (!isJson && !validCookies.includes('=')) {
// If it's a long string without =, it might be a raw token.
// We can't know the key, so we might guess `__Secure-1PSID` but that failed before.
// Let's assume if it's raw, it's garbage unless we know for sure.
// But actually, we previously tried prepending. Let's keep that only if we are desperate.
// For now, let's just use what we have.
if (validCookies.length > 50) {
validCookies = `__Secure-1PSID=${validCookies}`; // Last resort guess
}
}
// 3. Relaxed Validation: Don't error if 1PSID is missing, just try.
// Some users might have different cookie names (e.g. __Secure-3PSID).
if (!validCookies.includes('=')) {
return NextResponse.json({
error: 'Invalid Cookie Format',
details: 'Cookies must be in "name=value" format or a JSON list.'
}, { status: 400 });
}
console.log(`[API] Uploading reference image (${category}, ${mimeType})...`);
console.log(`[API] Using cookies (first 50 chars): ${validCookies.substring(0, 50)}...`);
const client = new WhiskClient(validCookies);
// Remove header if present for WhiskClient (it expects clean base64 sometimes, or maybe not?
// whisk-client.ts uploadReferenceImage constructs dataUri itself: `data:${mimeType};base64,${fileBase64}`
// So we should pass RAW base64 without header.
const rawBase64 = imageBase64.replace(/^data:image\/\w+;base64,/, "");
const mediaId = await client.uploadReferenceImage(rawBase64, mimeType, category);
if (!mediaId) {
return NextResponse.json({ error: 'Upload returned no ID' }, { status: 500 });
}
return NextResponse.json({ success: true, id: mediaId });
} catch (error: any) {
console.error("Reference Upload API failed:", error);
return NextResponse.json({
error: error.message || 'Upload failed',
details: error.toString()
}, { status: 500 });
}
}