/** * Inference Proxy — /predict * * Lets a separately-hosted frontend (e.g. the Vercel deployment, which has * no Python inference process of its own) reach this Space's internal * FastAPI service. Gated on a shared secret since it bypasses the * Firebase-authenticated /api/predict route entirely — this is * backend-to-backend, not meant to be called from a browser. */ import { NextRequest } from 'next/server' import { rateLimit, getRateLimitHeaders } from '@/lib/security/rateLimiter' import { createSecureResponse, addSecurityHeaders } from '@/lib/security/headers' import { getInferenceUrl } from '@/lib/server/inferenceUrl' const INFERENCE_TIMEOUT_MS = 30_000 function isAuthorized(request: NextRequest): boolean { const expected = process.env.INFERENCE_PROXY_TOKEN if (!expected) return false return request.headers.get('x-inference-proxy-token') === expected } export async function POST(request: NextRequest) { const rateLimitResponse = rateLimit(request, '/api/inference/predict') if (rateLimitResponse) { return addSecurityHeaders(rateLimitResponse) } if (!isAuthorized(request)) { return createSecureResponse({ error: 'Unauthorized' }, 401) } let inferenceUrl: string try { inferenceUrl = getInferenceUrl() } catch (error) { console.error('Inference proxy: service misconfigured:', error) return createSecureResponse({ error: 'Prediction service is not configured.' }, 503) } const formData = await request.formData() let upstream: Response try { upstream = await fetch(`${inferenceUrl}/predict`, { method: 'POST', body: formData, signal: AbortSignal.timeout(INFERENCE_TIMEOUT_MS), }) } catch (error) { console.error('Inference proxy: upstream unreachable:', error) return createSecureResponse( { error: 'Prediction service unavailable. Please try again shortly.' }, 503 ) } let result: any try { result = await upstream.json() } catch { console.error('Inference proxy: upstream returned non-JSON, status:', upstream.status) return createSecureResponse({ error: 'Prediction failed. Please try again later.' }, 500) } const response = createSecureResponse(result, upstream.status) const rateLimitHeaders = getRateLimitHeaders(request, '/api/inference/predict') Object.entries(rateLimitHeaders).forEach(([key, value]) => { response.headers.set(key, value) }) return response }