apix/app/api/grok-image/route.ts
Khoa.vo e69c6ba64d
Some checks are pending
CI / build (18.x) (push) Waiting to run
CI / build (20.x) (push) Waiting to run
chore: Remove Grok integration, simplify Settings UI
- 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
2026-01-07 19:21:51 +07:00

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: ![...](url) 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 }
);
}
}