package handler import ( "io" "log" "net/http" "os" "os/exec" "github.com/alberdjuniawan/anput-api/middleware" "github.com/alberdjuniawan/anput-api/repository" "github.com/alberdjuniawan/anput-api/service" "github.com/alberdjuniawan/anput-api/util" chiMiddleware "github.com/go-chi/chi/v5/middleware" ) type HTTPHandler struct { AIService service.AIService Repo repository.Repository } func NewHTTPHandler(aiService service.AIService, repo repository.Repository) *HTTPHandler { return &HTTPHandler{ AIService: aiService, Repo: repo, } } func (h *HTTPHandler) UploadAudioFile(w http.ResponseWriter, r *http.Request) { reqID := chiMiddleware.GetReqID(r.Context()) userIDVal := r.Context().Value(middleware.UserIDKey) if userIDVal == nil { util.WriteError(w, http.StatusUnauthorized, "Unauthorized access", reqID) return } userID := userIDVal.(string) slug := r.URL.Query().Get("slug") if slug == "" { util.WriteError(w, http.StatusBadRequest, "Missing query parameter: slug", reqID) return } schemaData, err := h.Repo.GetSchemaBySlug(r.Context(), userID, slug) if err != nil { log.Printf("[%s] Schema lookup error: %v", reqID, err) util.WriteError(w, http.StatusNotFound, "Schema not found", reqID) return } if err := r.ParseMultipartForm(50 << 20); err != nil { util.WriteError(w, http.StatusBadRequest, "File too big (Max 50MB)", reqID) return } file, header, err := r.FormFile("audio") if err != nil { util.WriteError(w, http.StatusBadRequest, "Missing audio file field", reqID) return } defer file.Close() tempInput, err := os.CreateTemp("", "raw-upload-*"+header.Filename) if err != nil { log.Printf("[%s] Temp file creation error: %v", reqID, err) util.WriteError(w, http.StatusInternalServerError, "Internal storage error", reqID) return } defer os.Remove(tempInput.Name()) if _, err := io.Copy(tempInput, file); err != nil { log.Printf("[%s] File write error: %v", reqID, err) util.WriteError(w, http.StatusInternalServerError, "Failed to save audio", reqID) return } tempInput.Close() tempOutput := tempInput.Name() + ".wav" defer os.Remove(tempOutput) cmd := exec.Command("ffmpeg", "-y", "-i", tempInput.Name(), "-ar", "16000", "-ac", "1", "-c:a", "pcm_s16le", tempOutput) if output, err := cmd.CombinedOutput(); err != nil { log.Printf("[%s] FFmpeg Error: %v | Output: %s", reqID, err, string(output)) util.WriteError(w, http.StatusBadRequest, "Audio conversion failed. Please verify your audio format.", reqID) return } cleanAudioBytes, err := os.ReadFile(tempOutput) if err != nil { log.Printf("[%s] Read converted file error: %v", reqID, err) util.WriteError(w, http.StatusInternalServerError, "Processing error", reqID) return } result, err := h.AIService.ProcessAudioFull(r.Context(), cleanAudioBytes, schemaData.Definition) if err != nil { log.Printf("[%s] AI Processing Error: %v", reqID, err) util.WriteError(w, http.StatusInternalServerError, "AI processing failed", reqID) return } util.WriteSuccess(w, http.StatusOK, result, reqID) }