specifications:characard
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| specifications:characard [2026/03/18 03:49] – [Other CharaCard "Standards"] tys | specifications:characard [2026/03/18 05:23] (current) – [Implementation Sketch] tys | ||
|---|---|---|---|
| Line 2: | Line 2: | ||
| The CharaCard specification covers three formats and describes its interaction with the PNG specification. As with any community-defined specification, | The CharaCard specification covers three formats and describes its interaction with the PNG specification. As with any community-defined specification, | ||
| - | ===== Overall | + | ===== CharaCard |
| Character Cards are usually distributed as PNG images or JSON text documents. The JSON document directly contains the CharaCard JSON structure, while the PNG contains the same JSON CharaCard structure as metadata. Note that the PNG is **not** a polymorphic JSON/PNG hybrid file, but a fully standards-compliant (if unusually constructed) PNG, with metadata which can be decoded back into a JSON CharaCard structure. | Character Cards are usually distributed as PNG images or JSON text documents. The JSON document directly contains the CharaCard JSON structure, while the PNG contains the same JSON CharaCard structure as metadata. Note that the PNG is **not** a polymorphic JSON/PNG hybrid file, but a fully standards-compliant (if unusually constructed) PNG, with metadata which can be decoded back into a JSON CharaCard structure. | ||
| - | ===== CCv1 ===== | + | When parsing these fields, many implementations omit unsupported fields from generated output. It is recommended to handle invalid/ |
| + | |||
| + | ==== CCv1 ==== | ||
| Version 1 was created with [[: | Version 1 was created with [[: | ||
| Line 17: | Line 19: | ||
| | scenario | String | Specific scenario that the Card and user are engaging with. | | | scenario | String | Specific scenario that the Card and user are engaging with. | | ||
| - | ===== CCv2 ===== | + | ==== CCv2 ==== |
| - | ===== CCv3 ===== | + | ==== CCv3 ==== |
| CharaCard Version 3 is backwards compatible, adding only optional, additional fields. | CharaCard Version 3 is backwards compatible, adding only optional, additional fields. | ||
| - | |||
| - | When parsing these fields, note that many implementations omit unsupported fields from generated output. It is recommended to handle invalid/ | ||
| === JSON Structure === | === JSON Structure === | ||
| Line 47: | Line 47: | ||
| | character_version | String | Version provided by the Card author. Not used in prompt generation. | | | character_version | String | Version provided by the Card author. Not used in prompt generation. | | ||
| | extensions | Object | Can be anything the generator populates here. | | | extensions | Object | Can be anything the generator populates here. | | ||
| - | | **New CCv3 Fields** | + | | **New CCv3 Fields** |
| | assets | Asset Array | Array of Asset objects (see below). Uncommon. | | | assets | Asset Array | Array of Asset objects (see below). Uncommon. | | ||
| | nickname | String | When present, nickname is the name of the character //in// the Card, and name can be a different name for the Card itself. | | | nickname | String | When present, nickname is the name of the character //in// the Card, and name can be a different name for the Card itself. | | ||
| Line 58: | Line 58: | ||
| === Asset object === | === Asset object === | ||
| - | ^ Field Name ^ Type ^ Description | + | ^ Field Name ^ Type ^ |
| - | | type | String | + | | type | String | |
| - | | uri | String | + | | uri | String | |
| - | | name | String | + | | name | String | |
| - | | ext | String | | | + | | ext | String | |
| There are more details to be added here, especially with regards to RisuAI' | There are more details to be added here, especially with regards to RisuAI' | ||
| ===== Lorebook ===== | ===== Lorebook ===== | ||
| - | Lorebook | + | A Lorebook |
| + | |||
| + | Interfaces rarely implement //all// Lorebook features. It is recommended to rely on as few features as possible when writing these structures. | ||
| + | |||
| + | === JSON Structure === | ||
| + | ^ Field Name ^ Type ^ Description ^ | ||
| + | | name | String | This field is often missing! | ||
| + | | description | String | Not used in prompt generation. | | ||
| + | | scan_depth | Number | How many messages to look back into for key matches. | | ||
| + | | token_budget | String | Limits the amount of tokens used by the lorebook. | | ||
| + | | recursive_scanning | String | Controls the ability of entries to trigger other entries. | | ||
| + | | extensions | Object | Can be anything the generator populates here. | | ||
| + | | entries | Entry Array | | | ||
| + | |||
| + | === Entry Object === | ||
| + | |||
| + | ^ Field Name ^ Type ^ Description ^ | ||
| + | | keys | String Array | Text matches which trigger this entry. | | ||
| + | | content | String | The content which is added to the prompt when this entry is triggered. | | ||
| + | | extensions | Object | Can be anything the generator populates here. | | ||
| + | | enabled | Boolean | | | ||
| + | | insertion_order | Number | Sorts different entries when triggered | ||
| + | | case_sensitive | Boolean | Controls case sensitivity when looking for key matches. | | ||
| + | | use_regex | Boolean | If true, keys contain valid regex which should be used for finding a match. | | ||
| + | | constant | Boolean | If true, always activated. | | ||
| + | | name | String | Name of this entry. Not used in prompt generation. | | ||
| + | | priority | Number | If token limits are reached, lower priority values are omitted first. | | ||
| + | | id | Number/ | ||
| + | | comment | String | Additional note or comment left by the author. Not used in prompt generation. | | ||
| + | | selective | Boolean | If true, require match from both keys and secondary_keys to trigger entry. | | ||
| + | | secondary_keys | String Array | Text matches referenced by selective to further restrict entry activation. | | ||
| + | | position | String | Either ' | ||
| ===== PNG ===== | ===== PNG ===== | ||
| - | PNG metadata | + | A PNG file is far more than an array of bytes forming an image. While some interfaces can retrieve data from disordered chunks or incorrectly typed metadata, the following specifications seem to define the only reliable way to build Character Cards for various interfaces. |
| + | |||
| + | ==== Chunk Organization ==== | ||
| + | "A PNG file consists of a PNG signature followed by a series of chunks," | ||
| + | * Header (IHDR) | ||
| + | * Image (PLTE, IDAT, etc.) | ||
| + | * End (IEND) | ||
| + | CharaCard metadata is required to inhabit an tEXt metadata fragment. While metadata is typically placed after the header and before the image (exiftool warns of this). However, CharaCard (and several implementations) require this tEXt metadata chunk to appear at the very end of the PNG, immediately before the End. The resulting structure should be in the following format: | ||
| + | * Header (IHDR) | ||
| + | * Image (PLTE, IDAT, etc.) | ||
| + | * **CharaCard Metadata (tEXt)** | ||
| + | * End (IEND) | ||
| + | |||
| + | ==== tEXt Chunk Composition ==== | ||
| + | The tEXt Chunk is specified [[https:// | ||
| + | |||
| + | |||
| + | ==== Implementation Sketch ==== | ||
| + | [[https:// | ||
| + | |||
| + | <code c> | ||
| + | //prepare in_png with png_create_read_struct | ||
| + | //prepare out_png with png_create_write_struct | ||
| + | //prepare in_info and out_info with png_create_info_struct(in/ | ||
| + | |||
| + | //configure in_png to read from file/ | ||
| + | png_read_png(in_png, | ||
| + | |||
| + | //At this point, in_png and in_info have the input file successfully prepared | ||
| + | // out_png and out_info are ready for writing, but are currently blank. | ||
| + | |||
| + | //Build png_text structures for tEXt as follows: | ||
| + | //key_count could be 1 or 2 depending on chara or ccv3 and chara | ||
| + | png_text *text_chunks = (png_text *)malloc(sizeof(png_text) * key_count); | ||
| + | for (int i = 0; i < key_count; i++) { | ||
| + | text_chunks[i].compression = -1; | ||
| + | text_chunks[i].key = key; //pointer to key (chara/ | ||
| + | text_chunks[i].text = data; //pointer to data (base64-encoded JSON) | ||
| + | text_chunks[i].text_length = data_len; | ||
| + | text_chunks[i].itxt_length = 0; | ||
| + | text_chunks[i].lang = NULL; | ||
| + | text_chunks[i].lang_key = NULL; | ||
| + | } | ||
| + | |||
| + | //modify read PNG to remove any tEXt fields. | ||
| + | png_free_data(in_png, | ||
| + | |||
| + | //At this point, write fields from read PNG into the write PNG fields | ||
| + | png_write_info(out_png, | ||
| + | |||
| + | //Write image chunks | ||
| + | png_bytep *row_pointers = png_get_rows(read_png, | ||
| + | if (!row_pointers) { | ||
| + | fprintf(stderr, | ||
| + | exit(1); | ||
| + | } | ||
| + | png_set_text(out_png, | ||
| + | |||
| + | //Specify the tEXt metadata | ||
| + | //This has to be performed after image chunks have been written to place the tEXt correctly. | ||
| + | png_set_text(out_png, | ||
| + | |||
| + | //Closeout written PNG | ||
| + | png_write_end(out_png, | ||
| + | |||
| + | </ | ||
| + | Note that this is only a sketch - memory management, file I/O, and further implementation is left as an exercise for the reader. | ||
| ===== Other CharaCard " | ===== Other CharaCard " | ||
| - | malfoyslastname' | + | malfoyslastname' |
| - | kwaroran' | + | kwaroran' |
specifications/characard.1773805741.txt.gz · Last modified: by tys
