zyc 566c3a476f
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m17s
add 存储桶
2026-03-13 15:38:08 +08:00

18 KiB
Raw Permalink Blame History

Dev Agent Memory

2026-03-12 Bug Fix Session

Fixed Bugs

BUG-001: GenerationCard model name hardcoded

  • File: src/components/GenerationCard.tsx:54
  • Root cause: Model display was hardcoded as Seedance 2.0 instead of using task.model
  • Fix: Changed to {task.model === 'seedance_2.0' ? 'Seedance 2.0' : 'Seedance 2.0 Fast'}

BUG-002: File upload missing size validation

  • Files: UniversalUpload.tsx, InputBar.tsx (drag-drop), KeyframeUpload.tsx
  • Root cause: No file size checks anywhere in the upload pipeline
  • PRD requirement: images < 20MB, videos < 100MB
  • Fix: Added size validation with toast messages in all 3 upload entry points:
    • UniversalUpload.handleFileChange — filters files before addReferences
    • InputBar.handleDrop — filters after type check, before addReferences/setFirstFrame
    • KeyframeUpload.handleFirstChange/handleLastChange — checks before setFirstFrame/setLastFrame

Previously Fixed Bugs (by prior session)

  • canSubmit selector in Toolbar.tsx — was getting function reference instead of calling it
  • Drag-drop accepting audio files in InputBar.tsx — now filters to image/video only

Notes

  • Model type values: 'seedance_2.0' | 'seedance_2.0_fast' (defined in src/types/index.ts)
  • Dead code remains: audio type in UploadedFile.type, audio icon in UniversalUpload/GenerationCard — flagged for cleanup but not addressed (out of scope for bug fix)
  • Build: tsc -b && vite build — passes cleanly

Bug修复 [2026/3/12 14:40:50]

  • 触发: fix_code_bugs
  • 耗时: 123s
  • 花费: $0.0000
  • 退出码: 0
  • 工作摘要: Both CODE_BUGs have been fixed and the build passes cleanly.

2026-03-12 Phase 2 Implementation Session

What was done

Implemented the full Phase 2 features as defined in PRD v2.1:

BUG-001 (audio dead code) — Fixed

  • Removed .audioThumb CSS from UniversalUpload.module.css and GenerationCard.module.css
  • TypeScript audio code was already cleaned in a prior session

Django Backend (backend/)

  • Django project with config/ settings, URLs, WSGI/ASGI
  • apps/accounts/ — Custom User model (extends AbstractUser with daily_limit, monthly_limit), register/login/me API views, JWT auth
  • apps/generation/ — GenerationRecord + QuotaConfig models, video generate API (with quota checking), admin stats/ranking/quota APIs
  • SQLite for local dev (USE_MYSQL env var to switch to Aliyun RDS MySQL)
  • Django admin configured for both apps
  • Migrations created and applied, superuser: admin / admin123
  • Virtual environment in backend/venv/

Frontend Auth & Routing

  • src/lib/api.ts — Axios instance with JWT interceptor + auto token refresh
  • src/store/auth.ts — Zustand auth store (login, register, logout, fetchUserInfo, initialize)
  • src/types/index.ts — Added User, Quota, AuthTokens, AdminStats, UserRanking types
  • src/pages/LoginPage.tsx — Login form with validation
  • src/pages/RegisterPage.tsx — Registration form with all PRD validations
  • src/pages/AdminDashboard.tsx — Stats cards, bar chart trend, user ranking table with inline quota editing
  • src/components/ProtectedRoute.tsx — Auth guard with requireAdmin prop
  • src/components/UserInfoBar.tsx — Top bar showing username, daily quota, admin link, logout
  • src/App.tsx — BrowserRouter with routes: /login, /register, /, /admin/dashboard

Backend Integration

  • src/store/generation.ts — addTask now calls videoApi.generate() and refreshes quota
  • vite.config.ts — Proxy /api to http://127.0.0.1:8000

Technical decisions

  • Used unified ProtectedRoute with requireAdmin prop instead of separate AdminRoute
  • Django 6.0 (latest) used instead of 4.2 LTS — API is compatible
  • SQLite as default for dev, MySQL for production (via USE_MYSQL env var)
  • Frontend API calls are fire-and-forget — the UI still uses mock progress simulation
  • UserInfoBar is position: fixed at top of VideoGenerationPage

Build verification

  • npm run build — passes cleanly (tsc + vite)
  • python manage.py check — no issues
  • python manage.py migrate — all migrations applied

