Skip to content

Commit b6787d0

Browse files
authored
Merge pull request #1 from VladVP/main
Add initial system prompt to create behavior identical with and/or equivalent to ChatGPT on the web.
2 parents ee6fc50 + d9d50d8 commit b6787d0

File tree

5 files changed

+87
-26
lines changed

5 files changed

+87
-26
lines changed

.env.example

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,9 @@ DISCORD_BOT_TOKEN=x
33
DISCORD_CLIENT_ID=x
44

55
ALLOWED_SERVER_IDS=1
6-
SERVER_TO_MODERATION_CHANNEL=1:1
6+
7+
OPENAI_API_URL=https://api.openai.com/v1/chat/completions
8+
OPENAI_MODEL=gpt-3.5-turbo
9+
10+
SYSTEM_MESSAGE="You are ChatGPT, a large language model trained by OpenAI. Answer as concisely as possible. Knowledge cutoff: {knowledge_cutoff} Current date: {current_date}"
11+
KNOWLEDGE_CUTOFF="2021-09"

README.md

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@ Thank you!
1616
---
1717
# GPT Discord Bot
1818

19-
Example Discord bot written in Python that uses the [completions API](https://beta.openai.com/docs/api-reference/completions) to have conversations with the `text-davinci-003` model, and the [moderations API](https://beta.openai.com/docs/api-reference/moderations) to filter the messages.
20-
21-
**THIS IS NOT CHATGPT.**
19+
Example Discord bot written in Python that uses the [completions API](https://beta.openai.com/docs/api-reference/completions) to have conversations with the `gpt-3.5-turbo` or `gpt-4` models.
2220

2321
This bot uses the [OpenAI Python Library](https://github.com/openai/openai-python) and [discord.py](https://discordpy.readthedocs.io/).
2422

@@ -53,9 +51,9 @@ This bot uses the [OpenAI Python Library](https://github.com/openai/openai-pytho
5351
5452
# Optional configuration
5553
56-
1. If you want moderation messages, create and copy the channel id for each server that you want the moderation messages to send to in `SERVER_TO_MODERATION_CHANNEL`. This should be of the format: `server_id:channel_id,server_id_2:channel_id_2`
57-
1. If you want to change the personality of the bot, go to `src/config.yaml` and edit the instructions
58-
1. If you want to change the moderation settings for which messages get flagged or blocked, edit the values in `src/constants.py`. A lower value means less chance of it triggering.
54+
- If you want to change the model used, you can do so in `OPENAI_MODEL`. Currently only `gpt-3.5-turbo` and `gpt-4` work with the present codebase.
55+
56+
- If you want to change the behavior/personality of the bot, change the system prompt in `SYSTEM_MESSAGE`, with optional variables enclosed in `{`curly braces`}`. Currently the only variables available are `current_date` and `knowledge_cutoff`, with the latter being equivalent to the environment variable of the same name. The former is always in ISO 8601 format.
5957
6058
# FAQ
6159

src/constants.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
OPENAI_API_URL = os.environ['OPENAI_API_URL']
1212
OPENAI_MODEL = os.environ['OPENAI_MODEL']
1313

14+
SYSTEM_MESSAGE = os.environ["SYSTEM_MESSAGE"]
15+
KNOWLEDGE_CUTOFF = os.environ["KNOWLEDGE_CUTOFF"]
16+
1417
ALLOWED_SERVER_IDS: List[int] = []
1518
server_ids = os.environ["ALLOWED_SERVER_IDS"].split(",")
1619
for s in server_ids:
@@ -36,5 +39,5 @@
3639
ACTIVATE_THREAD_PREFX = "💬✅"
3740
INACTIVATE_THREAD_PREFIX = "💬❌"
3841
MAX_CHARS_PER_REPLY_MSG = (
39-
1500 # discord has a 2k limit, we just break message into 1.5k
42+
2000 # discord has a 2k limit
4043
)

src/main.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import datetime
12
import discord
23
from discord import Message as DiscordMessage
34
import logging
@@ -8,6 +9,8 @@
89
ACTIVATE_THREAD_PREFX,
910
MAX_THREAD_MESSAGES,
1011
SECONDS_DELAY_RECEIVING_MSG,
12+
SYSTEM_MESSAGE,
13+
KNOWLEDGE_CUTOFF
1114
)
1215
import asyncio
1316
from src.utils import (
@@ -78,8 +81,17 @@ async def chat_command(int: discord.Interaction, message: str):
7881
auto_archive_duration=60,
7982
)
8083
async with thread.typing():
84+
# prepare the initial system message
85+
current_date = datetime.datetime.now().strftime("%Y-%m-%d")
86+
system_message = SYSTEM_MESSAGE.format(
87+
knowledge_cutoff=KNOWLEDGE_CUTOFF,
88+
current_date=current_date
89+
)
8190
# fetch completion
82-
messages = [Message(user='system', text=message)]
91+
messages = [
92+
Message(user='system', text=system_message),
93+
Message(user='user', text=message)
94+
]
8395
response_data = await generate_completion_response(
8496
messages=messages,
8597
)
@@ -145,13 +157,21 @@ async def on_message(message: DiscordMessage):
145157
f"Thread message to process - {message.author}: {message.content[:50]} - {thread.name} {thread.jump_url}"
146158
)
147159

160+
# prepare the initial system message
161+
current_date = datetime.datetime.now().strftime("%Y-%m-%d")
162+
system_message = SYSTEM_MESSAGE.format(
163+
knowledge_cutoff=KNOWLEDGE_CUTOFF,
164+
current_date=current_date
165+
)
166+
148167
channel_messages = [
149168
discord_message_to_message(
150169
message=message,
151170
bot_name=client.user)
152171
async for message in thread.history(limit=MAX_THREAD_MESSAGES)
153172
]
154173
channel_messages = [x for x in channel_messages if x is not None]
174+
channel_messages.append(Message(user='system', text=system_message))
155175
channel_messages.reverse()
156176

157177
# generate the response

src/utils.py

Lines changed: 52 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,30 +26,65 @@ def discord_message_to_message(
2626
logger.info(
2727
f"field.name - {field.name}"
2828
)
29-
return Message(user="system", text=field.value)
29+
return Message(user="user", text=field.value)
3030
else:
3131
if message.content:
3232
user_name = "assistant" if message.author == bot_name else "user"
3333
return Message(user=user_name, text=message.content)
3434
return None
3535

3636

37-
def split_into_shorter_messages(message: str) -> List[str]:
38-
indices_object = re.finditer(
39-
pattern='```',
40-
string=message)
41-
42-
indices = [index.start() for index in indices_object]
43-
indices[1::2] = [x + 4 for x in indices[1::2]]
44-
indices.insert(0, 0)
45-
indices.append(len(message))
46-
47-
result = []
48-
for i in range(1, len(indices)):
49-
result.append(message[indices[i-1]:indices[i]])
50-
51-
return result
52-
37+
def split_into_shorter_messages(text, limit=MAX_CHARS_PER_REPLY_MSG, code_block='```'):
38+
def split_at_boundary(s, boundary):
39+
parts = s.split(boundary)
40+
result = []
41+
for i, part in enumerate(parts):
42+
if i % 2 == 1:
43+
result.extend(split_code_block(part))
44+
else:
45+
result += split_substring(part)
46+
return result
47+
48+
def split_substring(s):
49+
if len(s) <= limit:
50+
return [s]
51+
for boundary in ('\n', ' '):
52+
if boundary in s:
53+
break
54+
else:
55+
return [s[:limit]] + split_substring(s[limit:])
56+
57+
pieces = s.split(boundary)
58+
result = []
59+
current_part = pieces[0]
60+
for piece in pieces[1:]:
61+
if len(current_part) + len(boundary) + len(piece) > limit:
62+
result.append(current_part)
63+
current_part = piece
64+
else:
65+
current_part += boundary + piece
66+
result.append(current_part)
67+
return result
68+
69+
def split_code_block(s):
70+
if len(code_block + s + code_block) <= limit:
71+
return [code_block + s + code_block]
72+
else:
73+
lines = s.split('\n')
74+
result = [code_block]
75+
for line in lines:
76+
if len(result[-1] + '\n' + line) > limit:
77+
result[-1] += code_block
78+
result.append(code_block + line)
79+
else:
80+
result[-1] += '\n' + line
81+
result[-1] += code_block
82+
return result
83+
84+
if code_block in text:
85+
return split_at_boundary(text, code_block)
86+
else:
87+
return split_substring(text)
5388

5489
def is_last_message_stale(
5590
interaction_message: DiscordMessage, last_message: DiscordMessage, bot_id: str

0 commit comments

Comments
 (0)