UNPKG

@lenml/char-card-reader

Version:

SillyTavern character card info reader

3 lines 13.1 kB
function W(o){if(typeof Buffer<"u"&&Buffer.isBuffer(o))return Promise.resolve(o.toString("base64"));if(typeof Blob<"u"&&o instanceof Blob)return new Promise((t,a)=>{let r=new FileReader;r.onload=()=>{let s=r.result.split(",")[1];t(s)},r.onerror=a,r.readAsDataURL(o)});let e;if(o instanceof ArrayBuffer)e=new Uint8Array(o);else if(o instanceof Uint8Array)e=o;else throw new TypeError("Unsupported input type");if(typeof Buffer<"u")return Promise.resolve(Buffer.from(e).toString("base64"));{let t="";for(let a=0;a<e.length;a++)t+=String.fromCharCode(e[a]);return Promise.resolve(btoa(t))}}function V(o){return typeof o!="string"?!1:!!(o.startsWith("http://")||o.startsWith("https://")||o.startsWith("data:"))}var S=globalThis.structuredClone?globalThis.structuredClone:o=>JSON.parse(JSON.stringify(o)),E=class{static encode(e){if(typeof window<"u"&&typeof window.btoa=="function")return window.btoa(unescape(encodeURIComponent(e)));if(typeof Buffer<"u")return Buffer.from(e,"utf-8").toString("base64");throw new Error("Base64.encode: Environment not supported.")}static decode(e){if(typeof window<"u"&&typeof window.atob=="function")return decodeURIComponent(escape(window.atob(e)));if(typeof Buffer<"u")return Buffer.from(e,"base64").toString("utf-8");throw new Error("Base64.decode: Environment not supported.")}};function j(o){return typeof o=="object"&&o!==null}function R(o){return o!=null}function O(...o){let e=new Set(o.flatMap(Object.keys));return Object.fromEntries(Array.from(e).map(t=>{let a=o.map(r=>r[t]);return a.some(Array.isArray)?[t,[...a].reverse().filter(R).filter(Boolean)[0]]:a.some(j)?[t,O(...a.filter(j))]:[t,[...a].reverse().filter(R)[0]]}))}function k(o){return Array.from(new Set(o))}var U=class o{static from_json(e){if(typeof e!="object"||e===null)throw new Error("data must be an object");let t=[];Array.isArray(e)?t=e:t=Array.isArray(e?.entries)?e.entries:Array.isArray(e?.data?.character_book?.entries)?e.data.character_book.entries:[];let a=new o(t),r=e?.character_book??e?.data?.character_book??e;return a.name=r?.name,a.description=r?.description,a.recursive_scanning=r?.recursive_scanning??!0,a.scan_depth=r?.scan_depth??10,a.extensions=r?.extensions??{},a}name="unknown";description="";token_budget;recursive_scanning=!0;extensions={};entries=[];scan_depth=10;constructor(e=[]){this.entries=S(e),this._keys_fix()}_keys_fix(){let e=/[,|;,;]/g;for(let t of this.entries){let{keys:a}=t,r=[];for(let n of a)e.test(n)?r.push(...n.split(e).map(s=>s.trim()).filter(Boolean)):r.push(n);t.keys=r}}_scan(e,t=[],a=1){if(a>=(this.scan_depth??10))return k(t);let r=[e,...k(t).map(s=>s.content)].join(` `),n=this.entries.filter(s=>s.content?.trim()).filter(s=>s.enabled&&!t.includes(s));if(n.length===0)return k(t);for(let s of n)s.keys.some(p=>r.includes(p))&&t.push(s);return this.recursive_scanning?this._scan(e,t,a+1):k(t)}scan(e){let t=this._scan(e),a=this.entries.filter(r=>r.constant&&r.enabled&&r.content?.trim());return k([...t,...a]).sort((r,n)=>r.insertion_order-n.insertion_order)}};var C;(a=>{function o(r){let n=[],s=2;for(;s<r.length;){if(r[s]!==255)throw new Error(`Invalid marker at offset ${s}`);let c=r[s+1];for(;c===255;)s++,c=r[s+1];let p=s;if(s+=2,c===217||c===218)break;let i=r[s]<<8|r[s+1],u=s+2,_=u+i-2,f=r.slice(u,_),h={marker:`FF ${c.toString(16).toUpperCase().padStart(2,"0")}`,offset:p,length:i,type:"Other",preview:Array.from(f.slice(0,16)).map(w=>w.toString(16).padStart(2,"0")).join(" ")};c===224&&String.fromCharCode(...f.slice(0,5))==="JFIF\0"?h.type="JFIF":c===225?String.fromCharCode(...f.slice(0,6)).startsWith("Exif")?h.type="EXIF":String.fromCharCode(...f.slice(0,29)).includes("http://ns.adobe.com/xap/1.0/")?h.type="XMP":h.type="APP1":c===254&&(h.type="Comment",h.comment=new TextDecoder().decode(f)),n.push(h),s=_}return n}a.parse_chunks=o;function e(r,n){if(n>=r.length)return;let s=r[n]<<8|r[n+1],c=!1;if(s===18761)c=!0;else if(s===19789)c=!1;else return;let p=v=>{let m=n+v;return m+2>r.length?0:c?r[m]|r[m+1]<<8:r[m]<<8|r[m+1]},i=v=>{let m=n+v;return m+4>r.length?0:c?(r[m]|r[m+1]<<8|r[m+2]<<16|r[m+3]<<24)>>>0:(r[m]<<24|r[m+1]<<16|r[m+2]<<8|r[m+3])>>>0},u=(v,m)=>{let M=p(v);for(let T=0;T<M;T++){let D=v+2+T*12;if(p(D)===m)return{type:p(D+2),count:i(D+4),valueOffsetField:D+8}}return null},_=i(4);if(_===0)return;let f=_,h=u(_,34665);h&&(f=i(h.valueOffsetField));let w=u(f,37510);if(!w)return;let{count:g,valueOffsetField:d}=w,x=i(d);g<=4&&(x=d);let y=n+x,l=r.slice(y,y+g),b=String.fromCharCode(...l.slice(0,8));return b.startsWith("ASCII\0\0\0")?new TextDecoder("utf-8").decode(l.slice(8)):b.startsWith("UNICODE\0")?new TextDecoder("utf-16").decode(l.slice(8)):new TextDecoder("utf-8").decode(l)}function t(r,n){if(n.type!=="EXIF")return;let s=n.offset+10;return e(r,s)}a.extract_user_comment=t})(C||={});var I;(e=>{function o(t){let a=[],r=8;for(;r<t.length&&!(r+8>t.length);){let n=(t[r]<<24|t[r+1]<<16|t[r+2]<<8|t[r+3])>>>0,s=String.fromCharCode(t[r+4],t[r+5],t[r+6],t[r+7]),c=r+8,p=c+n;if(p+4>t.length)break;let i=t.slice(c,p),u=(t[p]<<24|t[p+1]<<16|t[p+2]<<8|t[p+3])>>>0,_={type:s,length:n,crc:u};if(s==="IHDR")_.width=(i[0]<<24|i[1]<<16|i[2]<<8|i[3])>>>0,_.height=(i[4]<<24|i[5]<<16|i[6]<<8|i[7])>>>0,_.bitDepth=i[8],_.colorType=i[9];else if(s==="tEXt"){let f=new TextDecoder().decode(i),h=f.indexOf("\0");h>=0?(_.keyword=f.slice(0,h),_.text=f.slice(h+1)):_.rawText=f}a.push(_),r=p+4}return a}e.parse_chunks=o})(I||={});var A;(t=>{function o(a,r){let n=r.offset+8;if(n>=a.length)return;a[n]===69&&a[n+1]===120&&a[n+2]===105&&a[n+3]===102&&(n+=6);let s=a[n]<<8|a[n+1],c=!1;if(s===18761)c=!0;else if(s===19789)c=!1;else{console.error("\u65E0\u6CD5\u8BC6\u522B\u7684 TIFF \u5934:",s.toString(16));return}let p=g=>{let d=n+g;return d+2>a.length?0:c?a[d]|a[d+1]<<8:a[d]<<8|a[d+1]},i=g=>{let d=n+g;return d+4>a.length?0:c?(a[d]|a[d+1]<<8|a[d+2]<<16|a[d+3]<<24)>>>0:(a[d]<<24|a[d+1]<<16|a[d+2]<<8|a[d+3])>>>0},u=i(4);if(u===0)return;let _=(g,d)=>{let x=p(g);for(let y=0;y<x;y++){let l=g+2+y*12;if(p(l)===d)return{type:p(l+2),count:i(l+4),valueOffsetOrData:l+8}}return null},f=u,h=_(u,34665);h&&(f=i(h.valueOffsetOrData));let w=_(f,37510);if(w){let{count:g,valueOffsetOrData:d}=w,x=i(d);g<=4&&(x=d);let y=n+x,l=a.slice(y,y+g),b=String.fromCharCode(...l.slice(0,8));return b.startsWith("ASCII\0\0\0")?new TextDecoder("utf-8").decode(l.slice(8)):b.startsWith("UNICODE\0")?new TextDecoder("utf-16").decode(l.slice(8)):new TextDecoder("utf-8").decode(l)}}t.extract_user_comment=o;function e(a){let r=[],n=12,s=a.length;for(;n+8<=s;){let c=String.fromCharCode(a[n],a[n+1],a[n+2],a[n+3]),p=a[n+4]|a[n+5]<<8|a[n+6]<<16|a[n+7]<<24,i=n+8,u=i+p;if(u>s)break;r.push({type:c,offset:n,length:p,preview:Array.from(a.slice(i,i+16)).map(_=>_.toString(16).padStart(2,"0")).join(" ")}),n=u+p%2}return r}t.parse_chunks=e})(A||={});function L(o){let e=o instanceof Uint8Array?o:new Uint8Array(o),t=e.slice(0,8).every((n,s)=>n===[137,80,78,71,13,10,26,10][s]),a=e[0]===255&&e[1]===216,r=String.fromCharCode(...e.slice(0,4))==="RIFF"&&String.fromCharCode(...e.slice(8,12))==="WEBP";if(t)return{format:"png",chunks:I.parse_chunks(e)};if(a)return{format:"jpeg",segments:C.parse_chunks(e)};if(r)return{format:"webp",chunks:A.parse_chunks(e)};throw new Error("Unsupported image format")}var P=class extends Error{};var J=class o{constructor(e,t=""){this.raw_data=e;this.fallback_avatar=t}static async from_file(e){let t=L(e),a=await W(e),r=`data:image/${t.format};base64,${a}`,n=this.parse_char_info(e,t);return new o({spec:"chara_card_v1",spec_version:"1.0",data:{},...n},r)}static from_json(e,t=""){return new o(e,t)}static parse_char_info(e,t){let a;if(t.format==="png"){let s=["chara","character_card"],c=t.chunks.find(i=>s.some(u=>i.keyword?.toLowerCase()===u.toLowerCase()));a=t.chunks.find(i=>i.keyword==="ccv3")?.text??c?.text}else if(t.format==="jpeg"){let s=t.segments.find(p=>p.type==="EXIF");a=C.extract_user_comment(e instanceof Uint8Array?e:new Uint8Array(e),s)}else if(t.format==="webp"){let s=t.chunks.find(c=>c.type==="EXIF");s&&(a=A.extract_user_comment(e instanceof Uint8Array?e:new Uint8Array(e),s))}if(!a)throw new P("Failed to extract chara card data from image");let r=E.decode(a);return JSON.parse(r)}async get_avatar(e=!1){let t=e?"":this.fallback_avatar;return[this.raw_data.avatar,this.raw_data.data?.avatar,t].filter(V)[0]}get avatar(){return[this.raw_data.avatar,this.raw_data.data?.avatar,this.fallback_avatar].filter(V)[0]}get spec(){return this.raw_data.spec||"unknown"}get spec_version(){return this.raw_data.spec_version||"unknown"}get name(){switch(this.spec){case"chara_card_v2":return this.raw_data.data?.name??this.raw_data.name;case"chara_card_v3":return this.raw_data.data?.name??this.raw_data.name;default:return this.raw_data.char_name??this.raw_data.name??"unknown"}}get description(){switch(this.spec){case"chara_card_v2":return this.raw_data.data?.description??this.raw_data.description;case"chara_card_v3":return this.raw_data.data?.description??this.raw_data.description;default:return this.raw_data.description??"unknown"}}get first_message(){switch(this.spec){case"chara_card_v2":return this.raw_data.data?.first_mes??this.raw_data.first_mes;case"chara_card_v3":return this.raw_data.data?.first_mes??this.raw_data.first_mes;default:return this.raw_data.first_mes??"unknown"}}get message_example(){switch(this.spec){case"chara_card_v2":return this.raw_data.data?.mes_example??this.raw_data.mes_example;case"chara_card_v3":return this.raw_data.data?.mes_example??this.raw_data.mes_example;default:return this.raw_data.mes_example??"unknown"}}get create_date(){switch(this.spec){case"chara_card_v2":return this.raw_data.data?.create_date??this.raw_data.create_date;case"chara_card_v3":return this.raw_data.data?.create_date??this.raw_data.create_date;default:return this.raw_data.create_date??"unknown"}}get personality(){switch(this.spec){case"chara_card_v2":return this.raw_data.data?.personality??this.raw_data.personality;case"chara_card_v3":return this.raw_data.data?.personality??this.raw_data.personality;default:return this.raw_data.personality??"unknown"}}get scenario(){switch(this.spec){case"chara_card_v2":return this.raw_data.data?.scenario??this.raw_data.scenario;case"chara_card_v3":return this.raw_data.data?.scenario??this.raw_data.scenario;default:return this.raw_data.scenario??"unknown"}}get alternate_greetings(){switch(this.spec){case"chara_card_v2":return this.raw_data.data?.alternate_greetings;case"chara_card_v3":return this.raw_data.data?.alternate_greetings;default:return[]}}get character_book(){switch(this.spec){case"chara_card_v2":return this.raw_data.data?.character_book;case"chara_card_v3":return this.raw_data.data?.character_book;default:return{entries:[],name:this.name,extensions:{}}}}get tags(){switch(this.spec){case"chara_card_v2":return this.raw_data.data?.tags;case"chara_card_v3":return this.raw_data.data?.tags;default:return[]}}toSpecV1(){let e=t=>this[t]??this.raw_data[t]??this.raw_data.data?.[t];return{name:e("name")??e("char_name"),description:e("description"),personality:e("personality"),scenario:e("scenario"),first_mes:e("first_mes"),mes_example:e("mes_example")}}toSpecV2(){let e=t=>this[t]??this.raw_data[t]??this.raw_data.data?.[t];return S({spec:"chara_card_v2",spec_version:"2.0",data:{name:e("name")??e("char_name"),description:e("description"),mes_example:e("mes_example"),first_mes:e("first_mes"),personality:e("personality"),scenario:e("scenario"),creator_notes:e("creator_notes"),system_prompt:e("system_prompt"),post_history_instructions:e("post_history_instructions"),alternate_greetings:e("alternate_greetings"),character_book:e("character_book"),tags:e("tags"),creator:e("creator"),character_version:e("character_version"),extensions:e("extensions")}})}toSpecV3(){let e=t=>this[t]??this.raw_data[t]??this.raw_data.data?.[t];return S({spec:"chara_card_v3",spec_version:"3.0",data:{name:e("name")??e("char_name"),description:e("description"),tags:e("tags"),creator:e("creator"),character_version:e("character_version"),mes_example:e("mes_example"),extensions:e("extensions"),system_prompt:e("system_prompt"),post_history_instructions:e("post_history_instructions"),first_mes:e("first_mes"),alternate_greetings:e("alternate_greetings"),personality:e("personality"),scenario:e("scenario"),creator_notes:e("creator_notes"),character_book:e("character_book"),assets:e("assets"),nickname:e("nickname"),creator_notes_multilingual:e("creator_notes_multilingual"),source:e("source"),group_only_greetings:e("group_only_greetings"),creation_date:e("create_date")??e("creation_date"),modification_date:e("modify_date")??e("modification_date")}})}toMaxCompatibleSpec(){return O(this.toSpecV1(),this.toSpecV2(),this.toSpecV3())}clone(e="v3"){let t=null;switch(e){case"v1":{t=this.toSpecV1();break}case"v2":{t=this.toSpecV2();break}case"v3":{t=this.toSpecV3();break}default:throw new Error(`Unsupported version ${e}`)}return o.from_json({spec:"chara_card_v1",spec_version:"1.0",data:{},...t})}get_book(){return U.from_json(this.raw_data)}};export{U as CharacterBook,J as CharacterCard,C as JPEG,I as PNG,A as WebP,L as parseImageMetadata}; //# sourceMappingURL=main.mjs.map