lkatzey 1 місяць тому
батько
коміт
d3a2a77b72
4 змінених файлів з 110 додано та 2 видалено
  1. 9 0
      .dockerignore
  2. 75 0
      Dockerfile
  3. 4 2
      apps/web/src/app/api/download/route.ts
  4. 22 0
      docker-compose.yml

+ 9 - 0
.dockerignore

@@ -0,0 +1,9 @@
+node_modules
+.next
+dist
+output
+.git
+.env
+.claude
+*.md
+!packages/*/README.md

+ 75 - 0
Dockerfile

@@ -0,0 +1,75 @@
+# Stage 1: Install dependencies
+FROM node:22-bookworm AS deps
+
+# 使用阿里云镜像源
+RUN sed -i 's|deb.debian.org|mirrors.aliyun.com|g' /etc/apt/sources.list.d/debian.sources
+
+RUN corepack enable && corepack prepare pnpm@10.24.0 --activate
+
+RUN apt-get update && \
+    apt-get install -y --no-install-recommends ffmpeg python3 python3-pip && \
+    rm -rf /var/lib/apt/lists/*
+
+RUN pip3 install --break-system-packages -i https://mirrors.aliyun.com/pypi/simple/ faster-whisper
+
+WORKDIR /app
+
+COPY package.json pnpm-lock.yaml pnpm-workspace.yaml turbo.json ./
+COPY apps/cli/package.json apps/cli/
+COPY apps/web/package.json apps/web/
+COPY packages/shared/package.json packages/shared/
+COPY packages/core/package.json packages/core/
+COPY packages/tts/package.json packages/tts/
+COPY packages/templates/package.json packages/templates/
+COPY packages/collect/package.json packages/collect/
+
+RUN pnpm config set registry https://registry.npmmirror.com && \
+    pnpm install --frozen-lockfile
+
+# Stage 2: Build
+FROM deps AS build
+
+COPY . .
+RUN pnpm build
+
+# Stage 3: Runtime
+FROM node:22-bookworm-slim AS runtime
+
+RUN sed -i 's|deb.debian.org|mirrors.aliyun.com|g' /etc/apt/sources.list.d/debian.sources
+
+RUN apt-get update && \
+    apt-get install -y --no-install-recommends ffmpeg python3 python3-pip && \
+    rm -rf /var/lib/apt/lists/*
+
+RUN pip3 install --break-system-packages -i https://mirrors.aliyun.com/pypi/simple/ faster-whisper
+
+WORKDIR /app
+
+COPY --from=build /app/package.json ./
+COPY --from=build /app/node_modules node_modules/
+COPY --from=build /app/apps/cli/dist apps/cli/dist/
+COPY --from=build /app/apps/cli/package.json apps/cli/
+COPY --from=build /app/apps/web/.next apps/web/.next/
+COPY --from=build /app/apps/web/node_modules apps/web/node_modules/
+COPY --from=build /app/apps/web/package.json apps/web/
+COPY --from=build /app/apps/web/next.config.ts apps/web/
+COPY --from=build /app/apps/web/src apps/web/src/
+COPY --from=build /app/packages/shared/dist packages/shared/dist/
+COPY --from=build /app/packages/shared/package.json packages/shared/
+COPY --from=build /app/packages/core/dist packages/core/dist/
+COPY --from=build /app/packages/core/package.json packages/core/
+COPY --from=build /app/packages/tts/dist packages/tts/dist/
+COPY --from=build /app/packages/tts/package.json packages/tts/
+COPY --from=build /app/packages/tts/scripts packages/tts/scripts/
+COPY --from=build /app/packages/templates/dist packages/templates/dist/
+COPY --from=build /app/packages/templates/src packages/templates/src/
+COPY --from=build /app/packages/templates/package.json packages/templates/
+COPY --from=build /app/packages/collect/dist packages/collect/dist/
+COPY --from=build /app/packages/collect/package.json packages/collect/
+COPY --from=build /app/assets assets/
+COPY --from=build /app/config config/
+
+EXPOSE 3000
+
+WORKDIR /app/apps/web
+CMD ["./node_modules/.bin/next", "start"]

+ 4 - 2
apps/web/src/app/api/download/route.ts

@@ -1,5 +1,6 @@
 import { NextResponse } from "next/server";
 import { readFileSync, existsSync, statSync } from "node:fs";
+import { resolve } from "node:path";
 
 export async function GET(request: Request) {
   const { searchParams } = new URL(request.url);
@@ -10,8 +11,9 @@ export async function GET(request: Request) {
     return NextResponse.json({ error: "Missing file parameter" }, { status: 400 });
   }
 
-  // Security: only allow files under the project output directory or /tmp/pipeline-jobs
-  if (!filePath.startsWith("/persist/lkatzey/") && !filePath.startsWith("/tmp/pipeline-jobs/")) {
+  // Security: only allow files under the output directory or job store
+  const outputDir = resolve(process.cwd(), "output");
+  if (!filePath.startsWith(outputDir) && !filePath.startsWith("/tmp/pipeline-jobs/")) {
     return NextResponse.json({ error: "Access denied" }, { status: 403 });
   }
 

+ 22 - 0
docker-compose.yml

@@ -0,0 +1,22 @@
+services:
+  pipeline:
+    build: .
+    ports:
+      - "${PORT:-13000}:3000"
+    environment:
+      - OPENAI_API_KEY=${OPENAI_API_KEY}
+      - OPENAI_BASE_URL=${OPENAI_BASE_URL}
+      - OPENAI_TTS_API_KEY=${OPENAI_TTS_API_KEY}
+      - OPENAI_TTS_BASE_URL=${OPENAI_TTS_BASE_URL}
+      - FISH_AUDIO_API_KEY=${FISH_AUDIO_API_KEY}
+      - MINIMAX_API_KEY=${MINIMAX_API_KEY}
+      - MINIMAX_GROUP_ID=${MINIMAX_GROUP_ID}
+      - ELEVENLABS_API_KEY=${ELEVENLABS_API_KEY}
+    volumes:
+      - pipeline-output:/app/apps/web/output
+      - pipeline-jobs:/tmp/pipeline-jobs
+    restart: unless-stopped
+
+volumes:
+  pipeline-output:
+  pipeline-jobs: