Skip to content

Commit 6c9ec9a

Browse files
author
Flamingo Fiesta
committed
fixed the tokenizer for the claude models. Using the same one as for gpt-4-turbo since anthropic doesnt have their tokenizer public. Also added the possibility to enable or disable the logging in the console
1 parent fd12649 commit 6c9ec9a

File tree

6 files changed

+60
-72
lines changed

6 files changed

+60
-72
lines changed

bot/bot.py

+14-4
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,13 @@
4444

4545
# setup
4646
db = database.Database()
47+
4748
logger = logging.getLogger(__name__)
4849

4950
user_semaphores = {}
5051
user_tasks = {}
5152

52-
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(name)s - %(message)s') #logging error
53+
5354
HELP_MESSAGE = """Commands:
5455
5556
⚪ /new – Start new dialog
@@ -92,11 +93,19 @@ def update_user_roles_from_config(db, roles):
9293
)
9394
print("User roles updated from config.")
9495

95-
9696
def split_text_into_chunks(text, chunk_size):
9797
for i in range(0, len(text), chunk_size):
9898
yield text[i:i + chunk_size]
9999

100+
def configure_logging():
101+
# Configure logging based on the enable_detailed_logging value
102+
if config.enable_detailed_logging:
103+
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(name)s - %(message)s')
104+
else:
105+
logging.basicConfig(level=logging.CRITICAL, format='%(asctime)s - %(levelname)s - %(name)s - %(message)s')
106+
107+
# Set the logger level based on configuration
108+
logger.setLevel(logging.getLogger().level)
100109

101110
async def register_user_if_not_exists(update: Update, context: CallbackContext, user: User):
102111
user_registered_now = False
@@ -1663,7 +1672,7 @@ async def model_settings_handler(update: Update, context: CallbackContext):
16631672

16641673
elif data.startswith('claude-model-set_settings|'):
16651674
# Check for API key
1666-
if config.claude_api_key is None or config.claude_api_key == "":
1675+
if config.anthropic_api_key is None or config.anthropic_api_key == "":
16671676
await context.bot.send_message(
16681677
chat_id=user_id,
16691678
text="This bot does not have the Anthropic models available :(",
@@ -1678,7 +1687,7 @@ async def model_settings_handler(update: Update, context: CallbackContext):
16781687
elif data.startswith('model-set_settings|'):
16791688
_, model_key = data.split("|")
16801689
# Prevent Claude models from being set without API key
1681-
if "claude" in model_key.lower() and (config.claude_api_key is None or config.claude_api_key == ""):
1690+
if "claude" in model_key.lower() and (config.anthropic_api_key is None or config.anthropic_api_key == ""):
16821691
await context.bot.send_message(
16831692
chat_id=user_id,
16841693
text="This bot does not have the Anthropic models available :(",
@@ -2148,6 +2157,7 @@ def run_bot() -> None:
21482157
bot_instance = application.bot
21492158

21502159
update_user_roles_from_config(db, config.roles)
2160+
configure_logging()
21512161

21522162
application = (
21532163
ApplicationBuilder()

bot/config.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@
1414
# config parameters
1515
telegram_token = config_yaml["telegram_token"]
1616
openai_api_key = config_yaml["openai_api_key"]
17-
claude_api_key = config_yaml.get("claude_api_key", None)
17+
anthropic_api_key = config_yaml.get("anthropic_api_key", None)
1818
developer_username = config_yaml.get("developer_username", "")
1919
timezone = config_yaml.get("database_timezone", "UTC")
20+
enable_detailed_logging = config_yaml.get("enable_detailed_logging", True)
2021
stripe_secret_key = config_yaml.get("stripe_secret_key", None)
2122
stripe_webhook_secret = config_yaml.get("stripe_webhook_secret", None)
2223
openai_api_base = config_yaml.get("openai_api_base", None)

bot/openai_utils.py

+37-61
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@
1010

1111
import json #logging error
1212

13-
from tokenizers import Tokenizer, models, pre_tokenizers, trainers
13+
#from tokenizers import Tokenizer, models, pre_tokenizers, trainers # other tokenizer module
14+
1415
# setup openai
1516
openai.api_key = config.openai_api_key
17+
anthropic.api_key = config.anthropic_api_key
18+
1619
if config.openai_api_base is not None:
1720
openai.api_base = config.openai_api_base
18-
logger = logging.getLogger(__name__)
19-
20-
anthropic.api_key = config.claude_api_key
2121

2222
OPENAI_COMPLETION_OPTIONS = {
2323
"temperature": 0.7,
@@ -28,24 +28,36 @@
2828
"request_timeout": 60.0,
2929
}
3030

31-
#GPT HELP 2
31+
logger = logging.getLogger(__name__)
32+
33+
def configure_logging():
34+
# Configure logging based on the enable_detailed_logging value
35+
if config.enable_detailed_logging:
36+
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(name)s - %(message)s')
37+
else:
38+
logging.basicConfig(level=logging.CRITICAL, format='%(asctime)s - %(levelname)s - %(name)s - %(message)s')
39+
40+
# Set the logger level based on configuration
41+
logger.setLevel(logging.getLogger().level)
42+
43+
configure_logging()
44+
3245
def validate_payload(payload): #maybe comment out
3346
# Example validation: Ensure all messages have content that is a string
3447
for message in payload.get("messages", []):
3548
if not isinstance(message.get("content"), str):
3649
logger.error("Invalid message content: Not a string")
3750
raise ValueError("Message content must be a string")
38-
#GPT HELP 2
39-
4051

52+
4153
class ChatGPT:
4254
def __init__(self, model="gpt-4-1106-preview"):
4355
assert model in {"text-davinci-003", "gpt-3.5-turbo-16k", "gpt-3.5-turbo", "gpt-4", "gpt-4-1106-preview", "gpt-4-vision-preview", "gpt-4-turbo-2024-04-09", "gpt-4o", "claude-3-opus-20240229", "claude-3-sonnet-20240229", "claude-3-haiku-20240307"}, f"Unknown model: {model}"
4456
self.model = model
4557
self.is_claude_model = model.startswith("claude")
4658
self.logger = logging.getLogger(__name__)
4759
self.headers = {
48-
"Authorization": f"Bearer {config.claude_api_key if self.is_claude_model else config.openai_api_key}",
60+
"Authorization": f"Bearer {config.anthropic_api_key if self.is_claude_model else config.openai_api_key}",
4961
"Content-Type": "application/json",
5062
}
5163

@@ -64,7 +76,7 @@ async def send_message(self, message, dialog_messages=[], chat_mode="assistant")
6476
if not prompt.strip():
6577
raise ValueError("Generated prompt is empty")
6678

67-
client = anthropic.AsyncAnthropic(api_key=config.claude_api_key)
79+
client = anthropic.AsyncAnthropic(api_key=config.anthropic_api_key)
6880
response = await client.completions.create(
6981
model=self.model,
7082
messages=[{"role": "user", "content": prompt}],
@@ -147,7 +159,7 @@ async def send_message_stream(self, message, dialog_messages=[], chat_mode="assi
147159
if not prompt.strip():
148160
raise ValueError("Generated prompt is empty")
149161

150-
client = anthropic.AsyncAnthropic(api_key=config.claude_api_key)
162+
client = anthropic.AsyncAnthropic(api_key=config.anthropic_api_key)
151163

152164
async with client.messages.stream(
153165
model=self.model,
@@ -393,52 +405,31 @@ def _generate_claude_prompt(self, message, dialog_messages, chat_mode, image_buf
393405
combined_prompt += "\n\nAssistant:"
394406
return combined_prompt
395407

396-
397408
def _postprocess_answer(self, answer):
398409
self.logger.debug(f"Pre-processed answer: {answer}")
399410
answer = answer.strip()
400411
self.logger.debug(f"Post-processed answer: {answer}")
401412
return answer
402413

403414
def _count_tokens_from_messages(self, messages, answer, model="gpt-4-1106-preview"):
415+
404416
if model.startswith("claude"):
405-
tokenizer = self._get_claude_tokenizer()
417+
encoding = tiktoken.encoding_for_model("gpt-4-turbo-2024-04-09")
406418
else:
407419
encoding = tiktoken.encoding_for_model(model)
408420

409421
tokens_per_message = 3
410422
tokens_per_name = 1
411423

412-
if model == "gpt-3.5-turbo-16k":
413-
tokens_per_message = 4 # every message follows <im_start>{role/name}\n{content}<im_end>\n
414-
tokens_per_name = -1 # if there's a name, the role is omitted
415-
elif model == "gpt-3.5-turbo":
416-
tokens_per_message = 4
417-
tokens_per_name = -1
418-
elif model == "gpt-4":
419-
tokens_per_message = 3
420-
tokens_per_name = 1
421-
elif model == "gpt-4-1106-preview":
422-
tokens_per_message = 3
423-
tokens_per_name = 1
424-
elif model == "gpt-4-vision-preview":
425-
tokens_per_message = 3
426-
tokens_per_name = 1
427-
elif model == "gpt-4-turbo-2024-04-09":
428-
tokens_per_message = 3
429-
tokens_per_name = 1
430-
elif model == "gpt-4o":
424+
if model.startswith("gpt-3"):
425+
tokens_per_message = 4 # every message follows <im_start>{role/name}\n{content}<im_end>\n
426+
tokens_per_name = -1 # if there's a name, the role is omitted
427+
elif model.startswith("gpt-4"):
431428
tokens_per_message = 3
432429
tokens_per_name = 1
433-
elif model == "claude-3-opus-20240229":
434-
tokens_per_message = 3
435-
tokens_per_name = 1
436-
elif model == "claude-3-sonnet-20240229":
430+
elif model.startswith("claude"):
437431
tokens_per_message = 3
438432
tokens_per_name = 1
439-
elif model == "claude-3-haiku-20240307":
440-
tokens_per_message = 3
441-
tokens_per_name = 1
442433
else:
443434
raise ValueError(f"Unknown model: {model}")
444435

@@ -450,49 +441,33 @@ def _count_tokens_from_messages(self, messages, answer, model="gpt-4-1106-previe
450441
for sub_message in message["content"]:
451442
if "type" in sub_message:
452443
if sub_message["type"] == "text":
453-
if model.startswith("claude"):
454-
n_input_tokens += len(tokenizer.encode(sub_message["text"]).tokens)
455-
else:
456-
n_input_tokens += len(encoding.encode(sub_message["text"]))
444+
n_input_tokens += len(encoding.encode(sub_message["text"]))
457445
elif sub_message["type"] == "image_url":
458446
pass
459447
else:
460448
if "type" in message:
461449
if message["type"] == "text":
462-
if model.startswith("claude"):
463-
n_input_tokens += len(tokenizer.encode(message["text"]).tokens)
464-
else:
465-
n_input_tokens += len(encoding.encode(message["text"]))
450+
n_input_tokens += len(encoding.encode(message["text"]))
466451
elif message["type"] == "image_url":
467452
pass
468453

469-
470454
n_input_tokens += 2
471455

472456
# output
473-
if model.startswith("claude"):
474-
n_output_tokens = 1 + len(tokenizer.encode(answer).tokens)
475-
else:
476-
n_output_tokens = 1 + len(encoding.encode(answer))
457+
n_output_tokens = 1 + len(encoding.encode(answer))
477458

478459
return n_input_tokens, n_output_tokens
479460

480461
def _count_tokens_from_prompt(self, prompt, answer, model="text-davinci-003"):
481462
if model.startswith("claude"):
482-
tokenizer = self._get_claude_tokenizer()
483-
n_input_tokens = len(tokenizer.encode(prompt).tokens) + 1
484-
n_output_tokens = len(tokenizer.encode(answer).tokens)
463+
encoding = tiktoken.encoding_for_model("gpt-4-turbo-2024-04-09")
485464
else:
486465
encoding = tiktoken.encoding_for_model(model)
487-
n_input_tokens = len(encoding.encode(prompt)) + 1
488-
n_output_tokens = len(encoding.encode(answer))
489466

490-
return n_input_tokens, n_output_tokens
467+
n_input_tokens = len(encoding.encode(prompt)) + 1
468+
n_output_tokens = len(encoding.encode(answer))
491469

492-
def _get_claude_tokenizer(self):
493-
tokenizer = Tokenizer(models.BPE())
494-
tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel()
495-
return tokenizer
470+
return n_input_tokens, n_output_tokens
496471

497472
async def transcribe_audio(audio_file) -> str:
498473
r = await openai.Audio.atranscribe("whisper-1", audio_file)
@@ -501,6 +476,7 @@ async def transcribe_audio(audio_file) -> str:
501476

502477
async def generate_images(prompt, model="dall-e-2", n_images=4, size="1024x1024", quality="standard"):
503478
"""Generate images using OpenAI's specified model, including DALL-E 3."""
479+
#redundancy to make sure the api call isnt made wrong
504480
if model=="dalle-2":
505481
model="dall-e-2"
506482
quality="standard"

