import { get } from "svelte/store" import { alertConfirm, alertError, alertNormal, alertStore } from "./alert" import { DataBase, defaultSdDataFunc, type character, saveImage, setDatabase } from "./database" import { checkNullish, selectSingleFile, sleep } from "./util" import { language } from "src/lang" import { encode as encodeMsgpack, decode as decodeMsgpack } from "@msgpack/msgpack"; import { v4 as uuidv4 } from 'uuid'; import exifr from 'exifr' import { PngMetadata } from "./exif" import { characterFormatUpdate } from "./characters" import { downloadFile, readImage } from "./globalApi" type OfficialCardSpec = { spec: 'chara_card_v2' spec_version: '2.0' // May 8th addition data: { name: string description: string personality: string scenario: string first_mes: string mes_example: string creator_notes: string system_prompt: string post_history_instructions: string alternate_greetings: string[] character_book?: CharacterBook tags: string[] creator: string character_version: number extensions: Record } } type CharacterBook = null export async function importCharacter() { try { const f = await selectSingleFile(['png', 'json']) if(!f){ return } if(f.name.endsWith('json')){ const da = JSON.parse(Buffer.from(f.data).toString('utf-8')) if(await importSpecv2(da)){ return } if((da.char_name || da.name) && (da.char_persona || da.description) && (da.char_greeting || da.first_mes)){ let db = get(DataBase) db.characters.push({ name: da.char_name ?? da.name, firstMessage: da.char_greeting ?? da.first_mes, desc: da.char_persona ?? da.description, notes: '', chats: [{ message: [], note: '', name: 'Chat 1', localLore: [] }], chatPage: 0, image: '', emotionImages: [], bias: [], globalLore: [], viewScreen: 'none', chaId: uuidv4(), sdData: defaultSdDataFunc(), utilityBot: false, customscript: [], exampleMessage: '' }) DataBase.set(db) alertNormal(language.importedCharacter) return } else{ alertError(language.errors.noData) return } } alertStore.set({ type: 'wait', msg: 'Loading... (Reading)' }) await sleep(10) const img = f.data const readed = (await exifr.parse(img, true)) console.log(readed) if(readed.chara){ // standard spec v2 imports const charaData:CharacterCardV2 = JSON.parse(Buffer.from(readed.chara, 'base64').toString('utf-8')) if(await importSpecv2(charaData)){ return } } if(readed.risuai){ // old risu imports await sleep(10) const va = decodeMsgpack(Buffer.from(readed.risuai, 'base64')) as any if(va.type !== 101){ alertError(language.errors.noData) return } let char:character = va.data let db = get(DataBase) if(char.emotionImages && char.emotionImages.length > 0){ for(let i=0;i 0){ for(let i=0;i", name: char.name, personality: "", scenario: "", talkativeness: "0.5" } await sleep(10) img = PngMetadata.write(img, { 'chara': Buffer.from(JSON.stringify(tavernData)).toString('base64'), 'risuai': data }) alertStore.set({ type: 'wait', msg: 'Loading... (Writing)' }) char.image = '' await sleep(10) await downloadFile(`${char.name.replace(/[<>:"/\\|?*\.\,]/g, "")}_export.png`, img) alertNormal(language.successExport) } catch(e){ alertError(`${e}`) } } async function importSpecv2(card:CharacterCardV2):Promise{ if(!card ||card.spec !== 'chara_card_v2'){ return false } let data = card.data let db = get(DataBase) const risuext = data.extensions.risuai if(risuext && risuext.emotions){ for(let i=0;i" name: string personality: "" scenario: "" talkativeness: "0.5" }