Потоковые API

Потоковый API держит открытое соединение и шлёт данные по мере их появления — приложение показывает обновления сразу, без повторных запросов.

REST так не умеет: там каждый ответ приходит на отдельный запрос. Потоковые API нужны там, где данные меняются постоянно: счёт матча, котировки, чат, уведомления.

Чаще всего для этого используют Server Sent Events (SSE), реже — WebSocket.

Чем потоковый API отличается от REST

  • REST API:

    • Запрос — ответ: клиент спрашивает, сервер отвечает.
    • Соединение: каждая пара «запрос — ответ» самостоятельна, после ответа соединение закрывается.
    • Когда подходит: данные меняются нечасто, мгновенные обновления не нужны.
    • Пример ответа:
    {  
      "event": "match_score",
      "data": {
        "team1": "Red Dragons",
        "team2": "Silver Sharks",
        "score": "2-1"
      }
    }
  • Потоковый API (Server Sent Events):

    • Непрерывный поток: сервер держит соединение и шлёт данные, как только они появляются.
    • Соединение: остаётся открытым, клиент ничего не запрашивает повторно.
    • Когда подходит: живые обновления — счёт матча, уведомления, чат.
    • Пример ответа:
    event: match_score
    data: {"team1": "Red Dragons", "team2": "Silver Sharks", "score": "2-1"}
    
    event: match_score
    data: {"team1": "Red Dragons", "team2": "Silver Sharks", "score": "3-1"}
    
    event: match_score
    data: {"team1": "Red Dragons", "team2": "Silver Sharks", "score": "3-2"}

Пример: сводка отзывов от ИИ

Соберём экран, где ИИ разбирает отзывы о товаре, а текст сводки появляется на глазах — по мере генерации.

Вот что получится:

Работа делится на пять шагов:

  1. Собрать интерфейс
  2. Создать вызов API
  3. Завести переменные состояния
  4. Вызвать API и разобрать ответ
  5. Достать данные для диаграммы

1. Интерфейс

На экране — средняя оценка, число отзывов и подробная сводка: плюсы, минусы и распределение настроений. Понадобятся два виджета:

  • Text — сама сводка и списки плюсов и минусов.
  • Chart (столбчатая диаграмма) — распределение положительных, нейтральных и отрицательных отзывов.

streaming-api-example-demo.png

2. Вызов API

Возьмём Chat Completion API от OpenAI. Сначала создайте и протестируйте вызов в проекте.

Затем откройте Advanced Settings и включите Process Streaming Response.

Вот как это делается:

3. Переменные состояния

Понадобятся две переменные:

  1. summary — полный текст сводки: общее настроение, ключевые мысли покупателей, плюсы и минусы. Начальное значение — пустая строка.
  2. sentimentValues — распределение настроений: список чисел double с количеством положительных, нейтральных и отрицательных отзывов. Эти значения пойдут в столбчатую диаграмму. Начальное значение — три нуля. streaming-page-state.png

4. Вызов и разбор ответа

Вызывается потоковый API так же, как обычный, а вот данные приходят иначе — не в переменную вывода, а через три действия:

  • onMessage — срабатывает на каждую новую порцию данных; здесь обновляют интерфейс.
  • onError — ошибка соединения; здесь показывают сообщение или пробуют переподключиться.
  • onClose — соединение закрыто; здесь убирают за собой и сообщают пользователю, что поток закончился.

Тело очередного сообщения доступно в OnMessage > Set Variable > Action Parameters > OnMessageInput, а разбирается оно опциями потокового сообщения.

В примере используется Server Sent Event Stream Data JSON и путь $['choices'][0]['delta']['content'].

Порядок действий:

5. Данные для диаграммы

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

совет
  • После сохранения sentimentValues те же цифры стоит убрать из текста сводки, чтобы они не дублировались.
  • Так же вытаскивают плюсы и минусы и показывают их отдельно.

Поля потокового сообщения

Событие SSE состоит из нескольких частей, и FlutterFlow даёт доступ к каждой.

Server Sent Event Data JSON (тип JSON)

Результат разбора поля data как JSON. Например:

event: chat

data: {"response": "hello", "version": 7}

id: 2

Значение будет таким:

{
  "response": "hello",
  "version": 7
}

Если данные не в формате JSON, значение будет пустым:

event: ping

data: Server time is 2024-06-28T11:52:56+00:00

id: 2

Здесь Server Sent Event Data JSON равно null.

Server Sent Event Data Text (тип String)

Текст поля data как есть. Если полей data несколько, они склеиваются через перевод строки. Для события:

event: ping

data: Server time is 2024-06-28T11:52:56+00:00

id: 2

значение будет Server time is 2024-06-28T11:52:56+00:00.

А для события:

event: journalEntry

data: Today I went to the park.

data: For Lunch I had a sandwich.

id: 3

значение будет таким:

Today I went to the park.

For Lunch I had a sandwich.

Server Sent Event Name (тип String)

Текст поля event. Например:

event: ping

data: Server time is 2024-06-28T11:52:56+00:00

id: 2

Значение — ping.

Server Sent Event ID (тип Integer)

Текст поля id — по нему отслеживают, что сервер прислал последним. Например:

event: ping

data: Server time is 2024-06-28T11:52:56+00:00

id: 2

Значение — 2.

Server Sent Event Retry (тип String?)

Поле retry: через сколько клиенту стоит попытаться переподключиться.

Message Text (тип String)

Сообщение SSE целиком, со всеми полями и переводами строк:

event: ping

data: Server time is 2024-06-28T11:52:56+00:00

id: 2

Частые вопросы

Почему приходит null?

Значение null в поле Server Sent Event Data JSON означает, что данные пришли не в формате JSON.

Например, вот такие данные разобрать как JSON нельзя:

event: ping
data: Server time is 2024-06-28T11:52:56+00:00
id: 2

Обойти это можно [встроенным выражением](../../functions/utility-functions.md#inline-function-code-expressions):

responseData ?? ''

Если responseData равно null, вернётся пустая строка.

перевод официальной документации FlutterFlow

обновлено

ESC