37 lines
1.8 KiB
TypeScript
37 lines
1.8 KiB
TypeScript
import { CreateWorldRequestSchema, WorldStarterSchema, moderate13Plus } from '@dng/shared'
|
||
import { buildJsonCompletion, parseJsonCompletion } from '../../utils/ai-provider'
|
||
|
||
export default defineEventHandler(async event => {
|
||
const raw = await readBody(event)
|
||
const prompt = typeof raw?.prompt === 'string' ? raw.prompt : ''
|
||
const answers = raw?.answers && typeof raw.answers === 'object' ? raw.answers : {}
|
||
const moderation = moderate13Plus(`${prompt} ${Object.values(answers).join(' ')}`)
|
||
if (!moderation.allowed) throw createError({ statusCode: 422, statusMessage: 'This concept falls outside the alpha’s 13+ content boundary.' })
|
||
|
||
const config = useRuntimeConfig()
|
||
const request = CreateWorldRequestSchema.parse({ messages: [{ role: 'user', content: `${prompt}\nPreferences: ${JSON.stringify(answers)}` }] })
|
||
let completion
|
||
try {
|
||
completion = buildJsonCompletion(config, {
|
||
system: 'Create an original 13+ TTRPG starting world. Return only valid JSON matching the supplied WorldStarter structure, with exactly 3 NPCs and 2 factions. Do not use protected franchises.',
|
||
messages: request.messages,
|
||
schemaName: 'world_starter',
|
||
jsonSchema: WorldStarterSchema.toJSONSchema(),
|
||
})
|
||
} catch (error) {
|
||
throw createError({ statusCode: 500, statusMessage: error instanceof Error ? error.message : 'Invalid AI provider configuration.' })
|
||
}
|
||
|
||
const response = await fetch(completion.endpoint, {
|
||
method: 'POST',
|
||
headers: completion.headers,
|
||
body: JSON.stringify(completion.body),
|
||
})
|
||
if (!response.ok) throw createError({ statusCode: 502, statusMessage: 'The coauthor is temporarily unavailable.' })
|
||
try {
|
||
return WorldStarterSchema.parse(parseJsonCompletion(await response.json()))
|
||
} catch {
|
||
throw createError({ statusCode: 502, statusMessage: 'The coauthor returned an invalid world structure.' })
|
||
}
|
||
})
|