Мы стараемся поддерживать информацию в данной статье в актуальном состоянии. Все последние обновления для работы с сервисами TWIN в первую очередь публикуются на ресурсе https://developers.twin24.ai
Команда TWIN постоянно совершенствуем свои сервисы. В связи с этим возможно внесение изменений в наше API. Просим вас учитывать этот факт при реализации интеграции чат-платформы TWIN с вашими приложениями. Важно обратить на это внимание при согласовании гарантийных обязательств.

В дальнейшем интеграцию чат-платформу TWIN планируется осуществлять с помощью SDK (находиться в разработке). Это позволит производить процесс интеграции быстрее и обеспечит более высокую стабильность работы. 


Оглавление



Информация об интеграции

Интеграция чат-платформы TWIN в приложение (кодовую базу) клиента идёт на стороне клиента. 

Возможность интеграции и её срок определяется специалистами на стороне клиента.

Со своей стороны TWIN предоставляет необходимую документацию по методам подключения и взаимодействия платформы с приложением заказчика.

Для обеспечения двухсторонней связи используется библиотека Socket.IO, построенная на основе протокола WebSocket.


Интеграция осуществляется в несколько простых шагов:

  1. Старт чат-сессии. Происходит при помощи API.
  2. Отправка сообщения в чат сессию. Происходит при помощи API.
  3. Получение сообщений, подтверждение получения сообщений - происходит с помощью socket.io. Важно: на каждое полученное сообщение необходимо отправить событие (emit) о прочтении сообщения.


Ниже детально описаны все перечисленные этапы с примерами кода на языке python версии 3.11.

О примере

Для примера интеграции мы рассмотрим простую программу. Суть и логика программы: запускается эхо-бот, который повторяет введенное в терминале пользователем сообщение. Завершение эхо-чата происходит по ключевому слову "стоп".


Пример отображения диалога в виджете. Здесь в качестве демонстрации показано как бот при старте диалога отправляет картинку. Также продемонстрирована возможность отправки файла в чат.


Список зависимостей окружения

Для корректной работы описанной эхо-программы, рекомендуем установить следующие зависимости:

aiohttp==3.8.4
aiosignal==1.3.1
async-timeout==4.0.2
attrs==23.1.0
bidict==0.22.1
certifi==2023.5.7
charset-normalizer==3.1.0
frozenlist==1.3.3
idna==3.4
multidict==6.0.4
python-engineio==3.14.2
python-socketio==4.6.1
requests==2.31.0
six==1.16.0
urllib3==2.0.3
websocket-client==1.6.0
yarl==1.9.2



Старт новой чат-сессии

Метод: POST

Authorization: No Auth 

URL: https://tcl.twin24.ai/api/chats/v1/chats/{chat_id}/sessions?x_widget=1

Пример функции на языке python:

def start_chat_session(chat_id: str, name: str = "integration_example") -> dict:
    """
    Создаёт чат-сессию и возвращает коллекцию данных о ней.
    :param chat_id: Идентификатор чата.
    :param name: Имя чат-сессии. Задается для облегчения поиска чат-сессии в личном кабинете TWIN.
    :return: Коллекция данных о созданной чат-сессии.
    """
    url = f"https://tcl.twin24.ai/api/chats/v1/chats/{chat_id}/sessions?x_widget=1"
    headers = {"Content-Type": "application/json"}
    payload = json.dumps({"name": name})
    response = requests.request("POST", url, headers=headers, data=payload)

    return response.json()


Описание параметров пути:

Поле

Тип

Обязательно

Описание

chatId

string

Да

Идентификатор чата. Он определяет настройки чата и схему работы бота.


Тело запроса

{
  "name": "string",
  "clientExternalId": "string",
  "clientMetadata": {
    "var1": "val1",
    "var2": "val2",
    "var3": "val3"
  }
}


Описание полей метода:

Поле

Тип

Обязательно

Описание

name

string

Да

Имя сессии.

clientExternalId

string

Нет

Определяемый пользователем идентификатор клиента, инициировавшего сеанс чата.

clientMetadata

object

Нет

Любые определенные пользователем пары ключ/значение в качестве переменных бота.


Ответы

Код 201

Description: Successful session creation

