diff --git a/Dockerfile b/Dockerfile index d8f32e76..f2c94ee3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -45,13 +45,10 @@ RUN CGO_ENABLED=0 \ FROM python:3.11-slim AS runtime ENV PYTHONUNBUFFERED=1 \ - UV_INSTALL_DIR=/usr/local/bin \ - UV_PATH=/usr/local/bin/uv \ HOST=0.0.0.0 \ PORT=8080 \ DATABASE_PATH=/app/data/scriberr.db \ - UPLOAD_DIR=/app/data/uploads \ - WHISPERX_ENV=/app/data/whisperx-env + UPLOAD_DIR=/app/data/uploads WORKDIR /app @@ -61,14 +58,15 @@ RUN apt-get update \ curl ca-certificates ffmpeg git \ && rm -rf /var/lib/apt/lists/* -# Install uv (fast Python package manager). The script installs under -# /root/.local/bin by default; ensure it's available at /usr/local/bin/uv. +# Install uv (fast Python package manager) directly to system PATH RUN curl -LsSf https://astral.sh/uv/install.sh | sh \ - && if [ -x /root/.local/bin/uv ]; then ln -sf /root/.local/bin/uv ${UV_INSTALL_DIR}/uv; fi + && cp /root/.local/bin/uv /usr/local/bin/uv \ + && chmod 755 /usr/local/bin/uv \ + && uv --version # Add non-root user and data directory RUN useradd -m -u 10001 appuser \ - && mkdir -p /app/data/uploads /app/data/transcripts /app/data/whisperx-env \ + && mkdir -p /app/data/uploads /app/data/transcripts \ && chown -R appuser:appuser /app # Copy binary @@ -80,5 +78,8 @@ VOLUME ["/app/data"] USER appuser +# Verify uv is available for appuser +RUN uv --version + # Default command ENTRYPOINT ["/app/scriberr"] diff --git a/internal/transcription/quick_transcription.go b/internal/transcription/quick_transcription.go index 4ce5bf9f..f7362c99 100644 --- a/internal/transcription/quick_transcription.go +++ b/internal/transcription/quick_transcription.go @@ -298,7 +298,7 @@ func (qs *QuickTranscriptionService) buildWhisperXCommand(job *models.Transcript // Use standard WhisperX command for quick transcriptions args := []string{ - "run", "--native-tls", "--project", qs.whisperX.getEnvPath(), "python", "-m", "whisperx", + "run", "--native-tls", "--project", "whisperx-env", "python", "-m", "whisperx", job.AudioPath, "--output_dir", outputDir, } @@ -400,11 +400,11 @@ func (qs *QuickTranscriptionService) buildWhisperXCommand(job *models.Transcript } args = append(args, "--print_progress", "False") - cmd := exec.Command(qs.whisperX.getUVPath(), args...) + cmd := exec.Command("uv", args...) cmd.Env = append(os.Environ(), "PYTHONUNBUFFERED=1") // Debug: log the command being executed - fmt.Printf("DEBUG: Quick WhisperX command: %s %v\n", qs.config.UVPath, args) + fmt.Printf("DEBUG: Quick WhisperX command: uv %v\n", args) return cmd, nil } diff --git a/internal/transcription/whisperx.go b/internal/transcription/whisperx.go index f972787a..f5aee6f6 100644 --- a/internal/transcription/whisperx.go +++ b/internal/transcription/whisperx.go @@ -18,14 +18,11 @@ import ( // WhisperXService handles WhisperX transcription type WhisperXService struct { - config *config.Config } // NewWhisperXService creates a new WhisperX service func NewWhisperXService(cfg *config.Config) *WhisperXService { - return &WhisperXService{ - config: cfg, - } + return &WhisperXService{} } // TranscriptResult represents the WhisperX output format @@ -125,7 +122,7 @@ func (ws *WhisperXService) ensurePythonEnv() error { } // Check if WhisperX import works; if not, try to install via fallback - cmd := exec.Command(ws.getUVPath(), "run", "--native-tls", "--project", envPath, "python", "-c", "import whisperx") + cmd := exec.Command("uv", "run", "--native-tls", "--project", envPath, "python", "-c", "import whisperx") if err := cmd.Run(); err != nil { return ws.installWhisperX() } @@ -158,7 +155,7 @@ func (ws *WhisperXService) installWhisperX() error { envPath := ws.getEnvPath() // Install WhisperX and diarization dependencies - cmd := exec.Command(ws.getUVPath(), "add", "--native-tls", "--project", envPath, + cmd := exec.Command("uv", "add", "--native-tls", "--project", envPath, "git+https://github.com/m-bain/whisperX.git", "torch", "torchaudio", "numpy", "pandas", "pyannote.audio", "faster-whisper") @@ -173,7 +170,7 @@ func (ws *WhisperXService) installWhisperX() error { // uvSync runs `uv sync` for the given project path func (ws *WhisperXService) uvSync(projectPath string) error { - cmd := exec.Command(ws.getUVPath(), "sync", "--native-tls", "--project", projectPath) + cmd := exec.Command("uv", "sync", "--native-tls", "--project", projectPath) cmd.Dir = projectPath out, err := cmd.CombinedOutput() if err != nil { @@ -196,7 +193,7 @@ func (ws *WhisperXService) writeEmbeddedFile(name, dest string) error { } // InitEmbeddedPythonEnv initializes the Python env on app start (blocking). -// Assumes uv is installed and accessible via config.UVPath. +// Assumes uv is installed and accessible in system PATH. func (ws *WhisperXService) InitEmbeddedPythonEnv() error { if err := ws.ensurePythonEnv(); err != nil { return err @@ -213,7 +210,7 @@ func (ws *WhisperXService) buildWhisperXCommand(job *models.TranscriptionJob, ou // Use WhisperX CLI for both regular transcription and diarization args := []string{ - "run", "--native-tls", "--project", ws.config.WhisperXEnv, "python", "-m", "whisperx", + "run", "--native-tls", "--project", ws.getEnvPath(), "python", "-m", "whisperx", job.AudioPath, "--output_dir", outputDir, } @@ -332,11 +329,11 @@ func (ws *WhisperXService) buildWhisperXCommand(job *models.TranscriptionJob, ou // Hard-coded: disable print progress for cleaner output args = append(args, "--print_progress", "False") - cmd := exec.Command(ws.getUVPath(), args...) + cmd := exec.Command("uv", args...) cmd.Env = append(os.Environ(), "PYTHONUNBUFFERED=1") // Debug: log the command being executed - fmt.Printf("DEBUG: WhisperX command: %s %v\n", ws.config.UVPath, args) + fmt.Printf("DEBUG: WhisperX command: uv %v\n", args) return cmd, nil } @@ -392,16 +389,12 @@ func (ws *WhisperXService) parseAndSaveResult(jobID, resultPath string) error { return nil } -// getEnvPath returns the path used for the WhisperX environment, defaulting -// to data/whisperx-env when not configured. +// getEnvPath returns the hardcoded path for the WhisperX environment. +// Creates the environment in a local "whisperx-env" directory. func (ws *WhisperXService) getEnvPath() string { - // Always use a stable default under the app's data directory. - return filepath.Join("data", "whisperx-env") + return "whisperx-env" } -// getUVPath returns the uv binary path, defaulting to "uv". -func (ws *WhisperXService) getUVPath() string { return "uv" } - // GetSupportedModels returns a list of supported WhisperX models func (ws *WhisperXService) GetSupportedModels() []string { return []string{