auto-save 2026-05-15 14:47 (+6, ~5)

This commit is contained in:
2026-05-15 14:48:01 +08:00
parent ce04cf4b60
commit 27e200239d
12 changed files with 333 additions and 20 deletions

23
.dockerignore Normal file
View File

@@ -0,0 +1,23 @@
.git
.gitignore
.memory
.logs
.pids
.playwright-mcp
.DS_Store
*.log
node_modules
web/node_modules
web/.next
web/out
api/.venv
api/jobs
jobs
data
.env
.env.local
.env.production
deploy/.env.production

1
.gitignore vendored
View File

@@ -14,6 +14,7 @@ __pycache__/
*.log
.logs/
.pids/
deploy/.env.production
# api
api/.venv/

View File

@@ -1,18 +1,5 @@
{
"entries": [
{
"files_changed": 2,
"hash": "dd2e8c9",
"message": "auto-save 2026-05-13 23:17 (~2)",
"ts": "2026-05-13T23:18:31+08:00",
"type": "commit"
},
{
"files_changed": 1,
"message": "Claude 会话活跃 · 最近命令claude · 1 项未提交变更 · 最近提交auto-save 2026-05-13 23:17 (~2)",
"ts": "2026-05-13T15:23:08Z",
"type": "session-heartbeat"
},
{
"files_changed": 1,
"hash": "38091d3",
@@ -3251,6 +3238,19 @@
"message": "auto-save 2026-05-15 14:33 (~1)",
"hash": "8090674",
"files_changed": 1
},
{
"ts": "2026-05-15T14:42:29+08:00",
"type": "commit",
"message": "auto-save 2026-05-15 14:42 (~1)",
"hash": "ce04cf4",
"files_changed": 1
},
{
"ts": "2026-05-15T06:44:46Z",
"type": "session-heartbeat",
"message": "Codex 会话活跃 · 最近命令codex · 5 项未提交变更 · 最近提交auto-save 2026-05-15 14:42 (~1)",
"files_changed": 5
}
]
}

View File

