Перейти до вмісту

Реалізація автоматичного перекладу повідомлень

Я реалізував автоматичний переклад повідомлень з російської на українську у своєму чаті в Telegram. Не вдаватимуся в подробиці, навіщо це знадобилося. Декому з користувачів ця функція сподобалася, а інших дратувала чи викликала сумніви в її доцільності. Скажімо так, я взявся за цей технічний виклик задля особистого зростання. На роботі я переважно займаюся організаційними завданнями, які виснажують мене, і я не надто вправний у них і не маю до них особливого запалу.

Тож, скажімо так, я взявся за цей проєкт, щоб опанувати нову технологію, і отримую задоволення від набуття нових навичок та від того, що роблю щось самостійно. Це підкреслює, що російська — чужа мова в українському просторі, і ненав'язливо підштовхує людей перейти на українську чи, можливо, навіть зовсім покинути чат. Гаразд, перейдімо до технічного боку.

У мене є бот, який працює на PHP — мові програмування, якою я користуюся найчастіше. Спершу я шукав рішення для визначення мови повідомлень, бо не хотів надсилати кожне повідомлення до API перекладу. Я натрапив на бібліотеку LanguageDetector на GitHub (landrok/language-detector). Інтегрувавши її в бота, я вирішив обчислювати бали для кожної мови та порівнювати їх. Це було потрібно, бо саме лише визначення мови бібліотекою часто плутало кириличні мови. Можливо, потрібні ширші набори даних, але я не зміг знайти їх одразу.

Поекспериментувавши й потестувавши на коротких фразах, я віднімав український бал від російського. Якщо різниця була більша за 0.016, а загальний російський бал перевищував 0.05, повідомлення вважалося російським. Зрештою я зупинився на значеннях 0.02 та 0.1, щоб зменшити частоту спрацьовування переходу для коротких слів і фраз, де переклад однаково не сильно відрізнявся б.
Для самого перекладу я обрав DeepL, бо це наразі найкращий варіант на ринку, наскільки мені відомо. Робити запити до API DeepL для перекладу повідомлень виявилося нескладно. Я оформив безкоштовний доступ до API, який надає півмільйона символів на місяць, чого має вистачити для чату, де більшість повідомлень і так уже українською.

Спочатку я налаштував бота визначати мову автоматично, але згодом задав йому перекладати з російської. Це було потрібно, бо визначення мови не завжди правильно розпізнавало російську й часом надсилало українські повідомлення на переклад. Оскільки повідомлення вже були українською, DeepL інколи визначав мову введення як іншу кириличну, наприклад болгарську, що призводило до кумедних результатів перекладу.

Після дня тестування функції перекладу я помітив, що визначення мови часто давало збій і надсилало українські повідомлення на переклад. Я спробував знайти кращі рішення, але не зміг відшукати доступного API. Утім, переглядаючи проблеми (issues) в репозиторії визначника мови на GitHub, я натрапив на рекомендацію PHP-розширення Compact Language Detector 2 (fntlnz/cld2-php-ext), яке, як казали, було кращим.

Спершу мені було лячно, бо складання розширення з вихідного коду здавалося складним, і в минулому я мав із цим проблеми. Я вирішив спробувати. На жаль, компіляція провалилася, а мої спроби знайти рішення через пошук в інтернеті виявилися марними. Та, повернувшись до розділу issues репозиторію, я дізнався, що розширення несумісне з PHP 8, але є pull request, щоб зробити його сумісним (hiteule/cld2-php-ext/tree/support-php8). Тож я завантажив розширення з гілки цього PR, і воно зібралося успішно.

Потім я усвідомив, що мій бот працює на PHP 7, тоді як CLI — на PHP 8. Я подумував перемкнути версію PHP в CLI, але натомість вирішив увімкнути PHP 8. Ця зміна мала б покращити продуктивність, а проблем із сумісністю не було. У процесі я також налаштував SSH-ключ на GitHub, чого раніше не робив. Це дозволило мені клонувати репозиторії через SSH і стало для мене новим досвідом на GitHub. На щастя, це виявилося нескладно, бо я часто користуюся SSH для інших завдань і вже додавав ключі до інших сервісів.

Алгоритм визначення мови CLD2 значно краще працює з повними реченнями, правильно розпізнаючи мову. Однак йому важко визначити мову для коротких фраз і поодиноких слів, і в таких випадках він не дає жодних припущень. Тож я реалізував механізм відкату до попереднього Language Detector у ситуаціях, коли мову не вдавалося визначити або коли бал визначення російської був меншим за 97%. Я помітив, що коли бал визначення був нижчим за 97%, це могла бути якась поламана українська або фраза, що не потребувала перекладу.

Та навіть так траплялися випадки збою визначення мови, а це означало, що переклади показувалися навіть тоді, коли жодного перекладу не відбулося. Поекспериментувавши, я придумав рішення, яке зводилося до того, що я лишав з оригінального й перекладеного тексту лише малі кириличні літери, а потім порівнював рядки із цих літер. Переклад не відображався, якщо рядки збігалися на 85% чи більше. Цей підхід відсіював випадки, коли текст лишався незмінним після перекладу або мав лише незначні відмінності. Він також вирішив проблему з українським апострофом, який по-різному відображається на різних клавіатурах і системах.

Цей проєкт повернув мене до того, що мені до вподоби. За останній місяць я неодноразово натрапляв на пораду зосереджуватися на завданнях, якими захоплюєшся і в яких добре розбираєшся. Відчуття звершення, яке я дістав від реалізації цієї невеличкої функції, перевершило будь-яке проходження відеогри. На жаль, практична користь цієї реалізації обмежена, і, попри початкові позитивні відгуки, тепер я стикаюся з постійним негативним фідбеком. Я навіть налаштував бота публікувати переклади без відповіді на початкове повідомлення. Щоб запобігати таким ситуаціям, мені треба стати кращим product owner'ом, але цей виклик я прибережу для роботи, а не для свого хобі.

Увімкніть коментарі, прийнявши куки.

Необхідні куки працюють завжди. Куки для статистики та коментарів використовуються лише з вашої згоди. Докладніше