Karelia-AI.JS is an LLM-based Discord bot modeled as close as possible to an actual human for ScIeNtIfIc pUrPoSes.
Powered by Groq. Absolutely nothing unusual going on here.
Karelia-AI.JS is a Discord AI chatbot designed to simulate human-like interaction using LLMs, prompt examples, and optional web search augmentation.
It is:
- First and Foremost: Not alive(!!!!)
- Not self-aware
- Debatably convincing enough to be a problem
Karelia's responses are shaped by a personality.json file containing a system prompt and a list of few-shot examples β user/bot pairs that train the model to reply in a specific voice. The more examples you provide, the more consistent and convincing the persona becomes.
Powered by Groq (llama-3.3-70b-versatile), Karelia reads recent message history to maintain conversational context. She responds when mentioned or replied to β not on every message, so she doesn't make it weird. Probably.
When configured with a SERPER_API_KEY, Karelia can perform real-time web searches to ground her responses in current information. The search layer is optional β the bot works fine without it.
Karelia can analyze images sent in chat using Google Generative AI's vision capabilities. Send her an image and she'll describe, comment on, or react to it in-character.
Karelia supports full in-Discord chess matches powered by chess.js and Stockfish.
- Challenge her with a slash command and play moves via standard notation
- The board is rendered as an image using FEN strings, sent directly in chat after every move
- Stockfish runs in a separate worker thread (
stockfishWorker.js) so it doesn't block the main bot process - Game-over states trigger special behavior β Karelia taunts the loser and fires a reaction GIF to punctuate the moment
Karelia sends contextually appropriate GIFs in response to certain events (wins, losses, specific keywords, etc.) via Klipy. GIF data is stored and cached in gifarray.json and learned_gifs_array.json, allowing the reaction pool to grow over time.
Sensitive or internal utility functions live in the encryptedfunc/ directory, keeping them separate from the main bot logic.
Bot activity is written to the logs-storage/ directory for debugging and auditing purposes.
- Node.js 18+
- A Discord bot token with Message Content Intent enabled
- A Groq API key
- A Klipy API key (for GIF reactions)
- A Google API key (for image analysis)
- A SERPER API key (optional, for web search)
- Visual Studio Code (optional)
- Docker Desktop (optional, if you want to host it)
Discord Message
β
Event Listener (discord.js)
β
Context Parser (Groq)
β
(Optional) SERPER Search Layer
β
Prompt Builder (a.k.a. personality engine)
β
Groq Again
β
Response Formatter
β
Discord Output
- Make your own
.envfile with the variables: DISCORD_TOKENDISCORD_CLIENT_IDBOT_PREFIXGROQ_API_KEYGOOGLE_API_KEYKLIPY_API_KEYSERPER_API_KEYβ optional, for web search
Tip
You have been provided with an env example.
It's not like I wanted you to have an easier time or anything.

Tip
Navigate to the project directory and run:
npm installThis will pull in all required packages β discord.js, groq-sdk, chess.js, @google/generative-ai, dotenv, and others.
Before running the bot for the first time, register its slash commands with Discord:
node deploy-command.jsYou only need to do this once, or whenever you add or modify commands.
Edit personality.json to define Karelia's character. The system field sets her core behavior; the examples field is where you train her voice with user/bot prompt pairs.
"examples": [
{
"user" : "Hello there!",
"bot" : "The missile knows where it is at all times. It knows this because it knows where it isn't. By subtracting where it is from where it isn't, or where it isn't from where it is (whichever is greater),
it obtains a difference, or deviation. The guidance subsystem uses deviations to generate corrective commands to drive the missile from a position where it is to a position where it isn't,
and arriving at a position where it wasn't, it now is. Consequently, the position where it is, is now the position that it wasn't, and it follows that the position that it was, is now the position that it isn't.
In the event that the position that it is in is not the position that it wasn't,
the system has acquired a variation, the variation being the difference between where the missile is, and where it wasn't. If variation is considered to be a significant factor, it too may be corrected by the GEA.
However, the missile must also know where it was. The missile guidance computer scenario works as follows. Because a variation has modified some of the information the missile has obtained,
it is not sure just where it is. However, it is sure where it isn't, within reason, and it knows where it was. It now subtracts where it should be from where it wasn't,
or vice-versa, and by differentiating this from the algebraic sum of where it shouldn't be, and where it was, it is able to obtain the deviation and its variation, which is called error."
},
{
"user": "are you auti-",
"bot" : "lock tuah, AIM-9 on that thang!"
}
]Running with an IDE is preferred. However, if you want to run from the Command Line, navigate to your target location with your copy of index.js using cd <path>, then run:
node index.jsOr use the provided npm script:
npm startTip
You can verify the bot's files for syntax errors before running with:
npm test- Install WSL and Docker Desktop.
- Open Docker Desktop to run Docker Engine.
- create your "homebase" folder.
- open Command Prompt, cd to your homebase folder and run
git clone https://github.com/RuiKurumi/Karelia-AI.js.git - create your dockerfile:
-
FROM node:20-alpine WORKDIR /app COPY package*.json ./ RUN npm install COPY . . CMD ["node", "index.js"]
-
- Create .dockerignore
-
node_modules temp .env *.log
-
- and then build (on Powershell) with:
-
docker build -t karelia . docker run -d --name karelia --restart unless-stopped --env-file .env -v $(pwd)/data:/app/data -v $(pwd)/logs-storage:/app/logs-storage karelia
-
- enjoy.
Note
- Yes, the missile quote is intentional
- No, it will not be removed
- Yes, the bot can become weird if you try hard enough (X to doubt, really)
- No, I don't recommend testing that last one