feat: implement English Style Converter
- SvelteKit project scaffolded with TypeScript - Type definitions for Style, StyleCategory, ConversionRequest, ConversionResponse, LLMConfig - Style definitions with 6 categories and 25 sub-styles - Intensity mapping (1-5) with prompt modifier placeholders - LLM client using OpenAI-compatible API (Ollama default) - POST /api/convert endpoint with input validation - Animated loading modal with per-letter animations - Main page UI with category/style selectors, intensity slider - Copy to clipboard, collapsible prompt display - Vitest tests for styles, LLM prompt building, and API validation - Environment configuration for LLM settings
This commit is contained in:
62
src/routes/api/convert/+server.ts
Normal file
62
src/routes/api/convert/+server.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { json } from '@sveltejs/kit';
|
||||
import type { RequestHandler } from './$types';
|
||||
import { getStyleById, getIntensityConfig } from '$lib/styles';
|
||||
import { convertText } from '$lib/llm';
|
||||
import type { ConversionRequest, ConversionResponse } from '$lib/types';
|
||||
|
||||
export const POST: RequestHandler = async ({ request }) => {
|
||||
let body: ConversionRequest;
|
||||
try {
|
||||
body = await request.json();
|
||||
} catch {
|
||||
return json({ error: 'Invalid JSON body' }, { status: 400 });
|
||||
}
|
||||
|
||||
const { text, styleId, intensity } = body;
|
||||
|
||||
// Validate text
|
||||
if (!text || typeof text !== 'string' || text.trim().length === 0) {
|
||||
return json({ error: 'Text is required and must be non-empty' }, { status: 400 });
|
||||
}
|
||||
|
||||
// Validate styleId
|
||||
if (!styleId || typeof styleId !== 'string') {
|
||||
return json({ error: 'styleId is required' }, { status: 400 });
|
||||
}
|
||||
|
||||
const style = getStyleById(styleId);
|
||||
if (!style) {
|
||||
return json({ error: `Unknown style: ${styleId}` }, { status: 400 });
|
||||
}
|
||||
|
||||
// Validate intensity
|
||||
if (typeof intensity !== 'number' || !Number.isInteger(intensity) || intensity < 1 || intensity > 5) {
|
||||
return json({ error: 'Intensity must be an integer between 1 and 5' }, { status: 400 });
|
||||
}
|
||||
|
||||
const intensityConfig = getIntensityConfig(intensity);
|
||||
if (!intensityConfig) {
|
||||
return json({ error: 'Invalid intensity level' }, { status: 400 });
|
||||
}
|
||||
|
||||
try {
|
||||
const result = convertText(text, style.promptModifier, intensityConfig.instruction);
|
||||
|
||||
// Await the promise
|
||||
const { converted, systemPrompt, userMessage } = await result;
|
||||
|
||||
const response: ConversionResponse = {
|
||||
original: text,
|
||||
converted,
|
||||
styleId,
|
||||
intensity,
|
||||
systemPrompt,
|
||||
userMessage
|
||||
};
|
||||
|
||||
return json(response);
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : 'LLM call failed';
|
||||
return json({ error: `Failed to convert text: ${message}` }, { status: 502 });
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user