Discord

Pythonライブラリのlangdetectでメッセージの言語判定をさせよう

いつもの
Discord, Discord.py, 国旗リアクションで翻訳するbot

langdetect · PyPI

いきなりタイ語がgoogletransで反応しなくなってしまったので、いい加減公式様のapiに移行しなくては…と思いつつ、言語判定部分で料金をケチるためにインターネットの海を徘徊し、 langdetect というライブラリを発見。結果だけ言うと問題なく動作しています。

googletrans(非公式)

  • 速度: 一般的には速いが、不安定な場合があります。小規模なリクエストには十分ですが、大量のリクエストでは遅延が発生することがあります。
  • 影響する要因: 非公式APIであるため、サーバーの状態やアクセスの集中により応答速度が変動することがあります。

langdetect

  • 速度: 通常は非常に高速です。簡単な言語検出処理のため、リクエストに対する応答は迅速に行われます。
  • 影響する要因: テキストの長さや処理するテキストの量によって影響を受けることがありますが、一般的にはリクエストの処理は高速です。

なお、言語判定をlangdetectで行うように変更したら、タイ語はgoogletransで翻訳可能になりました。よくわからない。

import discord
from discord.ext import commands
from langdetect import detect, LangDetectException

# ボットの設定
intents = discord.Intents.default()
intents.message_content = True  # メッセージコンテンツの読み取りを可能にする
bot = commands.Bot(command_prefix=" ", intents=intents)

@bot.event
async def on_ready():
    print(f"Logged in as {bot.user}")

@bot.event
async def on_raw_reaction_add(payload):
    # メッセージを取得するためのチャンネル
    channel = bot.get_channel(payload.channel_id)

    try:
        # メッセージを取得
        message = await channel.fetch_message(payload.message_id)
    except discord.NotFound:
        print("Message not found.")
        return

    # リアクションが国旗絵文字の場合にのみ処理
    if payload.emoji.name in ["🇯🇵", "🇺🇸", "🇫🇷", "🇩🇪"]:  # 必要な国旗絵文字を追加
        try:
            detected_language = detect(message.content)
            print(f"Detected language: {detected_language}")
        except LangDetectException as e:
            print(f"Language detection error: {e}")
            # 必要に応じてユーザーに通知する処理を追加

# トークンの設定 (環境変数や直接指定)
TOKEN = "YOUR_DISCORD_BOT_TOKEN"
bot.run(TOKEN)

この if payload.emoji.name in ["🇯🇵", "🇺🇸", "🇫🇷", "🇩🇪"] については適当ですみません。ここは、ダラダラと書くとえらいことになるので、例えば flag.txt というファイルを別途用意することでコード自体を読みやすくできます。

🇯🇵
🇺🇸
🇫🇷
🇩🇪

そして、このあたり書き換えます。

@bot.event
async def on_ready():
    print(f"Logged in as {bot.user}")

# 国旗絵文字のリストをファイルから読み込む
with open("flags.txt", "r") as file:
    flag_emojis = [line.strip() for line in file]

@bot.event
async def on_raw_reaction_add(payload):
    # メッセージを取得するためのチャンネル
    channel = bot.get_channel(payload.channel_id)

    try:
        # メッセージを取得
        message = await channel.fetch_message(payload.message_id)
    except discord.NotFound:
        print("Message not found.")
        return

    # リアクションが国旗絵文字の場合にのみ処理
    if payload.emoji.name in flag_emojis:
        try:
            detected_language = detect(message.content)
            print(f"Detected language: {detected_language}")
        except LangDetectException as e:
            print(f"Language detection error: {e}")

見やすいので絵文字のままにしてますが、実際にpayload.emoji.nameで得られるのはUnicodeです。

LangDetectExceptionは、langdetectライブラリにおいて、言語検出プロセス中に何らかの問題が発生した場合に発生する例外です。このライブラリはテキストの内容を分析して言語を推定するために使用されますが、特定の状況下で言語を正確に識別できない場合があります。

LangDetectExceptionが発生する主な理由は次のとおりです:

テキストが短すぎるか、あいまいすぎる: 言語検出アルゴリズムは、一般にテキストの内容を分析して言語を識別します。テキストが非常に短い、または多くの言語に共通する単語(例えば「OK」)のみを含む場合、言語を正確に識別するのが困難になることがあります。
この場合、何も気にせずGoogle側に翻訳を投げるという頭の悪い発想で解決することが可能です。例えば “Hello” という単語ですが、langdetectは “fi” という結果を返すことがほとんどです。しかし、挨拶はDeepLでもGoogleでも同じ翻訳結果を返します。特に短文の場合、意図しない翻訳結果になるケースは稀です。

“頭の悪い発想”と言いましたが、langdetectがサポートしている言語は55種類です。そのため、判定不可能であった場合、google翻訳に処理を回すのは今のところ最も現実的な解決策かと思います。

サポートされていない言語: 上に書いた通り、langdetectライブラリは多くの言語をサポートしていますが、全ての言語をカバーしているわけではありません。サポートされていない言語のテキストを分析しようとした場合、エラーが発生する可能性があります。
ただし、Discord内で出会うことは稀です。わたしは見たことないです。

アルゴリズムの制約: どんな高度な言語検出アルゴリズムでも、100%の正確性を保証することはできません。言語の特徴が曖昧であるか、または複数の言語が混在している場合、誤った検出が発生することがあります。ユーザーが原文を引用し、別の言語でメッセージを追加する時に陥りやすい現象です。そいつが100%悪い

LangDetectExceptionを適切に処理するには、例外処理機構(try-exceptブロック)を使用し、エラーが発生した場合の対処方法を定義することが重要です。例えば、エラーメッセージをログに記録したり、リアクションしたユーザーに言語が識別できなかったことを通知するなどの処理を行うことができます。
ただ、この翻訳botは例外処理をしなくても、エラーが出るだけでとりあえず動きます。エラーをエラーのまま放置しても良いことはないので、例外処理はしましょう。

翻訳botの性質上、エラーが出たらgoogle先生に投げる、それでもエラーが出るならpassする、くらいでいいんじゃないかと思っています。ここの塩梅は自分の領域内でしか判断できないので、なんとも言えません。

おまけ:バカみたいな辞書

さらっと国旗の絵文字を載せていますが、実際にはgoogletransで使用する 国旗のUnicode:Googleの言語コード という辞書を流用していてます。レインボーフラッグなどを除き、Discordで絵文字として扱っている国旗すべてを対象とし、離島から何から何まで書きました。目が一等疲れました。

Tagged ,

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です