Как написать бота для Telegram на c

Написал статью на хабр, которая пока что висит в песочнице, решил продублировать и здесь. Не так давно Павел Дуров объявил о конкурсе для разработчиков Telegram ботов. Мне было интересно принять в нем участие и изучить новые технологии. В статье будут рассмотрены принципы работы Telegram API для ботов, пара подводных камней при использовании готовой библиотеки на C#, а также процесс получения сертификата и установки WebHook.

Общие принципы работы API

Telegram API присылает вашему приложению-боту массив в формате JSON — это объект Update. В нем содержится множество информации — id чата, пользователя, сам текст сообщения, прикрепленные фотографии и другие файлы, может быть местоположение пользователя или карточка контакта из его телефона. Есть два основных способа получения этой информации.

При первом способе ваше приложение каждые 100мс (или реже) соединяется с сервером Telegram и спрашивает, не появилось ли чего нового — это метод getUpdates. Минусы этого подхода в том, что создается большая нагрузка на сервера Telegram, а также иногда при большой нагрузке сервер может отдать 503 ошибку и это нужно обработать в приложении. Зато такой способ проще в реализации.

Telegram bot powered by C++ | Бот для наблюдения за курсом валют | Currency monitoring Telegram bot

Второй способ — вы делаете свое приложение в виде «сервера» который слушает определенный порт, и Telegram, при наличии обновлений, отправляет их нашему приложению. Тут минус в том, что нужен SSL-сертификат, хотя бы и самоподписанный, а также желательно наличие доменного имени. Но есть и способы сделать всё очень просто, которые я опишу ниже.

Цель моего бота

У меня была несложная задумка — бот должен принимать от пользователя файлы и загружать их на файлообменник, а также выдавать пользователю хотя бы 10 последних ссылок на закачанные файлы. Также я хотел сделать Inline режим — при упоминании ника бота в чате, он выдает последнюю ссылку на закачанный в файлообменник файл. В качестве файлообменника я выбрал Mega.nz , так как он поддерживает шифрование файлов, там дается 50 ГБ места, и к его API так же нашлась библиотека на C#. В перспективе думаю подключить API Яндекс-диска и Dropbox.

В качестве готовой библиотеки я взял решение от MrRoundRobin. Она хорошо написана, а также есть примеры работы. Пример с Echo с получением обновлений через getUpdate заработал у меня сразу, что вдохновило на дальнейшую разработку. В процессе столкнулся с парой нюансов. Во-первых, иногда приложение выдавало ошибки при билде. Решалось это запуском/перезапуском dnvm через консоль.

Во-вторых, Telegram выдавал ошибку, что в ответных сообщениях от приложения при работе в Inline режиме нет поля message_text, а судя по API оно должно быть. Это решилось добавлением поля в InlineQueryResultNew.cs:

[JsonProperty(«message_text», Required = Required.Always)] public string MessageText

С WebHook также получилось работать после получения сертификата, для этого используется Microsoft Owin.

Работа с Inline-сообщениями

Как написать бота для телеграм на С#

Это сообщения, когда бота упоминают по нику в другом чате. Например, упомянув бота youtube и задав ему поисковый запрос вы можете скинуть в чат ссылку на видео. У моего бота поиска нет, но при inline-упоминании он отдает последнюю ссылку на загруженный пользователем файл. Реализация такова: проверяется что update.InlineQuery != null Далее в поле update.InlineQuery.Query можно получить поисковый запрос пользователя, но я обошелся без него. Для ответа содержащего ссылку я использовал InlineQueryResultArticle где задавал Url, Title, Description а также MessageText. Затем вызывался метод AnswerInlineQuery, но он принимает в себя массив вот так:

InlineQueryResultArticle art = new InlineQueryResultArticle(); art.Description = «Description:»; art.Url= «http://yandex.ru»; art.MessageText = «Url is: » + art.Url;//this is text that will be sent to chat. InlineQueryResultArticle[] array = new InlineQueryResultArticle[1]; array[0] = art; var t = await TGBot.AnswerInlineQuery(update.InlineQuery.Id, array);

Еще по теме:  Как зайти в Телеграмм без доступа к аккаунту

Получение сертификата и ngrok

Когда логика бота более-менее заработала, я решил переписать его через WebHook. Самый легкий путь сделать это — воспользоваться сервисом Ngrok Он выдаст вам https-адрес, и будет перенаправлять пакеты к вам на локальную машину. Но при этом все равно нужно воспользоваться urlacl как написано здесь а в качестве certhash прописать хэш от ngrok — 53e6c6860a403880ad77703a8b6d4bd1d4dcc451.

После этого вы сможете запустить бота даже на своей локальной машине, указав в качестве ссылки для SetWebhook ту, что вам даст ngrok. Я решил пойти более сложным путем и получить свой собственный сертификат. Так вышло, что у меня есть VPS-сервер на WIndows от parking.ru, и я захотел развернуть приложение бота на нем. Я нашел замечательный сервис Startssl.

