Горшочек варит
@gorshochekvarit·Разработчик
AI-саммари
Проектирует в спеках, имплементацию отдаёт агентам — и честно признаётся, что без AI не взялся бы за текущий проект: оценки слишком нереалистичны, а с агентами «сейчас за 5 минут соберу» превращается в недели и космический корабль вместо простой идеи. Прогоняет по пять раундов на каждую спеку, вычитывая по часу — беглый просмотр пропускает фатальные ошибки. Ловит удовольствие, когда Claude хвалит проработанность без запроса. В своём прогнозе держится в стороне от «AI всех заменит» — наблюдает, как вчерашние скептики начинают «бегать» и всем вокруг показывать насколько это круто, и замечает консенсус: не использовать AI и оставаться востребованным будет сложно. Пишет спеки и работает с агентами на английском, чтобы избежать кривого LLM-сленга. GPT-4o сгенерировал дедлок в задаче с веб-стримами — переключился на o3-mini-high и получил рабочий код. Скриптит прямо в DOM-консоли браузера; перевёл 68 Кб текста через LLM за доллар и пятнадцать минут вместо $150 и двух недель.
Не люблю заниматься предсказаниями. Но прогнозы вокруг AI стали настолько навязчивыми и при этом, как мне видится, поверхностными, что я решил написать свой. И он лежит немного в стороне от популярных вроде «AI всех заменит» или «весь код скоро будет писать AI».
Немного о том, что я наблюдаю в своём «пузыре».
— Всё больше скептиков и критиков AI, которые ещё вчера говорили, что это баловство и «не трушно», начинают активно им пользоваться. Причём часто делают вид, будто никогда и не критиковали. А иногда начинают «бегать» и всем вокруг показывать насколько это круто. Есть те, кто «бегал» и раньше — теперь они бегают ещё быстрее. Хотя большинство и так это видит: нехватки «бегающих» никогда не было, они вещают из каждого утюга. Есть и те, кто посередине — потихоньку въезжают или делают действительно интересные вещи с AI.
— Постепенно складывается консенсус: использование AI действительно повышает продуктивность. Спорящих с этим становится всё меньше. Более того, спорить с тем, что не использовать AI и оставаться востребованным в ближайшем будущем будет сложно, уже практически невозможно.
— Модели и инфраструктура вокруг них за последний год заметно выросли. Рост эффективности я впервые отчётливо заметил ещё в конце прошлого лета — с тех пор всё стало ещё полезнее и лучше.
— Конкретную модель или сервис имеет смысл менять только если вы энтузиаст, исследователь или очень нетерпеливы. Все у всех учатся и быстро перенимают. Конкуренция сейчас высока как никогда, и всё лучшее так или иначе доезжает до всех — вопрос времени.
— Всё это создаёт ожидание, что инженеры скоро станут не нужны. По крайней мере в том виде, в котором мир знает их сегодня. Модели и агенты уже пишут код на уровне выше среднего разработчика — и делают это быстрее. Поэтому довольно устойчиво звучит мысль, что скоро весь код будет писать AI. Но к этому я еще вернусь ниже.
— При этом никто на самом деле не понимает, куда всё движется. Есть только гипотезы. Сейчас слишком много новых эффектов и последствий. После серии волн увольнений наступила пауза: бизнес, похоже, тоже пытается понять, что происходит. Уволить всех инженеров не проблема. Вопрос — что делать дальше. Кто будет решать проблемы, если они возникнут? Как понять, что они вообще возникли? То, что инженеры «не пишут код», никак не снимает вопросы: кто отвечает, кто чинит, кто обеспечивает SLA и т.д.
Это очень грубое описание того, что я сейчас наблюдаю. Во всей этой истории, как мне кажется, упускают главное: инженеры не пишут код — инженеры решают проблемы. Не все, конечно. Некоторые ничего не делают, а некоторые эти самые проблемы и создают. Но если исходить из основ, то она именно в этом.
Проблема в том, что большинство прогнозов сегодня строится вокруг скорости генерации кода. А не вокруг реального решения проблем, для которых этот код вообще существует.
Я попробовал посмотреть на происходящее именно с этой точки зрения и написал небольшую статью с прогнозом на ближайший год. Через год посмотрим, насколько точно попал.
https://medium.com/@rdvornov/ai-and-the-coming-correction-e93bb31b9476
Я стараюсь не "общаться" с LLM на русском, потому что проще описывать и читать технические моменты на английском, без путаницы в терминах, без кривых объяснений и проблем перевода. А еще LLM часто выдают странный сленг, местами переходящий в кринж. Уж не знаю на каких текстах обучают модели, что они выдают такое.
Но иногда все таки вопрошаю на русском, когда надиктовываю по быстрому на ходу или нужно описать что-то очень малопонятное, для чего сложно подобрать слова на любом языке. И они выдают интересные термины и формулировки. На русском это особенно цепляет, потому профессиональные тексты читаю практически только на английском (если исключить "блоги"), и тут получаешь не англицизмы, а принятые в академической литературе конструкции, которые редко где встретишь, если не читать научные работы из прошлого века.
Так вот, моё слово дня – "низведение" (lowering, подходит и для desugaring). Встречал его когда то в институте, в математике, но тогда это был еще один скучный термин. Сейчас же, в контексте моих задач, оно заиграло новыми красками. Настолько понравилось, что не смог не поделиться :)
Написал 7 спек для одного нового проекта со вчерашнего вечера. Это вот такие документы, 5-18кб текста, где расписаны все детали. Планировал расписать лишь 2 спеки, а остальные 5 появились уже по ходу. 3 из них – это совсем новые идеи, о которых даже не думал пока не начал работать над документами, и пока в контексте – проработал и расписал. Еще одна – решил заодно описать идею, над которой не планировал работать, из разряда nice to have, она не очень сложная в реализации, но провалился в проектирование на пару часов. И еще одна скорее систематизация, но тоже оказалось полезно.
И вот так одно за другим тянется. Стоит лишь войти во вкус. А самое удивительное, насколько хорошо получилось проработать, еще не имплементировано – а мне уже нравится как все работает. Хотя насколько хорошо еще предстоит выяснить :)
Но сейчас одназначно можно сказать, что получилось весьма быстро проработать весьма сложные штуки. Без ИИ было бы в разы дольше. Хотя я бы и не занимался этим проектом без ИИ – не потому что не справился бы, а потому что даже самые оптимистичные оценки по временным затратам выглядят слишком нереалистичными. А с ИИ всегда кажется, сейчас за 5 минут соберу, чего там. А потом "Few moments later..." пролетели дни, недели... и у тебя из простой идеи уже космический корабль получается :)
А еще приятно получать комплименты от агентов про проработанность после часов работы над спеками, хотя этого не просишь. Более проработанные спеки = лучше анализ для планирования и имплементация. Ну и больше комплиментарных комментариев 🙂
Вот я специально скопировал с моим небрежным промптом, чтобы показать что я не просил оценки спек и самих фич (возможно "cool features" повлияло, но не думаю что сильно). От агента лишь требовалось, чтобы новые спеки были учтены в планировании предстоящих работ, и только – то есть расширение контекста и горизонта планирования. А он (Claude 4.5) вон чего.
То что наш образ (опыт) работы с приходом ИИ поменяется – это правда.
Я все больше занимаюсь тем, что проектирую и пишу спеки/дизайн документы, а имплементацию отдаю агентам. Конечно, я делаю ревью, инструктию и направляю, заставляю переделывать, провожу интервенции в процесс написания кода, через рефакторинг руками. И при всех недостатках текущих моделей/агентов, и издержках с этим связанных – я замечаю, такой подход к процессу более эффективный и быстрый. Может казаться, что самому руками быстрее, и в каких то задачах действительно так. Но в основном, наоборот руками медленее – хотя может восприниматься по другому. Но чтобы получалось действительно эффективно, нужно учиться и нарабатывать опыт взаимодействия с ИИ.
Раньше я кидался реализовывать самостоятельно, экспериментируя и подбирая решения по ходу. Теперь описываю сырую идею (идеи) ИИ и затем в несколько раудов мы доводим до ума, и финализируем в виде доки (дизайн документ, спека, вижн или подобное). Раунды достаточно длинные – пока вычитаешь в деталях ответ модели, выпишешь замечания или опишешь новые мысли, подумаешь глубже, проходит от нескольких минут до часа и больше. Получаешь новый ответ – снова вычитываешь, и так пока ошибок, нестыковок и пропущенных моментов не останется. Раундов обычно около 5, иногда значительно больше – зависит от масштаба и сложности.
Просто копипастить результат, прочитав по диагонали, потому "выглядит похоже на правду" – не лучшая идея. Потому практически всегда остаются недаработанные моменты, искажения идеи, нестыковки, да и нередко просто фатальные ошибки, которые при беглом просмотре не распознаешь. Если такое отдаешь в работу агенту (и не агенту), то в итоге придется разгребать последствия, когда уже дорого менять и усилия могут быть выше чем перепроектировать и переимлементировать с нуля. Причем не всегда получается починить неработающее (например, ошибочный подход или решение), все равно придется переделывать с нуля. В любом случае получается большой штраф в виде потерянного времени. И если не вкладываться в проектирование, то можно наступать на те же грабли не раз, и не два.
Поэтому лучше сосредоточиться и вложиться на этапе проектирования, потратить больше времени на вычитку и проработку деталей. Чем более проработанная спека/дизайн документ – тем выше шансы на успех, агенты с таким справляются на порядок быстрее и лучше, меньше отклонения от цели и затыков в процессе исполнения. Получается как в советском мультфильме "Крылья, ноги, хвост": "лучше день потерять, потом за час долететь".
Кроме того, остаются артифакты в виде документов в хорошем состоянии, которые в последствии можно переработать в документацию. Из таких документов получается более проработанная документация – меньше править. Документация, или сами документы, хороший материал для будущих фич, и даже для задач на других проектах в качестве референса. И для тест плана такие документ безценный материал, если проработы нюасы, примеры и крайние случаи. В общем сплошные плюсы.
Но нужно учитывать, что работать с документацией и ИИ – это тоже особый навык, который нужно нарабатывать. Много букв и умные слова по тексту не равно полезный документ.
Jora Making Me Crazy
Еще одна статья, в этот раз не моя, автора не знаю. Наткнулся на нее несколько недель назад, просматривая рефералы на одном из репозиториев. Сначала подумал, что это очередной авто-блог генерируемый AI. Но оказалось, что очень даже человеком написаная статья, но отрефайненная через AI.
Почему я уверен что написана человеком? Во-первых, тема, мягко говоря, не самая хайповая 😉 Во вторых, описывается не "фасад", то есть суммаризация первого, что попадается по теме – а фичи, которые я намеренно не офишировал, но и не прятал и их можно найти, если хотя бы прочитать ридми проектов. В третьих, явно на каком-то опыте написано, и примеры, и скриншоты, и вывод из консоли — не вызывает сомнения что это что-то персональное.
Отдельно порадовало, что автор откопал малоизвестный jora-cli, который я значимо обновил в феврале (и не написал об этом). Так вот, если вам, например, нужно убрать из JSON форматирование (или добавить), или сделать выборку (используя jora, у которого уже неплохая документация), и все это невзирая на размер – то jora-cli ваш друг.
Но автор нашел еще, что jora-cli поддерживает экспериментальный бинарный энкодинг `jsonxl` (который поддерживает и Discovery.js, и проекты на нем), как на вход так и на выход, и можно значительно уменьшить размер JSON файлов (и они еще хорошо gzip'ятся!). У автора разница в примере меньше 2,5 раз, но для .cpuprofile или stats.json размер обычно уменьшается в десятки раз. И разница особо чувствуется для данных в десятки и сотни мегабайт JSON. Попробуйте на ваших данных, интересно какие у вас будут результаты.
В общем приятно читать, когда кто-то делится своим опытом использования штук, которые делаешь. Рекомендую статью, хотя бы пролистать.
Я экспериментировал с Playground. В нем тоже нельзя вставлять супер большие сообщения. Но есть отдельная секция Prompt messages, куда можно добавить без проблем. Впрочем, результаты оказались посредственными, модели теряются когда нужно сделать большую сложную выборку из большого текста. И к тому же очень медленно работают, когда контекст под завязку (хотя не факт, что проблема в самих моделях). Я думаю, если попросить найти какой-то факт по тексту, то может что-то и выйдет. А вот если нужно вычленить несколько десятков килобайт текста, который идет не подряд — то это уже невыполнимая задача. В итоге я вручную выбрал посты где затрагивалась заданная тема. Вышло 68Kb текста или 16k токенов.
С меньшим размером текста модели стали работать заметно быстрее. Однако результат получался далеко даже от приемлемого. Я просил генерировать на английском, переводя на лету с русского. В какой-то момент подумал, что это будет усложнением для LLM и решил перевести материал один раз на английский и потом работать с ним.
68Kb кажется небольшим объемом. Но это субъективно. Чтобы оценить такой объем - стоит начать переводить. Или хотя бы вдумчиво прочитать. Так вот с задачами перевода и адаптации текста LLM справляют отлично. Я попросил перевести и сохранить авторский стиль. И результат получился весьма качественный, насколько я смог оценить читая по диагонали. Заняло это все около 5 минут или больше, но точно не больше 15 минут. Стоило это меньше доллара. И это действительно поражает (до сих пор).
> Помню, как мой коллега заказывал перевод примерно такого объема лет 7 назад, он тогда отдал не менее 150 долларов (не помню, может и в 2-3 раза больше), ему переведили 2 недели и качество перевода было весьма посредственное, так как переводчик не очень знал профессиональную лексику.
С материалом на английском, модели стали еще шустрее работать и качество ответов повысилось. Осталось получить статью.
Первое, что нужно было сделать — это сдампить все посты из канала. Думаете это делается в пару кликов? Тоже так думал. Но обошел несколько раз интерфейсную часть телеграм и не нашел такой возможности. Погуглил, нашел инструкции — все говорят, что это просто, показывают кнопки, иду в телеграм — а этих кнопок нет. Видимо такую возможность выпилили. Печаль.
Подумал — не беда, ChatGPT же теперь умеет ходить в сеть и делать поиск - попробую напрямую из ChatGPT запросить. Тоже не выходит: телеграм закрывается от ботов, хоть через поиск, хоть по прямой ссылке — ChatGPT не может получить содержимое телеграм каналов.
Что ж, пришлось действовать старым "дедовским" способом. Открыл веб-версию канала и пролистал всю ленту, чтобы загрузились все сообщения (там используется подгрузка при скроле). Далее открыл консоль и буквально "на коленке" написал скрипт, который через DOM выбрает все блоки постов, выбрает нужные данные из них, отчищает текст сообщений от лишней разметки и превращает его в markdown. Наконец-то пригодилось знание DOM для чего-то полезного 😏 Код вышел грязным и в лоб – но свою работу делает.
В итоге вышло ~450Kb текста с атрибутами, без изображений и видео. В Word'е в дефолтных настройках (Calibri 12pt) это 166 страниц (58 тысяч слов). Этот текст превращается в ~118 тысяч токенов (OpenAI Tokenizer), что умещается в текущий стандарт для размера окна контекста в 128k токенов и еше немного остается.
Несмотря на размер контекста модели (для GPT-4o — 128k, GPT-4.1 — 1M, GPT-o4-mini — 200k), в интерфейсе ChatGPT нельзя отправлять сообщения более определенной длины. Точных размеров не выяснял, но это где-то около 100Kb (символов, не токенов). То есть скормить текст такого размера как у меня (450Kb) целиком в чат не выйдет, или по крайней мере не одним сообщением.
Хорошо, у нас еще есть возможность прикреплять файлы. Пробуем, но это работает совсем не так как ожидается. Целиком файл не обрабатывется, AI модель так или иначе делает выборки из файла (фрагмент или фрагменты) и работает с выбранным. Для выборок обычно модель пишет Python код. Что попадет в выборку и по какому принципу, тот еще вопрос. Вернее как модель решит. Например, может взять первые несколько килобайт (для чего напишет скрипт), или решит искать по ключевым словам (то есть напишет код, который это делает), при этом поиск строгий и набор слов (количество и состав) — это как повезет. Надежность такого подхода сомнительная. В целом, работа с прикрепленным файлом носит очень приблизительный характер. Может хорошо работать для файлов с данными, типа CSV, так как это лучше поддается детерминированой программной обработке. Но вот для текста (markdown), где большая вариативность — работает так себе. Вероятность успеха (success rate) не нулевая, но чем больше текст тем больше падают шансы.
В общем, для полноценной работы с текстом (например, чтобы не потерялись какие либо факты или детали) весь он должен быть в контекстном окне. Чтобы использовать контексное окно целиком для больших текстов, остается только использовать либо API (в конечном итоге), либо Playground. Плюсы: больше контроля, можно управлять параметрами, например, температурой (насколько рандомизируется результат). Главный минус — стоит отдельных денег, то есть нужно оплачивать входящие/выходящие токены, но цены вполне умеренные.
На самом деле, эта серия статей в некоторой степени последствие экспериментов с LLM. А точнее исследование их ограничений и возможностей. Хочу оговориться, что я не делал масштабных экспериментов — не мой профиль. Я опробовал лишь несколько моделей от OpenAI, так как наиболее нам доступны. И все же есть чем поделиться.
Одна из моих задач не такого уж далекого будущего — это использование AI для анализа профилей производительности. И здесь мы сталкиваемся с большими контекстами. И дело не только в размерах самих профилей, которые могут быть сотни мегабайт — с этим можно справиться, например, обернув тот же CPUpro в MCP, и предоставив возможности для необходимых выборок.
Но я думаю немного дальше, как не только определить проблемное место, но и найти способы это исправить. И вот это еще одно направление, где нужен большой контекст — потому что проблема часто не в том месте, где тратится больше всего времени, она может быть где угодно. И чем больше проект, тем больший контекст необходим. Да, можно выбирать лишь части кода, например, связанные функции с определенной глубиной. Но, думаю, у большинства есть этот опыт при отладке, когда можно "проваливаться" достаточно глубоко внутрь, прежде чем необходимое место будет найдено. Так и любой AI агент будет добирать в свой контект все больше и больше функций (кода) пока, возможно, не захлебнется.
В общем контекст может получаться большим. Отдельная проблема как это все выбирать, но представим, что это уже есть (то есть реализовано). Насколько большим может быть контекст? Влияет ли размер контекста на результат? Будет ли это работать? Для ответа на вопросы можно опираться на публикации, заявления и даже спеки к моделям. Но пока не попробуешь на конкретной задаче в реальных условиях — это все "конь в вакууме".
Так, я решил поэкспериментировать. И даже еще больше упростить задачу для LLM. Сначала я думал взять достаточно большой модуль и пробовать задачи на нем. Но код это сложно, плюс всегда есть зависимости от других модулей, пакетов и API, что может влиять на качество результата. Поэтому я подумал, а что если взять просто текст — работа же с текстом сильная сторона LLM — и сначала проверить на задачах с текстом. Так можно получить т.н. baseline, и если все хорошо, то продолжить двигаться в сторону кода.
В качестве цели я выбрал собрать развернутую статью (или серию статей) про веб-стримы, на основе своих постов в этом канале. Я хотел собрать статью еще как только закончил цикл постов, но время на это не нашлось. А тут получалось совместить приятное с полезным.
И тут может показаться, что задача плёвая — «мы уже сто тыщ милльонов раз видели суммаризацию». Но в данном случае, задача не такая простая. Во-первых, нужно выбрать материал, который перемешан с другой тематикой и стороними мыслями, который к тому же не структурирован как что-то цельное, так как писался в формате блога или летописи. Во-вторых, нужно сгенерировать очень большой текст, со структурой и перекрестными ссылками, чтобы в результате использовались все моменты и нюансы из оригинального материала. В-третьих, у меня есть (надеюсь) своя стилистика, вкус и виденье каким должен быть результат – то есть недостаточно просто создать статью, она должна быть определенного уровня и качества. В-четвертых, это техническая статья и поэтому формулировки должны быть точными, факты – достоверными на момент публикации, примеры и фрагменты кода – логичными и корректными, и т.д.
То есть задача достаточно непростая, кто использовал LLM для генерации больших текстов — тот знает. Но попробовать все таки стоит – интересно же, что может получиться.
Детальный разбор StreamTransformSelector, пожалуй, выходит за рамки формата телеграм поста. Пытливый читатель может найти код реализации здесь. Я же отмечу, что основной вызов это правильно перевязать controller внешнего стрима с readable и writable внутреннего стрима. Это то, с чем я не справился в прошлый раз: решение работало для небольших данных, но взрывалось на больших. Было очевидно, что какой-то из стримов не успевал завершить работу и закрывался слишком рано, что приводило к неполным данным на конце и ошибке парсинга. Отлаживать стримы достаточно проблематично, многое происходит под капотом, просто некуда поставить брейкпоинт. А специализированных инструментов под отладку пока не изобрели.
Так, применяя все свои навыки отладчика, я перепробывал все идеи, но мне так не удалось исправить проблему за полчаса. И я уже был готов сдаться. Но вспомнил в какое время мы живем, и решил почеленджить ChatGPT этой проблемой. Не без скепсиса. Прошлый раз, в декабре, ChatGPT на вопросы про код с веб стримами выдавал откровенный бред. Но за это время модели прокачались (без сарказма), как знать, может что-то изменилось. Описал проблему, приложил код StreamTransformSelector, и скормил ChatGPT. В итоге, GPT4o не справилась, переписала мой код в нерабочий (добавила дедлок). А вот o3-mini-high, на удивление, с задачей справилась. По сути, своим ответом, модель подсказала то, что я упустил, нужно было дождаться pipeTo() во flush(), кто бы мог подумать.
Более того, o3-mini-high предложила альтернативный вариант, т.н. "A Simpler “Lookahead” Approach", когда используется асинхронная функция, вычитывающая первый чанк, создающая TransformStream на его основе, и потом, в цикле, перекидывающая чанки из одного стрима в другой. Похожее решение было и у меня, то с чего начинал попытки встроить DecompressionStream, но в итоге от него отказался. Стоит отметить, что имплементации не совпадают один в один, в моей реализации я использовал pipeThrough() вместо цикла. Но сути это не меняет, и проблема вовсе не в цикле, а в эргономике: при таком подходе уже не получается композировать стримы только лишь через pipeThrough(), приходится перемешивать стримы с промисами, как-то так:
async function consumeStream(input: ReadableStream) { const stream1 = input.pipeThrough(...); const stream2 = await applyStreamTransformers(stream1, transformers); const finalStream = stream2.pipeThrough(...);
// ... }
Для сравнения, без перемешивания с промисами:
async function consumeStream(input: ReadableStream) { const finalStream = input .pipeThrough(...) .pipeThrough(new TransformStream(new StreamTransformSelector(transformers))) .pipeThrough(...);
// ... }
Трансформеры не обязательно должны менять данные, которые через них проходят. Например, трансформер может нарезать чанки на более мелкие, или наоборот – буферизировать. Они также могут считать размер проходимых через них данных и таким образом можно отображать прогресс:
const finalStream = stream .pipeThrough(new TransformStream(new ProgressTransformer(setProgress))) .pipeThrough(...)
Используем `Response`
Для преобразования "одиночных" значений в ReadableStream можно также использовать конструктор Response() и прокидывать его в аналог loadDataFromResponse() или передавать его свойство body сразу в loadDataFromStream().
loadDataFromResponse(new Response('...file content...')); loadDataFromStream(new Response('...file content...').body);
Конструктор Response() принимает широкий набор значений: Blob, ArrayBuffer, TypedArray, DataView, FormData, ReadableStream, URLSearchParams и строки.
Таким образом, Response() может служить достаточно универсальным конвертером одиночных значений в ReadableStream. Однако стоит понимать, что переданное значение обычно не бьётся на чанки (если это не ReadableStream; тогда чанки из стрима передаются как есть, но могут и переразбиваться). Так, если в Response() положить ArrayBuffer на 100 мегабайт, то, скорее всего, он (а вернее, его копия) и выпадет на принимающей стороне единственным чанком. Поэтому реальной пользы от конвертации в стрим, кроме как подгонки под интерфейсы, не будет.
---
Интересно заметить, что Response() можно использовать для конвертации FormData() в строку ("multipart/form-data") и обратно, что я обнаружил, когда писал этот текст. Сам FormData() по какой-то причине такой функциональностью не обладает. Но, манипулируя методами Response(), этого несложно добиться:
> Не думаю, что так было задумано, скорее побочный эффект, от того решение выглядит ещё более интересным. Я даже помучал ChatGPT (4o и o1-preview), и он не знал и не смог вывести решение (чат с o1). Гугл тоже не помог найти что-то подобное. Но я не претендую на оригинальность 😉
const formData = new FormData(); formData.set('value', 123); formData.set('myfile', new File(['{"hello":"world"}'], 'demo.json', { type: 'application/json' }));
// FormData -> multipart/form-data string const multipartString = await new Response(formData).text();
console.log(multipartString); // ------WebKitFormBoundaryQi7NBNu0nAmyAhpU // Content-Disposition: form-data; name="value" // // 123 // ------WebKitFormBoundaryQi7NBNu0nAmyAhpU // Content-Disposition: form-data; name="myfile"; filename="demo.json" // Content-Type: application/json // // {"hello":"world"} // ------WebKitFormBoundaryQi7NBNu0nAmyAhpU--
// multipart/form-data string -> FormData const boundary = multipartString.match(/^\s*--(\S+)/)[1]; const restoredFormData = await new Response(multipartString, { headers: { // Без правильного заголовка не распарсится 'Content-Type': 'multipart/form-data;boundary=' + boundary } }).formData();
console.log([...restoredFormData]); // [ // ['value', '123'], // ['myfile', File { ... }] // ]