🌳
pt0/gamesapp/serverF/telgame/aiDrawDescriptionAI.mjs
9export const aiDrawMockCtx = genContext()
11const mockIpfsCid = 'mock-cid-placeholder'
13const timeoutPromise = (ms) => new Promise((_, reject) =>
14 setTimeout(() => reject(new Error(`AI draw timeout after ${ms}ms`)), ms)
17export const aiDrawDescription = async (/** @type {{descriptionText: string, model?: string}} */ { descriptionText, model }) => {
18 const mockCtx = aiDrawMockCtx.getStore()
19 if (mockCtx?.useMock) {
20 return { ipfsCid: mockIpfsCid, model: 'mock', costUsd: 0, genTimeMs: 0 }
21 }
23 model ||= defaultAiDrawModel
25 try {
26 const startTime = Date.now()
27 const { result: resp } = await Promise.race([
29 modelIds: [model],
30 opts: {
31 max_tokens: 4000,
32 aiMessages: [{role: 'user', content: `Create an image: ${descriptionText}. Do not include any text, letters, numbers, or words in the image.`}],
33 modalities: ['image'],
34 },
35 context: 'aiDrawDescription',
36 }),
37 timeoutPromise(aiDrawTimeoutMs),
38 ])
39 const genTimeMs = Date.now() - startTime
41 if (!resp) {
42 betLog('aiDrawDescription unexpected: no result', {model})
43 return null
44 }
46 let imageDataUrl = resp.choices[0].message.images?.[0]?.image_url?.url
47 if (!imageDataUrl) {
48 const content = resp.choices[0].message.content || ''
49 const m = content.match(/data:image\/[a-z]+;base64,[A-Za-z0-9+/=]+/)
50 if (m) imageDataUrl = m[0]
51 }
52 if (!imageDataUrl) {
53 betLog('aiDrawDescription unexpected: no image', {model, choiceKeys: Object.keys(resp.choices?.[0]?.message || {})})
54 return null
55 }
57 const base64Data = imageDataUrl.replace(/^data:image\/\w+;base64,/, '')
58 const imageBuffer = Buffer.from(base64Data, 'base64')
59 const ipfsCid = await uploadToIpfs(imageBuffer)
60 const {mfsRoot, kvKey} = deriveMfsParams('gamesapp')
61 await addToIpfsMfsRoot({cid: ipfsCid, ext: 'png', mfsRoot, kvKey}).catch(err => {
62 betLog('addToGamesMediaRootFail', {ipfsCid, errMsg: err.message})
63 })
65 return { ipfsCid, model, costUsd: resp.costUsd, genTimeMs }
66 } catch (err) {
67 betLog('aiDrawDescription error', {model, err})
68 await maybeNotifError({err})
69 return null
70 }