[Python, Asterisk, Социальные сети и сообщества, Flask] Реализация аудиоконференций в Telegram + Asterisk
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
В предыдущей статье я описывал реализацию выбора пользователем места жительства при регистрации в моем telegram боте, который я создавал вдохновившись идеей «Телефонного эфира». В этой же статье я опишу интеграцию бота с Asterisk.
Зачем ?
Многим не нравится что в Telegram нельзя осуществлять групповые звонки.
Ну не использовать же Viber ?)
Также есть ряд кейсов именно для такой реализации, например:
- Для проведения анонимных аудиоконференций, когда не хочется «засветить» свой номер либо id среди участников конференции (сразу на ум приходит шабаш хакеров либо клуба анонимных алкоголиков). Не нужно находиться в какой либо группе, сообществе, канале
- Когда не известно кто подключиться к конференции вообще, но нужно ограничить доступ паролем
- Все прелести Asterisk: управление конференцией (mute/umute, kick), организация гибридных аудиоконференций с участием клиентов, зарегистрированных на asterisk, telegram и PSTN. Неплохо можно сэкономить на международных звонках
- Организация корпоративного callback via telegram и т.п.
На ум приходит куча вариантов, их много, ограничено лишь фантазией. После многих лет работы с Asterisk я считаю, что главное завести на него звонок, а дальше с ним можно сделать все что годно, хоть в космос отправить.
Связка Asterisk VoIP- Telegram VoIP
Сама связка VoIP реализована благодаря библиотеки tg2sip. Использование ее описано в самом репозитории в разделе Usage. Есть еще несколько статей по настройке. Даже есть Docker образ.
Описание этой связки выходит за рамки данной статьи.
Единственный нюанс который я хотел бы озвучить — это то, что нельзя позвонить на telegram_id, номера которого нет в Вашей книге контактов. Поэтому звонить нужно на номер телефона, на который зарегистрирован telegram.
В моем боте реализованы как публичные аудиоконференции (Эфиры), к которым может подключиться любой желающий, так и приватные аудиоконференции с доступом по паролю. Приватные комнаты/пароли создают сами пользователи и могут использовать бот в качестве площадки дле проведения аудиоконференций, совещаний и т.п.
Взаимодействие telegram bot — Asterisk
Схема взаимодействия в моем боте выглядит следующим образом.
Пользователь выбирает желаемую комнату в меню бота, бот вызывает функцию взаимодействия с Asterisk по API передав в POST запросе параметры для подключения:
— номер телефона абонента
— идентификатор конференц комнаты
— callerid для презентации в конференц комнате
— язык для озвучивания пользователю уведомлений в системе Asterisk на родном языке
Далее, Asterisk осуществляет исходящий звонок через каналы telegram на номер, указанный в параметрах запроса. После ответа пользоветелем на звонок, Asterisk подключает его в соответствующую комнату.
Можно было бы использовать прямое подключение с бота на Astersik AMI, но я предпочитаю работать через API, чем проще — тем лучше.
API на стороне Asterisk сервера
Код простого API на python. Для инициализации звонка используются .call файлы
#!/usr/bin/python3
from flask import Flask, request, jsonify
import codecs
import json
import glob
import shutil
api_key = "s0m3_v3ry_str0ng_k3y"
app = Flask(__name__)
@app.route('/api/conf', methods= ['POST'])
def go_conf():
content = request.get_json()
## Блок авторизации
if not "api_key" in content:
return jsonify({'error': 'Authentication required', 'message': 'Please specify api key'}), 401
if not content["api_key"] == api_key:
return jsonify({'error': 'Authentication failure', 'message': 'Wrong api key'}), 401
## Проверка наличия нужных параметров в запросе
if not "phone_number" in content or not "room_name" in content or not "caller_id" in content:
return jsonify({'error': 'not all parameters are specified'}), 400
if not "lang" in content:
lang = "ru"
else:
lang = content["lang"]
phone_number = content["phone_number"]
room_name = content["room_name"]
caller_id = content["caller_id"]
calls = glob.glob(f"/var/spool/asterisk/outgoing/*-{phone_number}*")
callfile = "cb_conf-" + phone_number + "-" + room_name + ".call"
filename = "/var/spool/asterisk/" + callfile
if calls:
return jsonify({'message': 'error', "text": "call already in progress"})
with codecs.open(filename, "w", encoding='utf8') as f:
f.write("Channel: LOCAL/" + phone_number + "@telegram-out\n")
f.write("CallerID: <" + caller_id + ">\n")
f.write("MaxRetries: 0\nRetryTime: 5\nWaitTime: 30\n")
f.write("Set: LANG=" + lang + "\nContext: conf-in\n")
f.write("Extension: " + room_name + "\nArchive: Yes\n")
shutil.chown(filename, user="asterisk", group="asterisk")
shutil.move(filename, "/var/spool/asterisk/outgoing/" + callfile)
return jsonify({'message': 'ok'})
if __name__ == '__main__':
app.run(debug=True,host='0.0.0.0', port=8080)
При этом диалплан Asterisk в простом виде выглядит следующим образом:
[telegram-out]
exten => _+.!,1,NoOp()
same => n,Dial(SIP/${EXTEN}@telegram)
exten => _X!,1,NoOp()
same => n,Dial(SIP/+${EXTEN}@telegram)
[conf-in]
exten => _.!,1,NoOp()
same => n,Answer()
same => n,Wait(3)
same => n,Playback(beep)
same => n,Set(CHANNEL(language)=${LANG})
same => n,ConfBridge(${EXTEN})
same => n,Hangup
Данное API можно использовать и в других кейсах, например, для организации той же callback кнопки «Перезвонить мне» и т.п.
Функция вызова API
telephony_api.py
import requests
# Заменить example.com на Ваш url
url = "http://example.com:8080/api/conf"
api_key = "s0m3_v3ry_str0ng_k3y"
def go_to_conf(phone_number, room_name, caller_id, lang="ru"):
payload = "{\n\t"phone_number" : ""+phone_number+"",\n\t"room_name" : ""+room_name+"",\n "caller_id" : ""+caller_id+"",\n\t"lang": ""+lang+"",\n\t"api_key": ""+api_key+""\n}"
headers = {
'content-type': "application/json",
'cache-control': "no-cache",
}
try:
response = requests.request("POST", url, data=payload, headers=headers, timeout=2, verify=False)
if "call already in progress" in response.text:
return False, "Ошибка. Звонок еще не завершен."
elif "error" in response.text:
print(response.text)
return False, "Ошибка. Произошел сбой. Попробуйте позже."
else:
return True, response.text
except:
return False, "Ошибка. Произошел сбой. Попробуйте позже."
Этих двух инструментов уже хватит для интеграции в Ваш бот, заворачивайте его в свою логику и используйте.
Пример бота для инициализации вызова в конференц комнату
#!/usr/bin/python3.6
import telebot
from telephony_api import go_to_conf
bot = telebot.TeleBot("ВашTOKEN")
pnone_number = "799999999999"# Ваш номер телефона, на который зарегистрирован telegram аккаунт
@bot.message_handler(content_types=['text'])
def main_text_handler(message):
if message.text == "Подключи меня в аудиоконференцию":
bot.send_message(message.chat.id, "Ok. Сейчас на telegram Вам прийдет звонок, ответив на который Вы будете подключены в аудиоконференцию")
func_result, func_message = go_to_conf(pnone_number, "ROOM1", "Bob", "ru")
if not func_result:
bot.send_message(chat_id=message.chat.id, text=func_message)
if __name__ == "__main__":)
print("bot started")
bot.polling(none_stop=True)
В данном примере номер телефона задан статически, в реальности же можно например, делать запросы в базу на соответствие message.chat.id — номер телефона.
Надеюсь, моя статья поможет кому-то создать крутые проекты и в свою очередь поделиться ними с сообществом.
===========
Источник:
habr.com
===========
Похожие новости:
- [Python, Семантика] Ищем «Троллей». Алгоритм шинглов & косинусное сходство
- [Законодательство в IT, Социальные сети и сообщества] TikTok рассказал об удалении видео по запросам властей, в том числе в России
- [Социальные сети и сообщества, Лайфхаки для гиков, Здоровье, Научно-популярное] Социальные сети управляют вами, но есть способы дать им отпор (перевод)
- [Open source, Python, GitHub, Искусственный интеллект] Как трекать людей в масках или универсальный подход к трекингу объектов произвольной природы
- [Open source, Openshift, Виртуализация, Учебный процесс в IT] Шпаргалка по Ansible k8s, практичный учебник по awk, а также 4 причины использовать Jamstack при веб-разработке
- [Дизайн, Социальные сети и сообщества] «Википедия» изменит дизайн впервые за десятилетие
- [Python, Node.JS, Машинное обучение] Machine learning in browser: ways to cook up a model
- [Asterisk, IT-инфраструктура, Сетевое оборудование, Сетевые технологии] I want to break free. Обзор беспроводной DECT гарнитуры Snom A170
- [Законодательство в IT, Копирайт, Социальные сети и сообщества] YouTube: истец сам загрузил на платформу фильмы, а затем заявил о массовом нарушении авторских прав
- [Высокая производительность, Python, Распределённые системы, Финансы в IT] Фоновые задачи на Faust, Часть II: Агенты и Команды
Теги для поиска: #_python, #_asterisk, #_sotsialnye_seti_i_soobschestva (Социальные сети и сообщества), #_flask, #_telegrambot (телеграм-бот), #_asterisk, #_python, #_python, #_asterisk, #_sotsialnye_seti_i_soobschestva (
Социальные сети и сообщества
), #_flask
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 14:00
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
В предыдущей статье я описывал реализацию выбора пользователем места жительства при регистрации в моем telegram боте, который я создавал вдохновившись идеей «Телефонного эфира». В этой же статье я опишу интеграцию бота с Asterisk. Зачем ? Многим не нравится что в Telegram нельзя осуществлять групповые звонки. Ну не использовать же Viber ?) Также есть ряд кейсов именно для такой реализации, например:
На ум приходит куча вариантов, их много, ограничено лишь фантазией. После многих лет работы с Asterisk я считаю, что главное завести на него звонок, а дальше с ним можно сделать все что годно, хоть в космос отправить. Связка Asterisk VoIP- Telegram VoIP Сама связка VoIP реализована благодаря библиотеки tg2sip. Использование ее описано в самом репозитории в разделе Usage. Есть еще несколько статей по настройке. Даже есть Docker образ. Описание этой связки выходит за рамки данной статьи. Единственный нюанс который я хотел бы озвучить — это то, что нельзя позвонить на telegram_id, номера которого нет в Вашей книге контактов. Поэтому звонить нужно на номер телефона, на который зарегистрирован telegram. В моем боте реализованы как публичные аудиоконференции (Эфиры), к которым может подключиться любой желающий, так и приватные аудиоконференции с доступом по паролю. Приватные комнаты/пароли создают сами пользователи и могут использовать бот в качестве площадки дле проведения аудиоконференций, совещаний и т.п. Взаимодействие telegram bot — Asterisk Схема взаимодействия в моем боте выглядит следующим образом. Пользователь выбирает желаемую комнату в меню бота, бот вызывает функцию взаимодействия с Asterisk по API передав в POST запросе параметры для подключения: — номер телефона абонента — идентификатор конференц комнаты — callerid для презентации в конференц комнате — язык для озвучивания пользователю уведомлений в системе Asterisk на родном языке Далее, Asterisk осуществляет исходящий звонок через каналы telegram на номер, указанный в параметрах запроса. После ответа пользоветелем на звонок, Asterisk подключает его в соответствующую комнату. Можно было бы использовать прямое подключение с бота на Astersik AMI, но я предпочитаю работать через API, чем проще — тем лучше. API на стороне Asterisk сервера Код простого API на python. Для инициализации звонка используются .call файлы #!/usr/bin/python3
from flask import Flask, request, jsonify import codecs import json import glob import shutil api_key = "s0m3_v3ry_str0ng_k3y" app = Flask(__name__) @app.route('/api/conf', methods= ['POST']) def go_conf(): content = request.get_json() ## Блок авторизации if not "api_key" in content: return jsonify({'error': 'Authentication required', 'message': 'Please specify api key'}), 401 if not content["api_key"] == api_key: return jsonify({'error': 'Authentication failure', 'message': 'Wrong api key'}), 401 ## Проверка наличия нужных параметров в запросе if not "phone_number" in content or not "room_name" in content or not "caller_id" in content: return jsonify({'error': 'not all parameters are specified'}), 400 if not "lang" in content: lang = "ru" else: lang = content["lang"] phone_number = content["phone_number"] room_name = content["room_name"] caller_id = content["caller_id"] calls = glob.glob(f"/var/spool/asterisk/outgoing/*-{phone_number}*") callfile = "cb_conf-" + phone_number + "-" + room_name + ".call" filename = "/var/spool/asterisk/" + callfile if calls: return jsonify({'message': 'error', "text": "call already in progress"}) with codecs.open(filename, "w", encoding='utf8') as f: f.write("Channel: LOCAL/" + phone_number + "@telegram-out\n") f.write("CallerID: <" + caller_id + ">\n") f.write("MaxRetries: 0\nRetryTime: 5\nWaitTime: 30\n") f.write("Set: LANG=" + lang + "\nContext: conf-in\n") f.write("Extension: " + room_name + "\nArchive: Yes\n") shutil.chown(filename, user="asterisk", group="asterisk") shutil.move(filename, "/var/spool/asterisk/outgoing/" + callfile) return jsonify({'message': 'ok'}) if __name__ == '__main__': app.run(debug=True,host='0.0.0.0', port=8080) При этом диалплан Asterisk в простом виде выглядит следующим образом: [telegram-out] exten => _+.!,1,NoOp() same => n,Dial(SIP/${EXTEN}@telegram) exten => _X!,1,NoOp() same => n,Dial(SIP/+${EXTEN}@telegram) [conf-in] exten => _.!,1,NoOp() same => n,Answer() same => n,Wait(3) same => n,Playback(beep) same => n,Set(CHANNEL(language)=${LANG}) same => n,ConfBridge(${EXTEN}) same => n,Hangup Данное API можно использовать и в других кейсах, например, для организации той же callback кнопки «Перезвонить мне» и т.п. Функция вызова API telephony_api.py import requests
# Заменить example.com на Ваш url url = "http://example.com:8080/api/conf" api_key = "s0m3_v3ry_str0ng_k3y" def go_to_conf(phone_number, room_name, caller_id, lang="ru"): payload = "{\n\t"phone_number" : ""+phone_number+"",\n\t"room_name" : ""+room_name+"",\n "caller_id" : ""+caller_id+"",\n\t"lang": ""+lang+"",\n\t"api_key": ""+api_key+""\n}" headers = { 'content-type': "application/json", 'cache-control': "no-cache", } try: response = requests.request("POST", url, data=payload, headers=headers, timeout=2, verify=False) if "call already in progress" in response.text: return False, "Ошибка. Звонок еще не завершен." elif "error" in response.text: print(response.text) return False, "Ошибка. Произошел сбой. Попробуйте позже." else: return True, response.text except: return False, "Ошибка. Произошел сбой. Попробуйте позже." Этих двух инструментов уже хватит для интеграции в Ваш бот, заворачивайте его в свою логику и используйте. Пример бота для инициализации вызова в конференц комнату #!/usr/bin/python3.6
import telebot from telephony_api import go_to_conf bot = telebot.TeleBot("ВашTOKEN") pnone_number = "799999999999"# Ваш номер телефона, на который зарегистрирован telegram аккаунт @bot.message_handler(content_types=['text']) def main_text_handler(message): if message.text == "Подключи меня в аудиоконференцию": bot.send_message(message.chat.id, "Ok. Сейчас на telegram Вам прийдет звонок, ответив на который Вы будете подключены в аудиоконференцию") func_result, func_message = go_to_conf(pnone_number, "ROOM1", "Bob", "ru") if not func_result: bot.send_message(chat_id=message.chat.id, text=func_message) if __name__ == "__main__":) print("bot started") bot.polling(none_stop=True) В данном примере номер телефона задан статически, в реальности же можно например, делать запросы в базу на соответствие message.chat.id — номер телефона. Надеюсь, моя статья поможет кому-то создать крутые проекты и в свою очередь поделиться ними с сообществом. =========== Источник: habr.com =========== Похожие новости:
Социальные сети и сообщества ), #_flask |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 14:00
Часовой пояс: UTC + 5