Skip to content

feat:backend dev - #75

Open
xiaocheny214 wants to merge 75 commits into
1024XEngineer:mainfrom
xiaocheny214:feat/backend-dev
Open

feat:backend dev#75
xiaocheny214 wants to merge 75 commits into
1024XEngineer:mainfrom
xiaocheny214:feat/backend-dev

Conversation

@xiaocheny214

Copy link
Copy Markdown
Contributor

背景:

feat(backend): 后端核心模块实现 — 基础设施 + 生成管线 + API 契约

新增能力

common(共享层)

  • 统一响应格式 Response[T] / ListResponse[T]
  • 全局异常处理(BizException 继承体系)
  • 共享 DTO(CharacterCard、ActionSpec、GenRoute)

framework(基础设施层)

  • PostgreSQL 连接(SQLAlchemy 2.x + psycopg3)
  • 七牛 Kodo 对象存储(上传/删除/签名 URL)
  • AI Provider 配置(OpenAI-compatible)
  • 视频 i2v Provider(qnaigc Kling o3)
  • 抠图 Provider(onnxruntime u2netp,macOS x86_64 自动降级 Pillow)

ai_engine(AI 能力层)

  • 视频路线角色动作生成管线
  • 策略分发:VIDEO_I2V(walk/run/jump/attack)、PER_FRAME、PROC_IDLE
  • 帧提取(imageio/pyav)、步态周期检测、一次性动作裁剪
  • 像素化、脚线对齐、root motion、sprite sheet 打包
  • 提示词构建(侧视/正视 walk、jump、attack)

app(应用层)

  • 项目 CRUD(约束配置:视角、尺寸、风格)
  • 角色 CRUD(outfit → action → frame 嵌套数据)
  • 媒体上传(七牛直传 + 确认)
  • 生成 API(图片生成 + 动作生成 + 任务轮询)
  • 项目约束校验(输入尺寸必须匹配项目配置)
  • 风格参考图(sprite_sample_url → 图生图模式)
  • 后台任务执行(executor 编排 → ai_engine → 上传 → 回写)

xiaocheny214 and others added 30 commits July 23, 2026 11:46
Describe the backend package layout (common/framework/app) and the server domain module split: user, project, asset, character with action/character_template/wearable subdomains, generation and media. All modules currently define abstract interfaces only.
Add the shared response/exception kernel in windup_common: Response/ListResponse unified bodies (HTTP always 200, business code in body), BizException base, ModelException for LLM calls, and the BizCode/ModelErrorType enums. Add the app-level global exception handlers that convert these into Response.fail.
Add windup_framework infrastructure abstractions: SQLAlchemy db base/session, config loaders (database/provider/storage), LLM provider protocols (chat/image/video) and Kodo object storage.
Add abstract service interfaces and domain models for the server modules: user, project, asset, character (with action/character_template/wearable subdomains), generation and media. Drop the now-obsolete .gitkeep placeholders.
Drop the placeholder health router and its registration in create_app; the web layer now revolves around the global exception handlers.
Expose the windup CLI entrypoint (windup_app.bootstrap.app:main) and add python-multipart for form/file uploads; refresh uv.lock accordingly.
Point the sub-entity references at the nested character subpackages (character.action / character_template / wearable) instead of the old top-level paths.
Remove unused imports flagged by ruff F401 in generation/interface.py and user/model.py.
将 validate-branch 与 validate-commits 从 backend.yml 拆到独立的 naming.yml。命名规范门禁不局限于 backend 范畴,应作为仓库级 CI 单独维护(PR review:@minorcell 建议)。

backend.yml 仅保留 lint-and-test;naming.yml 用独立 concurrency group 避免与 backend 共用 group 互相取消。
Add SqlAlchemyProjectService inheriting ProjectService; implements
create/get/list/delete plus project_name_exists against SQLAlchemy.

- interface: reconcile ProjectService to session-per-call; session is
  passed per request via get_session, create_project takes **fields.
- service: stateless impl as a module-level `service` singleton; flush
  only, commit/rollback handled by get_session; list ordered by id desc.
- model: id uses BigInteger().with_variant(Integer, "sqlite") so the
  in-memory SQLite test DB autoincrements; Postgres unchanged.
- api/bootstrap: import service from the service module, register
  project_router, add a print_banner startup stub.
Add SQLite in-memory test fixtures and project module tests.

- conftest: SQLite in-memory fixtures (StaticPool, single connection)
  with no Docker Postgres dependency; get_session override for the API
  TestClient.
- test_project_service: 14 unit tests for create/exists/get/list/delete
  covering the unique constraint, pagination, id-desc ordering and user
  filter.