{
  "id": "bce7d22e-dde6-4427-b391-ebbdfda44de6",
  "clientId": "bce7d22e-dde6-4427-b391-ebbdfda44de6",
  "startedAt": "2018-10-31T11:56:07+00:00",
  "ttl": 3600,
  "messages": [
    {
      "body": "string",
      "answers": [
        "string"
      ],
      "actions": [
        {
          "key1": "value1",
          "key2": "value2",
          "key3": "value3"
        }
      ],
      "attachments": [
        {
          "id": "bce7d22e-dde6-4427-b391-ebbdfda44de6",
          "isPrivate": true,
          "createdAt": "2018-10-31T11:56:07+00:00",
          "name": "bot.png",
          "baseName": "bot",
          "extension": "png",
          "sugestedExtension": "png",
          "path": "string",
          "size": 12400,
          "url": "string",
          "downloadLink": "string"
        }
      ]
    }
  ]
}

 

Описание полей ответа

Поле

Тип

Обязательно

Описание

id
stringДа Идентификатор чат-сессии.
clientId 
string
Идентификатор клиента.
startedAt
string
Отметка времени старта чат-сессии.
ttl
integer
Время жизни чат-сессии в секундах.
messages
array of objects
Массив данных о сообщении.
| body
string
Текс сообщения.
| answers
array of strings
Варианты ответов (кнопки с вариантами ответов).
| actions
array of objects
Информация о дополнительной функциональности в данном сообщении (например форма опроса).
| attachments
array of objects
Список идентификаторов вложений.
| | id
string
Идентификатор файла.
| | isPrivate
boolean
Отметка о том, что данное вложение приватно для текущего чата.
| | createdAt
string
Отметка времени о создании.
| | name
string
Полное имя файла (с расширением).
| | baseName
string
Имя файла.
| | extension
string
Расширение файла.
| | sugestedExtension
string
Предлагаемое расширение файла.
| | path
string
Путь (расположение) во внутреннем хранилище.
| | size
int64
Размер файла в байтах.
| | url
string
Ссылка на файл во внутреннем хранилище.
| | downloadLink
string
Ссылка на скачивание файла.


В успешном ответе содержится идентификатор чат-сессии. Именно этот параметр будет в дальнейшем использоваться для отправки сообщения в чат-сессию и подключения socket.io для "прослушивания" событий в данной чат-сессии.



Отправка сообщения в чат сессию

Метод: POST

Authorization: No Auth 

URL: https://chats-api.twin24.ai/api/v1/sessions/{session_id}/messages


Пример функции на языке python:

def send_msg_to_chat_session(session_id: str, message_text: str) -> dict:
    """
    Отправляет сообщение.
    :param session_id: Идентификатор чат-сессии.
    :param message_text: Текст сообщения.
    :return: Коллекция данных об отправленном сообщении.
    """
    url = f"https://chats-api.twin24.ai/api/v1/sessions/{session_id}/messages"
    headers = {'Content-Type': 'application/json'}
    payload = json.dumps({"body": message_text, "attachments": []})
    response = requests.request("POST", url, headers=headers, data=payload)
 
    return response.json()

Описание параметров пути:

Поле

Тип

Обязательно

Описание

sessionId

string

Да

Идентификатор чат-сессии.


Тело запроса

{
  "body": "string",
  "attachments": [
    "bce7d22e-dde6-4427-b391-ebbdfda44de6"
  ],
  "replyToMessageId": "string"
}


Описание полей метода:

Поле

Тип

Обязательно

Описание

body

string

ДаТекст сообщения
attachments

array of strings

НетСписок идентификаторов вложений (файлов), которые были прикреплены при отправке сообщения.
replyToMessageId

string

НетЕсли сообщение является ответом, идентификатор исходного сообщения.


Ответы

Код 201

Description: Successful message creation

{
  "id": "bce7d22e-dde6-4427-b391-ebbdfda44de6",
  "createdAt": "2018-10-31T11:56:07+00:00"
}


Описание полей ответа

Поле

Тип

Обязательно

Описание

id
stringДаИдентификатор сообщения.
createdAt
stringДаОтметка даты и времени, когда было отправлено сообщение.


Отправка файлов в чат-сессию

Для отправки файлов в чат сессию для начала необходимо загрузить файл используя метод, описанный ниже.

Метод: POST

Authorization: No Auth 

URL: https://tcl.twin24.ai/api/chats/v1/files?x_widget=1


Пример функции на языке python для отправки файла с расширением png:

def uploading_file_to_chat_session(file_name, file_path) -> dict:
    """
    Функция загрузки файла изображения в хранилище TWIN.
    :param file_name: Полное имя файла с расширением.
    :param file_path: Путь к файлу.
    :return: Массив данных о загруженном файле.
    """
    url = "https://tcl.twin24.ai/api/chats/v1/files?x_widget=1"

    payload = {}
    files = [("file[]", (file_name, open(file_path, 'rb'), 'image/png'))]
    headers = {}

    response = requests.request("POST", url, headers=headers, data=payload, files=files)

    return response.json()


Примечание: данная функция демонстрирует загрузку изображений. Если необходимо отправить pdf-файл, необходимо указать в переменной file следующее:
files = [("file[]", (file_name, open(file_path, 'rb'), 'application/pdf'))]


Ответы

Код 201

[
    {
        "id": "c419011c-a998-4189-b897-e82117e6a803",
        "isPrivate": true,
        "createdAt": "2022-06-26T15:44:32+00:00",
        "contentType": "image/jpeg",
        "name": "for_test.png",
        "baseName": "for_test",
        "extension": "png",
        "suggestedExtension": "png",
        "path": "",
        "size": 18463,
        "url": "string",
        "downloadLink": "string",
        "ownerId": null
    }
]


Описание полей ответа

Поле

Тип

Обязательно

Описание

id
stringДа Идентификатор файла.
isPrivate
booleanДа Отметка о приватности. True если файл загружен пользователем или оператором, False - если ботом.
name
stringДа Полное имя файла (с расширением).
baseName
stringДа Имя файла.
extension
stringДа Расширение файла.
suggestedExtensionstringДа Предлагаемое расширение файла.
pathstringДа Путь (расположение) во внутреннем хранилище.
sizeint64Да Размер файла в байтах.
urlstringДа Ссылка на файл во внутреннем хранилище.
downloadLinkstringДа Ссылка на скачивание файла.
ownerId
stringДа ID владельца


Далее, для отправки сообщения используется метод отправки сообщения в чат сессию (описан в начале текущего раздела). Важно, при отправке сообщения в котором прикреплён файл, указать в параметрах запроса attachments идентификатор(ы) файла(ов).



Подключение к сокетам

Socket.IO - это библиотека для создания приложений, работающих в режиме реального времени, имеющих двунаправленный канал связи и основанных на событиях. Более подробно ознакомиться с библиотекой можно на сайте официальной документации.

Для взаимодействия с socket.io взята библиотека python-socketio версии 4.6.1

Справочная информация о событиях socket.io для виджета чат-платформы TWIN

Протокол Socket.IO основан на событиях. Когда сервер хочет установить связь с клиентом, он создает событие. Каждое событие имеет имя и список аргументов.

Ниже представлены ключевые события, которые возникают в виджете и описаны параметры каждого события.
Данная информация носит справочный характер и позволяет определить, какие события необходимо инициировать для корректной интеграции чат-платформы в кодовую базу приложения на стороне клиента.


Процесс набора текста

[
    "showTypingIndicatorEmit",
    {
        "authorType": "BOT"
    }
]

Описание параметров события showTypingIndicatorEmit

Поле

Тип

Обязательно

Описание

authorType
stringДаТип автора. Определяет, кто отправил сообщение: бот или оператор.



СООБЩЕНИЯ

Получение сообщения от бота

[
    "chatMessageCreatedEmit",
    {
        "id": "d0f10a74-53fe-4a83-ac1f-ce55c0939df2",
        "authorId": "4f8151ed-8e7a-4a12-a6a5-c94f99c58019",
        "authorType": "BOT",
        "authorName": "МетроБот",
        "type": "REGULAR",
        "body": "Переключаю на оператора",
        "answers": [],
        "createdAt": "2021-03-10T08:37:53+00:00",
        "sessionId": "4d32dc5a-73d3-457e-9b30-5f7ff4c5fa24",
        "attachments": [],
        "actions": [],
        "avatar": null
    }
]

Получение сообщения от оператора

