Giter Club home page Giter Club logo

chatrpg-be's Introduction

ChatRPG: a virtual Dungeon Master for RPG adventures

Maintainability Rating Reliability Rating Quality Gate Status Coverage Vulnerabilities Security Rating Java CI

ChatRPG is a Discord bot powered by JDA that is connected to Azure's OpenAI GPT API. It is cabaple of generating text using base or finetuned models, and was made to act primarily as a chatbot and as an RPG dungeon master. Developed by veteran AI Dungeon and NovelAI players and contributors, aimed to make text-based RPGs more flexible and easier to use on Discord.

Technologies used

  • Java 21
  • Maven
  • Spring Boot
  • Spring WebFlux
  • Spring Data
  • Spring Security
  • JDA
  • PostgreSQL
  • HuggingFace Tokenizer

What does it do?

ChatRPG is mainly focused on RPG DM'ing, but it can also be used as a normal chatbot. The Persona feature allows users to customize behavior and personality for the bot, making it talk or act in a specific way. Channel configs can be set to three game mods, which are RPG, Author and Chat, allowing usage of the bot as an RPG game master, an author of a play or story or a regular chatbot.

Is it free?

Yes and no. The code is free for usage, and so is Discord's API. But as it relies on Azure's API to power the AI, you need to have a subscription on their side and pay according to usage and model chosen. Do take that into consideration before running ChatRPG or choosing a model to run it.

Does it work with other GPT models?

For now, only OpenAI models of the GPT-3.5 and GPT-4 families are supported. ChatRPG does not support Eleuther AI's, GooseAI's, Meta's or AI21's models as of now, nor does it support usage of OpenAI's GPT-2 models locally.

Building from source

To run ChatRPG, you can clone the code and execute him locally. To do so, you'll need to have JDK 21, a PostgreSQL database (ChatRPG comes with a docker-compose.yaml for convenience) and Maven. You will also need a Discord Developer account set up with an app created with the proper permissions, as well as an Azure account.

Discord app permissions

To have ChatRPG work, your Discord app needs to have both the Server Members and Message Content intents allowed in the Bot menu of the Discord Developer dashboard. When inviting the bot to your server, make sure to add the bot and applications.commands scopes added in the OAuth > URL Generator menu of the Discord Developer dashboard. The bot also needs to have permission to read, send and delete messages in the channels specified in its personas, because when a comment is problematic, it will try to delete it. For OAuth2 authentication to work with the ChatRPG API, you will also need to set up integration with Discord and generate a login link, which relies on a redirect URI being created (by the default, ChatRPG uses localhost:8080/auth/code, and unless you change the port and/or the host ChatRPG is running on, you should just use that URL as well).

API keys

You need to have both yout Discord API Key and your Azure API key in hand to set up ChatRPG.

Building

  1. Clone the repo
  2. Add both keys to the bot's application.yaml
    • The recommended way of doing this is setting the keys to the DISCORD_BOT_API_TOKEN and OPENAI_API_TOKEN environment variables respectively, in which case you won't need to modify those values in the YAML; and everything is also safer that way
  3. Enable Developer Mode on your Discord client and right click > copy ID of the channels you want the bot to have access to
  4. Set up the database and either rewrite the values in the YAML or add the values to their respective environment variable
    • Same advice as for the API keys: instead of rewriting the config file, add the proper environment variables
  5. Compile the code with mvn clean install
  6. Run the bot
    • Through the IDE of your choice
    • Through the console with Maven by running mvn spring-boot:run on the bot's root folder
    • Through the console by running the JAR file directly with java -jar chatrpg-0.0.1-SNAPSHOT.jar

Features

