feat: stream chapter-name generation via SSE batching
All checks were successful
Release / Test backend (push) Successful in 51s
Release / Check ui (push) Successful in 47s
Release / Docker / caddy (push) Successful in 44s
Release / Docker / backend (push) Successful in 3m0s
Release / Docker / runner (push) Successful in 2m38s
Release / Docker / ui (push) Successful in 2m16s
Release / Gitea Release (push) Successful in 36s
All checks were successful
Release / Test backend (push) Successful in 51s
Release / Check ui (push) Successful in 47s
Release / Docker / caddy (push) Successful in 44s
Release / Docker / backend (push) Successful in 3m0s
Release / Docker / runner (push) Successful in 2m38s
Release / Docker / ui (push) Successful in 2m16s
Release / Gitea Release (push) Successful in 36s
Split chapter-name LLM requests into 100-chapter batches and stream results back as SSE so large books (e.g. Shadow Slave: 2916 chapters) never time out or truncate. Frontend shows live batch progress inline and accumulates proposals as they arrive.
This commit is contained in:
@@ -2,10 +2,11 @@
|
||||
* POST /api/admin/text-gen/chapter-names
|
||||
*
|
||||
* Admin-only proxy to the Go backend's chapter-name generation endpoint.
|
||||
* Returns AI-proposed chapter titles; does NOT persist anything.
|
||||
* The backend streams SSE events; this handler pipes the stream through
|
||||
* directly so the browser can consume it without buffering.
|
||||
*/
|
||||
|
||||
import { json, error } from '@sveltejs/kit';
|
||||
import { error } from '@sveltejs/kit';
|
||||
import type { RequestHandler } from './$types';
|
||||
import { log } from '$lib/server/logger';
|
||||
import { backendFetch } from '$lib/server/scraper';
|
||||
@@ -28,6 +29,22 @@ export const POST: RequestHandler = async ({ request, locals }) => {
|
||||
throw error(502, 'Could not reach backend');
|
||||
}
|
||||
|
||||
const data = await res.json().catch(() => ({}));
|
||||
return json(data, { status: res.status });
|
||||
// Non-2xx: the backend returned a JSON error before switching to SSE.
|
||||
if (!res.ok) {
|
||||
const data = await res.json().catch(() => ({}));
|
||||
return new Response(JSON.stringify(data), {
|
||||
status: res.status,
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
});
|
||||
}
|
||||
|
||||
// Pipe the SSE stream straight through — do not buffer.
|
||||
return new Response(res.body, {
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': 'text/event-stream',
|
||||
'Cache-Control': 'no-cache',
|
||||
'X-Accel-Buffering': 'no'
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user