В первой части статьи я рассказывала о том, как извлекала культурные реалии из субтитров фильмов. Теперь пришло время оптимизировать сам подход, скрипт и результаты анализа. В этот раз я обработала все четыре сезона любимого многими яркого и отдыхающего сериала Emily in Paris и узнала, например, что "hemorrhaging clients" — это отнюдь не "геморройные клиенты" и даже не клиенты с геморроем в медицинском смысле, а стремительная потеря клиентов (по аналогии с кровотечением, которое, как мы знаем, "hemorrhage" на английском). Узнала, что раскованные французы поднимают бокалы с возгласом Tchin-tchin!, заимствованном, между прочим, из китайского, а сдержанные норвежцы в этой же ситуации произносят Skol! И это "сакральное" знание обошлось мне всего в 40 рублей.
Что нового в подходе
Субтитры сериалов часто распространяются в zip-архивах, содержащих множество srt-файлов по сезонам. Поэтому я доработала скрипт: добавила автоматическую распаковку архивов с помощью библиотеки zipfile
, разделение данных по сезонам и предварительный подсчёт токенов с использованием tiktoken
. Это позволяет оценить стоимость обработки до её начала.
Пример расчёта выглядит так:
-
Подсчитываем количество англоязычных токенов.
-
Умножаем их на два. Почему? Потому что для каждого предложения не всегда найдётся культурная реалия, но если найдётся — объяснение на русском языке займёт больше токенов из-за особенностей языка.
-
Рассчитываем итоговую стоимость анализа, используя данные о стоимости batch API processing:
Предупреждение выглядит так:

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

Установка температуры на 0 заметно снизила склонность модели к длинным и не всегда релевантным объяснениям. Однако я столкнулась с неприятной эстетической проблемой обрыва предложений посередине, поэтому добавила методы обработки строк, которые обрезают текст после точки и убирают лишние дефисы и тире в начале строк.
Кроме того, я ограничила длину выдачи до 120 токенов. Этого оказалось достаточно, чтобы объяснить реалии в 2-3 предложениях на русском языке. Итоговые тексты стали лаконичными и понятными:

Почему я в итоге выбрала GPT-4o, а не mini
Я остановилась на GPT-4o, несмотря на соблазн сэкономить, используя менее мощную модель. Причина в качестве объяснений: GPT-4 выдаёт более точные и осмысленные результаты. Разница в стоимости оказалась несущественной в абсолютных цифрах, хотя конечно в относительных отличается на порядки (40 рублей против 1 рубля), но моё жизненное кредо — «Не гонялся бы ты, поп, за дешевизной». Качество всегда оправдывает затраты.
Аналитика и категоризация
Для дальнейшего анализа я решила классифицировать найденные реалии. Начальный список категорий выглядел так, я составила его скорее интуитивно, и осознаю, что между pun и joke не всегда можно провести чёткую грань:
categories = ["set expression", "pun", "joke", "location", "venue", "event", "drug", "famous team", "food", "drink", "corporate humor", "science", "movie", "song", "book"]
Однако умная модель выбрала более гибкий подход — кластеризацию. В итоге она предложила дополнительные категории, такие как "meme", "opera", "photographer", "device", "superstition" и другие. Это добавило вариативности, но потребовало ручной обработки. Например, я стандартизировала метки (перевод в нижний регистр, устранение дублирующихся категорий вроде "corporate" и "corporate humor").
Тепловая карта и результаты анализа
Для визуализации сразу по всем 4 сезонам я построила тепловую карту с помощью matplotlib
.

На первый взгляд кажется, что категория location доминирует, и может сложиться впечатление, будто почти все культурные реалии связаны с городами и местами. Но есть нюанс. Значительная часть этих locations представляет собой очевидную информацию, вроде "Париж — столица Франции" или "Чикаго — крупный промышленный центр США". Несмотря на мои старания, GPT продолжает радовать меня географическими фактами уровня школьной программы за 7 класс. Исключение городов из анализа посредством фразы exclude cities в промпте, возможно, и помогло бы сократить шум, но я сознательно решила сохранить эту категорию, чтобы не потерять более ценные находки. Например, такие:
"Сен-Реми-де-Прованс — небольшой город на юге Франции, известный как место, где Ван Гог провёл год в психиатрической больнице и создал многие из своих известных работ."
Это ведь тоже город, но я была не в курсе, что именно там лечился Ван Гог. Пока я не нашла способа, как логически научить модель отличать просто географические точки на карте от мест с особой историей, важной для понимания сюжета. Поэтому решила смириться с этой погрешностью, и уделила большее внимание другим категориям реалий. Для этого отфильтровала реалии по сезонам и по убыванию:

Оказалось, что на втором месте после location по популярности находятся устойчивые выражения, следом ожидаемо идут фильмы, песни, события, корпоративный юмор, книги, еда и напитки.
В итоге за четыре сезона я извлекла чуть более 1000 реалий (примерно 300 на сезон), привожу здесь наиболее интересные, на мой взгляд:

Очевидно, что меня как лингвиста больше всего порадовали каламбуры, построенные на изящном переплетении слов французского и английского языка, а также исконно французские выражения, которые придают фильму неповторимый колорит.
Получившийся скрипт оказался универсальным: его можно использовать для обработки субтитров к любым фильмам, сериалам или другим медийным материалам. Для желающих ознакомиться с кодом — он доступен здесь: Film/cultural_notes_to_films_version_2.py на GitHub. А результат работы, включая 1000+ культурных реалий из четырёх сезонов Emily in Paris, можно найти в этой Google-таблице.
На данный момент я не планирую дальнейшее развитие скрипта, поскольку он полностью закрыл мои практические потребности. Однако очевидно, что его потенциал выходит далеко за рамки фильмов и сериалов. Например, его можно адаптировать для анализа книг, подкастов или даже исторических документов, что открывает множество возможностей для изучения языка и культуры.
Автор: JuliaEfimka