Для начала они мне выдали сертификат на мою почту (Email Validation). Потом я понял что нельзя выпустить сертификат на IP адрес моего сервера, но у меня был доменный адрес. Я сделал поддомен bott.mydomainname.ru и перенаправил его на IP моего сервера с помощью настроек DNS в панели управления доменом. Просто сделал там DNS-запись «bott.mydomainname.ru IN A 1.2.3.4» где указал IP своего сервера.

Затем пришлось слегка разобраться с IIS — Startssl выдал мне html файл для подтверждения домена (опция Website control validation), который должен был быть доступен по адресу типа http://bott.mydomainname.ru/startssl_answer.html. На этом этапе я запустил IIS и сделал статичный сайт из этой самой одной html-странички.

После этого мне выдали сертификат на год для моего домена, я его установил и его хэш указал в urlacl для параметра certhash. Смешно получилось, когда бот запускался, но не получал никакой информации, а оказалось что я забыл открыть порт 8443 в firewall. Для подключения к Mega.nz я воспользовался библиотекой MegaApiClient . К сожалению, не получилось использовать её в анонимном режиме, и я просто подключился под новым обычным аккаунтом. Это может стать проблемой, если место в 50 ГБ у него кончится, но пока хватает.

Метрики и производительность.

Для сбора метрик есть два хороших сервиса — это Appmetrica от Яндекс а также Botan. В первом случае есть готовая библиотека Nuget, во втором можно использовать простые Http вызовы сервиса Botan. Я воспользовался решением от Яндекс, но скорее в режиме тестирования — не собираю много информации, и не делаю сложной аналитики.

Насчет производительности, не проверял как мой бот поведет себя под нагрузкой. Он использует кучу сторонних dll — Owin, newtonsoft.Json, Nlog, Yandex.Metrica. Надо бы протестировать, так как в описании конкурса говорилось что бот должен быть реально быстрый. Также я пока не добавлял связь с БД, для хранения расшаренных пользователем ссылок, пока храню в памяти.

Код к задаче: «Как легко написать Telegram бота»

Листинг программы

namespace Telegram.Bot.Examples.WebHook < static class Bot < public static readonly Api Api = new Api(«235071994:AAEXNGmQbVCklAplF8eFiaPTr1hl9La1i2A»); >static class Program < static void Main(string[] args) < // Endpoint musst be configured with netsh: // netsh http add urlacl url=https://+:8443/ user=// netsh http add sslcert ipport=0.0.0.0:8443 certhash= appid= using (WebApp.Start(«http://aff92433.ngrok.io:8443»)) < // Register WebHook Bot.Api.SetWebhook(«https://aff92433.ngrok.io/WebHook»).Wait(); Console.WriteLine(«Server Started»); string ttt = Bot.Api.GetMe().Result.Username; int chatId = 206231864; // int chatId = Bot.Api.GetMe().Result.Id; Console.WriteLine(ttt); Bot.Api.SendTextMessage(chatId, «LLLLLLLLLL»); // Stop Server after Console.ReadLine(); // Unregister WebHook Bot.Api.SetWebhook().Wait(); > > > public class Startup < public void Configuration(IAppBuilder app) < var configuration = new HttpConfiguration(); configuration.Routes.MapHttpRoute(«WebHook», «»); app.UseWebApi(configuration); > > public class WebHookController : ApiController < public async TaskPost(Update update) < var message = update.Message; Console.WriteLine(«Received Message from «, message.Chat.Id); if (message.Type == MessageType.TextMessage) < // Echo each Message await Bot.Api.SendTextMessage(message.Chat.Id, message.Text); >else if (message.Type == MessageType.PhotoMessage) < // Download Photo var file = await Bot.Api.GetFile(message.Photo.LastOrDefault()?.FileId); var filename = file.FileId + «.» + file.FilePath.Split(‘.’).Last(); using (var saveImageStream = File.Open(filename, FileMode.Create)) < await file.FileStream.CopyToAsync(saveImageStream); >await Bot.Api.SendTextMessage(message.Chat.Id, «Thx for the Pics»); > return Ok(); > > >

Еще по теме:  Как установить аву в Телеграмме

Источник: studassistent.ru

Создание и применение ботов

ChatGPT представляет чат-бот с искусственным интеллектом от компании OpenAI, который может в диалоговом режиме отвечать на запросы. B OpenAI предоставляет API, который позволяет нам встроить взаимодействие с ChatGPT ботом в свое приложение. Но официальных библиотек для взавимодействия с этим API нет, поэтому весь код придется писать с нуля. Рассмотрим простейший пример.

