import { NextRequest, NextResponse } from 'next/server'; import { MetaAIClient } from '@/lib/providers/meta-client'; /** * Meta AI Chat API * Uses MetaAIClient directly (GraphQL-based) for Llama 3 chat * No external Crawl4AI service needed */ export async function POST(req: NextRequest) { try { const body = await req.json(); const { message, history, metaCookies } = body; if (!message) { return NextResponse.json({ error: "Message is required" }, { status: 400 }); } if (!metaCookies) { return NextResponse.json( { error: "Meta AI cookies required. Configure in Settings." }, { status: 401 } ); } console.log(`[Meta Chat] Message: "${message.substring(0, 50)}..."`); // Use MetaAIClient to send chat message // The Meta AI API is primarily designed for image generation, // but we can use it for text chat by not prefixing with "Imagine" const client = new MetaAIClient({ cookies: metaCookies }); // For chat, we need to initialize session and send via GraphQL // Since MetaAIClient.generate() adds "Imagine" prefix for images, // we'll create a direct chat method or adapt the prompt // Send message directly - the response will contain text, not images const chatPrompt = message; // Don't add "Imagine" prefix for chat try { // Use the internal sendPrompt mechanism via generate // But we'll extract the text response instead of images const response = await sendMetaChatMessage(client, chatPrompt, metaCookies); return NextResponse.json({ response }); } catch (chatError: any) { // If the direct approach fails, provide helpful error throw new Error(chatError.message || "Failed to get response from Meta AI"); } } catch (error: any) { console.error('[Meta Chat] Error:', error); const msg = error.message || ""; const isAuthError = msg.includes("401") || msg.includes("cookies") || msg.includes("expired") || msg.includes("Login"); return NextResponse.json( { error: error.message || 'Internal Server Error' }, { status: isAuthError ? 401 : 500 } ); } } /** * Send a chat message to Meta AI and extract text response */ async function sendMetaChatMessage(client: MetaAIClient, message: string, cookies: string): Promise { const META_AI_BASE = "https://www.meta.ai"; const GRAPHQL_ENDPOINT = `${META_AI_BASE}/api/graphql/`; // Normalize cookies from JSON array to string format const normalizedCookies = normalizeCookies(cookies); // First we need to get session tokens const sessionResponse = await fetch(META_AI_BASE, { headers: { "Cookie": normalizedCookies, "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36", } }); const html = await sessionResponse.text(); // Extract LSD token const lsdMatch = html.match(/\"LSD\",\[\],\{\"token\":\"([^\"]+)\"/) || html.match(/\"lsd\":\"([^\"]+)\"/) || html.match(/name=\"lsd\" value=\"([^\"]+)\"/); const lsd = lsdMatch?.[1] || ''; // Extract access token const tokenMatch = html.match(/\"accessToken\":\"([^\"]+)\"/); const accessToken = tokenMatch?.[1]; if (html.includes('login_form') || html.includes('login_page')) { throw new Error("Meta AI: Cookies expired. Please update in Settings."); } // Send chat message const variables = { message: { text: message, content_type: "TEXT" }, source: "PDT_CHAT_INPUT", external_message_id: Math.random().toString(36).substring(2) + Date.now().toString(36) }; const body = new URLSearchParams({ fb_api_caller_class: "RelayModern", fb_api_req_friendly_name: "useAbraSendMessageMutation", variables: JSON.stringify(variables), doc_id: "7783822248314888", ...(lsd && { lsd }), }); const response = await fetch(GRAPHQL_ENDPOINT, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded", "Cookie": normalizedCookies, "Origin": META_AI_BASE, "Referer": `${META_AI_BASE}/`, "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36", "Sec-Fetch-Site": "same-origin", "Sec-Fetch-Mode": "cors", "Sec-Fetch-Dest": "empty", "Accept": "application/json", "Accept-Language": "en-US,en;q=0.9", ...(accessToken && { "Authorization": `OAuth ${accessToken}` }) }, body: body.toString() }); // Get response text first const responseText = await response.text(); // Check if response is HTML (error page) if (responseText.trim().startsWith('<') || responseText.includes(' "foo=bar; ..." */ function normalizeCookies(cookies: string): string { if (!cookies) return ''; try { const trimmed = cookies.trim(); // Check if it's JSON array if (trimmed.startsWith('[')) { const parsed = JSON.parse(trimmed); if (Array.isArray(parsed)) { return parsed .map((c: any) => `${c.name}=${c.value}`) .join('; '); } } // Check if it's JSON object with multiple arrays (merged cookies) if (trimmed.startsWith('{')) { const parsed = JSON.parse(trimmed); // If it's an object, iterate values const entries = Object.entries(parsed) .map(([k, v]) => `${k}=${v}`) .join('; '); return entries; } } catch (e) { // Not JSON, assume it's already a string format } return cookies; }