From 37b52545a231d8749bc43490d619fd1538312724 Mon Sep 17 00:00:00 2001 From: Sun-ZhenXing <1006925066@qq.com> Date: Wed, 15 Oct 2025 20:38:26 +0800 Subject: [PATCH] feat: update opencut --- src/opencut/.env.example | 73 +++++++++++++--- src/opencut/README.md | Bin 2224 -> 9920 bytes src/opencut/README.zh.md | 144 ++++++++++++++++++++++++-------- src/opencut/docker-compose.yaml | 111 +++++++++++++++--------- 4 files changed, 247 insertions(+), 81 deletions(-) diff --git a/src/opencut/.env.example b/src/opencut/.env.example index 5e31c4a..d1c17d9 100644 --- a/src/opencut/.env.example +++ b/src/opencut/.env.example @@ -1,12 +1,65 @@ -# FreeSound API 配置 -FREESOUND_CLIENT_ID=your_freesound_client_id -FREESOUND_API_KEY=your_freesound_api_key +# ============================================================================ +# OpenCut Configuration +# ============================================================================ -# Cloudflare R2 配置(可选,用于转录功能) -CLOUDFLARE_ACCOUNT_ID=your_cloudflare_account_id -R2_ACCESS_KEY_ID=your_r2_access_key_id -R2_SECRET_ACCESS_KEY=your_r2_secret_access_key -R2_BUCKET_NAME=your_r2_bucket_name +# Timezone (optional, default: UTC) +TZ=UTC -# Modal 转录服务 URL(可选) -MODAL_TRANSCRIPTION_URL=your_modal_transcription_url +# ---------------------------------------------------------------------------- +# Version Configuration +# ---------------------------------------------------------------------------- +POSTGRES_VERSION=17 +REDIS_VERSION=7-alpine +SERVERLESS_REDIS_HTTP_VERSION=latest +# Note: OpenCut web image needs to be built from source +# See: https://github.com/OpenCut-app/OpenCut +OPENCUT_WEB_IMAGE=opencut/web:latest + +# ---------------------------------------------------------------------------- +# Port Override Configuration +# ---------------------------------------------------------------------------- +# PostgreSQL port (default: 5432) +POSTGRES_PORT_OVERRIDE=5432 +# Redis port (default: 6379) +REDIS_PORT_OVERRIDE=6379 +# Serverless Redis HTTP port (default: 8079) +SERVERLESS_REDIS_HTTP_PORT_OVERRIDE=8079 +# OpenCut web port (default: 3100) +OPENCUT_WEB_PORT_OVERRIDE=3100 + +# ---------------------------------------------------------------------------- +# PostgreSQL Configuration +# ---------------------------------------------------------------------------- +POSTGRES_USER=opencut +POSTGRES_PASSWORD=change-me-to-secure-password +POSTGRES_DB=opencut + +# ---------------------------------------------------------------------------- +# Redis Configuration +# ---------------------------------------------------------------------------- +# Token for serverless Redis HTTP interface +SERVERLESS_REDIS_HTTP_TOKEN=change-me-to-random-token + +# ---------------------------------------------------------------------------- +# OpenCut Application Configuration +# ---------------------------------------------------------------------------- +# Better Auth configuration +OPENCUT_BETTER_AUTH_URL=http://localhost:3100 +OPENCUT_BETTER_AUTH_SECRET=change-me-to-random-secret-key + +# FreeSound API configuration (required) +OPENCUT_FREESOUND_CLIENT_ID=your_freesound_client_id +OPENCUT_FREESOUND_API_KEY=your_freesound_api_key + +# ---------------------------------------------------------------------------- +# Optional: Transcription Features +# Leave blank to disable auto-captioning +# ---------------------------------------------------------------------------- +# Cloudflare R2 configuration +OPENCUT_CLOUDFLARE_ACCOUNT_ID= +OPENCUT_R2_ACCESS_KEY_ID= +OPENCUT_R2_SECRET_ACCESS_KEY= +OPENCUT_R2_BUCKET_NAME= + +# Modal transcription service URL +OPENCUT_MODAL_TRANSCRIPTION_URL= diff --git a/src/opencut/README.md b/src/opencut/README.md index 05fdceb74220899751996d6d36f7e6a250275746..6dc552e0cb0aafa0cab31ed29535859ea78a4897 100644 GIT binary patch literal 9920 zcmb`N+in|25{CO)H~R{+FtD2hkr>;todk;oWXdN*2S=1*c#VZbNtC4xMQTMU8wa`1 zYvf6j{l6}jx@R~uB;|mRIP61Jb)Bnv{`mb~D8f#-41+KV-Eb4G!-_ud!ZZDTABN#P zOu||Cclac%g-+Pj_Zu&jUT3i_-H*qwPG=cwg(8Va=s>j^o~mAo)_|Zg33r4b4yWWV@gSN`N&EA8uinPxZN0ebD@kzDHUO z&4u8N!#5G$ec>*`_qTZ9;PZ%m5PEUnNITZ_bR{{!*E8+D7S@R%bo4o$t~Ng9t2qYr$Idj0 z?_>owYFdWJIMvLJsJIS)jgmIb8x=jBcvt>_|C{;`{)0%-hHQc7m!fe`v>oXGPWV=9 zwx^WsMvNy@Oq?A%!7j~X6@p_v6Z>;GX1jQWt4JAsw#=CwVFODy>ZN>D)fpwLE6?Q3p{nZx_N^^=i3a!(+IY?Tfm_tme5+$r-QpA1$0j zzMp5X;QK&x*O4381Ch$CscIQj`NLZ{y&)cMO8#U6=s{N>lR)BmJO6g&AAG0lIvV}< zR%VOr&-Jbz+Tk2I8XZq{rf!rQ^l$4#5kS6cU4Bd;{S zt+{=TY({7+;ma7ek~eq%WfHiG-Wofc@0qc7VguHT{^DgW_1`?xjh>6JDxc(hOrH5s zq+wlqz(jVGs7R3#Tg*KJo)_!=$88>BSqM208NpEFV80ga55xWNg+Bijc8_Mg2#siD zSeY@;XE@DD_XGvMS&o+}f?M3gR`V>xA)UxK8=TiuTHcF0U>c;KK>aE-T4|$p4Z#&f^`QnF)LP-a5or9(}3Ud8h4)0@OeGD|z!W)lFJBkHR<7m?LRMy(cejqsU@X^hkpglm5+S>UZ;V`!TcKm8|OX{~K8* z7Qeg|C9SK|{<~ElXgl>2ktnaX7;`^2i)}-`qv?EiJ6DoJZY7IIU>QrO)r>7?7V~m@;a^ie?`c0i_vaXc+kGz;RyXq%RjX^N$UNsnZ`Y^wRW-*f zrkQD*m-L>~{9G?-^rAH8*}G|AnbK;-*e)fD<5k?tREV?Px4OFU&!VEPTCAg>TqCw) zPntSgJ?_abG*yJ{wz(-??Zjb=BAumn_Fp||VPEU`H%|v6?X~D-+*^iZDkwvF^ z)_Q?fIje5z$X9gMMAYN94-;!iDNbyf#&r;pfhy zr&XzDw{Bk3f7W-E8Sm>m!LqxPEy1~nbkMP^&iXE+$uL?U6`19{b!%4Q{miPYaIufk zG`qHG+*W?fY=U64dKaRJm-#q6pw~>lVRrmQX)MjN>kI9ARM}-Kn0=&*^ntjW_LQG~ zk+!goor&;s&DgI*0;EYzdpQcM42@QzlEqGEQ|QEo|{j6at~6 z@%*NVe)>omAwgp)pKjfN$5kHjp4<3KjTy% zJO_9Dc$l(ujbl}vt9zg3V>FESHk=;(7_i*q<@!P;obzu@yrTm@{L|kh>ByF;iH{@+ z-g<$aPDyv0Y02M0p&EhX+$9^|UkfgAh~E|)Og65K=mIn2xsowI_8+Y_zwc3FSi)&u N+vYfl=NH(-{{a$GDZ&5% literal 2224 zcmZ`*+iu%N5Pj!Y4B!_>fGEdKZ$?o-q3A}4EUA=~A}|7RMGmEHC@#CZl&wJT{e%8R z-}^yDzoRot>SER5gGKJno;f?0GroXPiA7LZ&wB`qWiHL?)1}{u!fx+A^w;St*uld; zfB*IGpMRXJe_8RC=QU?R8W062LTVdT=>%aTQ&fPdw6a*zW(uN8rGiqc1dZXvG8Z;e zdhL7O#RZHtYW%&DMp`tU_u7XK{0Gt zGj1K@enFQLx%}eL9OXcjTd*qxd=l$2r{7{DwJO#Ok;xoyJr4llI9>>|;@6}EpN#zd z0sd%AJjY%YnOs&H9juFx#`GEPMrbJ(IU2Y`Q({7#@+};~2Fy8WU>sFS9NlnYg|-gW zpx(&j|J+iQd`3-Y*QGKDRSE6%!0n9>-Go!=ARci+;k2kTLCF^ue&jq+nsSwhe5H)N zy?K3g^^*(Sr1nQyZbQsPlTy9k}97qiG*EhG>z%F{+#?WfK*sP0Yzs< z;gNfrh~FU*$%^*4%7W84u>V%;S8~-oRz<6I3u8r*VZP4b#8IztbTInn&CRtlsyzkl z>9G0j&38YXY`&XL$I#sUVDtSI*?2qn&?J#c;_TT$4^5(F>1y_D(|ztB;?Ci^*b!9w zYY(;Z*S4DV6AK3w-$h|K8O?^hc`)dQ!|A-=iyNQE0z0`+SiPZ@d73BPV z_%Uv*cW1Rq{nhO3f6k$T!D!aI8+4;^-VFkxx97EkAXinI<$@Zf(Ex7U!21D^`(VEtns+Be>;b|AN9I}`84VdCqdL7Py3_cd=?F2Vs)=lk%QHu zIM!FA1wbZbaS|)9btp0t?Xy!E=`LxM@nL{sgRsa&@fl=BqHk3@5w3Pw^QjvPMbr^f zOnr|cVV ztVFS_6f9&s`s;sMOhHR4aEg{xIS%x(}Pc>#RX-zu3$$!!i+|26S;?x zmP^SNwaT{}mG`$|ogb&{QrcCu@M*KtNOPNHdH>#7LBLHFqfzhOeNlI}ornom+H`M(4=xqR +5. 访问 Web 界面: ## 服务 -- `opencut`: OpenCut Web 应用。 -- `postgres`: PostgreSQL 数据库。 -- `redis`: Redis 缓存。 +- `web`:OpenCut Web 应用程序 +- `db`:PostgreSQL 数据库 +- `redis`:Redis 缓存 +- `serverless-redis-http`:用于 Upstash 兼容性的 Redis HTTP 接口 ## 配置 -- **Web 应用**: 端口 3100 -- **PostgreSQL 数据库**: 端口 5432 -- **Redis 缓存**: 端口 6379 -- **Redis HTTP 服务**: 端口 8079 +### 版本配置 -| 变量 | 描述 | 必需 | -| ------------------------- | ------------------- | ---- | -| `FREESOUND_CLIENT_ID` | FreeSound 客户端 ID | 是 | -| `FREESOUND_API_KEY` | FreeSound API 密钥 | 是 | -| `CLOUDFLARE_ACCOUNT_ID` | Cloudflare 账户 ID | 否* | -| `R2_ACCESS_KEY_ID` | R2 访问密钥 ID | 否* | -| `R2_SECRET_ACCESS_KEY` | R2 密钥 | 否* | -| `R2_BUCKET_NAME` | R2 存储桶名称 | 否* | -| `MODAL_TRANSCRIPTION_URL` | Modal 转录服务 URL | 否* | +- `POSTGRES_VERSION`:PostgreSQL 版本,默认为 `17` +- `REDIS_VERSION`:Redis 版本,默认为 `7-alpine` +- `SERVERLESS_REDIS_HTTP_VERSION`:Serverless Redis HTTP 版本,默认为 `latest` +- `OPENCUT_WEB_IMAGE`:OpenCut web 镜像名称,默认为 `opencut/web:latest` -*用于转录功能,如果不需要自动字幕功能可以留空。 +### 端口配置 -## 数据持久化 +- `POSTGRES_PORT_OVERRIDE`:PostgreSQL 主机端口,默认为 `5432` +- `REDIS_PORT_OVERRIDE`:Redis 主机端口,默认为 `6379` +- `SERVERLESS_REDIS_HTTP_PORT_OVERRIDE`:Redis HTTP 接口主机端口,默认为 `8079` +- `OPENCUT_WEB_PORT_OVERRIDE`:Web 应用程序主机端口,默认为 `3100` -- PostgreSQL 数据存储在 `postgres_data` 卷中 -- Redis 数据在内存中,重启后会丢失 +### 数据库配置 -## 安全说明 +- `POSTGRES_USER`:数据库用户名,默认为 `opencut` +- `POSTGRES_PASSWORD`:数据库密码,**必需** +- `POSTGRES_DB`:数据库名称,默认为 `opencut` -- 在生产环境中更改默认的数据库密码 -- 更新 `BETTER_AUTH_SECRET` 为一个安全的随机字符串 -- 考虑为外部访问设置反向代理 +### Redis 配置 + +- `SERVERLESS_REDIS_HTTP_TOKEN`:Redis HTTP 接口的令牌,**必需** + +### 应用程序配置 + +- `TZ`:时区,默认为 `UTC` +- `OPENCUT_BETTER_AUTH_URL`:身份验证服务 URL,默认为 `http://localhost:3100` +- `OPENCUT_BETTER_AUTH_SECRET`:身份验证密钥,**必需** +- `OPENCUT_FREESOUND_CLIENT_ID`:FreeSound 客户端 ID,**必需** +- `OPENCUT_FREESOUND_API_KEY`:FreeSound API 密钥,**必需** + +### 可选转录配置 + +留空以禁用自动字幕功能: + +- `OPENCUT_CLOUDFLARE_ACCOUNT_ID`:Cloudflare 账户 ID +- `OPENCUT_R2_ACCESS_KEY_ID`:R2 访问密钥 ID +- `OPENCUT_R2_SECRET_ACCESS_KEY`:R2 秘密访问密钥 +- `OPENCUT_R2_BUCKET_NAME`:R2 存储桶名称 +- `OPENCUT_MODAL_TRANSCRIPTION_URL`:Modal 转录服务 URL + +## 数据卷 + +- `postgres_data`:PostgreSQL 数据存储 + +## 资源限制 + +| 服务 | CPU 限制 | 内存限制 | CPU 预留 | 内存预留 | +| --------------------- | -------- | -------- | -------- | -------- | +| web | 2.00 | 2G | 0.50 | 512M | +| db | 2.00 | 1G | 0.50 | 256M | +| redis | 1.00 | 512M | 0.25 | 128M | +| serverless-redis-http | 1.00 | 256M | 0.25 | 64M | + +## 安全提示 + +⚠️ **重要安全建议:** + +- **在生产环境部署前修改所有默认密码和密钥** +- 为以下变量使用强随机生成的值: + - `POSTGRES_PASSWORD` + - `SERVERLESS_REDIS_HTTP_TOKEN` + - `OPENCUT_BETTER_AUTH_SECRET` +- 切勿将包含真实凭据的 `.env` 文件提交到版本控制系统 +- 考虑设置带 HTTPS 的反向代理以供外部访问 +- 在生产环境中将数据库和 Redis 端口限制在内部网络 +- 妥善保管 FreeSound API 密钥 + +## 从源代码构建 + +由于 OpenCut 不提供预构建的 Docker 镜像,您需要自行构建: + +```bash +# 克隆 OpenCut 仓库 +git clone https://github.com/OpenCut-app/OpenCut.git +cd OpenCut + +# 构建 web 镜像 +docker build -t opencut/web:latest -f apps/web/Dockerfile . + +# 返回到您的 compose 目录并启动服务 +cd /path/to/compose-anything/src/opencut +docker compose up -d +``` + +## 参考 + +- [OpenCut 官方仓库](https://github.com/OpenCut-app/OpenCut) +- [原始 docker-compose.yaml](https://github.com/OpenCut-app/OpenCut/blob/main/docker-compose.yaml) ## 许可证 -请参考官方 OpenCut 项目的许可信息。 +请参考 OpenCut 官方项目的许可证信息。 diff --git a/src/opencut/docker-compose.yaml b/src/opencut/docker-compose.yaml index e4f9672..aef3413 100644 --- a/src/opencut/docker-compose.yaml +++ b/src/opencut/docker-compose.yaml @@ -1,41 +1,67 @@ +x-default: &default + restart: unless-stopped + logging: + driver: json-file + options: + max-size: 100m + max-file: "3" + services: db: - image: postgres:17 - restart: unless-stopped + <<: *default + image: postgres:${POSTGRES_VERSION:-17} environment: - POSTGRES_USER: opencut - POSTGRES_PASSWORD: opencutthegoat - POSTGRES_DB: opencut + TZ: ${TZ:-UTC} + POSTGRES_USER: ${POSTGRES_USER:-opencut} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required} + POSTGRES_DB: ${POSTGRES_DB:-opencut} volumes: - postgres_data:/var/lib/postgresql/data ports: - - "5432:5432" + - "${POSTGRES_PORT_OVERRIDE:-5432}:5432" healthcheck: - test: ["CMD-SHELL", "pg_isready -U opencut"] + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-opencut}"] interval: 30s timeout: 10s retries: 5 start_period: 10s + deploy: + resources: + limits: + cpus: '2.00' + memory: 1G + reservations: + cpus: '0.50' + memory: 256M redis: - image: redis:7-alpine - restart: unless-stopped + <<: *default + image: redis:${REDIS_VERSION:-7-alpine} ports: - - "6379:6379" + - "${REDIS_PORT_OVERRIDE:-6379}:6379" healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 30s timeout: 10s retries: 5 start_period: 10s + deploy: + resources: + limits: + cpus: '1.00' + memory: 512M + reservations: + cpus: '0.25' + memory: 128M serverless-redis-http: - image: hiett/serverless-redis-http:latest + <<: *default + image: hiett/serverless-redis-http:${SERVERLESS_REDIS_HTTP_VERSION:-latest} ports: - - "8079:80" + - "${SERVERLESS_REDIS_HTTP_PORT_OVERRIDE:-8079}:80" environment: SRH_MODE: env - SRH_TOKEN: example_token + SRH_TOKEN: ${SERVERLESS_REDIS_HTTP_TOKEN:?SERVERLESS_REDIS_HTTP_TOKEN is required} SRH_CONNECTION_STRING: "redis://redis:6379" depends_on: redis: @@ -46,31 +72,36 @@ services: timeout: 10s retries: 5 start_period: 10s + deploy: + resources: + limits: + cpus: '1.00' + memory: 256M + reservations: + cpus: '0.25' + memory: 64M + web: - build: - context: . - dockerfile: ./apps/web/Dockerfile - args: - - FREESOUND_CLIENT_ID=${FREESOUND_CLIENT_ID} - - FREESOUND_API_KEY=${FREESOUND_API_KEY} - restart: unless-stopped + <<: *default + image: ${OPENCUT_WEB_IMAGE:-opencut/web:latest} ports: - - "3100:3000" # app is running on 3000 so we run this at 3100 + - "${OPENCUT_WEB_PORT_OVERRIDE:-3100}:3000" environment: - - NODE_ENV=production - - DATABASE_URL=postgresql://opencut:opencutthegoat@db:5432/opencut - - BETTER_AUTH_URL=http://localhost:3000 - - BETTER_AUTH_SECRET=your-production-secret-key-here - - UPSTASH_REDIS_REST_URL=http://serverless-redis-http:80 - - UPSTASH_REDIS_REST_TOKEN=example_token - - FREESOUND_CLIENT_ID=${FREESOUND_CLIENT_ID} - - FREESOUND_API_KEY=${FREESOUND_API_KEY} + TZ: ${TZ:-UTC} + NODE_ENV: production + DATABASE_URL: postgresql://${POSTGRES_USER:-opencut}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB:-opencut} + BETTER_AUTH_URL: ${OPENCUT_BETTER_AUTH_URL:-http://localhost:3100} + BETTER_AUTH_SECRET: ${OPENCUT_BETTER_AUTH_SECRET:?OPENCUT_BETTER_AUTH_SECRET is required} + UPSTASH_REDIS_REST_URL: http://serverless-redis-http:80 + UPSTASH_REDIS_REST_TOKEN: ${SERVERLESS_REDIS_HTTP_TOKEN} + FREESOUND_CLIENT_ID: ${OPENCUT_FREESOUND_CLIENT_ID:?OPENCUT_FREESOUND_CLIENT_ID is required} + FREESOUND_API_KEY: ${OPENCUT_FREESOUND_API_KEY:?OPENCUT_FREESOUND_API_KEY is required} # Transcription (Optional - leave blank to disable auto-captions) - - CLOUDFLARE_ACCOUNT_ID=${CLOUDFLARE_ACCOUNT_ID} - - R2_ACCESS_KEY_ID=${R2_ACCESS_KEY_ID} - - R2_SECRET_ACCESS_KEY=${R2_SECRET_ACCESS_KEY} - - R2_BUCKET_NAME=${R2_BUCKET_NAME} - - MODAL_TRANSCRIPTION_URL=${MODAL_TRANSCRIPTION_URL} + CLOUDFLARE_ACCOUNT_ID: ${OPENCUT_CLOUDFLARE_ACCOUNT_ID:-} + R2_ACCESS_KEY_ID: ${OPENCUT_R2_ACCESS_KEY_ID:-} + R2_SECRET_ACCESS_KEY: ${OPENCUT_R2_SECRET_ACCESS_KEY:-} + R2_BUCKET_NAME: ${OPENCUT_R2_BUCKET_NAME:-} + MODAL_TRANSCRIPTION_URL: ${OPENCUT_MODAL_TRANSCRIPTION_URL:-} depends_on: db: condition: service_healthy @@ -82,10 +113,14 @@ services: timeout: 10s retries: 5 start_period: 30s + deploy: + resources: + limits: + cpus: '2.00' + memory: 2G + reservations: + cpus: '0.50' + memory: 512M volumes: postgres_data: - -networks: - default: - name: opencut-network