DEV Community

Cover image for Making a Telegram bot with BotticelliBots
BotticelliBots
BotticelliBots

Posted on • Edited on

Making a Telegram bot with BotticelliBots

Image description

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

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();
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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);
    }
}

Enter fullscreen mode Exit fullscreen mode

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;
    }
}
Enter fullscreen mode Exit fullscreen mode

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:

Image description

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:

  1. Go to 'Your bots' pane: Image description
  2. Fill parameters and a description: Image description
  3. Press 'Unlock' button: Image description

** 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": "*"
}

Enter fullscreen mode Exit fullscreen mode

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

Top comments (0)