package api import ( "encoding/json" "net/http" "strings" "time" ) func (s *Server) handleOpenAITranscriptions(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { writeOpenAIError(w, http.StatusMethodNotAllowed, "method not allowed") return } if err := r.ParseMultipartForm(128 << 20); err != nil { writeOpenAIError(w, http.StatusBadRequest, err.Error()) return } modelID, err := s.models.Resolve(r.FormValue("model"), s.cfg.DefaultModel) if err != nil { writeOpenAIError(w, http.StatusBadRequest, err.Error()) return } modelPath, err := s.models.Path(modelID) if err != nil { writeOpenAIError(w, http.StatusBadRequest, err.Error()) return } audioPath, cleanup, err := s.saveUploadedOpenAI(r) if err != nil { writeOpenAIError(w, http.StatusBadRequest, err.Error()) return } defer cleanup() stt := s.parseOpenAISTTOptions(r) result, err := s.transcribe(r.Context(), modelPath, audioPath, stt) if err != nil { writeOpenAIError(w, http.StatusInternalServerError, err.Error()) return } switch strings.ToLower(strings.TrimSpace(r.FormValue("response_format"))) { case "text": w.Header().Set("Content-Type", "text/plain; charset=utf-8") w.WriteHeader(http.StatusOK) _, _ = w.Write([]byte(result.Text)) default: writeJSON(w, http.StatusOK, map[string]string{"text": result.Text}) } } func (s *Server) handleOpenAIModels(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { writeOpenAIError(w, http.StatusMethodNotAllowed, "method not allowed") return } ids, err := s.models.List() if err != nil { writeOpenAIError(w, http.StatusInternalServerError, err.Error()) return } now := time.Now().Unix() data := make([]map[string]any, 0, len(ids)) for _, id := range ids { data = append(data, map[string]any{ "id": id, "object": "model", "created": now, "owned_by": "go-whisper-api", }) } writeJSON(w, http.StatusOK, map[string]any{ "object": "list", "data": data, }) } func (s *Server) parseOpenAISTTOptions(r *http.Request) sttOptions { lang := strings.TrimSpace(r.FormValue("language")) if lang == "" { lang = s.cfg.Language } return sttOptions{ language: lang, punctuate: s.punctCfg.ShouldApplyAPI(r, s.cfg.DefaultPunctuation), } } func (s *Server) saveUploadedOpenAI(r *http.Request) (path string, cleanup func(), err error) { if r.MultipartForm == nil { if err := r.ParseMultipartForm(128 << 20); err != nil { return "", nil, err } } return saveUploadedRawFields(r, []string{"file", "audio", "wav"}) } func writeOpenAIError(w http.ResponseWriter, code int, msg string) { w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(code) _ = json.NewEncoder(w).Encode(map[string]any{ "error": map[string]any{ "message": msg, "type": openAIErrorType(code), }, }) } func openAIErrorType(code int) string { switch code { case http.StatusBadRequest: return "invalid_request_error" case http.StatusUnauthorized: return "authentication_error" case http.StatusNotFound: return "not_found_error" default: return "server_error" } }