[
    "chatMessageCreatedEmit",
    {
        "id": "25d27d8f-f633-42ef-b359-aeff3ce05001",
        "authorId": "389",
        "authorType": "OPERATOR",
        "authorName": "Первый Оператор V",
        "type": "REGULAR",
        "body": "\nHi",
        "answers": [],
        "createdAt": "2021-03-10T08:49:41+00:00",
        "sessionId": "b1a69f04-a759-4376-b8e5-ee82a7e0d247",
        "attachments": [],
        "actions": [],
        "avatar": {
            "id": "ed661c07-2d50-4b1f-b2c8-32f09a83065e",
            "isPrivate": false,
            "createdAt": "2021-02-05T12:58:33+00:00",
            "contentType": "image/jpeg",
            "name": "мяч.jpg",
            "baseName": "мяч",
            "extension": "jpg",
            "suggestedExtension": "jpg",
            "path": "",
            "size": 310723,
            "url": "https://minio.twin24.ai/twin-iam-dev/public/2021-02-05/ed661c07-2d50-4b1f-b2c8-32f09a83065e?response-content-type=image%2Fjpeg&response-content-disposition=inline%3B%20filename%3Dmyac.jpg%3B%20filename%2A%3Dutf-8%27%27%25D0%25BC%25D1%258F%25D1%2587.jpg",
            "downloadLink": "https://minio.twin24.ai/twin-iam-dev/public/2021-02-05/ed661c07-2d50-4b1f-b2c8-32f09a83065e?response-content-type=image%2Fjpeg&response-content-disposition=attachment%3B%20filename%3Dmyac.jpg%3B%20filename%2A%3Dutf-8%27%27%25D0%25BC%25D1%258F%25D1%2587.jpg&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=minio%2F20210310%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20210310T084942Z&X-Amz-SignedHeaders=host&X-Amz-Expires=604799&X-Amz-Signature=8810cdb3f30b4ccff3c521e7db6ece5d4dfe5814fbecd36b9eed4ae65e99c6fb",
            "ownerId": null
        }
    }
]

Описание параметров события chatMessageCreatedEmit

Поле

Тип

Обязательно

Описание

id
stringДаИдентификатор сообщения.
authorId
string
Идентификатор автора сообщения.
authorType
string
Тип автора. Определяет, кто отправил сообщение: бот или оператор.
authorName
string
Имя автора сообщения.
type
string
Тип сообщения. Может быть:
REGULAR - обычное сообщение;
TERMINAL - последнее (завершающее) сообщение в сессии. После этого сообщения сессия закрывается.
HELP - запрос помощи оператора.
body
string
Текст сообщения.
answers
array of objects
Варианты ответов (кнопки с вариантами ответов).
createdAt
string
Отметка времени о созданном сообщении.
sessionId
string
Идентификатор чат-сессии.
attachments
array of objects
Список идентификаторов вложений.
actions
string
Информация о дополнительной функциональности в данном сообщении (например форма опроса).
avatar
string
Аватар бота или оператора. Массив данных.
|  idstring
Идентификатор файла.
|  isPrivateboolean
False - бот, True - оператор
|  createdAtstring
Отметка времени о создании.
|  contentTypestring
Content type. Тип контента (тип передачи файла).
|  namestring
Полное имя файла (с расширением).
|  baseNamestring
Имя файла.
|  extensionstring
Расширение файла.
|  suggestedExtensionstring
Предлагаемое расширение файла.
|  pathstring
Путь (расположение) во внутреннем хранилище.
|  sizestring
Размер файла в байтах.
|  urlstring
Ссылка на файл во внутреннем хранилище.
|  downloadLinkstring
Ссылка на скачивание.
|  ownerIdstring
Идентификатор владельца.


Подтверждение о прочтении сообщения

[
    "chatMessageReadEmit",
    {
        "messageId": "23280e7d-8d2f-409b-9480-82c805fcbb95"
    }
]

Описание параметров события chatMessageReadEmit

Поле

Тип

Обязательно

Описание

messageId
stringДаИдентификатор сообщения


ОПЕРАТОРЫ

Назначение оператора после бота (первичное назначение)

[
    "operatorChangedEmit",
    {
        "operatorId": "494",
        "operatorName": "III Operator",
        "avatar": null,
        "previousOperatorId": "4f8151ed-8e7a-4a12-a6a5-c94f99c58019",
        "previousOperatorName": "МетроБот",
        "previousOperatorAvatar": null
    }
]


Назначение другого оператора (смена операторов)