ChatRPG was made with RPG DM'ing in mind, so we're striving to add commands and features that make that experience richer.

  • Slash commands to manage the bot.
  • Custom personas with their own model settings.
  • Custom worlds for the bot to generate adventures in.
  • Channel configurations to set up model definitions and moderation used.
  • Lorebook with regex capabilities to improve the AI's context on the adventure.
  • Lorebook entries that can be set as player characters so the AI knows who's who and refrains from speaking on behalf of players.
  • Moderation filters powered by OpenAI's API to avoid problematic and abusive topics.
  • Compatibility with GPT-3.5 and GPT-4.
  • Main use case is as an RPG dungeon master.
  • Can also be used as the author of a story.
  • Can also be used as a normal chatbot if the right intent is used.

chatrpg-be's People

Contributors

thaalesalves avatar

Stargazers

 avatar

Watchers

 avatar Jonathan Jordan avatar Kostas Georgiou avatar

chatrpg-be's Issues

Implementation of a permission check for the bot

Summary

A permission check system to make the sure the bot has the correct permissions to delete messages from a channel. This permission check should also be made for editing and retrying generations with the bot, as leaving those commands free can cause problems with trolling.

Details

When something goes wrong (i.e., filter is triggered or a fail in response generation), the bot deletes the message sent and asks the user to send a new one. For now, the only way to know the bot doesn't have the necessary permissions for that is when it tries to delete a message and an error is thrown. We should improve on this system by implementing a check (preferably before the bot starts listening to messages) and notify the bot owner/server admin that the permission is lacking.

Lorebook entries are always present in context

Summary

Lore entries are a way of giving the AI context on places, characters and details of a the story it's telling, creating a "world" for it to describe when the entries are mentioned. But only when they're mentioned.

Details

Entries are always in the context, which means they're being pulled from the database even when they're not mentioned. This not only clogs the context with unnecessary tokens, but could also cause leaks and break of format since the items in the entries are not being talked about in the current story/chat context.

Expected behavior

Given that a user has a lorebook entry called "John Doe", when that entry is mentioned by its regex tag, then it should be pulled from the DB and added into the top of the AI's memory context.

Actual behavior

Entries are always pulled into the context regardless of mentions of their regex tag. This clogs up context and adds risk of leaking and adding info of items that are not there in the current point of its context, and also wastes available tokens leading to more expensive bills on API usage.

Simplify intent names

Summary

Simplify intents chatbot and dungeonMaster to just chat and rpg to make usage simpler.

Implementation of DM assistance commands

Summary

Useful commands to assist game masters/players drive the AIs context in the direction they want.0

Details

Discord's limited way of dealing with messages makes it hard to drive the AIs outputs into a direction that is generally more compatible with what we want. Commands for DM assistance would be useful because they would allow players to edit AI outputs either generally (right after output is generated) or specifically (by choosing which message exactly to edit). From then on, the content sent to the AI for future completions would be more compatible with the general idea of the story.

Features

Commands that could help drive the course of the story. Examples proposed

  • /codm generate: sends content to the AI as per usual, but after generation shows a modal with the AI's output so that the player is allowed to edit things out and modify it the way they want to
  • /codm edit <MESSAGE-ID>: to edit a specific message so that the future content sent to the AI is more compatible with what's expected
  • /codm retry: deletes the last output and generates a new one

We can discuss on both what other actions would be useful for this command, as well as the command name itself.

Implement token limitation in lore entries

Summary

Limit lore entry descriptions and names by tokens instead of characters.

Details

When we deal with these models, characters are always meaningless, as they deal with tokens. Currently, we have a limit of 250 characters in entry descriptions, which is almost nothing. With 250 tokens, one would be able to create very details descriptions of people, while 250 characters is barely anything.

We can work with HuggingFace's Transformer library for Java and use their tokenizer to do this internally. When someone writes something that goes beyond the token limit for descriptions, the bot notifies them to try again through an ephemeral message.

Unfortunately Discord modals are very limited and we can't add buttons to it or create a modal from another modal, so we'd need to ask for the person to really use the slash command again in case something needs correction. We can also keep with JDA and Discord API in case they improve on modal usability.

Fix pipeline

CI pipeline is failing, and also needs proper steps.

  • Create a dummy bot-config file used for building and packaging
  • Add proper phases (build, test, SAST/DAST, package)
  • Structure properly and put feedback on repo page

Usage of world's custom prompt

Summary

Worlds have a custom prompt that can be used much like scenarios on AI Dungeon, but for now they're just a dummy property that is not used for anything.

Details

Implement mechanics to use the prompt provided for a world when either the user issues a command for that or right after a world being assigned to a channel config.

For now, we have the command /dmassist prompt. This command is used for speaking as the bot and allows for extra generation after a message is set as the bot. This command could have another option that would, instead of opening a modal to type a custom prompt, just use the world's own prompt and send it for the AI for generation on top of that prompt.

Another mechanic could be implemented. A channel config is assigned to a channel using /chconfig set <config-id>, and a world is assigned to that channel config by using /chconfig set <world-id>. We could add, besides the command, a config that spits the prompt right after the current channel is assigned a world.

We should discuss the continuation of that command once we change how those work. Since commands are bloated and long, when we go about simplifying them we should study how to do this for worlds as well.

Use RegEx to dynamically insert data into prompt

  1. Add table to database with columns: id,loreId,pattern. loreId should be a FK to the current data table.
  2. Hook the service to load all patterns and run them on the prompt. On matches, insert the corresponding lore at the top of the prompt.
  3. A given loreId should be inserted no more than once, no matter how many patterns are associated with it.

Questions:

  1. Should there be some sort of cap on the amount of lore to insert? What happens with that boundary is exceeded?
  2. Should we add any sort of priority ranking to lore in case there is too much to insert it all?

Idea: use reactions to flag intent to the AI.