Прежде всего для отправки запросов нам потребуется токен. Его можно сгенерировать в личном кабинете на сайте openai по адресу https://platform.openai.com/account/api-keys.

Подключение к чат-боту chatgpt в C#

После нажатия на кнопку «Create new secret key» отобразится окно с сгенерированным токеном, который надо скопировать и сохранить. Затем этот токен отобразится в списке ключей, и его затем можно в любой момент удалить.

Подключение к чат-боту chatgpt в программе на C#

Далее определим следующее консольное приложение:

using System.Net.Http.Json; using System.Text.Json.Serialization; // токен из личного кабинета string apiKey = «sk-95Ez2Z1rtgegrRTFFDSTVTdsdfsgdv3422kjhLghnh53QiT8F»; // адрес api для взаимодействия с чат-ботом string endpoint = «https://api.openai.com/v1/chat/completions»; // набор соообщений диалога с чат-ботом List messages = new List(); // HttpClient для отправки сообщений var httpClient = new HttpClient(); // устанавливаем отправляемый в запросе токен httpClient.DefaultRequestHeaders.Add(«Authorization», $»Bearer «); while (true) < // ввод сообщения пользователя Console.Write(«User: «); var content = Console.ReadLine(); // если введенное сообщение имеет длину меньше 1 символа // то выходим из цикла и завершаем программу if (content is not < Length: >0 >) break; // формируем отправляемое сообщение var message = new Message() < Role = «user», Content = content >; // добавляем сообщение в список сообщений messages.Add(message); // формируем отправляемые данные var requestData = new Request() < ModelId = «gpt-3.5-turbo», Messages = messages >; // отправляем запрос using var response = await httpClient.PostAsJsonAsync(endpoint, requestData); // если произошла ошибка, выводим сообщение об ошибке на консоль if (!response.IsSuccessStatusCode) < Console.WriteLine($»»); break; > // получаем данные ответа ResponseData? responseData = await response.Content.ReadFromJsonAsync(); var choices = responseData?.Choices ?? new List(); if (choices.Count == 0) < Console.WriteLine(«No choices were returned by the API»); continue; >var choice = choices[0]; var responseMessage = choice.Message; // добавляем полученное сообщение в список сообщений messages.Add(responseMessage); var responseText = responseMessage.Content.Trim(); Console.WriteLine($»ChatGPT: «); > // класс сообщения class Message < [JsonPropertyName(«role»)] public string Role < get; set; >= «»; [JsonPropertyName(«content»)] public string Content < get; set; >= «»; > class Request < [JsonPropertyName(«model»)] public string ModelId < get; set; >= «»; [JsonPropertyName(«messages»)] public List Messages < get; set; >= new(); > class ResponseData < [JsonPropertyName(«id»)] public string Id < get; set; >= «»; [JsonPropertyName(«object»)] public string Object < get; set; >= «»; [JsonPropertyName(«created»)] public ulong Created < get; set; >[JsonPropertyName(«choices»)] public List Choices < get; set; >= new(); [JsonPropertyName(«usage»)] public Usage Usage < get; set; >= new(); > class Choice < [JsonPropertyName(«index»)] public int Index < get; set; >[JsonPropertyName(«message»)] public Message Message < get; set; >= new(); [JsonPropertyName(«finish_reason»)] public string FinishReason < get; set; >= «»; > class Usage < [JsonPropertyName(«prompt_tokens»)] public int PromptTokens < get; set; >[JsonPropertyName(«completion_tokens»)] public int CompletionTokens < get; set; >[JsonPropertyName(«total_tokens»)] public int TotalTokens < get; set; >>

Прежде всего нам необходимо определить ряд классов для отправки и получения сообщений в формате json. Так, согласно OpenAI API формат получаемого от ChatGPT сообщения выглядит следующим образом:

< «id»: «chatcmpl-123», «object»: «chat.completion», «created»: 1677652288, «choices»: [< «index»: 0, «message»: < «role»: «assistant», «content»: «nnHello there, how may I assist you today?», >, «finish_reason»: «stop» >], «usage»: < «prompt_tokens»: 9, «completion_tokens»: 12, «total_tokens»: 21 >>

Для представления ответа определены следующие классы:

class Message < [JsonPropertyName(«role»)] public string Role < get; set; >= «»; [JsonPropertyName(«content»)] public string Content < get; set; >= «»; > class Request < [JsonPropertyName(«model»)] public string ModelId < get; set; >= «»; [JsonPropertyName(«messages»)] public List Messages < get; set; >= new(); > class ResponseData < [JsonPropertyName(«id»)] public string Id < get; set; >= «»; [JsonPropertyName(«object»)] public string Object < get; set; >= «»; [JsonPropertyName(«created»)] public ulong Created < get; set; >[JsonPropertyName(«choices»)] public List Choices < get; set; >= new(); [JsonPropertyName(«usage»)] public Usage Usage < get; set; >= new(); > class Choice < [JsonPropertyName(«index»)] public int Index < get; set; >[JsonPropertyName(«message»)] public Message Message < get; set; >= new(); [JsonPropertyName(«finish_reason»)] public string FinishReason < get; set; >= «»; > class Usage < [JsonPropertyName(«prompt_tokens»)] public int PromptTokens < get; set; >[JsonPropertyName(«completion_tokens»)] public int CompletionTokens < get; set; >[JsonPropertyName(«total_tokens»)] public int TotalTokens < get; set; >>

Еще по теме:  Айфон Телеграмм удалить чат и отписаться

Для сопоставления с полученными данными при десериализации ответа у каждого свойства классов устанавливаем соответствующий атрибут JsonPropertyName .

Формат отправляемого запроса выглядит следующим образом:

Для представления этих данных определен тип Request:

class Request < [JsonPropertyName(«model»)] public string ModelId < get; set; >= «»; [JsonPropertyName(«messages»)] public List Messages < get; set; >= new(); >

В самой программе сначала устанавливаем токен, который будет использоваться для отправки запросов к ChatGPT, и адрес запроса:

string apiKey = «sk-95Ez2Z1rtgegrRTFFDSTVTdsdfsgdv3422kjhLghnh53QiT8F»; string endpoint = «https://api.openai.com/v1/chat/completions»;

Далее определяем список сообщений (по умолчанию пустой) и объект HttpClient для отправки сообщений

List messages = new List(); var httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Add(«Authorization», $»Bearer «);

В бесконечном цикле считываем сообщения, введенные пользователем

Console.Write(«User: «); var content = Console.ReadLine();

Чтобы пользователь мог выйти из диалога с чат-ботом, пусть, если пользователь ввел пустую строку, то завершаем диалог:

if (content is not < Length: >0 >) break;

После ввода добавляем введеное сообщение в список messages:

var message = new Message() < Role = «user», Content = content >; messages.Add(message);

Для текущего пользователя для свойство Role устанавливаем «user», а свойство Content хранит собственно текст сообщения, которое отправляется чат-боту.

Дальше с помощью выполняем запрос к ChatGPT:

var requestData = new Request() < ModelId = «gpt-3.5-turbo», Messages = messages >; using var response = await httpClient.PostAsJsonAsync(endpoint, requestData);

Для выполнения запроса создаем объект Request , свойствам которого передаются название модели и список сообщений.

После этого из переменной response мы сможем получить ответ чат-бота.

ResponseData? responseData = await response.Content.ReadFromJsonAsync(); var choices = responseData?.Choices ?? new List(); if (choices.Count == 0) < Console.WriteLine(«No choices were returned by the API»); continue; >var choice = choices[0]; var responseMessage = choice.Message;

Далее выводим ответ от ChatGPT на консоль и добавляем его ответ в список messages:

messages.Add(responseMessage); var responseText = responseMessage.Content.Trim(); Console.WriteLine($»ChatGPT: «);

Пример работы программы:

Источник: metanit.com

Как создать чат-бота для Telegram. Пишем бота на C#. Интенсив по С#

Как написать бота для Telegram на С#? Системный архитектор Павел Платонов расскажет о принципах работы чат-бота. Познакомит с библиотекой Telegram Bot на С#. Научит добавлять в настройки API-ключ.

Интенсив «Введение в С#: пишем 3-х чат-ботов за 3 дня» будет полезен тем, кого интересует материал по C для начинающих. Разберетесь в устройстве C#-библиотек для связи своих приложений с Telegram и «ВКонтакте». Создадите бота, который будет отвечать на команды пользователей.

На онлайн-обучении Skillbox расскажем, как сделать бота на С#, используя сторонние приложения. На практике вы создадите бот-викторину и запустите его в консоли, Telegram, даже, если никогда не программировали.

0:00 — Начало
15:00 — Skillbox
15:50 — Приветствие от Антона Доржинкевича
19:51 — Спикер Павел Платонов
20:15 — Продолжение написания кода чат-бота
20:40 — Создаем чат-бот для Telegram
55:33 — Ответ на вопрос о С#
56:42 — Распродажа курсов от Skillbox
1:13:55 — Дальше пишем чат-бот
1:46:12 — Ответы на вопросы
1:51:33 — О домашнем задании

Подписывайтесь на наш канал, чтобы не пропустить анонсы новых вебинаров и онлайн-конференций.
А также заглядывайте в наши соцсети, там много полезной информации: https://vk.com/skillbox_education
https://www.facebook.com/skillboxru
https://www.instagram.com/skillbox.ru
https://ok.ru/skillbox
https://t.me/skillboxru

#skillbox #программирование #с

Источник: best-coding.ru

Рейтинг
( Пока оценок нет )
Загрузка ...