From b52cd58395dcf0c0ebeb35a7d820f0625bd5631a Mon Sep 17 00:00:00 2001 From: Cameron Reikes Date: Thu, 1 Jun 2023 18:10:30 -0700 Subject: [PATCH] Prompt with chat history --- assets/new_level.json | 8 ++++---- character_info.h | 38 +++++++++++++++++++++++++++----------- main.c | 1 + makeprompt.h | 31 +++++++++++++++++++++++-------- 4 files changed, 55 insertions(+), 23 deletions(-) diff --git a/assets/new_level.json b/assets/new_level.json index 6e7042d..0752b86 100644 --- a/assets/new_level.json +++ b/assets/new_level.json @@ -382,8 +382,8 @@ "rotation":0, "visible":true, "width":32, - "x":1506.00000000001, - "y":2563.66666666667 + "x":1540.66666666668, + "y":2094.33333333334 }, { "class":"", @@ -443,8 +443,8 @@ "rotation":0, "visible":true, "width":32, - "x":1572.66666666667, - "y":2226 + "x":1523.33333333334, + "y":2551.33333333333 }], "opacity":1, "type":"objectgroup", diff --git a/character_info.h b/character_info.h index e19c9e9..a989048 100644 --- a/character_info.h +++ b/character_info.h @@ -95,11 +95,28 @@ ItemInfo items[] = { }, }; +typedef enum +{ + MSG_SYSTEM, + MSG_USER, + MSG_ASSISTANT, +} MessageType; + +typedef struct +{ + MessageType type; + char *character_name; // not the enum name + char *dialog; + char *action_taken; // has the ACT prefix, so ACT_action. If it's null it means ACT_none + char *action_argument; // if not null then action argument provided in parenthesis +} ChatHistoryElem; + typedef struct { char *name; char *enum_name; char *prompt; + ChatHistoryElem previous_conversation[32]; } CharacterGen; CharacterGen characters[] = { #define NUMEROLOGIST "They are a 'numberoligist' who believes in the sacred power of numbers, that if you have the number 8 in your birthday you are magic and destined for success. " @@ -260,17 +277,16 @@ CharacterGen characters[] = { #define NPC_NAME "Bill" .name = NPC_NAME, .enum_name = "Bill", - .prompt = "\n" - "The NPC you will be acting as is named " NPC_NAME ". Unlike other NPCs, he's not from around this medieval fantasy land. He's a divorced car insurance accountant from Philadelphia with a receding hairline in his mid 40s. He lives in a one bedroom studio and his kids don't talk to him. An example of an interaction between the player and the NPC, " NPC_NAME ":\n" - "\n" - PLAYERSAY("Hey what's up") - NPCSAY("Oh...Oh my gosh JESUS FUCKING CHRIST WHERE AM I") - PLAYERSAY("Calm down dude") - NPCSAY("First I was at home, now all the sudden there's all these monsters and FREAKS! GET ME THE FUCK OUT!!") - PLAYERSAY("Freaks? What is the point of this world, where are we?") - NPCDOSAY("ACT_joins_player", "I have no idea man, but I'm freaked out and don't know where I am. I'm like you, from the normal world, not like these crazy fantasy people. Get me out of here GET ME OUT OF HERE!") - "\n" - "You, " NPC_NAME ", are very eager to join the player out of fear for your own survival. You will do anything to escape this weird fantasy world.", + .prompt = "He's not from around this medieval fantasy land, instead " NPC_NAME " is a divorced car insurance accountant from Philadelphia with a receding hairline in his mid 40s. He lives in a one bedroom studio and his kids don't talk to him. " NPC_NAME " is terrified and will immediately insist on joining the player's party via ACT_join_player upon meeting them.", + .previous_conversation = { + { .type = MSG_USER, .character_name = "Jester", .dialog = "Hehehe! Quit quant, a peasant from the mortal realm!" }, + { .type = MSG_ASSISTANT, .character_name = NPC_NAME, .dialog = "No...Please! Stay away from me! Who the Hell are you!" }, + { .type = MSG_USER, .character_name = "Jester", .dialog = "Poor Bill, I'm sure your wife says the same..." }, + { .type = MSG_ASSISTANT, .character_name = NPC_NAME, .dialog = "You evil BASTARD!! What is this place???" }, + { .type = MSG_USER, .action_taken = "ACT_causes_testicular_torsion", .character_name = "Jester", .dialog = "I'll leave that for you to find out ;)" }, + { .type = MSG_ASSISTANT, .character_name = NPC_NAME, .dialog = "AUGGHGHHH!!! THE PAIN IS UNBEARABLE" }, + { .type = MSG_USER, .action_taken = "ACT_undoes_testicular_torsion", .character_name = "Jester", .dialog = "That's just a taste of what's to come! Bye bye~" }, + }, }, { #undef NPC_NAME diff --git a/main.c b/main.c index c57811e..1368ce1 100644 --- a/main.c +++ b/main.c @@ -1199,6 +1199,7 @@ void reset_level() ENTITIES_ITER(gs.entities) { + if(false) if (it->npc_kind == NPC_TheBlacksmith) { Memory test_memory = {0}; diff --git a/makeprompt.h b/makeprompt.h index b5ac978..86955f4 100644 --- a/makeprompt.h +++ b/makeprompt.h @@ -370,13 +370,6 @@ bool npc_does_dialog(Entity *it) return it->npc_kind < ARRLEN(characters); } -typedef enum -{ - MSG_SYSTEM, - MSG_USER, - MSG_ASSISTANT, -} MessageType; - // for no trailing comma just trim the last character MD_String8 make_json_node(MD_Arena *arena, MessageType type, MD_String8 content) { @@ -460,8 +453,30 @@ MD_String8 generate_chatgpt_prompt(MD_Arena *arena, Entity *e) MD_String8List list = {0}; MD_S8ListPushFmt(scratch.arena, &list, "["); + + MD_String8List first_system_string = {0}; + + MD_S8ListPushFmt(scratch.arena, &first_system_string, "%s\n", global_prompt); + MD_S8ListPushFmt(scratch.arena, &first_system_string, "The NPC you will be acting as is named \"%s\". %s", characters[e->npc_kind].name, characters[e->npc_kind].prompt); + MD_S8ListPush(scratch.arena, &list, make_json_node(scratch.arena, MSG_SYSTEM, MD_S8ListJoin(scratch.arena, first_system_string, &(MD_StringJoin){0}))); - MD_S8ListPush(scratch.arena, &list, make_json_node(scratch.arena, MSG_SYSTEM, MD_S8Fmt(scratch.arena, "%s\n%s\n", global_prompt, characters[e->npc_kind].prompt))); + for(int i = 0; i < ARRLEN(characters[e->npc_kind].previous_conversation); i++) + { + ChatHistoryElem *cur = &characters[e->npc_kind].previous_conversation[i]; + if(!cur->character_name) break; + + MD_String8List cur_node_string = {0}; + char *action_string = "ACT_none"; + if(cur->action_taken) action_string = cur->action_taken; + MD_S8ListPushFmt(scratch.arena, &cur_node_string, "%s: %s", cur->character_name, action_string); + if(cur->action_argument) + { + MD_S8ListPushFmt(scratch.arena, &cur_node_string, "(%s)", cur->action_argument); + } + MD_S8ListPushFmt(scratch.arena, &cur_node_string, " \"%s\"", cur->dialog); + + MD_S8ListPush(scratch.arena, &list, make_json_node(scratch.arena, cur->type, MD_S8ListJoin(scratch.arena, cur_node_string, &(MD_StringJoin){0}))); + } ItemKind last_holding = ITEM_none; BUFF_ITER(Memory, &e->memories)