- test_project_api: 9 end-to-end tests via TestClient covering CRUD and
  the unified response contract (HTTP 200, code in body, 400/404).
Reflect character/media/generation/user module redesigns in the split
document.
Replace strategy pattern with typed submit methods.

- model: add CharacterImageOutput/CharacterActionOutput/CharacterActionFrame
  as typed task results, remove generic GenerationResult
- interface: split submit into generate_character_image and
  generate_character_action with typed inputs
- document SSE streaming flow (GET /generation/tasks/{id}/stream)
  replacing frontend polling
Remove OAuth abstract methods and models from UserService.

Commented-out methods: get_oauth_authorize_url, login_by_oauth,
bind_oauth, get_oauth_bindings. Related imports OAuthCallbackInput and
UserOAuth removed from interface. The OAuth region is preserved as a
placeholder for future extension.
Add ObjectStorageMediaService implementing MediaService.

- service: upload to Kodo via KodoStorage adapter, auto-generated
  object keys with category prefix, no user filenames in keys
- app: register media router (POST /media/upload) in create_app
ci: split naming gate into its own workflow
feat:project module
跨层契约(common,无内部依赖):ActionType/GenRoute/CharacterCard/ActionSpec/AssetPackageRef。ai_engine 与 app 均依赖此。Refs 1024XEngineer#53。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
SufyVideoProvider(kling i2v,OpenAI 兼容异步 /videos)+ OnnxU2NetMatteProvider(onnxruntime 直跑 u2netp,替代 rembg 在 3.12 无轮子的 numba 链)+ 能力接口(Image/Video/MatteProvider)。同时声明 framework 代码实际 import 的依赖(langchain-openai/onnxruntime/qiniu/pillow/numpy)——补齐 1024XEngineer#64 机器审指出的缺依赖。Refs 1024XEngineer#53 1024XEngineer#35。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
填充空骨架:slicing(抽帧 + 周期/一次性选帧)、strategy(ROUTE_MATRIX 分流 + VideoFrameStrategy 图生视频)、prompt(walk/jump/attack/idle 提示词库)、postprocess(像素化 + 脚线对齐 + 打包 + 逐帧时长)、generator 串联。MVP:root_motion 暂不做(character_data.frames 无该字段,见 1024XEngineer#63);graph/ 留占位非本 PR。Refs 1024XEngineer#53 1024XEngineer#35 #21。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Remove dead storage module (empty __init__.py and kodo.py) from framework
- Implement actual Qiniu Kodo SDK upload in ObjectStorageMediaService
- Move MediaCategory to windup_common.enums.media, remove duplicate from media/model
- Update media __init__ to import MediaCategory from common
Move qiniu import inside upload() so module collection does not fail
when qiniu is not installed (e.g. CI test runs).
按 MVP 边界(与作者对齐):CharacterGeneratorPort.generate(card, action, master, progress) → GeneratedAction(frames/durations/fps);母版由 server 以 bytes 传入,不再经 ArtifactStore;去掉 sprite sheet 打包与存储引用(上传/落库/导出在 server/export 侧)。补 VideoFrameStrategy.derive 离线端到端测试(monkeypatch 抽帧,不解码 mp4/不联网)。Refs 1024XEngineer#53。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
refactor(media): implement Qiniu upload and deduplicate MediaCategory
xiaocheny214 and others added 11 commits July 30, 2026 21:27
backend-dev 的 ActionType.JUMP 值是大写 "JUMP",与其它小写成员不一致,且 executor 按值映射到 ai_engine 的 JUMP="jump" 会失败;改为 "jump"。(原 #24 另加一个 JUMP="jump" 导致枚举'JUMP already defined'、pytest 挂——改成修正现有值,不重复定义。)另 ROUTE_MATRIX 把 idle 从空桩 PROC_IDLE 改走 VIDEO_I2V(build_idle_prompt 躯干呼吸)。现 walk/idle/attack/jump 四动作全走视频 i2v。Refs 1024XEngineer#53 1024XEngineer#35。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
feat(generation): 启用 jump 动作 + idle 走 i2v(四动作全跑通)
idle: 提示词原写 "chest and shoulders rise and fall",直接让肩膀起伏,
i2v 出的是耸肩不是呼吸。改为只让胸腔/躯干在慢节律里起伏、肩膀锁平同高,
并去掉亚阈值幅度词(barely/faintly),过 prompt_lint。

jump: 重甲带剑角色的跳跃强动作先验压不住——站立母版让 i2v 只举剑摆造型、
不腾空(同 attack 用站立母版会抡过头顶的老坑)。按 master_prep 既有铁律
"母版姿态决定动作,提示词只能微调",给 jump 在 MASTER_POSES 补极限蓄力
半蹲母版姿态;runtime 的 prepare_master 仍只补顶部留白,此项为纯 spec。

prompt_lint 通过。on-screen 效果复验待 qnaigc 视频源站从 522 恢复后补跑。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
fix(ai_engine): idle 去耸肩、jump 补蓄力母版压站姿先验

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

The current head has several backend correctness and security blockers. Inline comments cover task dispatch, project scoping, outbound URL fetching, and upload resource handling.

Additional Finding

  • [P1] Add database migrations before deployment. The PR introduces windup_project, windup_character, and windup_generation_task ORM tables, but schema creation only appears in tests via Base.metadata.create_all; the application has neither migrations nor startup schema creation. A fresh or existing deployment will fail with missing-table errors when these endpoints are called. Please add versioned migrations and document how they are applied.

Verification

GitHub reports lint-and-test, Branch name, and Commit messages successful for head dbbcb74723b722ae0f992aa056be0bd7af894533. I could not rerun the commands locally because uv is not installed in the review environment.

Comment thread backend/packages/app/src/windup_app/web/api/generation.py
Comment thread backend/packages/app/src/windup_app/server/orchestrator/service.py
Comment thread backend/packages/app/src/windup_app/server/orchestrator/executor.py
Comment thread backend/packages/app/src/windup_app/web/api/media.py
Comment thread backend/packages/app/src/windup_app/web/api/media.py
johnnyzhang-eng and others added 2 commits July 31, 2026 11:07
该包职责是**生成任务的编排调度**(建 PENDING 记录 → 后台 executor 驱动 → 查询状态),
实际 AI 生成在 ai_engine;原名 generation 易与"生成本身"混淆,更名为 orchestrator。

- git mv server/generation → server/orchestrator(rename 保留历史)
- 全部 windup_app.server.generation → .orchestrator(bootstrap / web api / 包内自引用 / 测试)
- 分层契约不变(约束在 windup_app.server 层级,不牵子包名)

门禁:ruff / lint-imports(2 kept) / 编排测试(3 passed) 全绿。类名(GenerationTask 等)
与 web 路由不动(仍描述生成任务,改动最小)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…n-orchestrator

refactor(app): generation 包更名为 orchestrator(生成任务编排/调度)
@vercel

vercel Bot commented Jul 31, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
windup Ignored Ignored Preview Aug 4, 2026 4:17pm

xiaocheny214 and others added 10 commits August 4, 2026 17:50
- Add name varchar(20) column to windup_character ORM model
- Add name field to CharacterCreate, CharacterUpdate, CharacterOut schemas
feat(character): add name field to character model and API schemas
- Add backend/Dockerfile with multi-stage build (uv + Python 3.12)
- Add docker-compose.yml with backend and PostgreSQL services
- Add db/init.sql for automatic database table initialization
- Add .env.example with configuration template
- PostgreSQL configured with port 7856 and secure password
…browser

三处让部署跑不起来的问题,都在这台服务器上实测定位:

1. 构建阶段 uv sync 超时。宿主机访问 pypi.org 需 8s,构建容器内默认超时会在
   下载大包(uvloop)时 "operation timed out" 直接失败。改走国内镜像源并把
   UV_HTTP_TIMEOUT 拉到 180s。

2. 容器起来即反复重启,报 "exec /app/.venv/bin/uvicorn: no such file or directory"。
   文件其实存在,报的是它 shebang 指向的解释器——uv 装出来的 venv 里 shebang 与
   .pth 都是绝对路径,builder 在 /build、runtime 在 /app,跨路径拷贝后解释器与
   workspace 包全部失效。把 builder 的 WORKDIR 也改成 /app 即可。

3. 七牛上传 TLS 握手超时、媒体上传请求挂死。宿主机网卡 MTU 1480,而 compose
   自建网络不继承 daemon 的 mtu 设置、默认仍是 1500,大包被丢。显式给网络设
   1450 后,up-z0.qiniup.com 从握手超时 14s 变为 1.0s,上传恢复正常。

4. 浏览器跨域被全部拦下:OPTIONS 预检返回 405、响应无 access-control-* 头,
   后端日志里连请求都看不到。挂上 CORSMiddleware,允许来源用
   WINDUP_CORS_ORIGINS 覆盖,并放行 Vercel 预览域名。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…imiting

- Add User ORM model and service implementation
- Add JWT dual token (access + refresh) authentication
- Add email verification via Resend
- Add Redis-based rate limiting middleware
- Add auth middleware with whitelist
- Add /auth/* API endpoints (register, login, send-code, refresh, logout, me, change-password)
- Add unit tests for user service (25 tests passing)
- Move Redis client to db package for better organization
- Add dependencies: redis, resend, passlib[bcrypt], pydantic[email]
- Add auth_client fixture with valid JWT token
- Update test_project_api.py to use auth_client
- Fix CI failures caused by auth middleware blocking unauthenticated requests
- Rate limit middleware now skips checks when Redis is not available
- Prevents CI failures in environments without Redis
- Logs warning when Redis connection fails
fix(deploy): 修好容器构建与浏览器可达性(服务器实测定位)
@johnnyzhang-eng

Copy link
Copy Markdown

把这个分支在真实服务器上部署跑通了,反馈三个它自身没暴露的问题 + 一处可能的重复工作

在一台云主机(Ubuntu 24.04 / 4 核 / 7GB / 无 GPU)上,用本分支的代码完整部署并端到端跑通了:13 个端点可用、媒体上传真打七牛并返回可公网访问的 URL、生成任务走完 pending → running → completed 拿到真实图片。

过程中卡了三次,都不是本分支代码写错,而是部署环境相关、但不修就起不来的问题。已提 PR 到本分支:#30(部署修复)、#31(SSE)。

一、三个卡点

1. 构建阶段 uv sync 超时。 宿主机访问 pypi.org 需 8s,构建容器内默认超时会在下载 uvloop 时 operation timed out 直接失败。加国内镜像源 + UV_HTTP_TIMEOUT=180 解决。

2. 容器起来即反复重启,报 exec /app/.venv/bin/uvicorn: no such file or directory

这条最值得说:那个文件其实是存在的。报错说的不是脚本本身,而是它 shebang 里指向的解释器 —— uv 装出来的 venv 里 shebang 与 workspace 包的 .pth 都是绝对路径,Dockerfile 里 builder 在 /build、runtime 在 /app,跨路径拷贝之后解释器和 workspace 包全部失效。把 builder 的 WORKDIR 也改成 /app 即可,不需要任何 relocate 技巧。

3. 七牛上传请求挂死、镜像拉取卡住。 根因是 Docker 网络 MTU 大于宿主机链路:eno1 是 1480,Docker 默认 1500,大包被丢,表现为 TLS 握手超时而不是明确报错(up-z0.qiniup.com 握手超时 14s)。

这条有个坑:只改 daemon.json 不够,compose 自建网络不继承 daemon 的 mtu,必须在 compose 的 networks.driver_opts 里显式设。我是分两次才定位到的 —— 第一次改完 daemon 以为好了,重建后容器里仍是 1500。修完 up-z0.qiniup.com 从握手超时 14s 变为 1.0s。

二、CORS 缺失会拦掉前端所有请求

没有 CORS 中间件时,OPTIONS 预检返回 405、响应无 access-control-* 头,而且后端日志里连请求都看不到,很容易被误判成前端问题。已在 #30 里加上,来源用 WINDUP_CORS_ORIGINS 覆盖。

补充一个前端侧的坑:本机开着代理时浏览器请求会全部失败并报 ERR_PROXY_CONNECTION_FAILED,而 curl 直连是通的。这跟后端无关,但现场极易误判成后端挂了。

三、可能的重复工作:SSE 推送

看到日报里提到「重新设计 workflow domain / sse 推送」—— 我在 #31 里已经实现了一版 SSE,为避免重复或冲突,想先对齐一下

我那版的要点,供参考或直接弃用:

  • 契约以实际消费方为准。前端 entities/generation/api.ts(PR feat(generation): add validated SSE task adapter #110)订阅的是单一事件名 task_update,payload 为 {task_id, task_type, status, result, error_message},收到 completed/failed 自行关流。
  • 两条前端会抛错断流(不是降级)的硬约束:failed 必须带 error_message;非 failed 必须不带。
  • ⚠️ docs/agent-sse-api-design.md 规定的是四个事件名(status / progress / completed / failed),与 interface.py docstring、module-split.md 和前端已落地的单事件不一致。这两套文档需要收敛成一份,否则做 Agent 那条线时会再撞一次。
  • 实现选了「轮询 DB + 状态变化才推」而非进程内事件总线:executor 走 BackgroundTasks 在同进程跑,事件总线看似更快,但一旦 uvicorn 起多 worker 就会出现「订阅在 A 进程、任务在 B 进程」的静默失效,而且不报错、只是永远收不到事件。

如果你的 workflow domain 重设计里已经包含 SSE,#31 可以关掉,我把上面这些实测结论并进去就行 —— 不必两份都留着。请告诉我怎么处理更合适。

四、另外单独提了一个不依赖本分支的 PR

#115 把 Dockerfile / docker-compose / CORS 直接提到了 mainmain 上目前这三样都没有)。这样「服务起得来、浏览器连得上」不必等本分支合入。如果本分支先合,两边会有重叠,以你的为准即可。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants