gifts2017

Создаем бота Telegram

Опубликовал Ден Ден (FirePyres) в раздел Программирование - Практика программирования

Легко и непринужденно создаем бота, который поможет получать данные из 1С, используя API Teletram

Используя побликации  http://infostart.ru/public/387433/ и http://infostart.ru/public/419846/ решил создать бота, используя API Telegram

Для разбора JSON использовалась обработка из публикации: http://infostart.ru/public/119601/

Регистрируем бот и получаем ТОКЕН, тут: http://infostart.ru/public/419846/  есть описание, как это сделать

В текущей версии реализована реакция на тестовые сообщения от пользователя;

"скажи" - бот в ответ посылает сообщение

"отчеты" - показывается клавиатура со списком доступных отчетов

"файлы" - показывается клавиатура со списком доступных файлов

Также бот получает присланные фотографии.

Основные процедуры бота:

&НаСервере
Процедура ПрочитатьСобщенияНаСервере() Экспорт
	Сервер = "api.telegram.org";    
	
	СтрокаСоединения = "/bot"+Токен+"/getUpdates" + ?(ПоследнийИД = "", "", "?offset=" + ПоследнийИД);
	
	HTTPЗапрос = Новый HTTPЗапрос();
	Заголовки = Новый Соответствие;
	
	HTTPЗапрос.Заголовки.Вставить("Connection", "keep-alive"); 
	HTTPЗапрос.АдресРесурса = СтрокаСоединения; 
	
	ЗащищенноеСоединение = Новый ЗащищенноеСоединениеOpenSSL(Новый СертификатКлиентаWindows, Новый СертификатыУдостоверяющихЦентровWindows);
	HTTPСоединение = 	Новый HTTPСоединение(Сервер,,,,Новый ИнтернетПрокси,, ЗащищенноеСоединение);
	Попытка 
		ОтветHTTP = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
	Исключение
		Сообщить(ОписаниеОшибки());
		Возврат;
	КонецПопытки;
	
	ДанныеКакСтрока = ОтветHTTP.ПолучитьТелоКакСтроку();
	
	обОбработка = РеквизитФормыВЗначение("Объект");
	
	Рез = обОбработка.мПрочитатьJSON(ДанныеКакСтрока);
	Если Рез["ok"] <> Истина Тогда
		Возврат;
	КонецЕсли;
	
	
	Рез = СоответвиеВСтруктуру(Рез);
	
	result = Рез.result;
	МаксИД = 0;
	
	Для Каждого mes из result Цикл
		
		ПоследнийИД = Формат(mes.update_id + 1, "ЧГ=");
		
		Попытка
			message	 = mes.message;
		Исключение
			Продолжить;
		КонецПопытки;
		
		Дата = '19700101' + message.date +7*60*60;
		
		Попытка
			from = message.from.username;
		Исключение
			from = message.from.first_name;
		КонецПопытки;
		
		chatИД = Формат(message.chat.id, "ЧГ=");
		
		Если message.Свойство("text") Тогда
			Ок= истина;
			Если Найти(ВРег(message.text), "СКАЖИ")<>0 Тогда
				
				HTTPЗапрос.АдресРесурса = "/bot"+Токен+"/sendMessage?text=Hello I am BOT&chat_id="+chatИД+"&reply_to_message_id=" + message.message_id; 
				HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
				
			ИначеЕсли  Врег(message.text) = "ОТЧЕТЫ" Тогда
				
				HTTPЗапрос.АдресРесурса = "/bot"+Токен+"/sendMessage?text=Доступные отчеты: &chat_id="+chatИД+"&reply_to_message_id=" + message.message_id + 
				"&reply_markup="+КлаваОтчеты;
				HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
				
			ИначеЕсли  Врег(message.text) = "ФАЙЛЫ" Тогда
				
				HTTPЗапрос.АдресРесурса = "/bot"+Токен+"/sendMessage?text=Доступные файлы: &chat_id="+chatИД+"&reply_to_message_id=" + message.message_id + 
				"&reply_markup="+КлаваФайлы;
				HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
				
			ИначеЕсли Лев(message.text, 7) = "Отчет: " Тогда
				
				HTTPЗапрос.АдресРесурса = "/bot"+Токен+"/sendMessage?text=Ждите. Отчет формируется&chat_id="+chatИД+"&reply_to_message_id=" + message.message_id;
				HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
				
				ТекстОтчета = ПолучитьТекстОтчета(message.text);
				
				HTTPЗапрос.АдресРесурса = "/bot"+Токен+"/sendMessage?parse_mode=HTML&text="+Кодировать(ТекстОтчета)+"&chat_id="+chatИД+"&reply_to_message_id=" + message.message_id;
				HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
				
			ИначеЕсли message.text = "Файл: PDF" Тогда
				
				ОтправитьФайлPDF(chatИД, HTTPСоединение, HTTPЗапрос)				
				
			ИначеЕсли message.text = "Файл: XLS" Тогда
				
				ОтправитьФайлXLS(chatИД, HTTPСоединение, HTTPЗапрос)				
				
			КонецЕсли;
			
		ИначеЕсли message.Свойство("photo") Тогда
			МассивФото = message.photo;
			Для Каждого Фото из МассивФото Цикл
				HTTPЗапрос.АдресРесурса = "/bot"+Токен+"/getFile?file_id=" + Фото.file_id;
				Ответ = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
				СтрокаОтвета = Ответ.ПолучитьТелоКакСтроку();
				Путь = СтрЗаменить(Сред(СтрокаОтвета, Найти(СтрокаОтвета,"photo\/") + 7) , """}}", "");
				СтрФото = Фотографии.Добавить();
				СтрФото.Имя = Путь;
				СтрФото.Размер = "" + Фото.height +"x" + Фото.width;
			КонецЦикла;
			
		КонецЕсли;
	КонецЦикла;
КонецПроцедуры


&НаСервере
Функция СоответвиеВСтруктуру(Рез) 
	мРез = Новый Структура;
	Для Каждого Эл из Рез Цикл
		Ключ = Эл.Ключ;
		мЗнач = Эл.Значение;
		Если ТипЗнч(мЗнач) =Тип("Соответствие") Тогда
			мЗнач = СоответвиеВСтруктуру(мЗнач);
		ИначеЕсли ТипЗнч(мЗнач) =Тип("Массив") Тогда
			мЗнач = Новый Массив;
			Для Каждого элМ из Эл.Значение Цикл
				мЗнач.Добавить(СоответвиеВСтруктуру(элМ));
			КонецЦикла;
		КонецЕсли;
		мРез.Вставить(Ключ, мЗнач);
	КонецЦикла;
	Возврат мРез;
КонецФункции

&НаСервере
функция Кодировать(Текст)
	Возврат ?(Текст = "", "Пусто", КодироватьСтроку(Текст,  СпособКодированияСтроки.URLВКодировкеURL));
КонецФункции

&НаСервере
Процедура ОтправитьФайлPDF(chat_id, HTTPСоединение, HTTPЗапрос)
	
	Таб = РеквизитФормыВЗначение("Объект").ПолучитьМакет("МакетОтчета");
	
	
    ИмяФайла = ПолучитьИмяВременногоФайла("PDF");
    Таб.АвтоМасштаб = Истина;
    Таб.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.PDF);
	
    
    СтрокаСоединения = "/bot" + Токен + "/sendDocument";
    
    Boundary = "----"+Строка(Новый УникальныйИдентификатор());
    
    //Определяем массив для процедуры ОбъединитьФайлы
    МассивФайловДляОбъединения = Новый Массив;
    
    //Формируем начальный фрагмент файла POST-запроса
    ИмяФайлаОтправкиНачало = ПолучитьИмяВременногоФайла("txt");
    ФайлОтправкиНачало = Новый ЗаписьТекста(ИмяФайлаОтправкиНачало, КодировкаТекста.UTF8);
    
    //Формируем конечный фрагмент файла POST-запроса
    ИмяФайлаОтправкиКонец = ПолучитьИмяВременногоФайла("txt");
    ФайлаОтправкиКонец = Новый ЗаписьТекста(ИмяФайлаОтправкиКонец, КодировкаТекста.UTF8);
    
    ТекстДляОтправки = "";
    
    ТекстДляОтправки = ТекстДляОтправки + "--"+Boundary + Символы.ПС;
    ТекстДляОтправки = ТекстДляОтправки + "Content-Disposition: form-data; name=""chat_id""" + Символы.ПС + Символы.ПС;
    ТекстДляОтправки = ТекстДляОтправки + chat_id + Символы.ПС;
    
    ТекстДляОтправки = ТекстДляОтправки + "--"+Boundary + Символы.ПС;
    ТекстДляОтправки = ТекстДляОтправки + "Content-Disposition: form-data; name=""document""; filename=""report.PDF""" + Символы.ПС;
    
    ФайлОтправкиНачало.ЗаписатьСтроку(ТекстДляОтправки );
    ФайлОтправкиНачало.Закрыть();
    
    МассивФайловДляОбъединения.Добавить(ИмяФайлаОтправкиНачало);
    
    МассивФайловДляОбъединения.Добавить(СокрЛП(ИмяФайла));
    
    ТекстДляОтправки = "" + Символы.ПС;
    ТекстДляОтправки = ТекстДляОтправки + "--"+Boundary+"--";
    ФайлаОтправкиКонец.ЗаписатьСтроку(ТекстДляОтправки);
    ФайлаОтправкиКонец.Закрыть();
    МассивФайловДляОбъединения.Добавить(ИмяФайлаОтправкиКонец);
    
    ИмяФайлаОтправки = ПолучитьИмяВременногоФайла("txt");
    ОбъединитьФайлы(МассивФайловДляОбъединения, ИмяФайлаОтправки);
    
    HTTPЗапрос.Заголовки.Вставить("Connection", "keep-alive");
    HTTPЗапрос.Заголовки.Вставить("Content-Type", "multipart/form-data; boundary="+Boundary);
    
    HTTPЗапрос.УстановитьИмяФайлаТела(ИмяФайлаОтправки);
    HTTPЗапрос.АдресРесурса = СтрокаСоединения;
    
    Попытка
        ОтветHTTP = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
    Исключение
        Сообщить(ОписаниеОшибки());
    КонецПопытки;
КонецПроцедуры

Добавлено:

Что бы клавиатура появлялась прямо в чате необходимо подавать другой текст клавиатуры в обработке он получается так:

	Строки = Новый Массив;
	Кнопки = Новый Массив;
	Кнопки.Добавить(Новый структура("text, callback_data", "Файл: PDF", "1"));
	Кнопки.Добавить(Новый структура("text, callback_data", "Файл: XLS", "2"));
	Строки.Добавить(Кнопки);

	КлавиатураВСообщении = JSON.мЗаписатьJSON(Новый Структура("inline_keyboard", Строки), Ложь);

если текстом:

КлавиатураВСообщении =
"{""inline_keyboard"":[[{""text"":""Файл: PDF"",""callback_data"":""1""},{""text"":""Файл: XLS"",""callback_data"":""2""}]]}"

обработка нажатия на эту кнопку отличается от обработки нажатия на простую клавиатуру, которая впринципе просто отсылает сообщение с нужным текстом:

блок "сallback_query" как раз говорит нам о нажатии на такую кнопку, в нем будет содержаться информации о коде нажатой кноки, в нашем примере это "1" или "2"

КодНажатойКнопки = mes.callback_query.data

далее обратабываем так как нам надо

Скачать файлы

Наименование Файл Версия Размер
ОбработкаБот 17
.epf 27,05Kb
30.09.16
17
.epf 27,05Kb Скачать

См. также

Подписаться Добавить вознаграждение

Комментарии

1. Илья Вильчик (TreeDogNight) 30.09.16 10:18
2. Геннадий Жаркой (ifal) 30.09.16 13:20
Желтый у вас заголовок, где же тут процесс создания бота?
3. Ден Ден (FirePyres) 30.09.16 14:01
(2) ifal, Как понять что он "желтый"?
4. Геннадий Жаркой (ifal) 30.09.16 15:18
(3) FirePyres, В заголовке статьи написано: " создаем бота..." -, я ожидал увидеть описание процесса, а что видим внутри? ссылки на другие статьи, где описан процесс, а все что ваше личное упрятано в обработку. Поэтому я делаю такой вывод. Правильней звучало бы "Пример использования бота Telegram".
5. Ден Ден (FirePyres) 04.10.16 05:41
(4) Добавил тексты основных процедур
Хотел описать, но код вроде настолько простой что вроде и объяснений не надо
6. Ден Ден (FirePyres) 06.10.16 10:35
Добавил пример inline клавиатуры
7. Михаил Беляев (METAL) 08.11.16 11:00
Добрый день!
Скажите, а не приходилось ли Вам делать интеграцию с Facebook API https://developers.facebook.com/ ?
Иными словами, можно ли то же самое прикрутить не к Телеграм, а к Фейсбуку?
Просто в нашей компании никто Телеграм не использует, а интеграцию с каким-нибудь популярным мессенджером хотят, и несмотря на мои уговоры, даже пробовать телеграм не хотят, аргумент такой - вот есть Фейсбук, приложение у всех стоит, АПИ есть, пусть корпоративный бот работает на этой платформе...
Но мне пока не удалось найти ни одного примера реализации бота.. Это потому что на порядок сложней, чем с телеграмом, или просто руки не дошли ни у кого?..
Спасибо!
8. Ден Ден (FirePyres) 09.11.16 05:15
(7) Я бы попробовал, но не совсем понимаю как это должно работать
Как вы это себе представляете?
9. Михаил Беляев (METAL) 09.11.16 10:15
(8) FirePyres, аналогично
Пользователь подписывается на бота
И дальше например пишет в чат ОТЧЕТЫ и может выбрать нужный отчёт за нужную дату (sales today - без кнопок для выбора тоже подойдёт, непринципиально)
Либо происходит событие в 1С какое-то, и пользователю в мессенджер приходит уведомление
Но насколько я вчёра смог разобраться - при разработке придётся использовать некую php-прослойку, так как для ФБ обязательно использовать webhook, как я понял.. По крайней мере, именно на этом этапе я споткнулся http://prntscr.com/d4yojf

Мнение одного специалиста, который делал и для ФБ (на php), и для телеграм (он писал мне в личку, поэтому имя не публикую):
На 1С не делал, делал на php. но там чуть чуть меньше возможностей, есть ограничения и т.д. В принципе можно на php запустить на сайте готовый какой нить движок работы с фейсбуком, и написать для него АПИ интерфейса для 1с. Это самое простое решение будет
10. Николай Иванов (PhoenixAOD) 09.11.16 10:40
12. Ден Ден (FirePyres) 10.11.16 05:50
Сегодня по радио услышал что Viber запустил для всех возможность создания публичного аккаунта

"Представленные паблик аккаунты — это чат-каналы, которые можно использовать для отправки важной (рекламной) информации пользователям, проводить презентации, размещать новости, полезные ссылки, GIF-изображения, всячески общаться и получать обратную реакцию от участников канала. Также создателям каналов доступны CRM-инструменты для управления чатом."
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа