Discord bot with ChatGPT API and SQL database for logging server events.
My Discord bot is designed to answer questions directly in chat using the ChatGPT API. This means that users can ask the bot any question they have, and the bot will respond with a relevant answer generated by the ChatGPT model. This is a great way to provide instant assistance and support to users, as they can get their questions answered quickly and easily.
During an API call, functions are specified to the models. These models are capable of intelligently generating a JSON object that includes the necessary arguments for invoking those functions. It's important to note that the Chat Completions API itself does not directly call the function. Instead, it generates JSON output that is utilized to make the function call.
Here is an example of function to get the current date & time.
def get_todays_date(timezone='US/Eastern'):
"""Get the current date and time based on the timezone"""
tz = pytz.timezone(timezone)
today = {"timezone": timezone,
"today": str(datetime.datetime.now(tz))}
return json.dumps(today)ChatGPT intelligently recognizes when to invoke this function and uses the information to generate a response.
The Grok integration (_ask / _voice) is self-aware: alongside xAI's server-side web/X search, every request exposes client-side tools that let Grok look up how the bot itself works instead of guessing:
| Tool | What it returns |
|---|---|
get_bot_documentation |
Curated member-facing docs (docs/self_knowledge/) on the bot overview, the _1st game, DinkCoin, AI features, and server stats |
list_bot_commands |
The live command list, generated from the registered cogs at runtime |
get_first_game_stats |
Live first-win leaderboard, most recent winner, and current streak |
get_juice_stats |
Live juice leaderboard (total juice), single-day high score |
get_dink_ledger |
Live top DINK holders and total circulation |
Ask the bot "how does juice work?" or "who has the most DINK?" and it pulls the answer from these tools. To extend its knowledge, add a markdown file to docs/self_knowledge/ and register it in utils/self_knowledge.py (TOPICS).
The bot is also connected to the DALL·E 3 API. It can take any prompt as described using natural language and generate a detail 1024x1024 image!
In addition to answering questions, the bot also writes events with usernames and timestamps to a MySQL database hosted on Amazon Web Services (AWS). This means that you can keep track of when users are interacting with your bot, and what commands they are sending. This information can be used to improve the performance and effectiveness of the bot over time, by analyzing the data to identify trends and patterns in user behavior.
Basic summaries of the data can be found in the server dashboard (https://peterdinklage.streamlit.app/) displaying information like monthly messages by user or the number of times a user has had the 1st message of the day.
Here it's being used to log and record who sends the first message of the day. Users will send a command as close to the stroke of midnight and the event will be recorded to the database. This has become one of the most popular games on our server!
The core Discord functionality of this project is contained in the bot.py file. The logic for the ChatGPT API request and intelligent function calling are contained in the chatgpt_functions.py file.
Successful _1st claims award 1 DINK (configurable via DINK_MINT_AMOUNT). Balances, the server ledger, and peer-to-peer trades all live in MySQL — no blockchain or crypto wallet required.
| Command | Description |
|---|---|
_balance |
Show your DINK balance |
_ledger |
Top holders leaderboard |
_pay @user <amount> |
Send DINK to another user |
Setup: run scripts/dinkcoin_schema.sql against your MySQL database once.
bot.py: Main bot file that initializes the Discord bot and loads command cogs.chatgpt_functions.py: Contains functions for interacting with the ChatGPT API and handling AI responses.cogs/: Directory containing modular command extensions:ai.py: AI-related commands including ChatGPT integration and DALL·E 3 image generation.first.py: Commands for tracking and managing first messages of the day.dinkcoin.py: DinkCoin balance, ledger, and peer-to-peer transfers.misc.py: Miscellaneous utility commands.server.py: Server management and dashboard-related commands.utility.py: General utility commands.
utils/: Utility modules:constants.py: Constants and configuration values.db.py: Database operations for logging messages and events.
scripts/dinkcoin_schema.sql: MySQL tables for the DINK ledger.requirements.txt: Python dependencies required for the project.requirements-dev.txt: Test dependencies (pytest, pytest-asyncio).tests/: Pytest suite (mocked command tests, unit tests, and live smoke tests).scripts/test.sh: Run the full test suite locally (mirrors CI).README.md: This documentation file.
- Clone the repository.
- Copy
.env.exampleto.envand fill in values from your hosting dashboard. - Run locally:
./scripts/dev.sh
The dev script creates a virtual environment, installs dependencies, and starts the bot.
Local runs use the same credentials as production (Discord token, MySQL, xAI). Only one bot session can be active per token, so stop the hosted bot first.
- Stop the bot on your hosting site.
- Ensure
.envis populated (see.env.example). - Run
./scripts/dev.sh - Test commands on your Discord server (prefix is
_). - Press Ctrl+C to stop, then restart the hosted bot.
You can't push directly to main. Open a pull request and the tests will run automatically in GitHub Actions. They need to pass before you can merge.
Run tests locally first:
./scripts/test.shTo skip live API and database calls:
./scripts/test.sh -m "not live"xAI (no Discord or DB):
source .venv/bin/activate
python test_grok.pyTo block pushes when tests fail, add a local git hook (not committed to the repo):
cat > .git/hooks/pre-push <<'EOF'
#!/usr/bin/env bash
./scripts/test.sh || exit 1
EOF
chmod +x .git/hooks/pre-pushTests run on pull requests (open, update, reopen) and on push to main. Results appear in three places:
- Checks tab — pass/fail status via JUnit (
Test Resultscheck) - Job summary — expected vs actual tables (prompts, Grok responses, command outputs, etc.)
- Artifacts — downloadable
junit.xmlandci-test-report.mdfrom the workflow run
Add these repository secrets under Settings → Secrets and variables → Actions:
XAI_API_KEYSQL_HOSTSQL_USERSQL_PASSWORDSQL_DATABASE
Locally, ./scripts/test.sh writes the same ci-test-report.md in the project root after each run.
Live MySQL smoke tests require your database to accept remote connections from GitHub Actions. If PebbleHost blocks external access, run ./scripts/test.sh -m "not live" locally and rely on mocked DB tests in CI until remote access is configured.





