Heim  >  Artikel  >  Backend-Entwicklung  >  Unbestimmtheit des „Mime“-Pakets in Go: Trust But Verify

Unbestimmtheit des „Mime“-Pakets in Go: Trust But Verify

WBOY
WBOYOriginal
2024-07-29 07:26:131196Durchsuche

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

Ursprünglich in meinem Blog gepostet: https://lazy.bearblog.dev/go-mime-wtf/

Hintergrund

Eines Wochenendes beschloss ich, einen Telegram-Bot für mich selbst zu schreiben, um Aufgaben- oder Einkaufslisten zu automatisieren.

Die Idee ist einfach. Ich sende dem Bot eine Liste der zu kaufenden Artikel und er erstellt eine Webseite mit Kontrollkästchen, die ich ankreuzen kann, während ich in der einen Hand mein Telefon und in der anderen einen Warenkorb halte.

Der Bot war ziemlich schnell geschrieben, aber dann wollte ich mit dem Whisper-Modell von OpenAI experimentieren. Deshalb habe ich beschlossen, meiner Bewerbung die Spracherkennung hinzuzufügen.

Jetzt funktioniert das Programm wie folgt:

  • Ich schicke dem Bot eine Sprachnachricht wie diese: „Kauf ein Kilogramm Kartoffeln, einen Bund Dill, einen Kohlkopf, ein paar Bier, ach, den Kohl brauche ich nicht, wir haben ihn“
  • Der Bot erkennt die Sprache und erstellt eine Seite mit Kontrollkästchen:
[ ] potatoes - 1 kg
[ ] dill - 1 bunch
[ ] beer - 2 bottles

Nun zum Artikel. In go-openai können Sie Audio mithilfe der Struktur openai.AudioRequest senden, die es Ihnen ermöglicht, einen Audiodatenstrom im Feld „Reader“ oder einen Dateipfad im Feld „FilePath“ anzugeben. Nun, ich dachte, diese Felder würden sich gegenseitig ausschließen, aber es stellte sich heraus, dass Sie FilePath auch dann angeben müssen, wenn Sie einen Audiostream verwenden. Die API verwendet dies wahrscheinlich, um den Stream-Typ zu bestimmen.

Auf der Telegram-Seite erhalten wir eine tgbotapi.Voice-Struktur, die ein MimeType-Feld enthält. Bei Sprachnachrichten ist es audio/ogg, aber das könnte sich in Zukunft leicht ändern.

Wir haben also den MIME-Typ des Audiostreams und müssen daraus die Dateierweiterung ermitteln und einen Dateinamen erstellen, um sicherzustellen, dass sich die OpenAI-API nicht über einen unbekannten Dateityp beschwert.

Was könnte einfacher sein?

Der Code scheint trivial:

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)

Vor Ort testen - es funktioniert:

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

Bereitstellung in der Cloud – es funktioniert nicht:

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

Überprüfen Sie die Go-Versionen, lokal und in der für die Erstellung verwendeten CI/CD – sie sind gleich.

Kommen wir zur Sache

Es stellt sich heraus, dass das Verhalten des Mime-Pakets nicht deterministisch ist und zur Laufzeit davon abhängt, ob eine /etc/mime.types-Datei im Betriebssystem und deren Inhalt vorhanden ist.

Dort liest das MIME-Paket die Laufzeittabelle der MIME-Typ-zu-Dateierweiterungszuordnungen.

Ich meine es absolut ernst: Sie kompilieren eine Binärdatei, führen alle Tests durch, alles scheint großartig, aber diese Binärdatei bestimmt die angenommenen Dateierweiterungen für denselben MIME-Typ in verschiedenen Umgebungen unterschiedlich.

So beheben Sie das Problem

Nehmen wir bekannte MIME-Typen von Audiodateien und ihre Erweiterungen und fügen sie manuell in der Init-Funktion mit mime.AddExtensionType hinzu.

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())
            }
        }
    }
}

Dadurch wird das Verhalten unserer Anwendung in Bezug auf die Domäne, mit der sie arbeiten wird (in meinem Fall Audiodateien), deterministisch.

Abschluss

Diese Erfahrung hat gezeigt, dass die Dinge in Go nicht immer deterministisch sind. Wenn Ihnen etwas merkwürdig vorkommt, zögern Sie nicht, in den Quellcode der Bibliothek einzutauchen und zu sehen, wie er implementiert wird. Dies kann Ihnen auf lange Sicht viel Zeit und Ärger ersparen.

Das obige ist der detaillierte Inhalt vonUnbestimmtheit des „Mime“-Pakets in Go: Trust But Verify. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn