Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
83 changes: 73 additions & 10 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,14 +1,63 @@
# 阿里云 DashScope API Key (用于通义千问等模型)
DASHSCOPE_API_KEY=your_dashscope_api_key_here
# 生图 Provider(推荐:OpenAI-compatible / 中转图像接口)
# 可选值: openai / dashscope
IMAGE_PROVIDER=openai
# 图编 Provider(默认跟生图一致;可单独切回 DashScope 或切到另一家 OpenAI-compatible 图编)
# 可选值: openai / dashscope
IMAGE_EDIT_PROVIDER=openai

# 阿里云 Access Key (用于 OSS、视频超分等服务)
# OpenAI-compatible 生图配置
# OPENAI_IMAGE_API_KEY 是生图主用 key;留空时会回退 OPENAI_IMAGE_EDIT_API_KEY,再回退 OPENAI_API_KEY
OPENAI_IMAGE_API_KEY=
OPENAI_IMAGE_BASE_URL=https://api.bltcy.ai/v1
OPENAI_IMAGE_MODEL=gpt-image2
# 图编可单独走另一家 OpenAI-compatible 提供方;OPENAI_IMAGE_EDIT_API_KEY 是图编主用 key,同时也是生图备用 key
# 留空时优先沿用 OPENAI_IMAGE_API_KEY,再回退 OPENAI_API_KEY
OPENAI_IMAGE_EDIT_API_KEY=
OPENAI_IMAGE_EDIT_BASE_URL=https://api.bltcy.ai/v1
OPENAI_IMAGE_EDIT_MODEL=gpt-image2

# 配音 Provider(推荐:OpenAI-compatible / 中转 TTS)
# 可选值: openai / dashscope
TTS_PROVIDER=openai

# OpenAI-compatible 配音配置
# 留空时 OPENAI_TTS_API_KEY / OPENAI_TTS_BASE_URL 可沿用文本模型 OPENAI_API_KEY / OPENAI_BASE_URL
OPENAI_TTS_API_KEY=
OPENAI_TTS_BASE_URL=https://yunwu.ai/v1
OPENAI_TTS_MODEL=qwen3-tts-flash

# OpenAI-compatible 多模态配置(用于参考图提示词优化链)
# 留空时 OPENAI_MULTIMODAL_API_KEY / OPENAI_MULTIMODAL_BASE_URL 可沿用文本模型 OPENAI_API_KEY / OPENAI_BASE_URL
OPENAI_MULTIMODAL_API_KEY=
OPENAI_MULTIMODAL_BASE_URL=https://yunwu.ai/v1
OPENAI_MULTIMODAL_MODEL=qwen-vl-max

# 阿里云 DashScope API Key(仅在保留 Wan / CosyVoice 兼容链路时需要)
DASHSCOPE_API_KEY=

# 火山引擎方舟 ARK API Key (用于 Seedance 2.0 视频生成)
ARK_API_KEY=your_ark_api_key_here

# 对象存储配置(可选,Seedance / Vidu / Kling 在需要 URL 模式时会用到)
# 可选值: tos / oss
OBJECT_STORAGE_PROVIDER=tos
OBJECT_STORAGE_BUCKET_NAME=ark-auto-2104181120-cn-beijing-default
OBJECT_STORAGE_ENDPOINT=https://tos-cn-beijing.volces.com
OBJECT_STORAGE_REGION=cn-beijing
OBJECT_STORAGE_BASE_PATH=seedance-inputs

# 字节 TOS Access Key(推荐:私有桶 + 预签名 URL)
TOS_ACCESS_KEY_ID=your_tos_access_key_id_here
TOS_SECRET_ACCESS_KEY=your_tos_secret_access_key_here

# 阿里云 Access Key(仅在 OBJECT_STORAGE_PROVIDER=oss 时需要)
ALIBABA_CLOUD_ACCESS_KEY_ID=your_aliyun_access_key_id_here
ALIBABA_CLOUD_ACCESS_KEY_SECRET=your_aliyun_access_key_secret_here

