Files
Dungeons-Ground/apps/web/server/api/worlds/generate.post.ts
pavel444-byte 031d094867
Some checks failed
CI / validate (push) Has been cancelled
CI / validate (pull_request) Has been cancelled
feat(memory): implement stability stage
Co-authored-by: multica-agent <github@multica.ai>
2026-09-02 15:04:18 +05:00

50 lines
2.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { CreateWorldRequestSchema, WorldStarterSchema, moderate13Plus } from '@dng/shared'
import { buildJsonCompletion, parseJsonCompletion } from '../../utils/ai-provider'
import { requireStageTwoUser, stageSixConsumeAiQuota, stageSixRecordAiUsage } from '../../utils/stage-two-supabase'
export default defineEventHandler(async event => {
const user = await requireStageTwoUser(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 alphas 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, 2 factions, and 3 distinct persistent AI companion heroes designed specifically for this universe. Give every companion complete playable mechanics, useful genre-appropriate equipment, and a distinctive persona. 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.' })
}
await stageSixConsumeAiQuota(user.id, null, 'world-preview')
const startedAt = Date.now()
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.' })
const payload = await response.json()
await stageSixRecordAiUsage({
userId: user.id, campaignId: null, requestKind: 'world-preview', completion, payload, latencyMs: Date.now() - startedAt,
}).catch(error => console.error('[web] could not record world preview usage:', error))
let world
try {
world = WorldStarterSchema.parse(parseJsonCompletion(payload))
} catch {
throw createError({ statusCode: 502, statusMessage: 'The coauthor returned an invalid world structure.' })
}
if (!moderate13Plus(JSON.stringify(world)).allowed) {
throw createError({ statusCode: 422, statusMessage: 'The generated world falls outside the alphas 13+ content boundary.' })
}
return world
})