Ursprünglich in meinem Blog gepostet: https://lazy.bearblog.dev/go-mime-wtf/
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:
[ ] 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.
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.
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.
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.
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!