- Removed all Grok-related code, API routes, and services - Removed crawl4ai service and meta-crawl client - Simplified Settings to always show cookie inputs for Meta AI - Hid advanced wrapper settings behind collapsible section - Provider selection now only shows Whisk and Meta AI - Fixed unused imports and type definitions
104 lines
3.5 KiB
TypeScript
104 lines
3.5 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server';
|
|
|
|
/**
|
|
* Grok Image Generation API
|
|
* Uses xLmiler/grok2api_python backend with OpenAI-compatible format
|
|
*/
|
|
export async function POST(req: NextRequest) {
|
|
try {
|
|
const body = await req.json();
|
|
const { prompt, numImages = 1, grokApiUrl, apiKey, sso } = body;
|
|
|
|
if (!prompt) {
|
|
return NextResponse.json({ error: "Prompt is required" }, { status: 400 });
|
|
}
|
|
|
|
if (!grokApiUrl) {
|
|
return NextResponse.json({ error: "Grok API URL not configured" }, { status: 400 });
|
|
}
|
|
|
|
console.log(`[Grok Image] Generating ${numImages} image(s) for: "${prompt.substring(0, 50)}..."`);
|
|
|
|
// Call xLmiler backend using OpenAI-compatible format
|
|
const headers: Record<string, string> = {
|
|
'Content-Type': 'application/json',
|
|
};
|
|
|
|
if (apiKey) {
|
|
headers['Authorization'] = `Bearer ${apiKey}`;
|
|
}
|
|
|
|
const response = await fetch(`${grokApiUrl}/v1/chat/completions`, {
|
|
method: 'POST',
|
|
headers,
|
|
body: JSON.stringify({
|
|
model: 'grok-4-imageGen',
|
|
messages: [
|
|
{
|
|
role: 'user',
|
|
content: prompt
|
|
}
|
|
],
|
|
// The xLmiler backend handles image generation via chat completions
|
|
})
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const errorText = await response.text();
|
|
console.error('[Grok Image] Error:', response.status, errorText);
|
|
return NextResponse.json(
|
|
{ error: `Grok API Error: ${response.status} - ${errorText.substring(0, 200)}` },
|
|
{ status: response.status }
|
|
);
|
|
}
|
|
|
|
const data = await response.json();
|
|
console.log('[Grok Image] Response:', JSON.stringify(data, null, 2).substring(0, 500));
|
|
|
|
// Extract image URLs from the response
|
|
// xLmiler returns images in the message content or as markdown images
|
|
const content = data.choices?.[0]?.message?.content || '';
|
|
|
|
// Parse image URLs from markdown format:  or direct URLs
|
|
const imageUrls: string[] = [];
|
|
|
|
// Match markdown image syntax
|
|
const mdImageRegex = /!\[.*?\]\((https?:\/\/[^\s)]+)\)/g;
|
|
let match;
|
|
while ((match = mdImageRegex.exec(content)) !== null) {
|
|
imageUrls.push(match[1]);
|
|
}
|
|
|
|
// Also match direct URLs
|
|
const urlRegex = /https:\/\/[^\s"'<>]+\.(png|jpg|jpeg|webp|gif)/gi;
|
|
while ((match = urlRegex.exec(content)) !== null) {
|
|
if (!imageUrls.includes(match[0])) {
|
|
imageUrls.push(match[0]);
|
|
}
|
|
}
|
|
|
|
// Return images in our standard format
|
|
const images = imageUrls.slice(0, numImages).map(url => ({
|
|
url,
|
|
prompt,
|
|
model: 'grok-4-imageGen'
|
|
}));
|
|
|
|
if (images.length === 0) {
|
|
// Return the raw content for debugging
|
|
return NextResponse.json({
|
|
error: "No images found in response",
|
|
rawContent: content.substring(0, 500)
|
|
}, { status: 500 });
|
|
}
|
|
|
|
return NextResponse.json({ images });
|
|
|
|
} catch (error: any) {
|
|
console.error('[Grok Image] Error:', error);
|
|
return NextResponse.json(
|
|
{ error: error.message || 'Generation failed' },
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
}
|