| 382 | | 382 | |
| 383 | /** @type {any} */ | 383 | /** @type {any} */ |
| 384 | const metadata = await result.json(); | 384 | const metadata = await result.json(); |
| 385 | const downloadUrl = metadata.node?.max_res_url; | 385 | const { definition, topics } = metadata.node; |
| | 386 | |
| | 387 | /** @type {TavernCardV2} */ |
| | 388 | const characterCard = { |
| | 389 | data: { |
| | 390 | name: definition.name, |
| | 391 | description: definition.personality, |
| | 392 | personality: definition.tavern_personality, |
| | 393 | scenario: definition.scenario, |
| | 394 | first_mes: definition.first_message, |
| | 395 | mes_example: definition.example_dialogs, |
| | 396 | creator_notes: definition.description, |
| | 397 | system_prompt: definition.system_prompt, |
| | 398 | post_history_instructions: definition.post_history_instructions, |
| | 399 | alternate_greetings: definition.alternate_greetings, |
| | 400 | tags: topics, |
| | 401 | creator: creatorName, |
| | 402 | character_version: '', |
| | 403 | character_book: definition.embedded_lorebook, |
| | 404 | extensions: definition.extensions, |
| | 405 | }, |
| | 406 | spec: 'chara_card_v2', |
| | 407 | spec_version: '2.0', |
| | 408 | }; |
| 386 | | 409 | |
| 387 | if (!downloadUrl) { | 410 | const defaultAvatarPath = path.join(serverDirectory, DEFAULT_AVATAR_PATH); |
| 388 | throw new Error('Download URL not found in character metadata'); | 411 | const defaultAvatarBuffer = fs.readFileSync(defaultAvatarPath); |
| 389 | } | | |
| 390 | | 412 | |
| 391 | const downloadResult = await fetch(downloadUrl); | 413 | let imageBuffer = defaultAvatarBuffer; |
| 392 | | 414 | |
| 393 | if (!downloadResult.ok) { | 415 | const imageUrl = metadata.node?.max_res_url; |
| 394 | const text = await downloadResult.text(); | 416 | |
| 395 | console.error('Chub returned error', downloadResult.statusText, text); | 417 | if (imageUrl) { |
| 396 | throw new Error('Failed to download character'); | 418 | const downloadResult = await fetch(imageUrl); |
| | 419 | if (downloadResult.ok) { |
| | 420 | imageBuffer = Buffer.from(await downloadResult.arrayBuffer()); |
| | 421 | } |
| 397 | } | 422 | } |
| 398 | | 423 | |
| 399 | const buffer = Buffer.from(await downloadResult.arrayBuffer()); | 424 | const buffer = write(imageBuffer, JSON.stringify(characterCard)); |
| 400 | const fileName = | 425 | const fileName = `${sanitize(characterCard.data.name)}.png`; |
| 401 | downloadResult.headers.get('content-disposition')?.split('filename=')[1]?.replace(/["']/g, '') || | 426 | const fileType = 'image/png'; |
| 402 | `${sanitize(projectName)}.png`; | | |
| 403 | const fileType = downloadResult.headers.get('content-type'); | | |
| 404 | | 427 | |
| 405 | return { buffer, fileName, fileType }; | 428 | return { buffer, fileName, fileType }; |
| 406 | } | 429 | } |