@@ -2,16 +2,28 @@
"company" : "SKG",
"created" : "2026-05-12",
"credentials" : [
{
"description" : "SKG AI 网关 API Key生产只放服务器 deploy/.env.production 的 LLM_API_KEY本地开发放 api/.env不入库",
"name" : "LLM_API_KEY",
"storage" : "api/.env / deploy/.env.production",
"type" : "api_key"
},
{
"description" : "MiniMax T2A 配音 API Key本地开发只放 api/.env 的 MINIMAX_API_KEY不入库",
"name" : "MINIMAX_API_KEY",
"storage" : "api/.env",
"type" : "api_key"
},
{
"description" : "SKG 豆包 / Seedance 视频生成 API Key生产只放服务器 deploy/.env.production 的 VIDEO_API_KEY本地开发放 api/.env不入库",
"name" : "VIDEO_API_KEY",
"storage" : "api/.env / deploy/.env.production",
"type" : "api_key"
}
],
"description" : "SKG AI 素材生产管线第二条思路验证TK 链接 → 拆轨 → 目标化关键帧 + ASR\/翻译 → 接 SKG 产品信息改写口播 → MiniMax 配音 → nano-banana-pro\/GPT Image 生图 → Seedance\/Kling\/Veo3 多模型生视频 → 合成带文案成品",
"kind" : "app",
"name" : "SKG AI 素材管线 - TK 二创验证",
"name" : "SKG Marketing Studio / SKG 营销内容工作台",
"ownership" : "company",
"pin_order" : 1778664997,
"pinned" : true,
@@ -32,7 +44,21 @@
],
"status" : "active",
"urls" : [
{
"label" : "production",
"type" : "app",
"url" : "https://marketing.skg.com"
},
{
"label" : "production-api",
"type" : "backend",
"url" : "https://marketing.skg.com/api"
},
{
"label" : "source-analysis",
"type" : "docs",
"url" : "docs/source-analysis.html"
}
],
"worklog" : {
"auto" : true,

22
Dockerfile.api Normal file
View File

@@ -0,0 +1,22 @@
FROM python:3.12-slim
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1 \
JOBS_DIR=/data/jobs
WORKDIR /app
RUN apt-get update \
&& apt-get install -y --no-install-recommends ffmpeg ca-certificates curl \
&& rm -rf /var/lib/apt/lists/*
COPY api/requirements.txt /app/requirements.txt
RUN pip install --no-cache-dir -r /app/requirements.txt
COPY api /app
RUN mkdir -p /data/jobs
EXPOSE 4291
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "4291", "--proxy-headers"]

22
Dockerfile.web Normal file
View File

@@ -0,0 +1,22 @@
FROM node:22-bookworm-slim AS builder
WORKDIR /app
RUN corepack enable && corepack prepare pnpm@10.28.2 --activate
COPY web/package.json web/pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
COPY web ./
ARG NEXT_PUBLIC_API_BASE=/api
ENV NEXT_PUBLIC_API_BASE=${NEXT_PUBLIC_API_BASE}
RUN pnpm build
FROM nginx:1.27-alpine
COPY deploy/nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=builder /app/out /usr/share/nginx/html
EXPOSE 80

View File

@@ -13,12 +13,16 @@
- 第一冲刺:步骤 1-4下载 / 拆轨 / 关键帧 / ASR+翻译)
## 部署事实
- 平台:待定
- 发布状态:未部署
- 主站 / 前端:待定
- API / 后端:待定
- 文档 / 解析:待定
- 平台:VPS `76.13.31.179`Ubuntu 24.04 / Docker Compose / Coolify Traefik
- 发布状态:生产部署配置已生成;公司域名 `marketing.skg.com` 已解析到 VPS待执行 Compose 上线和 HTTPS 验证
- 主站 / 前端:`https://marketing.skg.com`
- API / 后端:`https://marketing.skg.com/api`
- 文档 / 解析:`docs/source-analysis.html`(项目内独立文档,不公开挂主应用路由)
- 管理后台:待定
- 服务器目录:`/opt/skg-marketing-studio`
- 生产启动:`docker compose -f docker-compose.prod.yml --env-file deploy/.env.production up -d --build`
- 生产架构:`web` 容器用 Nginx 承载 Next 静态导出并反代 `/api/``api` 容器跑 FastAPI 4291Traefik 通过 `coolify` 外部网络接入 80/443
- 持久化目录:服务器 `./data/jobs` 挂载到后端 `/data/jobs`
## 快捷登录
- 登录地址:待补充
@@ -45,6 +49,7 @@
- `MINIMAX_TTS_BASE_URL` / `MINIMAX_TTS_MODEL` / `MINIMAX_TTS_VOICE_ID`MiniMax 配音端点、模型和兜底音色配置
- `MINIMAX_TTS_VOICE_POOL`MiniMax 英文随机音色池;当前默认男声 `English_magnetic_voiced_man`、女声 `English_Upbeat_Woman`、成熟声 `English_MaturePartner`
- `POE_API_KEY` / `VIDEO_API_KEY`:视频生成通道 Key只能放本地环境变量
- 生产环境变量:服务器只使用 `deploy/.env.production`,模板为 `deploy/.env.production.example`;真实 Key 不入库
## 规则
- 不允许编造不存在的部署域名、账号、密码

View File

@@ -0,0 +1,43 @@
# Copy this file to deploy/.env.production on the VPS.
# Keep real API keys out of git.
# Runtime
JOBS_DIR=/data/jobs
KEYFRAME_COUNT=12
CORS_ORIGINS=https://marketing.skg.com
API_PORT=4291
# SKG AI gateway, OpenAI-compatible
LLM_BASE_URL=https://ai.skg.com/ezlink/v1
LLM_API_KEY=
# Model routing
ASR_MODEL=whisper-1
ASR_FALLBACK_MODEL=gemini-2.5-flash
TRANSLATE_MODEL=gemini-2.5-flash
REWRITE_MODEL=gemini-2.5-pro
IMAGE_MODEL=gemini-3-pro-image-preview
# Audio rewrite and MiniMax TTS
AUDIO_REWRITE_MODEL=gemini-2.5-pro
AUDIO_PRODUCT_BRIEF="SKG smart massage products for daily neck, shoulder, back, eye, knee, and foot relaxation. Keep claims premium, clean, credible, and non-medical."
MINIMAX_API_KEY=
MINIMAX_TTS_BASE_URL=https://api.minimax.io
MINIMAX_TTS_MODEL=speech-2.8-turbo
MINIMAX_TTS_VOICE_ID=English_expressive_narrator
MINIMAX_TTS_VOICE_POOL=English_magnetic_voiced_man,English_Upbeat_Woman,English_MaturePartner
# Video generation. Use SKG Doubao / Seedance gateway in production.
POE_API_BASE_URL=https://api.poe.com/v1
POE_API_KEY=
VIDEO_API_BASE_URL=https://ai.skg.com/doubao
VIDEO_API_KEY=
VIDEO_MODEL=seedance
VIDEO_MODEL_SEEDANCE=doubao-seedance-2-0-fast-260128
VIDEO_MODEL_KLING=kling-omni
VIDEO_MODEL_VEO3=veo-3.1-fast
VIDEO_CREATE_PATHS=/api/v3/contents/generations/tasks
VIDEO_STATUS_PATH=/api/v3/contents/generations/tasks/{id}
VIDEO_CONTENT_PATH=/api/v3/contents/generations/tasks/{id}/content
VIDEO_DURATION_FIELD=seconds
VIDEO_POLL_TIMEOUT_SECONDS=900

32
deploy/nginx.conf Normal file
View File

@@ -0,0 +1,32 @@
server {
listen 80;
server_name _;
client_max_body_size 2g;
gzip on;
gzip_types text/plain text/css application/json application/javascript application/xml image/svg+xml;
location = /api {
return 308 /api/;
}
location /api/ {
proxy_pass http://api:4291/;
proxy_http_version 1.1;
proxy_request_buffering off;
proxy_buffering off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 1800s;
proxy_send_timeout 1800s;
proxy_connect_timeout 60s;
}
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;
}
}

55
docker-compose.prod.yml Normal file
View File

@@ -0,0 +1,55 @@
name: skg-marketing-studio
services:
api:
build:
context: .
dockerfile: Dockerfile.api
container_name: skg-marketing-api
env_file:
- ./deploy/.env.production
environment:
JOBS_DIR: /data/jobs
CORS_ORIGINS: https://marketing.skg.com
volumes:
- ./data/jobs:/data/jobs
restart: unless-stopped
networks:
- skg-marketing-internal
web:
build:
context: .
dockerfile: Dockerfile.web
args:
NEXT_PUBLIC_API_BASE: /api
container_name: skg-marketing-web
depends_on:
- api
restart: unless-stopped
networks:
- skg-marketing-internal
- coolify
labels:
- "traefik.enable=true"
- "traefik.docker.network=coolify"
- "traefik.http.middlewares.skg-marketing-gzip.compress=true"
- "traefik.http.middlewares.skg-marketing-redirect.redirectscheme.scheme=https"
- "traefik.http.routers.skg-marketing-http.entryPoints=http"
- "traefik.http.routers.skg-marketing-http.rule=Host(`marketing.skg.com`) && PathPrefix(`/`)"
- "traefik.http.routers.skg-marketing-http.middlewares=skg-marketing-redirect"
- "traefik.http.routers.skg-marketing-http.service=skg-marketing-http"
- "traefik.http.routers.skg-marketing-https.entryPoints=https"
- "traefik.http.routers.skg-marketing-https.rule=Host(`marketing.skg.com`) && PathPrefix(`/`)"
- "traefik.http.routers.skg-marketing-https.middlewares=skg-marketing-gzip"
- "traefik.http.routers.skg-marketing-https.tls=true"
- "traefik.http.routers.skg-marketing-https.tls.certresolver=letsencrypt"
- "traefik.http.routers.skg-marketing-https.service=skg-marketing-https"
- "traefik.http.services.skg-marketing-http.loadbalancer.server.port=80"
- "traefik.http.services.skg-marketing-https.loadbalancer.server.port=80"
networks:
skg-marketing-internal:
name: skg-marketing-internal
coolify:
external: true

63
docs/deploy-vps.md Normal file
View File

@@ -0,0 +1,63 @@
# SKG Marketing Studio VPS Deployment
Production domain:
- App: `https://marketing.skg.com`
- API: `https://marketing.skg.com/api`
Current VPS target:
- Host: `76.13.31.179`
- OS: Ubuntu 24.04
- Runtime: Docker Compose
- Public ingress: existing Coolify Traefik on ports 80/443
DNS:
```text
marketing.skg.com A 76.13.31.179
```
Do not run a host Nginx on ports 80/443. Those ports are already owned by Coolify / Traefik. This project publishes through Docker labels on the external `coolify` network.
## First Deploy
On the VPS:
```bash
mkdir -p /opt/skg-marketing-studio
cd /opt/skg-marketing-studio
cp deploy/.env.production.example deploy/.env.production
```
Fill `deploy/.env.production` with the real production keys. Keep this file out of git.
Then start:
```bash
docker compose -f docker-compose.prod.yml --env-file deploy/.env.production up -d --build
```
Verify:
```bash
curl -I https://marketing.skg.com
curl https://marketing.skg.com/api/health
docker compose -f docker-compose.prod.yml ps
```
## Update
Sync the repo to `/opt/skg-marketing-studio`, then run:
```bash
docker compose -f docker-compose.prod.yml --env-file deploy/.env.production up -d --build
```
## Runtime Notes
- `web` is a static Next export served by Nginx.
- `web` proxies `/api/` to `api:4291`.
- `api` is only on the internal project network and stores jobs under `/data/jobs`.
- Server-side job files persist in `./data/jobs` on the VPS.
- Large uploads are allowed up to `2g` at the Nginx proxy layer.

View File

@@ -533,6 +533,16 @@
<td><code>./scripts/stop-dev-background.sh</code></td>
<td><code>.pids/</code> 里的 PID 停止后台前端 / 后端进程。</td>
</tr>
<tr>
<td>生产站点</td>
<td><code>https://marketing.skg.com</code></td>
<td>公司域名已解析到 VPS <code>76.13.31.179</code>。线上由既有 Coolify / Traefik 负责 HTTPS 入口,项目 <code>web</code> 容器用 Nginx 承载静态前端并把 <code>/api/</code> 反代到 FastAPI。</td>
</tr>
<tr>
<td>生产部署</td>
<td><code>docker compose -f docker-compose.prod.yml --env-file deploy/.env.production up -d --build</code></td>
<td>服务器目录为 <code>/opt/skg-marketing-studio</code>;后端任务文件挂载到 <code>./data/jobs</code>,真实 Key 只放服务器 <code>deploy/.env.production</code></td>
</tr>
<tr>
<td>前端开发服务</td>
<td><code>cd web && pnpm dev</code></td>
@@ -929,6 +939,17 @@ SubjectAsset {
<h2>变更记录</h2>
<p>这个记录不是 git log 的替代品。它记录“产品理解发生了什么变化、影响了哪些源码、你以后描述需求时该怎么说”。后续每次改功能都要补一条。</p>
<div class="changelog">
<article class="change">
<header>
<h3>2026-05-15 · 公司域名生产部署配置</h3>
<span class="tag gray">Runtime</span>
<span class="tag blue">Deploy</span>
</header>
<div class="body">
<p><strong>改动:</strong>把生产入口确定为 <code>https://marketing.skg.com</code>DNS 已解析到 VPS <code>76.13.31.179</code>。新增 Docker Compose 生产配置:前端用 Next 静态导出 + Nginx<code>/api/</code> 反代到 FastAPI后端任务目录持久化到服务器 <code>./data/jobs</code>Traefik 通过既有 <code>coolify</code> 外部网络接管 80/443。</p>
<p><strong>影响:</strong><code>Dockerfile.web</code><code>Dockerfile.api</code><code>docker-compose.prod.yml</code><code>deploy/nginx.conf</code><code>deploy/.env.production.example</code><code>docs/deploy-vps.md</code><code>.project.json</code><code>RULES.md</code><code>docs/source-analysis.html</code></p>
</div>
</article>
<article class="change">
<header>
<h3>2026-05-15 · 本地启动改为后台不弹 Terminal</h3>