The AI could interpret certain reactions as directives. For example ๐Ÿ‘Ž might tell the AI to ignore a message (which you don't want to delete for some reason). A โญ might tell the AI to flag something as important in the memory.

Expand on this idea.
๐Ÿ›‘ Ignore this message and all previous messages. Leave out of context.
๐Ÿ‘Ž Ignore this message (maybe pick a different icon so it doesn't seem judgmental of the comment)
โญ Make this message important somehow (move closer to front of context?)

Bug: dmassist generate command doesn't work

Summary

Generate command calls for completion from the API but allows the player to edit the output before posting it to Discord.

Details

The command is not showing the modal that is supposed to allow users to edit the output, and sometimes doesn't even generate an output at all.

Expected behavior

Upon using /dmassist generate, the output generate is posted to Discord but a modal with the possibility of editing the output is shown right away. Upon submitting the text, the posted output is edited with whatever is in the text box.

Actual behavior

Either nothing happens and an error is throw or the output is posted to Discord without the possibility of editing it.

Review licensing

The bot is currently under the MIT license. Should we reconsider that?

Implement ChatGPT compatibility

Summary

Implement compatibility with ChatGPT (GPT-3.5-turbo) for the bot.

Details

Now that GPT-3.5 has been release, we need to add support for it and for the entire ChatGPT models. Their API is different, so we need to take that into consideration and re-format the request payload sent to the API.

Differences in API
/v1/completions payload (GPT-3)

{
  "model": "text-davinci-003",
  "prompt": "Say this is a test",
  "max_tokens": 7,
  "temperature": 1,
  "stop": "\n"
}

/v1/chat/completions payload (GPT-3.5)

{
  "model": "gpt-3.5-turbo",
  "messages": [
    {
      "role": "system",
      "content": "General bot instructions or details on persona"
    },
    {
      "role": "user",
      "content": "Message sent by the user"
    },
    {
      "role": "assistant",
      "content": "Reply made by the bot"
    }
  ],
  "max_tokens": 7,
  "temperature": 1,
  "stop": "\n"
}

The main difference there is that there is no prompt concept as it's a chat model. We need to break our message list into an array that follows the specific format OpenAI requires. The role prop in the messages array has fixed values, and can be one of these three: system, user or assistant. Other than that, all other props in the payloads are the same. The ersponse payload seems to be basically the same for both model families, it's easier to format. More details:

Implementation of retry policies on WebClient API calls

Summary

Implement both general and specific policies for API call retries when something goes wrong. Specify the number of retries for each one of these cases.

Details

Sometimes the API fails to generate outputs (HTTP 400, 500, 502 and 503 are relatively common), as well as empty responses (which has its own internal exception thrown). We should have a retry mechanic for those cases, and then any of them happens, the API is called again up to a number of retries set in the config.

The same could apply for outputs that the filter blocks. If something the AI generated goes against OpenAI's policies, instead of just getting flagged and notifying the user, it tries again up to X times and only notifies the user about the problem when the allowed attempts have been exhausted.

Commands for world and channel config retrieval

Summary

Although we won't add functionality for world and config management on Discord, a retrieval command should be available.

Details

Implement commands for these functions with the suggested syntax:
/world get -> returns all worlds saved in DB and channel configs linked
/world get <id> -> returns the world with specified ids and channel configs linked
/chconf get -> returns all chconfigs along with their linked worlds
/chconf get <id> -> returns the specified chconfig along with its linked worlds

Implementation of moderation filter in AI outputs

Summary

Filter AI outputs to make sure they are compatible with OpenAI's policies

Details

For now, the bot only passes the contents of inputs and lorebook entries through the moderation filter. Although that is the bare minimum required for things to work in compatibility with OAI's policies, we should also filter the AI outputs, as it may generate inappropriate content, which breaks functionality of the entire Discord channel being used by the AI until the bad messages are found and deleted.

Create form UI for the bot & simplify commands

Summary

A UI dashboard for managing the bot. This will give us more flexibility to use the bot and simplify commands on Discord.

Details

Commands have become bloated and hard to use. Keeping all of these functionalities on Discord itself is hard, and besides bloating the code limits the usage way too much. To circumvent this, we're implementing an UI to manage the bot. Creation of channel configs, worlds, lorebooks, lore entries, configurations and all of that will be done from the UI, and the commands related to these functionalities will be removed from Discord.

This will also allows to have a more flexible control over tokens, and we will be able to change configurations on the go without restarting the app.

An editable modal with [ Accept | Retry | Cancel ] options

Summary

A GM-assist mode where a GM (or the player tagging the bot) get's a popup modal containing the text of the AI response where they can accept (possibly after editing or completely rewriting), request a retry, or even just cancel to go back and edit previous messages before summoning again

Details

In this mode, summoning the bot would actually invoke a modal which would be populated by the contents of the AI reply.

  • When the user clicks accept, the bot says whatever is in the box.
  • If the user clicks retry, the contents of the modal are cleared and with another call to the AI (might require closing modal and opening new one)
  • If the user clicks cancel, the bot does nothing.

Feature

Behavior

Bug: Bot name missing from messages

Summary

ChatGPT/chatbot is stripping the bot name out of messages

Details

Feature

Behavior

Example:
Sent by User: "Good morning, Selkie," the text reads.
Send to OAI: ChatGptMessage(role=user, content=Shel said: "Good morning, ," the text reads.)

Bug Fix: DB entries send as user role

Summary

Currently the DungeonMasterUseCase adds database entries to the message queue, which results in them being assigned the user role when sent to ChatGPT. These entries might work better if they were assigned a system role.

Details

I think we might want to create an internal Message object. We don't want to have another Message object on top of the JDA Message object, so let's call it MessageData for now and hopefully think up a better name.

MessageData fields:

  • originatorId: Optional (if selfId, this would be an assistant message. If other discordId, this would be a user message. If empty a system message.
  • content: String
  • ?? (anything else that might be userful?)

Feature

Behavior

Implement lorebook commands

Summary

For now, the only way to add lore entries to the lorebook is by doing it directly into the DB. We need to implement slash commands for the bot so it's able to add entries to the DB in a friendlier way.

Details

Implementation of basic CRUD commands for the lorebook.
Slash command /lorebook ACTION UUID

  • Action: create, retrieve, update or delete. Basic actions for the bot to be able to use.
  • UUID: optional for create and retrieve but required for delete and update.

Usage

/lorebook create: Opens a modal window asking for entry name, regex (optional) and description. It should also ask whether the entry is a player character. Replies with an ephemeral message containing the JSON object of the entry created, along with its ID (that should be saved by the user).
/lorebook update <UUID>: Using the UUID provided when creating an entry, the user should be able to modify said entry. Shows a modal with all current data already filled, and lets the user modify what they need to modify there. Replies with the modified character JSON.
/lorebook delete <UUID>: Deletes that entry from the lorebook. Replies with a message saying the operation was successful (or not).
/lorebook retrieve: Retrieves all lorebook entries from the lorebook and reply with an ephemeral message containing a JSON file with all entries.
/lorebook retrieve <UUID>: Retrieves that specific entry from the lorebook and reply to the user with its JSON.

Implement NanoID instead of UUID

Summary

Implementation of NanoID instead of UUID to keep things just as safe and without risk of repetition while having smaller IDs that are easier to save.

Details

NanoID is a mechanic of ID that is just as safe and repetition risk-free as UUID, but we have more control over format and characters used, which makes them easier to use.

BugFix for ContextDatastore

reactor.core.Exceptions$ErrorCallbackNotImplemented: java.lang.NullPointerException: messageEventData not set
Caused by: java.lang.NullPointerException: messageEventData not set
	at es.thalesalv.gptbot.adapters.data.ContextDatastore.lambda$1(ContextDatastore.java:36)
	at java.base/java.util.Optional.orElseThrow(Optional.java:403)
	at es.thalesalv.gptbot.adapters.data.ContextDatastore.getMessageEventData(ContextDatastore.java:36)
	at es.thalesalv.gptbot.application.service.ChatGptModelService.generate(ChatGptModelService.java:37)

Lorebook command modals with problems

Summary

After the restructure of commands, lorebook commands work mostly but the create function modal returns an error

Details

When a modal is filled with the details, the app should proceed to detecting the proper service and have it add the into to the DB. But that's not happening.

Expected behavior

Modal is filled -> service catches the content -> builds the object -> inserts into DB

Actual behavior

After modal is filled and submitted, bot returns an error saying the command was not found. Check the behavior for other lorebook commands.

Database hangs when look for character profiles

Issue category

Type: Bug

Issue description

Malaquias is able to retrieve a player's character's profile when either the player is directly mentioned or when their nickname shows on the message list sent to the AI. This problem occurs during this stage, and after converting the derived query method name into an actual SQL query, the select hangs and the bot stops responding.

Bug: output moderation deletes input instead of trying to generate a new output (or deleting the problematic output)

Summary

Moderation of outputs is supposed to either try to generate a less problematic output or not post the one generated at all and notify the user about the problem. It is deleting the input and flagging it as problematic instead.

Details

Implement a fix that forces the bot to generate a new output in case the one generated is problematic. It should only notify the user about the problems after the re-attempts have been exhausted and problematic generations kept coming.

Define how other models would be used for context enhancement

We spoke about using Ada, Curie or Babbage to help with content summarization so Davinci has more context to work with which would lead to better generations. Which model will we use? What should be used as the prompt? How many messages for context? What settings should we use?

Dice roll mechanic for RPG mode

Summary

Dice rolls are a must-have for RPG mode. We must implement a mechanic for dice rolling and successes for this mode.

Details

Use other bots and different intents to interpret dice rolls and feed the storytelling AI the results

Author mode

Summary

Use AI to tell a continuous story with direction from user

Details

This is essentially chat mode but with some unneeded things stripped out that aren't needed.

Feature

Behavior

In this mode, there is no need to identify different users or retain previous direction, so we reclaim some room for context by passing only the most recent user message. We also strip out any "foo said:" that gets injected elsewhere and identify assistant/user by whether the bot said the message or someone else.

Refactor persona structure and implement custom personas and management commands

Summary

Currently, persona configuration is only doable from the YAML, which means that any change to them requires a full reboot of the application. We should make it so the YAML configs act more as "default" configs that will be ingested into a persona table that can be modified while the bot is running.

Details

Map YAML contents into a DB entity object and insert all default configs to DB. This makes the default configs more flexible before starting the bot for the first time, and just as flexible after it has started; this allows changes to be made to the persona while the bot runs.

Features

  • Allows the bot to be added to channels while it's used
  • Allows for change of its personality while in use
  • Allows for temperature, tokens and such configurations to be tweaked while it's used
  • Allows for creation of new personas while it's used

Considerations

  • The personas need to be ingested only once. Which means that if the bot is restarted and configs are already in the persona table, the bot should not ingest the YAML again. A check in the DB is needed to make sure data isn't overwritten after a reboot of the bot.
  • Permission check; only persona creators should be allowed to change their configs; we can discuss giving access to other people too
  • Needs creation of command /persona for this to be functional

Turn character entries into a lorebook

Now that we have fixed the problem with regex and the database hangs, we can expand on the concept of a lorebook. Instead of just saving player characters, we will now save general entries that can be added to the context when mentioned in the story. This will come with commands to manage these entries.

Implementation of OpenAI filter

Issue category

Type: Feature

Issue description

OpenAI has guidelines on what can be fed to the AI and what the AI can generate as a response. To avoid issues with problematic inferences by the AI or sensitive prompts being sent to it, we need to implement a call to OAI's filter API before a prompt is sent to the AI and before the AI's generated text is sent to Discord.

Implement character management commands

Issue description

For now, the only way to insert data into the bot's table is by connecting to the database manually since there is no function or method to insert data. To make usage of the bot simpler and more fluid, creating commands for the but is necessary; the first command to be added should be the creation of characters.

Re-engineering of the entire message flow

Summary

Separation of input and output mechanics for proper processing.

Details

The current architecture the bot has is very simplistic, so it doesn't have separated flows for inputs and outputs. We need top refactor the entire thing so it works in a more flow-friendly and flexible way that is easier to implement changes, maintain and debug. We should also properly document and diagram everything so we always know what's what.

Following of single-use principle is a must here, so we need to pay attention to those.

Document packages with package-info.java for clarity

Summary

The overall structure of the application is a little confusing or at least the architectural intent is unclear.

Details

Including package-info.java along with a bit of Javadoc can help clarify the intent of each package and make sure features find their right home. This needn't be done all at once (and not all packages need it), but can start at the top level and add on as clarity is required. Relevant stack overflow

Alternatively, this could be documented in a separate README, but should be intended for a more technical audience and shouldn't be part of the main README.

Implement DM assist commands for custom prompts or speak as the bot

Summary

DM assist commands help the player/user/DM drive the story in a way that's more compatible with their ideas. This would expand on that by letting people speak as the bot or add a prompt that the bot will then elaborate on.

Details

Implement commands that allow people to speak as the bot or give a pre-made prompt for the bot to expand on and make adventure starts more convenient and natural. This would also help users drive the story in a more specialized way.

Add support for worlds

Summary

Add support for custom scenarios (or worlds) that will expand on usage of the bot.

Details

Worlds are detached from each other. They have their own lorebooks, with their own characters and places and things. They would be created, maintained and chosen by slash commands.

  • 1..1 relation with the lorebook table (so each world has its own lorebook)
  • 1..1 relation with ChannelConfigs
  • Name and description. A general, short description of the world would be sent to the AI for context
  • Basic CRUD commands, as per usual
  • Choice command (so the chosen world can be used in the chosen channel)
  • Creation command also creates a lorebook and returns ID of both to the user
  • Update command command to change world data
  • Deletion command also deletes lorebook and its entries
  • Make private or public

Anything else that would be important to discuss about?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.