ホームページ  >  記事  >  バックエンド開発  >  Go の「mime」パッケージの不確定性: 信頼するが検証する

Go の「mime」パッケージの不確定性: 信頼するが検証する

WBOY
WBOYオリジナル
2024-07-29 07:26:131209ブラウズ

Indeterminacy of the `mime` Package in Go: Trust But Verify

元々のブログ投稿: https://lazy.bearblog.dev/go-mime-wtf/

背景

ある週末、私は ToDo リストや買い物リストを自動化するために自分用の Telegram ボットを作成することにしました。

アイデアはシンプルです。購入するアイテムのリストをボットに送信すると、片手に携帯電話を持ち、もう一方の手に買い物かごを持った状態で、チェックボックスをオンにできるチェックボックスを含む Web ページが作成されます。

ボットはすぐに作成できましたが、その後、OpenAI の Whisper モデルを試してみたくなりました。そこで、アプリケーションに音声認識を追加することにしました。

これで、プログラムは次のように動作します:

  • 私はボットに次のような音声メッセージを送信します。「ジャガイモ 1 キロ、ディル 1 束、キャベツ 1 個、ビール 2 杯買ってください、ああ、キャベツは必要ありません、私たちにはあります」
  • ボットは音声を認識し、チェックボックスのあるページを作成します。
[ ] potatoes - 1 kg
[ ] dill - 1 bunch
[ ] beer - 2 bottles

さて、記事について。 go-openai では、openai.AudioRequest 構造体を使用してオーディオを送信できます。これにより、Reader フィールドにオーディオ データ ストリームを指定するか、FilePath フィールドにファイル パスを指定できます。これらのフィールドは相互に排他的だと思っていましたが、オーディオ ストリームを使用する場合でも FilePath を指定する必要があることがわかりました。 API はおそらくこれを使用してストリーム タイプを決定します。

Telegram 側では、MimeType フィールドを持つ tgbotapi.Voice 構造体を受け取ります。音声メッセージの場合は audio/ogg ですが、将来簡単に変更される可能性があります。

したがって、オーディオ ストリームの MIME タイプがわかったので、そこからファイル拡張子を判断し、OpenAI API が不明なファイル タイプについてエラーを出さないようにファイル名を作成する必要があります。

もっとシンプルなものは何でしょうか?

コードは簡単そうに見えます:

extensions, err := mime.ExtensionsByType(mimeType)
if err != nil {
    return err
}
if len(extensions) == 0 {
    return fmt.Errorf("unsupported mime type: %s", mimeType)
}
ext := extensions[0]
log.Printf("Assumed extension: %s", ext)
fakeFileName := fmt.Sprintf("voice_message.%s", ext)

ローカルでテスト - 動作します:

2024/07/28 17:49:06 Assumed extension: oga

クラウドへのデプロイ - 機能しません:

2024/07/28 17:55:32 unsupported mime type: audio/ogg

ローカルとビルドに使用された CI/CD で Go のバージョンを確認します - それらは同じです。

本題に入りましょう

MIME パッケージの動作は決定的ではなく、実行時にオペレーティング システムに /etc/mime.types ファイルが存在するかどうかとその内容に依存することが判明しました。

ここで、MIME パッケージは MIME タイプとファイル拡張子のマッピングのランタイム テーブルを読み取ります。

私は非常に真剣です。バイナリをコンパイルし、すべてのテストを実行すると、すべてがうまくいっているように見えますが、このバイナリは、同じ MIME タイプに対して想定されるファイル拡張子を、異なる環境では異なる方法で決定します。

修正方法

オーディオ ファイルの既知の MIME タイプとその拡張子を取得し、mime.AddExtensionType を使用して init 関数に手動で追加しましょう。

var mimetypes = [][]string{
    {"audio/amr", "amr"},
    {"audio/amr-wb", "awb"},
    {"audio/annodex", "axa"},
    {"audio/basic", "au", "snd"},
    {"audio/csound", "csd", "orc", "sco"},
    {"audio/flac", "flac"},
    {"audio/midi", "mid", "midi", "kar"},
    {"audio/mpeg", "mpga", "mpega", "mp2", "mp3", "m4a"},
    {"audio/mpegurl", "m3u"},
    {"audio/ogg", "oga", "ogg", "opus", "spx"},
    {"audio/prs.sid", "sid"},
    {"audio/x-aiff", "aif", "aiff", "aifc"},
    {"audio/x-gsm", "gsm"},
    {"audio/x-mpegurl", "m3u"},
    {"audio/x-ms-wma", "wma"},
    {"audio/x-ms-wax", "wax"},
    {"audio/x-pn-realaudio", "ra", "rm", "ram"},
    {"audio/x-realaudio", "ra"},
    {"audio/x-scpls", "pls"},
    {"audio/x-sd2", "sd2"},
    {"audio/x-wav", "wav"},
}

func init() {
    log.Println("init mimetypes")
    for _, v := range mimetypes {
        typ := v[0]
        extensions := v[1:]

        for _, ext := range extensions {
            err := mime.AddExtensionType("."+ext, typ)
            if err != nil {
                log.Fatalf("mime: %s", err.Error())
            }
        }
    }
}

これにより、アプリケーションが動作するドメイン (私の場合はオーディオ ファイル) に関してアプリケーションの動作が決定的になります。

結論

この経験は、Go の物事が必ずしも決定的ではないことを示しました。何かが奇妙に思われる場合は、ためらわずにライブラリのソース コードを調べて、それがどのように実装されているかを確認してください。これにより、長期的には多くの時間とトラブルを節約できます。

以上がGo の「mime」パッケージの不確定性: 信頼するが検証するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。