|
| 1 | +# Потокова передача даних { #stream-data } |
| 2 | + |
| 3 | +Якщо ви хочете передавати потоком дані, які можна структурувати як JSON, див. [Потокова передача JSON Lines](../tutorial/stream-json-lines.md). |
| 4 | + |
| 5 | +Але якщо ви хочете передавати потоком чисті бінарні дані або строки, ось як це зробити. |
| 6 | + |
| 7 | +/// info | Інформація |
| 8 | + |
| 9 | +Додано у FastAPI 0.134.0. |
| 10 | + |
| 11 | +/// |
| 12 | + |
| 13 | +## Варіанти використання { #use-cases } |
| 14 | + |
| 15 | +Це можна використовувати, якщо ви хочете передавати потоком чисті строки, наприклад безпосередньо з виводу сервісу AI LLM. |
| 16 | + |
| 17 | +Також це можна використати для потокової передачі великих бінарних файлів, коли ви надсилаєте кожний фрагмент даних під час читання, без потреби завантажувати все в пам'ять одразу. |
| 18 | + |
| 19 | +Так само можна стрімити відео чи аудіо; їх навіть можна генерувати під час обробки та надсилання. |
| 20 | + |
| 21 | +## `StreamingResponse` з `yield` { #a-streamingresponse-with-yield } |
| 22 | + |
| 23 | +Якщо ви оголосите `response_class=StreamingResponse` у вашій функції операції шляху, ви можете використовувати `yield`, щоб послідовно надсилати кожний фрагмент даних. |
| 24 | + |
| 25 | +{* ../../docs_src/stream_data/tutorial001_py310.py ln[1:23] hl[20,23] *} |
| 26 | + |
| 27 | +FastAPI передаватиме кожний фрагмент даних до `StreamingResponse` як є; він не намагатиметься перетворити його на JSON чи щось подібне. |
| 28 | + |
| 29 | +### Не-async функції операції шляху { #non-async-path-operation-functions } |
| 30 | + |
| 31 | +Можна також використовувати звичайні функції `def` (без `async`) і так само застосовувати `yield`. |
| 32 | + |
| 33 | +{* ../../docs_src/stream_data/tutorial001_py310.py ln[26:29] hl[27] *} |
| 34 | + |
| 35 | +### Без анотації { #no-annotation } |
| 36 | + |
| 37 | +Для потокової передачі бінарних даних немає потреби оголошувати анотацію типу, що повертається. |
| 38 | + |
| 39 | +Оскільки FastAPI не намагатиметься перетворювати дані на JSON за допомогою Pydantic чи серіалізувати їх іншим чином, у цьому випадку анотація типу потрібна лише для вашого редактора та інструментів; FastAPI її не використовуватиме. |
| 40 | + |
| 41 | +{* ../../docs_src/stream_data/tutorial001_py310.py ln[32:35] hl[33] *} |
| 42 | + |
| 43 | +Це також означає, що з `StreamingResponse` у вас є свобода і відповідальність формувати та кодувати байти даних саме так, як їх потрібно надіслати, незалежно від анотацій типів. 🤓 |
| 44 | + |
| 45 | +### Потік байтів { #stream-bytes } |
| 46 | + |
| 47 | +Один з основних сценаріїв - передавати потоком `bytes` замість строк; це, звісно, підтримується. |
| 48 | + |
| 49 | +{* ../../docs_src/stream_data/tutorial001_py310.py ln[44:47] hl[47] *} |
| 50 | + |
| 51 | +## Користувацький `PNGStreamingResponse` { #a-custom-pngstreamingresponse } |
| 52 | + |
| 53 | +У наведених вище прикладах байти даних передавалися потоком, але у відповіді не було заголовка `Content-Type`, тому клієнт не знав, який тип даних він отримує. |
| 54 | + |
| 55 | +Можна створити власний підклас `StreamingResponse`, який встановлює заголовок `Content-Type` відповідно до типу даних, що ви стрімите. |
| 56 | + |
| 57 | +Наприклад, можна створити `PNGStreamingResponse`, який встановлює заголовок `Content-Type` у `image/png` за допомогою атрибута `media_type`: |
| 58 | + |
| 59 | +{* ../../docs_src/stream_data/tutorial002_py310.py ln[6,19:20] hl[20] *} |
| 60 | + |
| 61 | +Потім ви можете використати цей новий клас у `response_class=PNGStreamingResponse` у вашій функції операції шляху: |
| 62 | + |
| 63 | +{* ../../docs_src/stream_data/tutorial002_py310.py ln[23:27] hl[23] *} |
| 64 | + |
| 65 | +### Симулювати файл { #simulate-a-file } |
| 66 | + |
| 67 | +У цьому прикладі ми імітуємо файл за допомогою `io.BytesIO` - це об'єкт на кшталт файлу, який існує лише в пам'яті, але надає той самий інтерфейс. |
| 68 | + |
| 69 | +Наприклад, ми можемо ітеруватися по ньому, щоб зчитати вміст, так само як і з файлом. |
| 70 | + |
| 71 | +{* ../../docs_src/stream_data/tutorial002_py310.py ln[1:27] hl[3,12:13,25] *} |
| 72 | + |
| 73 | +/// note | Технічні деталі |
| 74 | + |
| 75 | +Інші дві змінні, `image_base64` та `binary_image`, - це зображення, закодоване в Base64, яке потім перетворюється на байти, щоб передати його в `io.BytesIO`. |
| 76 | + |
| 77 | +Лише для того, щоб усе містилося в одному файлі для цього прикладу, і ви могли скопіювати його та запустити як є. 🥚 |
| 78 | + |
| 79 | +/// |
| 80 | + |
| 81 | +Використовуючи блок `with`, ми гарантуємо, що об'єкт, подібний до файлу, буде закрито після завершення генераторної функції (функції з `yield`). Тобто після завершення надсилання відповіді. |
| 82 | + |
| 83 | +У цьому конкретному прикладі це не так важливо, адже це фальшивий файл у пам'яті (з `io.BytesIO`), але для справжнього файлу важливо переконатися, що файл закрито після завершення роботи з ним. |
| 84 | + |
| 85 | +### Файли та async { #files-and-async } |
| 86 | + |
| 87 | +У більшості випадків об'єкти, подібні до файлів, за замовчуванням несумісні з `async` та `await`. |
| 88 | + |
| 89 | +Наприклад, у них немає `await file.read()` або `async for chunk in file`. |
| 90 | + |
| 91 | +І часто їх читання є блокувальною операцією (що може блокувати цикл подій), адже дані зчитуються з диска або мережі. |
| 92 | + |
| 93 | +/// info | Інформація |
| 94 | + |
| 95 | +Наведений вище приклад - виняток, адже об'єкт `io.BytesIO` вже в пам'яті, тож читання нічого не блокує. |
| 96 | + |
| 97 | +Але в багатьох випадках читання файлу або схожого на файл об'єкта блокує виконання. |
| 98 | + |
| 99 | +/// |
| 100 | + |
| 101 | +Щоб уникнути блокування циклу подій, просто оголосіть функцію операції шляху зі звичайним `def` замість `async def`. Тоді FastAPI виконуватиме її в працівнику пулу потоків, щоб не блокувати головний цикл. |
| 102 | + |
| 103 | +{* ../../docs_src/stream_data/tutorial002_py310.py ln[30:34] hl[31] *} |
| 104 | + |
| 105 | +/// tip | Порада |
| 106 | + |
| 107 | +Якщо вам потрібно викликати блокувальний код усередині async-функції або async-функцію зсередини блокувальної функції, ви можете скористатися [Asyncer](https://asyncer.tiangolo.com) - спорідненою бібліотекою до FastAPI. |
| 108 | + |
| 109 | +/// |
| 110 | + |
| 111 | +### `yield from` { #yield-from } |
| 112 | + |
| 113 | +Коли ви ітеруєтеся по чомусь, наприклад по об'єкту, подібному до файлу, і робите `yield` для кожного елемента, можна також використати `yield from`, щоб віддавати кожен елемент напряму і пропустити цикл `for`. |
| 114 | + |
| 115 | +Це не специфічно для FastAPI, це просто Python, але корисний трюк. 😎 |
| 116 | + |
| 117 | +{* ../../docs_src/stream_data/tutorial002_py310.py ln[37:40] hl[40] *} |
0 commit comments