[
    "operatorChangedEmit",
    {
        "operatorId": "472",
        "operatorName": "II Dev",
        "avatar": null,
        "previousOperatorId": "389",
        "previousOperatorName": "Первый Оператор V",
        "previousOperatorAvatar": {
            "id": "ed661c07-2d50-4b1f-b2c8-32f09a83065e",
            "isPrivate": false,
            "createdAt": "2021-02-05T12:58:33+00:00",
            "contentType": "image/jpeg",
            "name": "мяч.jpg",
            "baseName": "мяч",
            "extension": "jpg",
            "suggestedExtension": "jpg",
            "path": "",
            "size": 310723,
            "url": "https://minio.twin24.ai/twin-iam-dev/public/2021-02-05/ed661c07-2d50-4b1f-b2c8-32f09a83065e?response-content-type=image%2Fjpeg&response-content-disposition=inline%3B%20filename%3Dmyac.jpg%3B%20filename%2A%3Dutf-8%27%27%25D0%25BC%25D1%258F%25D1%2587.jpg",
            "downloadLink": "https://minio.twin24.ai/twin-iam-dev/public/2021-02-05/ed661c07-2d50-4b1f-b2c8-32f09a83065e?response-content-type=image%2Fjpeg&response-content-disposition=attachment%3B%20filename%3Dmyac.jpg%3B%20filename%2A%3Dutf-8%27%27%25D0%25BC%25D1%258F%25D1%2587.jpg&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=minio%2F20210310%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20210310T090557Z&X-Amz-SignedHeaders=host&X-Amz-Expires=604799&X-Amz-Signature=6156df5e15d5ab535fdcf80204de440a3cfb8b8fa4d8e3a92b93cc6796f539a3",
            "ownerId": null
        }
    }
]

Описание параметров события chatMessageCreatedEmit

Поле

Тип

Обязательно

Описание

id
stringДаИдентификатор сообщения.
operatorId
string
Идентификатор оператора.
operatorName
string
Имя оператора.
avatar
string
Аватар оператора.
previousOperatorId
string
Идентификатор предыдущего оператора.
previousOperatorName
string
Имя предыдущего оператора.
previousOperatorAvatar
string
Аватар предыдущего оператора.
|  idstring
Идентификатор файла.
|  isPrivateboolean
Отметка о приватности.
|  createdAtstring
Отметка времени о создании.
|  contentTypestring
Content type. Тип контента (тип передачи файла).
|  namestring
Полное имя файла (с расширением).
|  baseNamestring
Предлагаемое расширение файла.
|  extensionstring
Расширение файла.
|  suggestedExtensionstring
Предлагаемое расширение файла.
|  pathstring
Путь (расположение) во внутреннем хранилище.
|  sizestring
Размер файла в байтах.
|  urlstring
Ссылка на файл во внутреннем хранилище.


Статус оператора

[
    "operatorStatusChangedEmit",
    {
        "operatorId": "389",
        "previousStatus": "ACTIVE",
        "currentStatus": "PAUSED"
    }
]

Описание параметров события operatorStatusChangedEmit

Поле

Тип

Обязательно

Описание

operatorId
stringДаИдентификатор оператора
previousStatus
stringДаПредыдущий статус оператора
currentStatus
stringДаТекущий статус оператора


Выход оператора из системы

[
    "operatorLoggedOutEmit",
    {
        "operatorId": "389"
    }
]

Описание параметров события operatorStatusChangedEmit

Поле

Тип

Обязательно

Описание

operatorId
stringДаИдентификатор оператора


Подключение чат-сессии к socket.io

Создание клиентского экземпляра

import socketio

# Создаем экземпляр клиента socketio
sio = socketio.Client()


Определение обработчиков событий

Регистрируем функцию обработчика событий с помощью декоратора socketio.Client.on() указывая имя события. Также после отправки сообщения, инициируем событие messageReceived - подтверждение прочтения сообщения.

# Обработка события получения сообщения.
@sio.on("chatMessageCreatedEmit")
def msg_handler(data: dict):
    """
    Обработка сообщений и общение с эхо-ботом.
    :param data: Массив данных с параметрами сообщения.
    """
    # Вывод в терминал
    print(f"{data['authorType']}: {data['body']}")

    # Подтверждение о прочтении сообщения
    response = {"action": "chatMessageCreated", "data": {"id": data["id"]}}
    sio.emit('messageReceived', response)

    # Завершение диалога после введения ключевого слова в терминале
    if data['type'] == 'TERMINAL':
        globals()['FLAG'] = False


