feat: catalogue enrichment — tagline, genres, warnings, quality score, batch covers
Backend (handlers_catalogue.go):
- POST /api/admin/text-gen/tagline — 1-sentence marketing hook
- POST /api/admin/text-gen/genres + /apply — LLM genre suggestions, editable + persist
- POST /api/admin/text-gen/content-warnings — mature theme detection
- POST /api/admin/text-gen/quality-score — 1–5 description quality rating
- POST /api/admin/catalogue/batch-covers (SSE) — generate covers for books missing one
- POST /api/admin/catalogue/batch-covers/cancel — cancel via in-memory job registry
- POST /api/admin/catalogue/refresh-metadata/{slug} (SSE) — description + cover refresh
Frontend:
- text-gen: 4 new tabs (Tagline, Genres, Warnings, Quality) with book autocomplete
- image-gen: localStorage style presets (save/apply/delete named prompt templates)
- catalogue-tools: new admin page with batch cover SSE progress + cancel
- admin nav: "Catalogue Tools" link added
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
24
ui/src/routes/api/admin/text-gen/content-warnings/+server.ts
Normal file
24
ui/src/routes/api/admin/text-gen/content-warnings/+server.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { json, error } from '@sveltejs/kit';
|
||||
import type { RequestHandler } from './$types';
|
||||
import { log } from '$lib/server/logger';
|
||||
import { backendFetch } from '$lib/server/scraper';
|
||||
|
||||
export const POST: RequestHandler = async ({ request, locals }) => {
|
||||
if (!locals.user || locals.user.role !== 'admin') {
|
||||
throw error(403, 'Forbidden');
|
||||
}
|
||||
const body = await request.text();
|
||||
let res: Response;
|
||||
try {
|
||||
res = await backendFetch('/api/admin/text-gen/content-warnings', {
|
||||
method: 'POST',
|
||||
headers: { 'content-type': 'application/json' },
|
||||
body
|
||||
});
|
||||
} catch (e) {
|
||||
log.error('admin/text-gen/content-warnings', 'backend proxy error', { err: String(e) });
|
||||
throw error(502, 'Could not reach backend');
|
||||
}
|
||||
const data = await res.json().catch(() => ({}));
|
||||
return json(data, { status: res.status });
|
||||
};
|
||||
24
ui/src/routes/api/admin/text-gen/genres/+server.ts
Normal file
24
ui/src/routes/api/admin/text-gen/genres/+server.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { json, error } from '@sveltejs/kit';
|
||||
import type { RequestHandler } from './$types';
|
||||
import { log } from '$lib/server/logger';
|
||||
import { backendFetch } from '$lib/server/scraper';
|
||||
|
||||
export const POST: RequestHandler = async ({ request, locals }) => {
|
||||
if (!locals.user || locals.user.role !== 'admin') {
|
||||
throw error(403, 'Forbidden');
|
||||
}
|
||||
const body = await request.text();
|
||||
let res: Response;
|
||||
try {
|
||||
res = await backendFetch('/api/admin/text-gen/genres', {
|
||||
method: 'POST',
|
||||
headers: { 'content-type': 'application/json' },
|
||||
body
|
||||
});
|
||||
} catch (e) {
|
||||
log.error('admin/text-gen/genres', 'backend proxy error', { err: String(e) });
|
||||
throw error(502, 'Could not reach backend');
|
||||
}
|
||||
const data = await res.json().catch(() => ({}));
|
||||
return json(data, { status: res.status });
|
||||
};
|
||||
24
ui/src/routes/api/admin/text-gen/genres/apply/+server.ts
Normal file
24
ui/src/routes/api/admin/text-gen/genres/apply/+server.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { json, error } from '@sveltejs/kit';
|
||||
import type { RequestHandler } from './$types';
|
||||
import { log } from '$lib/server/logger';
|
||||
import { backendFetch } from '$lib/server/scraper';
|
||||
|
||||
export const POST: RequestHandler = async ({ request, locals }) => {
|
||||
if (!locals.user || locals.user.role !== 'admin') {
|
||||
throw error(403, 'Forbidden');
|
||||
}
|
||||
const body = await request.text();
|
||||
let res: Response;
|
||||
try {
|
||||
res = await backendFetch('/api/admin/text-gen/genres/apply', {
|
||||
method: 'POST',
|
||||
headers: { 'content-type': 'application/json' },
|
||||
body
|
||||
});
|
||||
} catch (e) {
|
||||
log.error('admin/text-gen/genres/apply', 'backend proxy error', { err: String(e) });
|
||||
throw error(502, 'Could not reach backend');
|
||||
}
|
||||
const data = await res.json().catch(() => ({}));
|
||||
return json(data, { status: res.status });
|
||||
};
|
||||
24
ui/src/routes/api/admin/text-gen/quality-score/+server.ts
Normal file
24
ui/src/routes/api/admin/text-gen/quality-score/+server.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { json, error } from '@sveltejs/kit';
|
||||
import type { RequestHandler } from './$types';
|
||||
import { log } from '$lib/server/logger';
|
||||
import { backendFetch } from '$lib/server/scraper';
|
||||
|
||||
export const POST: RequestHandler = async ({ request, locals }) => {
|
||||
if (!locals.user || locals.user.role !== 'admin') {
|
||||
throw error(403, 'Forbidden');
|
||||
}
|
||||
const body = await request.text();
|
||||
let res: Response;
|
||||
try {
|
||||
res = await backendFetch('/api/admin/text-gen/quality-score', {
|
||||
method: 'POST',
|
||||
headers: { 'content-type': 'application/json' },
|
||||
body
|
||||
});
|
||||
} catch (e) {
|
||||
log.error('admin/text-gen/quality-score', 'backend proxy error', { err: String(e) });
|
||||
throw error(502, 'Could not reach backend');
|
||||
}
|
||||
const data = await res.json().catch(() => ({}));
|
||||
return json(data, { status: res.status });
|
||||
};
|
||||
24
ui/src/routes/api/admin/text-gen/tagline/+server.ts
Normal file
24
ui/src/routes/api/admin/text-gen/tagline/+server.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { json, error } from '@sveltejs/kit';
|
||||
import type { RequestHandler } from './$types';
|
||||
import { log } from '$lib/server/logger';
|
||||
import { backendFetch } from '$lib/server/scraper';
|
||||
|
||||
export const POST: RequestHandler = async ({ request, locals }) => {
|
||||
if (!locals.user || locals.user.role !== 'admin') {
|
||||
throw error(403, 'Forbidden');
|
||||
}
|
||||
const body = await request.text();
|
||||
let res: Response;
|
||||
try {
|
||||
res = await backendFetch('/api/admin/text-gen/tagline', {
|
||||
method: 'POST',
|
||||
headers: { 'content-type': 'application/json' },
|
||||
body
|
||||
});
|
||||
} catch (e) {
|
||||
log.error('admin/text-gen/tagline', 'backend proxy error', { err: String(e) });
|
||||
throw error(502, 'Could not reach backend');
|
||||
}
|
||||
const data = await res.json().catch(() => ({}));
|
||||
return json(data, { status: res.status });
|
||||
};
|
||||
Reference in New Issue
Block a user