Skip to content

Commit

Permalink
fix: Update the blueprint
Browse files Browse the repository at this point in the history
  • Loading branch information
jovyinny authored Jul 18, 2024
1 parent 8297208 commit 44e0287
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 71 deletions.
169 changes: 111 additions & 58 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Sarufi Telegram-Webhook chatbot blueprint

A blueprint for deploying telegram bots made using [Sarufi](https://docs.sarufi.io/). We need a webhook for this task to receive updates from telegram. You can use any of available solutions online. We shall cover setting up webhook using [ngrok](#using-ngrok) and [replit](#using-replit).
A blueprint for deploying telegram bots made using [Sarufi](https://docs.sarufi.io/). We need a webhook for this task to receive updates from telegram. Using webhook, we can deploy our chatbot as a lambda function. This way we can save resources and avoid delays.

You can use any of available solutions online. We shall cover setting up webhook using [ngrok](#using-ngrok) and [replit](#using-replit).

## Why use webhook instead of polling?

Expand All @@ -10,111 +12,147 @@ Using polling may render some delays and consume resorces. So you can use webhoo

Make sure you have [ngrok](https://ngrok.com) installed in your local machine.

### Getting ready
You will have to modify some commands shown here to suite your working environment. The commands like `python3` and `pip3` will depend on your working environment. You may have to use `python` and `pip` instead.

- Create Project directory
### Quick configuration

Create a project directory `Telegram bot`. In this directory we are going to create a virtual environment to hold our package.
- Create Project directory and Virtual environment

```bash
mkdir 'Telegram bot'
cd 'Telegram bot'
- Create a project directory `Telegram bot`.

In this directory we are going to create a virtual environment to hold our package.

```
```bash
mkdir 'Telegram bot'
cd 'Telegram bot'
```

- Make virtual environment and install requirements
- Make Virtual Environment

Using virtual environment is a good practice, so we are going to create one. You can read more on [why use virtual environment](https://www.freecodecamp.org/news/how-to-setup-virtual-environments-in-python/). We shall install all necessary packages in the environment
Using virtual environment is a good practice, so we are going to create one. You can read more on [why use virtual environment](https://www.freecodecamp.org/news/how-to-setup-virtual-environments-in-python/). We shall install all necessary packages in the environment

```bash
python3 -m venv sarufi
source sarufi/bin/activate
```
- Unix based systems
- Install virtual environment

- Creating a telegram bot
This step is optional as you may have python virtual environment already installed. If not, you can install it by running the command below.

To create a chatbot on Telegram, you need to contact the [BotFather](https://telegram.me/BotFather), which is essentially a bot used to create other bots.
```bash
sudo apt install python3-venv
```

- Create virtual environment and activate it

```bash
python3 -m venv sarufi
source sarufi/bin/activate
```

- Windows
- Install virtual environment

This step is optional as you may have python virtual environment already installed. If not, you can install it by running the command below.

The command you need is /newbot which leads to several steps. Follow the steps then you will have you `bot's token`
```bash
pip install virtualenv
```

### Configuration
- Create virtual environment and activate it

```bash
virtualenv sarufi
.\sarufi\Scripts\activate
```

In this part, we are going to clone the [Sarufi Telegram Chatbot deployment Blueprint](https://github.com/Neurotech-HQ/sarufi-telegram-webhook-blueprint) and install the packages.
### Setting up the project

- Clone and install requirements.

In this part, we are going to clone the [Sarufi Telegram Chatbot deployment Blueprint](https://github.com/Neurotech-HQ/sarufi-telegram-webhook-blueprint) and install the packages.

Run the commands below

```bash
git clone https://github.com/Neurotech-HQ/sarufi-telegram-webhook-blueprint.git
cd sarufi-telegram-webhook-blueprint
pip3 install -r requirements.txt
```
- Getting Sarufi credentials.
To authorize our chabot, we are are going to use authorization keys from sarufi. Log in into your [sarufi account](https://sarufi.io). Go to your Profile on account to get Authorization keys(client ID and client secret)
![Sarufi authorazation keys](img/sarufi_authorization.png)
```

- Environment variables

After installing packages, we need to configure our credentials. In `telegram-chatbot-blueprint`, create a file(`.env`) to hold environment variables.
After installing packages, we need to configure our credentials. In `telegram-chatbot-blueprint`, create a file(`.env`) to hold environment variables.

In `.env`, we are going to add the following credetials. To get your public ngrok url read [here](#get-public-url) Using your favourite text editor add the following:-
In `.env`, we are going to add the following credetials. To get your public ngrok url read [here](#get-public-url) Using your favourite text editor add the following:-

```text
SARUFI_API_KEY = your API KEY
SARUFI_BOT_ID= bot id
TELEGRAM_BOT_TOKEN = telegram token
START_MESSAGE= Hi {name}, Welcome To {bot_name}, How can i help you
START_MESSAGE= Hi {user_name}, Welcome To {bot_name}, How can i help you
```

**NOTE:** Do not replace `name` na `bot_name` here, they will be be placed automatically in the script
**Note**: The Start Message will be bot's reponse when a user sends /start command to your bot.
You can customize the message to your preference. You have the following variable that you can use in your start message to make it more personalized:-
- {name} - User's name. This is the name the user has on Telegram
- {bot_name} - Bot's name from Sarufi Dashboard
### Get Credentials
- Getting Sarufi credentials.
To authorize our chabot, we are are going to use authorization keys from sarufi. Log in into your [sarufi account](https://sarufi.io). Go to your Profile on account to get Authorization keys(client ID and client secret)
![Sarufi authorazation keys](img/sarufi_authorization.png)
- Creating a telegram bot
To create a chatbot on Telegram, you need to contact the [BotFather](https://telegram.me/BotFather), which is essentially a bot used to create other bots.
### Launch
To connect to Telegram, you need to create a Telegram bot. You can do this by following the instructions in the [Telegram documentation](https://core.telegram.org/bots#6-botfather). The instructions are as follows:
#### Get public url
1. Open Telegram and search for `@BotFather`.
2. Click on the bot to start a chat.
3. Send the `/newbot` command to create a new bot.
4. Follow the instructions to create a new bot.
- Starting ngrok
Once you have created a bot, you will receive a `token`. This token is used to authenticate your bot with Telegram.
### Fire up your bot
- Starting ngrok to get public url
Ngronk is a tool that allows you to expose a web server running on your local machine to the internet. You can read more on [ngrok](https://ngrok.com)
```bash
ngrok http 8000
```
You will have a public https url indicating that its forwarding to your `localhost:8000`
- Set Webhook Url via Telegram API
- Set Webhook Url
Using any of favourate API testing client or curl, set the webhook url as shown below
We are going to set the webhook url to our bot. This is telling telegram server to send updates to our bot via specified url. This way our server can rest whenever there is no update. With this option you can deploy your chatbot as a lambda function.
```bash
curl --location --request POST 'https://api.telegram.org/bot<your bot token>/setWebhook?url=<your ngrok public url>/telegram'
```
You can read more on [telegram webhook](https://core.telegram.org/bots/api#setwebhook)
Using any of favourate API testing client or curl, set the webhook url as shown below
```bash
curl --request POST 'https://api.telegram.org/bot<your bot token>/setWebhook?url=<your ngrok public url>'
```
**NOTE:** The port number(for this case, 8000) matches the port used in `main.py`
#### Running your bot
- Running your bot
Run python script
Its the time you have been waiting for. Lets lauch 🚀 our bot. Here depending on your `os`. You can run
Run python script. Its the time you have been waiting for. Lets lauch 🚀 our bot.
```python
python3 main.py
```
or
```python
python main.py
```
**NOTE:** All operations are done in activated virtual environment for convience
Open your telegram app, search for your bot --> Send it a text. You can see a sample bot [below](#sample-bot-test)
Open your telegram app, search for your bot --> Send it a text. You can see a sample bot [below](#chatbot-at-work)
## USING REPLIT
Expand Down Expand Up @@ -148,25 +186,40 @@ You will have to make little configuration to get you bot up running.
SARUFI_API_KEY = your API KEY
SARUFI_BOT_ID= bot id
TELEGRAM_BOT_TOKEN = telegram bot token
START_MESSAGE= Hi {name}, Welcome To {bot_name}, How can i help you
BASE_URL= https://<your repl name>.<your replit username>.repl.co
START_MESSAGE= Hi {user_name}, Welcome To {bot_name}, How can i help you
```
**NOTE:** Do not replace `name` na `bot_name` here, they will be programmatically in the script
**Note**:
The Start Message will be bot's reponse when a user sends /start command to your bot.
You can customize the message to your preference. You have the following variable that you can use in your start message to make it more personalized:-
- {user_name} - User's name. This is the name the user has on Telegram
- {bot_name} - Bot's name from Sarufi
### Fire up the bot
To launch your bot, you need to add a webhook url, which will be in format of `https://<your repl name>.<your replit username>.co`. In **main.py**, at line _39_ (Variable `BASE_URL`), place your formatted url.
Click the run button to start your bot. You will see the bot running on the console. A small webview will open up with a url like `https://<your repl name>.<your replit username>.co`. Copy the url as we are going to use it in the next step to set webhook url.
Below you can see where you can find the details in replit. So you will need to replace them with your own info.
### Set Webhook Url
![Where to find username and repl name](./img/repl-name-and-username-in-replit.png)
You can use any of favourate API testing client or curl, set the webhook url as shown below.
**Note** Spaces in the repl name will be replaced with with `-`. Example: `sarufi telegram webhook blueprint` is to be placed as `sarufi-telergam-webhook-blueprint` in the url.
- Using curl
```bash
curl --request POST 'https://api.telegram.org/bot<your bot token>/setWebhook?url=<your replit url>'
```
- Using API testing client
You can use any of your favourate API testing client. I will use [Postman](https://www.postman.com/).
Then send a POST request to `https://api.telegram.org/bot<your bot token>/setWebhook?url=<your replit url>`
Open your telegram app, search for your bot --> Send it a text. You can see a sample bot [below](#sample-bot-test)
## Sample Bot test
## ChatBot at work
Here is a sample bot deployed in Telegram
Expand Down
35 changes: 24 additions & 11 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,26 @@
simulate_typing,
get_clicked_button_text)

from logger import logger


app = FastAPI()

handler = Mangum(app)

load_dotenv()

# Check if all required environment variables are set

assert os.getenv("TELEGRAM_BOT_TOKEN") , "TELEGRAM_BOT_TOKEN not set"
assert os.getenv("SARUFI_API_KEY"), "SARUFI_API_KEY not set"
assert os.getenv("SARUFI_BOT_ID"), "SARUFI_BOT_ID not set"
assert os.getenv("START_MESSAGE"), "START_MESSAGE not set"

# Set up Sarufi and get bot's name
sarufi = Sarufi(api_key=os.getenv("SARUFI_API_KEY"))
bot_name=sarufi.get_bot(os.getenv("SARUFI_BOT_ID")).name
PORT = 8000
PORT = os.getenv("PORT", 8000)

@dataclass
class WebhookUpdate:
Expand Down Expand Up @@ -111,12 +121,17 @@ async def start(update: Update, context: CustomContext)->None:
"""
Starts the bot.
"""
first_name = update.message.chat.first_name
await reply_with_typing(
update,
context,
os.getenv("START_MESSAGE").format(name=first_name,bot_name=bot_name),
)
try:

first_name = update.message.chat.first_name
await reply_with_typing(
update,
context,
os.getenv("START_MESSAGE","Welcome to {bot_name}").format(user_name=first_name,bot_name=bot_name),
)
except Exception as error:
logger.error(f"Error: {error} starting the bot")
await reply_with_typing(update, context, "Welcome to the bot")


async def help(update: Update, context: CallbackContext)->None:
Expand All @@ -129,9 +144,7 @@ async def help(update: Update, context: CallbackContext)->None:

# Set up application
context_types = ContextTypes(context=CustomContext)
application = (
Application.builder().token(os.getenv("TELEGRAM_BOT_TOKEN")).updater(None).context_types(context_types).build()
)
application = Application.builder().token(os.getenv("TELEGRAM_BOT_TOKEN")).updater(None).context_types(context_types).build()

@app.get("/")
async def webhook(request: Request):
Expand All @@ -158,4 +171,4 @@ async def webhook_handler(request: Request,tasks: BackgroundTasks):


if __name__ == "__main__":
uvicorn.run("main:app", host="0.0.0.0", port=PORT,reload=True)
uvicorn.run("main:app",port=PORT)
5 changes: 3 additions & 2 deletions utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def get_buttons(data:dict,type:str)->list:
buttons=[]
if type=="reply_button":

for button in data.get("buttons"):
for button in data["buttons"]:
button_title=button.get("reply").get("title")
button_id=button.get("reply").get("id")
button_data=[InlineKeyboardButton(button_title,callback_data=button_id)]
Expand All @@ -17,7 +17,7 @@ def get_buttons(data:dict,type:str)->list:

else:

for menu in data.get("sections")[0].get("rows"):
for menu in data["sections"][0].get["rows"]:
menu_title=menu.get("title")
menu_id=menu.get("id")
menu_button=[InlineKeyboardButton(menu_title,callback_data=menu_id)]
Expand All @@ -29,6 +29,7 @@ def get_clicked_button_text(buttons:tuple,button_callback_data:str)-> str:
for button in buttons:
if button[0].callback_data==button_callback_data:
return button[0].text
return "Sorry, I can't find the button you clicked"


async def send_medias(update: Update,context: CallbackContext,media:dict,type:str):
Expand Down

0 comments on commit 44e0287

Please sign in to comment.