Skip to content

Commit 3a95f2c

Browse files
committed
give every user 100,000 free tokens
1 parent 39f7c01 commit 3a95f2c

File tree

4 files changed

+87
-15
lines changed

4 files changed

+87
-15
lines changed

‎.env.template‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
TELEGRAM_BOT_TOKEN=<your-telegram-bot-token-value-here>
21
DB_URI=<choose-a-path-for-sqlite-db-file>
2+
TELEGRAM_BOT_TOKEN=<your-telegram-bot-token-value-here>
33
OPENAI_API_KEY=<your-openai-key-here>
44
# https://console.groq.com/keys
55
GROQ_API_KEY=<your-groq-key-here>

‎telegram-bot/bot.py‎

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
)
1515

1616
from llm_client import LLMClient, Model, Provider
17+
from db_client import DBClient, Account
1718

1819

1920
logging.basicConfig(
@@ -25,6 +26,7 @@
2526

2627
# Environment variables names
2728
_TELEGRAM_BOT_TOKEN_VAR_NAME = "TELEGRAM_BOT_TOKEN"
29+
_DB_URI_VAR_NAME = "DB_URI"
2830

2931
_START_MESSAGE = (
3032
"Hi there! I'm a bot designed to assist you in rephrasing your text into polished English. "
@@ -38,30 +40,51 @@ async def start_command(update: Update, _: ContextTypes.DEFAULT_TYPE) -> None:
3840

3941

4042
async def rewrite(
41-
update: Update, context: ContextTypes.DEFAULT_TYPE, llm_client: LLMClient
43+
update: Update,
44+
context: ContextTypes.DEFAULT_TYPE,
45+
db_client: DBClient,
46+
llm_client: LLMClient,
4247
) -> None:
48+
# Handle the message
4349
input_message = None
4450
if update.message is not None:
4551
input_message = update.message.text
4652
elif update.edited_message is not None:
4753
input_message = update.edited_message.text
4854
assert input_message is not None, "No message to rewrite."
49-
rewritten_text = llm_client.rewrite(input_message)
55+
# Handle the user
56+
user_id = update.message.from_user.id
57+
username = update.message.from_user.username
58+
account = db_client.get_or_create_account(user_id=user_id, username=username)
59+
# Check if the user has run out of tokens.
60+
# If the user is a friend, they have an unlimited token balance. ;)
61+
if not account.is_friend and account.tokens_balance <= 0:
62+
await context.bot.send_message(
63+
chat_id=update.effective_chat.id,
64+
text="You have run out of tokens. 🥲\n Please contact the bot owner to get more.",
65+
)
66+
return
67+
# Rewrite the message. Do not touch the user's token balance if they are a friend.
68+
rewritten_text, num_tokens = llm_client.rewrite(input_message)
69+
if not account.is_friend:
70+
db_client.decrease_token_balance(account=account, num_tokens=num_tokens)
5071
await context.bot.send_message(
5172
chat_id=update.effective_chat.id,
5273
text=rewritten_text,
5374
)
5475

5576

5677
if __name__ == "__main__":
78+
db_client = DBClient(db_url=os.getenv(_DB_URI_VAR_NAME))
79+
llm_client = LLMClient(provider=Provider.GROQ, model=Model.GEMMA)
80+
5781
app = ApplicationBuilder().token(os.getenv(_TELEGRAM_BOT_TOKEN_VAR_NAME)).build()
5882

5983
app.add_handler(CommandHandler("start", start_command))
60-
61-
llm_client = LLMClient(provider=Provider.GROQ, model=Model.GEMMA)
6284
app.add_handler(
6385
MessageHandler(
64-
filters.TEXT & (~filters.COMMAND), partial(rewrite, llm_client=llm_client)
86+
filters.TEXT & (~filters.COMMAND),
87+
partial(rewrite, db_client=db_client, llm_client=llm_client),
6588
)
6689
)
6790

‎telegram-bot/db_client.py‎

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
from sqlalchemy import BigInteger
2+
from sqlmodel import create_engine, SQLModel, Session, select, Field
3+
4+
from llm_client import Model, Provider
5+
6+
_NUM_TOKENS_DEFAULT = 100_000
7+
8+
9+
class Account(SQLModel, table=True):
10+
id: int | None = Field(default=None, primary_key=True)
11+
user_id: str = Field(index=True, sa_type=BigInteger) # Telegram user ID
12+
username: str | None
13+
provider: Provider = Field(default=Provider.GROQ)
14+
model: Model = Field(default=Model.GEMMA)
15+
tokens_balance: int = Field(default=_NUM_TOKENS_DEFAULT)
16+
# Whether the user is a friend of the bot owner.
17+
# This is used to give the user an unlimited token balance.
18+
is_friend: bool = Field(default=False)
19+
20+
21+
class DBClient:
22+
def __init__(self, db_url: str, echo=True) -> None:
23+
self.engine = create_engine(db_url, echo=echo)
24+
SQLModel.metadata.create_all(self.engine)
25+
26+
def __del__(self) -> None:
27+
self.engine.dispose()
28+
29+
def get_or_create_account(self, user_id: str, username=None) -> Account:
30+
with Session(self.engine) as session:
31+
statement = select(Account).filter(Account.user_id == user_id)
32+
account = session.exec(statement).one_or_none()
33+
if account is None:
34+
account = Account(user_id=user_id, username=username)
35+
session.add(account)
36+
session.commit()
37+
session.refresh(account)
38+
return account
39+
40+
def decrease_token_balance(self, account: Account, num_tokens: int) -> None:
41+
with Session(self.engine) as session:
42+
account.tokens_balance -= num_tokens
43+
session.add(account)
44+
session.commit()
45+
session.refresh(account)

‎telegram-bot/llm_client.py‎

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
from enum import Enum, auto
2-
from typing import Callable, Union
1+
from enum import Enum
2+
from typing import Callable, Union, Tuple
33
import os
44

55
from langchain_core.messages import SystemMessage
@@ -33,15 +33,15 @@
3333

3434

3535
class Provider(Enum):
36-
OPENAI = auto()
37-
GROQ = auto()
36+
GROQ = "groq"
37+
OPENAI = "openai"
3838

3939

4040
class Model(Enum):
41+
GEMMA = "gemma-7b-it"
4142
GPT3 = "gpt-3.5-turbo"
4243
GPT4 = "gpt-4.0-turbo"
4344
MIXTRAL = "mixtral-8x7b-32768"
44-
GEMMA = "gemma-7b-it"
4545

4646

4747
# OpenAI can be used as a provider with the following models: GPT3, GPT4.
@@ -82,14 +82,18 @@ def get_chat(
8282

8383
class LLMClient:
8484
def __init__(
85-
self, provider: Provider, model: Model, temperature: float = 0.5
85+
self, provider: Provider, model: Model, temperature: float = 0.35
8686
) -> None:
8787
self.chat = get_chat(provider, model)(model, temperature)
8888

89-
def rewrite(self, text: str) -> str:
89+
def rewrite(self, text: str) -> Tuple[str, int]:
9090
output_parser = StrOutputParser()
91-
chain = _REWRITE_PROMPT | self.chat | output_parser
92-
return chain.invoke(
91+
chain = _REWRITE_PROMPT | self.chat
92+
output = chain.invoke(
9393
{"text": text},
9494
config={"callbacks": [ConsoleCallbackHandler()]},
9595
)
96+
return (
97+
output_parser.invoke(output),
98+
output.response_metadata["token_usage"]["total_tokens"],
99+
)

0 commit comments

Comments
 (0)