Making a Telegram bot with BotticelliBots
BotticelliBots
Posted on April 10, 2024
Let's imagine, that we need to create a .NET core - based chatbot, that shows us current time in UTC.
So, we need .NET Core 8.0 and very basic knowledge of C#.
Before you start
Please, check your .NET Core and Visual Studio version. You should have .NET Core 8 or higher and VS 2022 or Rider v. 2023.x (any edition). If no - check this and this. As a framework and chatbot-management system, we'll use BotticelliBots v. 0.3: see here. You may load it as a submodule with your git repository.
Docs
- Botticelli common documentation
- Bot adding/registration in admin pane
- Admin pane deployment scripts for Linux and Windows
What do we want
We need to create a chat bot, that will show you a UTC time on command
And also we need to administrate this bot.
Let's register our Telegram bot
Please, check a Telegram BotFather bot and follow the instructions
Some basics for BotticelliBots
Botticelli is an open-source .NET Core framework for building your own universal bots integrated with databases, queue brokers, speech engines and AI engines (such as ChatGPT, DeepSeek and YaGPT).
In our case, we need several entities to use:
- Commands - represents a messenger command (such as /test)
- Command Processors. Each command needs it's own processor to encapsulate any business logic
- IBot - interface, that represents main bot functions (such as sending message to a chat)
- Message - general message representation, that consists of ChatId, Id and contents
Let's start
Let's open our Visual Studio/Rider and create a WebApi project for .Net Core.
First of all, we need to make some injections in Program.cs:
var builder = WebApplication.CreateBuilder(args);
var settings = builder.Configuration
.GetSection(nameof(VeryBasicBotSettings))
.Get<VeryBasicBotSettings>();
// Adds telegram bot injections
builder.Services.AddTelegramBot(builder.Configuration,
new BotOptionsBuilder<TelegramBotSettings>()
.Set(s => s.SecureStorageSettings = new SecureStorageSettings
{
ConnectionString = settings?.SecureStorageConnectionString
})
.Set(s => s.Name = settings?.BotName));
// Adds a hosted service, intended for keeping bot working during all
// the lifecycle of a bot
builder.Services.AddHostedService<VeryBasicBotService>();
// Adds a command processor, being used for proceeding a business logic for
// '/GetUtc' command and also adds some validation (in this case - pass validator, that tells OK to any command args)
builder.Services.AddBotCommand<GetUtcCommand, GetUtcCommandProcessor<ReplyKeyboardMarkup>, PassValidator<GetUtcCommand>>();
var app = builder.Build();
app.Services.RegisterBotCommand<GetUtcCommand, GetUtcCommandProcessor<ReplyKeyboardMarkup>, TelegramBot>();
app.Run();
Command Processors
Each command needs to be processed in it's own processor. Please note, that we should follow a calling convention for a processor and a command:
class <*YourCommandName*>CommandProcessor<TReplyMarkupBase> : CommandProcessor<*YourCommandName*Command>
public class *YourCommandName*Command : ICommand
So, our command processor should be look like:
/// <summary>
/// A processor for "/GetUtc" command
/// </summary>
/// <typeparam name="TReplyMarkupBase"></typeparam>
public class GetUtcCommandProcessor<TReplyMarkupBase> : CommandProcessor<GetUtcCommand>
where TReplyMarkupBase : class
{
public GetUtcCommandProcessor(ILogger<GetUtcCommandProcessor<TReplyMarkupBase>> logger,
ICommandValidator<GetUtcCommand> validator,
MetricsProcessor metricsProcessor)
: base(logger, validator, metricsProcessor)
{
}
protected override Task InnerProcessContact(Message message, string argsString, CancellationToken token)
{
return Task.CompletedTask;
}
protected override Task InnerProcessPoll(Message message, string argsString, CancellationToken token)
{
return Task.CompletedTask;
}
protected override Task InnerProcessLocation(Message message, string argsString, CancellationToken token)
{
return Task.CompletedTask;
}
/// <summary>
/// All business logic is being called here...
/// </summary>
/// <param name="message"></param>
/// <param name="args"></param>
/// <param name="token"></param>
protected override async Task InnerProcess(Message message, string args, CancellationToken token)
{
// Creates a message for sending
var utcMessageRequest = new SendMessageRequest(Guid.NewGuid().ToString())
{
Message = new Message
{
Uid = Guid.NewGuid().ToString(),
ChatIds = message.ChatIds,
Body = $"Current UTC Time is: {DateTime.UtcNow.ToString(CultureInfo.InvariantCulture)}",
}
};
// Tries to send a message using a concrete implementation of Bot (TelegramBot, for example)
await _bot.SendMessageAsync(request: utcMessageRequest, optionsBuilder: (ISendOptionsBuilder<TReplyMarkupBase>)null!, token: token);
}
}
Hosted service
Also, we should run a hosted service in order to keep our bot onair:
namespace VeryBasicBot.Telegram;
/// <summary>
/// This hosted service intended keeping an application alive till the termination
/// </summary>
public class VeryBasicBotService : IHostedService
{
private readonly IOptionsMonitor<VeryBasicBotSettings> _settings;
private readonly IBot<TelegramBot> _telegramBot;
public VeryBasicBotService(IBot<TelegramBot> telegramBot, IOptionsMonitor<VeryBasicBotSettings> settings)
{
_telegramBot = telegramBot;
_settings = settings;
}
public Task StartAsync(CancellationToken token)
{
Console.WriteLine("Start serving...");
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
Console.WriteLine("Stop serving...");
return Task.CompletedTask;
}
}
you can download a whole code here: github
First run
So, we need to run our bot now. We need to get a freshly-generated a bot Id:
Deploying an admin-side
Admin pane deployment scripts for Linux
First of all, you need to choose where to deploy and admin pane.
We've 2 parts of admin:
- Backend
- Frontend
After deploying using proposed scripts, we need to register. So, after setting up frontend and backend, you should go to: https://: and press Registration button. On a registration form, please, put in your email and press Register. If your backend email server settings are correct, you'll receive a registration letter with username and password.
NOTE
If you experiencing some problems with untrusted certificate for backend, you may go to https://: in your browser and allow using untrusted certificate.
So, after registration, you may refresh a page and log in.
Adding a bot to admin pane
After registering and logging in, we need to add own freshly developed bot onto a "Your bots" pane and activate it as it's shown on pictures:
- Go to 'Your bots' pane:
- Fill parameters and a description:
- Press 'Unlock' button:
** Some additional settings **
In a bot solution, please, find appsettings.json
and make some changes:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"VeryBasicBotSettings": {
"SecureStorageConnectionString": "Filename=database.db;Password=123;ReadOnly=false",
"BotName": "TimeTellingBot"
},
"ServerSettings": {
"ServerUri": "http://<backend_url>:<backend_http_port>/v1/"
},
"AnalyticsSettings": {
"TargetUrl": "http://<analytics_url>:<analytics_http_port>/v1/"
},
"AllowedHosts": "*"
}
Since, we didn't deploy analytics component, we may set some mocking TargetUrl
Let's check the result
Now, all we need is to run a VeryBasicBot.Telegram project.
sources: github
based on BotticelliBots: https://botticellibots.com
email: botticellibots@gmail.com
telegram group: https://t.me/botticelli_bots
Air quality telegram bot, based on BotticelliBots: https://t.me/air_quality_info_bot
Posted on April 10, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.