Files
insta-recipe/src/routes/api/extract-stream/+server.ts
Giancarmine Salucci da58263aba feat: refactor frontend and fix LLM extraction
- Fix critical await bug in extract-stream endpoint
- Add comprehensive logging to LLM and parser modules
- Implement fallback to standard completion for incompatible models
- Create enhanced v2.0 prompts with social media handling and few-shot examples
- Add LLM health check endpoint
- Decompose share page into 6 focused Svelte 5 snippets

Resolves LM Studio integration issues and improves code maintainability
2025-12-21 03:49:33 +01:00

85 lines
2.3 KiB
TypeScript

/**
* Server-Sent Events (SSE) endpoint for real-time extraction progress
*
* This endpoint streams extraction progress updates to the frontend
* using the SSE protocol. Each event contains status updates, method attempts,
* retry information, and final results.
*/
import { json, type RequestHandler } from '@sveltejs/kit';
import { extractTextAndThumbnail, type ProgressEvent } from '$lib/server/extraction';
import { extractRecipe } from '$lib/server/parser';
export const POST: RequestHandler = async ({ request }) => {
const { url } = await request.json();
if (!url) {
return json({ error: 'URL is required' }, { status: 400 });
}
// Create a ReadableStream for SSE
const stream = new ReadableStream({
async start(controller) {
const encoder = new TextEncoder();
// Helper to send SSE message
const sendEvent = (event: ProgressEvent) => {
const data = JSON.stringify(event);
const message = `event: progress\ndata: ${data}\n\n`;
controller.enqueue(encoder.encode(message));
};
try {
// Extract with progress callback
const extracted = await extractTextAndThumbnail(url, sendEvent);
// Parse recipe from extracted text
sendEvent({
type: 'status',
message: 'Parsing recipe...',
timestamp: new Date().toISOString()
});
const recipe = await extractRecipe(extracted.bodyText);
// Send final result
const completeEvent: ProgressEvent = {
type: 'complete',
message: 'Extraction and parsing completed',
data: {
recipe,
thumbnail: extracted.thumbnail
},
timestamp: new Date().toISOString()
};
const completeMessage = `event: complete\ndata: ${JSON.stringify(completeEvent)}\n\n`;
controller.enqueue(encoder.encode(completeMessage));
controller.close();
} catch (error) {
// Send error event
const errorEvent: ProgressEvent = {
type: 'error',
message: error instanceof Error ? error.message : 'Unknown error occurred',
timestamp: new Date().toISOString()
};
const errorMessage = `event: error\ndata: ${JSON.stringify(errorEvent)}\n\n`;
controller.enqueue(encoder.encode(errorMessage));
controller.close();
}
}
});
// Return SSE response
return new Response(stream, {
headers: {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
Connection: 'keep-alive'
}
});
};