config/config.example.yml

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
telegram_token: ""
22
openai_api_key: ""
3-
claude_api_key: ""
3+
anthropic_api_key: ""
44
stripe_secret_key: ""
55
stripe_webhook_secret: "" # to recieve the payment updates
66
openai_api_base: null # leave null to use default api base or you can put your own base url here
@@ -10,6 +10,7 @@ return_n_generated_images: 1
1010
n_chat_modes_per_page: 5
1111
image_size: "1024x1024" #Can be configured within the bot menu, its initialized here to have a default
1212
enable_message_streaming: true # if set, messages will be shown to user word-by-word
13+
enable_detailed_logging: true # if set to true, youll get constant logs of what is happening in the bot
1314
developer_username: [""] #will be included in certain errors given to users so they can contact the developer easier
1415
database_timezone: "" #so that the user_roles command give you accurate time of when the users last used the bot
1516

@@ -30,4 +31,4 @@ roles:
3031
beta_tester: []
3132
friend: [] #unlimited usage of the bot, no admin privileges
3233
regular_user: []
33-
trial_user: []
34+
trial_user: [] #initial role for every user that registers, automatically upgrades to regular_user after first payment

config/models.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#available_text_models: ["gpt-3.5-turbo", "gpt-3.5-turbo-16k", "gpt-4-1106-preview", "gpt-4-vision-preview", "gpt-4-turbo-2024-04-09", "gpt-4", "text-davinci-003"] #Big menu
1+
#available_text_models: ["gpt-3.5-turbo", "gpt-3.5-turbo-16k", "gpt-4-1106-preview", "gpt-4-vision-preview", "gpt-4-turbo-2024-04-09", "gpt-4", "text-davinci-003", "claude-3-opus-20240229", "claude-3-sonnet-20240229", "claude-3-haiku-20240307"] #Big menu
22
available_text_models: ["gpt-3.5-turbo", "gpt-4-vision-preview", "gpt-4-turbo-2024-04-09", "gpt-4o", "claude-3-opus-20240229", "claude-3-sonnet-20240229", "claude-3-haiku-20240307"] #small menu with all needed models
33
available_image_models: ["dalle-2", "dalle-3"]
44

@@ -136,7 +136,7 @@ info:
136136

137137
scores:
138138
smart: 3
139-
fast: 5
139+
fast: 4
140140
cheap: 4
141141

142142
text-davinci-003:

requirements.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
python-telegram-bot[rate-limiter]==20.1
22
openai==0.28.1 #chatgpt library
3-
tiktoken>=0.3.0 #tokenizer for openai
3+
tiktoken>=0.3.0 #tokenizer
44
PyYAML==6.0 #configs
55
pymongo==4.3.3 #database
66
python-dotenv==0.21.0 #.env files
@@ -11,4 +11,4 @@ redis>=4.0.2 #payment recieve notif
1111
aioredis>=2.0.0 #payment recieve notif
1212
pytz==2023.3 #timezone management
1313
anthropic #claude library
14-
tokenizers #tokenizer for anthropic
14+
#tokenizers #other tokenizer if you want to also use the one in the utils file

0 commit comments

Comments
 (0)