# OSS 配置 (可选,用于图片/视频存储)
OSS_BUCKET_NAME=your_bucket_name
OSS_ENDPOINT=oss-cn-beijing.aliyuncs.com
OSS_BASE_PATH=comic_gen/
# 兼容旧版配置(如仍使用旧字段,代码也会自动兼容)
OSS_BUCKET_NAME=
OSS_ENDPOINT=
OSS_BASE_PATH=

# Kling AI 配置 (可选,用于 Kling 视频生成)
KLING_ACCESS_KEY=your_kling_access_key_here
Expand All @@ -27,6 +76,14 @@ VIDU_API_KEY=your_vidu_api_key_here
# OPENAI_BASE_URL=https://api.openai.com/v1
# OPENAI_MODEL=gpt-4o
#
# 云雾 API / OpenAI 兼容中转示例:
# LLM_PROVIDER=openai
# OPENAI_API_KEY=your_yunwu_api_key
# OPENAI_BASE_URL=https://yunwu.ai/v1
# OPENAI_MODEL=qwen3.6-plus
# OPENAI_IMAGE_BASE_URL=https://api.bltcy.ai/v1
# OPENAI_IMAGE_MODEL=gpt-image2
#
# DeepSeek 示例:
# LLM_PROVIDER=openai
# OPENAI_API_KEY=your_deepseek_api_key
Expand All @@ -39,14 +96,20 @@ VIDU_API_KEY=your_vidu_api_key_here
# OPENAI_BASE_URL=http://localhost:11434/v1
# OPENAI_MODEL=qwen2.5:72b

# API 服务配置
API_HOST=0.0.0.0
API_PORT=8000
# API 服务配置(本地默认只监听回环地址;Docker 镜像内由 Dockerfile 显式使用 0.0.0.0)
LUMENX_API_HOST=127.0.0.1
LUMENX_API_PORT=18177
LUMENX_CORS_ORIGIN_REGEX=^https?://(localhost|127\\.0\\.0\\.1)(:\\d+)?$
LUMENX_UPLOAD_MAX_MB=50

# 开发态运行时配置持久化路径(docker-compose 默认会指向 ./output/config/runtime.env)
# LUMENX_DEV_CONFIG_PATH=output/config/runtime.env

# ===============================
# API 端点配置 (可选,海外部署时切换到国际端点)
# 命名约定: {PROVIDER}_BASE_URL
# ===============================
# DASHSCOPE_BASE_URL=https://dashscope-intl.aliyuncs.com
# ARK_BASE_URL=https://ark.cn-beijing.volces.com/api/v3
# KLING_BASE_URL=https://api.klingai.com/v1
# VIDU_BASE_URL=https://api.vidu.cn/ent/v2
7 changes: 7 additions & 0 deletions .githooks/commit-msg
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env sh
set -eu

repo_root=$(git rev-parse --show-toplevel)
cd "$repo_root"

node scripts/git-policy.mjs commit-msg "$1"
7 changes: 7 additions & 0 deletions .githooks/pre-push
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env sh
set -eu

repo_root=$(git rev-parse --show-toplevel)
cd "$repo_root"

node scripts/git-policy.mjs pre-push
27 changes: 27 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# PR Summary

- 改动目标:
- 主要变更:
- 风险点 / 影响面:

## Verification

- [ ] 前端相关改动已执行 `npm run quality:frontend`
- [ ] 后端相关改动已执行 `pytest -q`
- [ ] 已执行与本次改动相关的最小验证
- [ ] 已说明未执行的验证项及原因(如有)
- [ ] 已确认分支命名与 commit message 符合仓库 Git 规范

## Copy / i18n Checklist

- [ ] 本次新增的用户可见文案,已判断是否属于英文保留白名单
- [ ] 不属于白名单的用户可见文案,已迁入 `frontend/src/lib/i18n/zh-CN.ts`,未在 `tsx/ts` 中硬编码
- [ ] 属于白名单的内容(品牌名、模型名、Prompt 语法、URL、环境变量、格式名等)保留英文原文
- [ ] 需要同时兼顾理解与识别的术语,已采用“中文主 + 英文辅”或“值英文、显示中文 label”的模式
- [ ] 若新增了新的英文保留项,已同步更新 `docs/中文化清单_影视创作者.md`
- [ ] 若新增内容会被巡检脚本误报,已同步评估是否需要更新 `frontend/scripts/audit-hardcoded-copy.mjs`

## Notes for Reviewers

- 建议重点关注:
- 需要一起确认的口径:
110 changes: 110 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
name: CI

on:
pull_request:
branches:
- main
push:
branches:
- main

jobs:
backend-quality-gate:
name: backend-quality-gate
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'

- name: Install backend dependencies
run: |
python -m pip install --upgrade pip
python -m pip install -r requirements.txt

- name: Run backend quality gate
run: python -m pytest -q -m "not e2e"

frontend-quality-gate:
name: frontend-quality-gate
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: npm
cache-dependency-path: frontend/package-lock.json

- name: Install frontend dependencies
working-directory: frontend
run: npm ci

- name: Run frontend quality gate
run: npm run quality:frontend

browser-e2e-smoke:
name: browser-e2e-smoke
runs-on: ubuntu-latest
needs:
- backend-quality-gate
- frontend-quality-gate

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: npm
cache-dependency-path: frontend/package-lock.json

- name: Install backend dependencies
run: |
python -m pip install --upgrade pip
python -m pip install -r requirements.txt

- name: Install root dev dependencies
run: npm install --no-audit --no-fund

- name: Install frontend dependencies
working-directory: frontend
run: npm ci

- name: Install Playwright Chromium
working-directory: frontend
run: npx playwright install --with-deps chromium

- name: Run browser E2E smoke pytest scenarios
env:
LUMENX_RUN_BROWSER_E2E: '1'
LUMENX_E2E_HEADLESS: '1'
LUMENX_KEEP_E2E_OUTPUT_ON_FAILURE: '1'
run: python -m pytest tests/test_e2e_smoke.py tests/test_prompt_quality_e2e.py -q

- name: Upload smoke summary JSON, failure screenshot, and preserved output
if: failure()
uses: actions/upload-artifact@v4
with:
name: browser-e2e-smoke-summary-screenshots
path: |
tmp/e2e-output-*/browser-smoke-*.json
tmp/e2e-output-*/browser-e2e-smoke-failure.png
tmp/e2e-output-*/**/*
if-no-files-found: ignore
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ venv/
*.db
*.sqlite3
.pytest_cache/
pytest-cache-files-*/
tmp-pytest-*/
.coverage
htmlcov/

Expand Down Expand Up @@ -80,6 +82,9 @@ frontend/.vercel
*.log
logs/
.lumen-x/
tmp/
test-results/
frontend/test-results/

# Secrets (extra safety)
*secret*
Expand All @@ -101,6 +106,7 @@ static/
GITHUB_RELEASE_CHECKLIST.md
CLAUDE.md
AGENTS.md
!AGENTS.md
demand/

# Local docs scratchpads
Expand Down
24 changes: 24 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# LumenX Codex Operating Rules

## Codex Built-In Imagegen Safety

- Treat Codex built-in image generation as a conversation-level request to `api-vip.codex-for.me/v1/responses`.
- Never attach or view original multi-reference storyboard/material images directly when using Codex built-in imagegen.
- Before any Codex built-in imagegen handoff, run `scripts/prepare_codex_imagegen_refs.py` and use only the generated safe reference images.
- Prefer handoff packages under `output/codex_imagegen_handoff/<project-or-frame>/`.
- The handoff package must include:
- `codex_safe_reference_manifest.json`
- safe reference images
- `codex_imagegen_prompt.md`
- `handoff_policy.json`
- High-consistency frames may use `two_stage_high_consistency`; generate it as a separate pack from the direct safe pack.
- In `two_stage_high_consistency`, stage 1 locks characters and key props; stage 2 attaches the stage 1 result, then refines scene, composition, and lighting with safe refs.
- The prompt shown to Codex should reference the safe reference pack and must not list raw source image paths.
- `codex_safe_reference_manifest.json` must expose prepared safe reference paths only; raw source paths are fixture/script input, not Codex handoff content.
- Keep the total prepared safe reference bytes conservative. Hard cap: no more than `1 MiB` of prepared JPEG refs per Codex handoff stage; within that cap, prefer the highest-fidelity safe refs that still fit. For heavy storyboard work, prefer `700 KiB` or lower only if the quality-first fit still leaves enough visual detail.
- If the safe pack cannot fit the budget, split the frame into staged handoffs instead of raising the budget.
- For `六一那天_v2` and similar multi-reference storyboard work, always use `safe_refs_only` or `two_stage_high_consistency`; use `off` only for a local-only experiment.

## Why This Exists

Codex built-in imagegen can fail with `413 Payload Too Large` when the aggregate conversation payload is too large. The limit is affected by the full request body, not just image count. A frame with six references can fail if the source images are large, even when each image is individually valid.
14 changes: 14 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,23 @@ git checkout -b feature/your-feature-name
```

**Branch Naming Convention**:
- `main` - release-ready history only
- `feature/description` - New features
- `fix/description` - Bug fixes
- `docs/description` - Documentation updates
- `refactor/description` - Code refactoring
- `test/description` - Test additions or updates
- `chore/description` - Tooling, dependency, or maintenance work
- `release/description` - Release preparation and version cut
- `codex/description` - Short-lived AI-assisted work branches

### 4. Enable Local Git Rules

```bash
npm run git:setup-hooks
```

This enables the repo-local hooks under `.githooks/` so branch names and commit messages are checked before they land.

## 🧭 Media Storage & Provider Routing Rules

Expand Down Expand Up @@ -155,6 +167,8 @@ fix(video): resolve FFmpeg concurrent processing issue
docs(readme): update installation instructions for Windows
```

The local hook also allows `Merge`, `Revert`, `fixup!`, and `squash!` messages when Git creates special commits.

## 🔄 Pull Request Process

### 1. Ensure Quality
Expand Down
8 changes: 5 additions & 3 deletions Dockerfile.backend
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ WORKDIR /app

# Copy and install Python dependencies (excluding pywebview)
COPY requirements-docker.txt requirements.txt
RUN pip install --no-cache-dir -r requirements.txt
RUN pip install --no-cache-dir -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt

# Copy application code
COPY src/ src/
Expand All @@ -22,7 +22,9 @@ RUN mkdir -p output/uploads output/video output/assets output/storyboard \
ENV NO_PROXY="*.aliyuncs.com,localhost,127.0.0.1"
ENV no_proxy="*.aliyuncs.com,localhost,127.0.0.1"
ENV PYTHONUNBUFFERED=1
ENV LUMENX_API_HOST=0.0.0.0
ENV LUMENX_API_PORT=18177

EXPOSE 17177
EXPOSE 18177

CMD ["python", "-m", "uvicorn", "src.apps.comic_gen.api:app", "--host", "0.0.0.0", "--port", "17177"]
CMD ["sh", "-c", "python -m uvicorn src.apps.comic_gen.api:app --host \"$LUMENX_API_HOST\" --port \"$LUMENX_API_PORT\""]
8 changes: 7 additions & 1 deletion Dockerfile.frontend
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@ FROM node:20-alpine AS builder
WORKDIR /app

COPY frontend/package.json frontend/package-lock.json* ./
RUN npm ci
RUN npm config set registry https://registry.npmmirror.com/ \
&& npm config set replace-registry-host always \
&& npm config set fetch-retries 5 \
&& npm config set fetch-retry-mintimeout 20000 \
&& npm config set fetch-retry-maxtimeout 120000 \
&& npm config set fetch-timeout 300000 \
&& npm ci --no-audit --no-fund

COPY frontend/ .

Expand Down
Loading