Подключаемся к серверу используя TLS/SSL подключение.
URL для подключения к серверу:
https://tcl.twin24.ai/operator/socket.io/?key={session_id}

Параметр session_id предварительно был получен при вызове функции start_chat_session

    sio.connect(url=f'https://tcl.twin24.ai/operator/socket.io/?key={chat_session_id}',
                transports=['polling', 'websocket'], 
                socketio_path='operator/socket.io')

После этого шага, всё готово для того чтобы "слушать" происходящие события в указанной чат-сессии. Можно отправлять сообщения и в случае завершения диалога по ключевому слову закрывать соединение.


Ниже представлена кодовая база всей программы:

# Импортируем все необходимые библиотеки
import json
from datetime import datetime
from time import sleep

import requests
import socketio

# Указываем идентификатор чата (получить идентификатор необходимо в личном кабинете)
# Важно: необходимо указывать свои параметры идентификатора чата! Это пример!
CHAT_ID = "3eb5cf6d-4d20-41c2-b886-f60374d11d19"

# Создаем экземпляр клиента socketio
sio = socketio.Client()


FLAG = True

# Определяем функции, необходимые для работы программы
def start_chat_session(chat_id: str, name: str = "integration_example") -> dict:
    """
    Создаёт чат-сессию и возвращает коллекцию данных о ней.
    :param chat_id: Идентификатор чата.
    :param name: Имя чат-сессии. Задается для облегчения поиска чат-сессии в личном кабинете TWIN.
    :return: Коллекция данных о созданной чат-сессии.
    """
    url = f"https://tcl.twin24.ai/api/chats/v1/chats/{chat_id}/sessions?x_widget=1"
    headers = {"Content-Type": "application/json"}
    payload = json.dumps({"name": name})
    response = requests.request("POST", url, headers=headers, data=payload)

    return response.json()


def send_msg_to_chat_session(session_id: str, message_text: str) -> dict:
    """
    Отправляет сообщение.
    :param session_id: Идентификатор чат-сессии.
    :param message_text: Текст сообщения.
    :return: Коллекция данных об отправленном сообщении.
    """
    url = f"https://chats-api.twin24.ai/api/v1/sessions/{session_id}/messages"
    headers = {'Content-Type': 'application/json'}
    payload = json.dumps({"body": message_text, "attachments": []})
    response = requests.request("POST", url, headers=headers, data=payload)

    return response.json()


@sio.event
def connect():
    pass


@sio.event
def connect_error(data):
    print(f"The connection failed!\n{data}")


@sio.event
def disconnect():
    pass


# Обработка события получения сообщения.
@sio.on("chatMessageCreatedEmit")
def msg_handler(data: dict):
    """
    Обработка сообщений и общение с эхо-ботом.
    :param data: Массив данных с параметрами сообщения.
    """
    # Вывод в терминал
    print(f"{data['authorType']}: {data['body']}")

    # Подтверждение о прочтении сообщения
    response = {"action": "chatMessageCreated", "data": {"id": data["id"]}}
    sio.emit('messageReceived', response)

    # Завершение диалога после введения ключевого слова в терминале
    if data['type'] == 'TERMINAL':
        globals()['FLAG'] = False


if __name__ == '__main__':
    # Отметка времени
    test_time = datetime.now().strftime("%d.%m.%Y_%H.%M.%S")
    # Старт чат-сессии. Получение результатов
    response_data = start_chat_session(CHAT_ID, f'Test: {test_time}')
    # Получаем ID чат-сессии
    chat_session_id = response_data['id']

    # Блок диалога с эхо-ботом
    msgs = response_data['messages']
    for msg in msgs:
        print(f"{msg['authorType']}: {msg['body']}")
    sio.connect(url=f'https://tcl.twin24.ai/operator/socket.io/?key={chat_session_id}',
                transports=['polling', 'websocket'],
                socketio_path='operator/socket.io')
    while FLAG:
        send_msg_to_chat_session(chat_session_id, input('USER: '))
        sleep(2)
    sio.disconnect()



Это минимальная программа, отображающая все шаги, необходимые для интеграции чат-платформы TWIN в кодовую базу приложения клиента.