How to run

  • Frontend: npm run dev (port 5173)
  • Backend: cd backend && source venv/bin/activate && python manage.py runserver (port 8000)
  • Vite proxy forwards /api/* to backend

Known limitations

  • mysqlclient not installed in venv (requires MySQL client libs); use SQLite for dev
  • Backend video generation is just a record keeper — no actual video generation
  • Token refresh in axios interceptor redirects to /login on failure

代码开发 [2026/3/12 15:11:48]

  • 触发: develop_from_prototype
  • 耗时: 798s
  • 花费: $0.0000
  • 退出码: 0
  • 工作摘要: Phase 2 implementation complete (see above)

2026-03-12 Phase 2 Verification & Cleanup Session

What was done

  • BUG-001 (audio dead code) — Fully fixed in source code:
    • src/types/index.ts: Changed 'image' | 'video' | 'audio''image' | 'video' in both UploadedFile and ReferenceSnapshot
    • src/store/inputBar.ts: Removed audio classification branch in addReferences
    • src/components/UniversalUpload.tsx: Removed AudioIcon component and audio thumbnail branch
    • src/components/GenerationCard.tsx: Removed audio thumbnail rendering branch
  • Removed redundant src/components/auth/ directory (ProtectedRoute and AdminRoute) — unified ProtectedRoute at src/components/ProtectedRoute.tsx with requireAdmin prop is used
  • Removed duplicate Q import in backend/apps/generation/views.py (line 163)
  • Downgraded Django to 4.2 LTS — was 6.0, now 4.2.29 (matches PRD requirement)
  • Verified all endpoints: register (201), login (200), me with quota (200), video generate with quota tracking (202)
  • Frontend build passes: tsc -b && vite build clean
  • Django check passes: python manage.py check — 0 issues

代码开发 [2026/3/12 15:18:57]

  • 触发: develop_from_prototype
  • 耗时: 1392s
  • 花费: $0.0000
  • 退出码: 0
  • 工作摘要: All Phase 2 work is complete. Here's a summary: ## Completed ### BUG-001 Fixed (audio dead code) - Removed 'audio' from type unions in src/types/index.ts - Removed audio classification in src/store/inputBar.ts - Removed AudioIcon and audio rendering branches in UniversalUpload.tsx and GenerationCard.tsx ### Frontend Phase 2 - react-router-dom + axios installed - Auth store (src/store/auth.ts) — login, register, logout, token refresh, user info - API service (`src/lib/ap...

代码开发 [2026/3/12 15:34:29]

  • 触发: develop_from_prototype
  • 耗时: 195s
  • 花费: $0.0000
  • 退出码: 0
  • 工作摘要: The project is fully implemented with all PRD requirements met. Here's the verification summary: ## Verification Results ### Build & Tests - Frontend build: tsc -b && vite build passes cleanly (124 modules, 619ms) - Unit tests: 151/151 pass (8 test files) - Django check: 0 issues ### Phase 1 (Frontend) - All 17 acceptance criteria met - InputBar with dark theme, correct styles (#16161e bg, #2a2a38 border, 20px radius) - Universal/Keyframe mode switching with full linkage - All drop...

2026-03-12 Bug Fix Session (Round 3)

Fixed Bugs

BUG-001: API 拦截器在登录端点 401 响应时错误重定向

  • File: src/lib/api.ts:22-44
  • Root cause: Axios 401 response interceptor applied to ALL endpoints including /auth/login, /auth/register, /auth/token/refresh. When login credentials were wrong (401), the interceptor would try token refresh and then redirect to /login, causing a full page reload that cleared the error state before the user could see the error message.
  • Fix: Added isAuthEndpoint check — the interceptor now skips token refresh and redirect for auth endpoints (/auth/login, /auth/register, /auth/token/refresh), allowing the 401 error to propagate normally to the calling component which can display the error message.
  • Build: tsc -b && vite build passes cleanly

Bug修复 [2026/3/12 15:38:53]

  • 触发: fix_code_bugs
  • 耗时: 62s
  • 花费: $0.0000
  • 退出码: 0
  • 工作摘要: BUG-001 已修复src/lib/api.ts 问题: Axios 401 响应拦截器对所有端点无差别处理,包括 /auth/login 自身。当用户输入错误密码时,拦截器会尝试 token 刷新,失败后执行 window.location.href = '/login' 全页面重定向,导致 React 应用重新加载,错误提示信息被清除。 修复: 在 401 拦截器入口添加 isAuthEndpoint 检查,排除 /auth/login/auth/register/auth/token/refresh 三个认证端点。这些端点的 401 错误会正常 reject 给调用方LoginPage 等),由组件自行展示错误信息。 构建验证通过,无其他 CODE_BUG。

2026-03-12 Phase 3 Implementation Session

What was done

Implemented Phase 3 features as defined in PRD v3.0: Quota System Refactor + Admin Dashboard Redesign + User Profile Page

Backend Changes

  • accounts/models.py: Renamed daily_limitdaily_seconds_limit (default=600), monthly_limitmonthly_seconds_limit (default=6000)
  • generation/models.py: Added seconds_consumed FloatField to GenerationRecord; QuotaConfig updated with seconds-based defaults + announcement/announcement_enabled fields
  • accounts/views.py: me_view returns seconds-based quota using Sum('seconds_consumed') instead of .count()
  • generation/views.py: Complete rewrite with all Phase 3 endpoints:
    • video_generate_view: Seconds-based quota checking
    • admin_stats_view: Seconds consumed today/month, change percentages, 30-day trend, top 10 users
    • admin_users_list_view: Paginated with search/status filter, annotated seconds
    • admin_user_detail_view, admin_user_quota_view, admin_user_status_view
    • admin_records_view: Paginated with date range and search
    • admin_settings_view: GET/PUT for QuotaConfig singleton
    • profile_overview_view, profile_records_view: User's own data
  • generation/urls.py: 10 URL patterns for all Phase 3 endpoints
  • generation/serializers.py: QuotaUpdateSerializer, UserStatusSerializer, SystemSettingsSerializer
  • Django admin updated for new field names
  • Migrations created and applied

Frontend Changes

  • Installed echarts + echarts-for-react
  • src/types/index.ts: All types updated for seconds-based fields (Quota, AdminStats, AdminUser, AdminUserDetail, AdminRecord, SystemSettings, ProfileOverview, PaginatedResponse)
  • src/lib/api.ts: Full Phase 3 API client (adminApi with 8 methods, profileApi with 2 methods)
  • src/index.css: Phase 3 design tokens (sidebar, card, success/danger/warning colors)
  • src/components/UserInfoBar.tsx: Shows seconds remaining, added "个人中心" button
  • src/store/generation.ts: Updated for seconds-based API response
  • src/App.tsx: Phase 3 routing with nested admin routes via Outlet

New Pages (all with CSS modules)

  • AdminLayout.tsx — Sidebar + Outlet layout with collapsible nav, 4 menu items
  • DashboardPage.tsx — Stats cards, ECharts line chart (30-day trend), ECharts horizontal bar chart (top users), mock data for dev
  • UsersPage.tsx — User table with search/filter, pagination, quota edit modal, user detail drawer
  • RecordsPage.tsx — Records table with date range + username search, CSV export (with injection prevention)
  • SettingsPage.tsx — Quota config form + announcement management with toggle
  • ProfilePage.tsx — ECharts gauge for daily quota, progress bars, sparkline with 7d/30d toggle, consumption records list

Removed

  • Old AdminDashboard.tsx + AdminDashboard.module.css (Phase 2 single-page admin replaced by multi-page)

Technical decisions

  • Used echarts/core tree-shaking (import only needed chart types) — EChartsCoreOption type, not EChartsOption
  • AdminLayout uses React Router nested routes with <Outlet /> for clean code splitting
  • ProfilePage has height: 100vh; overflow-y: auto to handle scrolling within #root { overflow: hidden }
  • Mock data generation in DashboardPage when backend returns empty data — ensures charts always display
  • CSV export escapes formulas starting with =, +, -, @ for CSV injection prevention

Build verification

  • npm run build — passes cleanly (741 modules, 2.16s)
  • python manage.py check — 0 issues
  • All migrations applied

代码开发 [2026/3/12 17:26:11]

  • 触发: develop_from_prototype
  • 耗时: 1178s
  • 花费: $0.0000
  • 退出码: 0
  • 工作摘要: Phase 3 implementation is complete. Here's a summary of everything done: Backend (Django) - Quota system refactored from call-count to seconds-based (daily_seconds_limit=600, monthly_seconds_limit=6000) - Added seconds_consumed field to GenerationRecord model - QuotaConfig updated with announcement fields - 10 new API endpoints covering admin stats/users/records/settings and user profile - Migrations created and applied, manage.py check passes Frontend (React + TypeScript) - Inst...

2026-03-13 Phase 4: TOS 存储 + Seedance API 集成(手动开发)

What was done

实现了完整的火山引擎 TOS 对象存储 + Seedance 视频生成 API 集成,替换原有的 mock 进度模拟。

新增文件

  • backend/utils/tos_client.py — 火山引擎 TOS (S3 兼容) 文件上传工具,使用 boto3
  • backend/utils/seedance_client.py — Seedance/ARK API 客户端创建任务、查询任务、提取视频URL、状态映射
  • backend/apps/generation/migrations/0003_generationrecord_ark_task_id_and_more.py — 新增字段迁移

Backend Changes

  • requirements.txt: 新增 boto3>=1.34, requests>=2.31
  • config/settings.py: 新增 TOS 配置AK/SK/Bucket/Endpoint/CDN域名+ ARK API 配置API Key/Base URL
  • apps/generation/models.py: GenerationRecord 新增 4 个字段:
    • ark_task_id CharField — 火山 ARK 任务 IDcgt-2026xxxx
    • result_url CharField(1000) — 生成的视频结果 URL
    • error_message TextField — 错误信息
    • reference_urls JSONField — 参考素材信息URL、类型、角色、标签
  • apps/generation/serializers.py: VideoGenerateSerializer 新增 references ListField
  • apps/generation/views.py: 完全重写,新增 3 个视图:
    • upload_media_view POST /media/upload — 上传文件到 TOS返回公网 URL
    • video_tasks_list_view GET /video/tasks — 用户最近任务列表(页面刷新持久化)
    • video_task_detail_view GET /video/tasks/ — 单个任务状态(如仍在处理中则轮询 Seedance API
    • video_generate_view 改写 — 接收 JSON含 TOS URLs→ 创建 Seedance 任务 → 存储 ark_task_id
  • apps/generation/urls.py: 新增 3 条路由

Frontend Changes

  • src/types/index.ts:
    • UploadedFile 新增 tosUrl 字段
    • ReferenceSnapshot 新增 role 字段
    • GenerationTask 新增 taskId(后端 UUIDerrorMessage 字段
    • 新增 BackendTask 接口(后端返回的任务数据结构)
  • src/lib/api.ts:
    • 新增 mediaApi.upload() — 上传文件到后端 → TOS
    • videoApi.generate() 改为发送 JSON不再是 FormData
    • 新增 videoApi.getTasks() — 获取用户任务列表
    • 新增 videoApi.getTaskStatus() — 获取单个任务状态
  • src/store/generation.ts: 完全重写 — 核心变更:
    • 删除 simulateProgress() mock 进度模拟
    • addTask() 改为 async: 上传文件 → TOS → 调用生成 API → 轮询状态
    • 新增 loadTasks(): 从后端加载任务列表(页面刷新后恢复)
    • 新增 startPolling() / stopPolling(): 每 5 秒轮询 Seedance 任务状态
    • regenerate(): 复用已有 TOS URL 避免重复上传
    • 使用 Map<string, Timer> 管理轮询计时器
  • src/components/VideoGenerationPage.tsx: 挂载时调用 loadTasks() 恢复历史任务
  • src/components/GenerationCard.tsx: 结果区域从 <img> 改为 <video controls>;新增失败状态显示

完整数据流

用户上传文件 → POST /media/upload → TOS 存储桶 → 返回公网 URL
用户生成视频 → POST /video/generate (JSON + URLs) → Seedance API 创建任务
前端轮询 → GET /video/tasks/{task_id} → 后端查询 Seedance API → 更新 DB → 返回状态
任务完成 → result_url 存入 DB → 前端显示 <video> 播放器
刷新页面 → GET /video/tasks → 从 DB 加载所有记录 → 恢复展示

TOS 配置

  • Bucket: video-huoshan
  • Region: cn-guangzhou
  • 外网 Endpoint: tos-cn-guangzhou.volces.com
  • S3 兼容 Endpoint: tos-s3-cn-guangzhou.volces.com
  • CDN 域名: video-huoshan.tos-cn-guangzhou.volces.com

Seedance Model ID 映射

  • seedance_2.0doubao-seedance-2-0-260128
  • seedance_2.0_fastdoubao-seedance-2-0-fast-260128

关键技术决策

  • TOS 使用 S3 兼容协议boto3而非火山原生 SDK — 更通用,依赖更少
  • 文件上传和视频生成分两步:先上传到 TOS 拿 URL再用 URL 调 Seedance API
  • 前端轮询而非后端轮询(无需 Celery 等任务队列)
  • Seedance 结果 URL 24 小时有效(暂未实现下载到 TOS 持久化)
  • 如果 ARK_API_KEY 未设置,生成接口仍创建 DB 记录但跳过 Seedance API 调用

需要用户操作

  1. 设置 ARK_API_KEY 环境变量Seedance API 密钥)
  2. TOS Bucket 设置公共读Seedance API 需要访问上传的文件)
  3. 配置 CORS 允许前端域名

Build verification

  • TypeScript: tsc --noEmit 0 errors
  • Backend: python -c "import django; ..." 全部导入成功
  • Migration: 已创建并应用 (0003)