Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
33d8e52802 | ||
|
|
9af50a9066 | ||
|
|
6c6fbae13a | ||
|
|
cb10da52fc |
172
Docs/BACKEND_README.md
Normal file
172
Docs/BACKEND_README.md
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
# ViGent2 后端开发指南
|
||||||
|
|
||||||
|
本文档为后端开发人员提供架构概览、接口规范以及开发流程指南。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🏗️ 架构概览
|
||||||
|
|
||||||
|
后端采用 **FastAPI** 框架,基于 Python 3.10+ 构建,主要负责业务逻辑处理、AI 任务调度以及与各微服务组件的交互。
|
||||||
|
|
||||||
|
### 目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
backend/
|
||||||
|
├── app/
|
||||||
|
│ ├── api/ # API 路由定义 (endpoints)
|
||||||
|
│ ├── core/ # 核心配置 (config.py, security.py)
|
||||||
|
│ ├── models/ # Pydantic 数据模型 (schemas)
|
||||||
|
│ ├── services/ # 业务逻辑服务层
|
||||||
|
│ │ ├── auth_service.py # 用户认证服务
|
||||||
|
│ │ ├── glm_service.py # GLM-4 大模型服务
|
||||||
|
│ │ ├── lipsync_service.py # LatentSync 唇形同步
|
||||||
|
│ │ ├── publish_service.py # 社交媒体发布
|
||||||
|
│ │ └── voice_clone_service.py# Qwen3-TTS 声音克隆
|
||||||
|
│ └── tests/ # 单元测试与集成测试
|
||||||
|
├── scripts/ # 运维脚本 (watchdog.py, init_db.py)
|
||||||
|
├── assets/ # 资源库 (fonts, bgm, styles)
|
||||||
|
└── requirements.txt # 依赖清单
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔌 API 接口规范
|
||||||
|
|
||||||
|
后端服务默认运行在 `8006` 端口。
|
||||||
|
|
||||||
|
- **文档地址**: `http://localhost:8006/docs` (Swagger UI)
|
||||||
|
- **认证方式**: Bearer Token (JWT)
|
||||||
|
|
||||||
|
### 核心模块
|
||||||
|
|
||||||
|
1. **认证 (Auth)**
|
||||||
|
* `POST /api/auth/login`: 用户登录 (手机号)
|
||||||
|
* `POST /api/auth/register`: 用户注册
|
||||||
|
* `GET /api/auth/me`: 获取当前用户信息
|
||||||
|
|
||||||
|
2. **视频生成 (Videos)**
|
||||||
|
* `POST /api/videos/generate`: 提交生成任务
|
||||||
|
* `GET /api/videos/tasks/{task_id}`: 查询任务状态
|
||||||
|
* `GET /api/videos/generated`: 获取历史视频列表
|
||||||
|
* `DELETE /api/videos/generated/{video_id}`: 删除历史视频
|
||||||
|
|
||||||
|
> **修正 (16:20)**:任务查询与历史列表接口已更新为 `/api/videos/tasks/{task_id}` 与 `/api/videos/generated`。
|
||||||
|
|
||||||
|
3. **素材管理 (Materials)**
|
||||||
|
* `POST /api/materials/upload`: 上传素材 (Direct Upload to Supabase)
|
||||||
|
* `GET /api/materials`: 获取素材列表
|
||||||
|
|
||||||
|
4. **社交发布 (Publish)**
|
||||||
|
* `POST /api/publish`: 发布视频到 B站/抖音/小红书
|
||||||
|
|
||||||
|
5. **资源库 (Assets)**
|
||||||
|
* `GET /api/assets/subtitle-styles`: 字幕样式列表
|
||||||
|
* `GET /api/assets/title-styles`: 标题样式列表
|
||||||
|
* `GET /api/assets/bgm`: 背景音乐列表
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎛️ 视频生成扩展参数
|
||||||
|
|
||||||
|
`POST /api/videos/generate` 支持以下可选字段:
|
||||||
|
|
||||||
|
- `subtitle_style_id`: 字幕样式 ID
|
||||||
|
- `title_style_id`: 标题样式 ID
|
||||||
|
- `subtitle_font_size`: 字幕字号(覆盖样式默认值)
|
||||||
|
- `title_font_size`: 标题字号(覆盖样式默认值)
|
||||||
|
- `bgm_id`: 背景音乐 ID
|
||||||
|
- `bgm_volume`: 背景音乐音量(0-1,默认 0.2)
|
||||||
|
|
||||||
|
## 📦 资源库与静态资源
|
||||||
|
|
||||||
|
- 本地资源目录:`backend/assets/{fonts,bgm,styles}`
|
||||||
|
- 静态访问路径:`/assets`(用于前端样式预览与背景音乐试听)
|
||||||
|
|
||||||
|
## 🎵 背景音乐混音策略
|
||||||
|
|
||||||
|
- 混音发生在 **唇形对齐之后**,避免影响字幕/口型时间轴。
|
||||||
|
- 使用 FFmpeg `amix`,禁用归一化以保持配音音量稳定。
|
||||||
|
|
||||||
|
## 🛠️ 开发环境搭建
|
||||||
|
|
||||||
|
### 1. 虚拟环境
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd backend
|
||||||
|
python -m venv venv
|
||||||
|
source venv/bin/activate # Linux/macOS
|
||||||
|
# .\venv\Scripts\activate # Windows
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 依赖安装
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 环境变量配置
|
||||||
|
|
||||||
|
复制 `.env.example` 到 `.env` 并配置必要的 Key:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
# Supabase
|
||||||
|
SUPABASE_URL=http://localhost:8008
|
||||||
|
SUPABASE_KEY=your_service_role_key
|
||||||
|
|
||||||
|
# GLM API (用于 AI 标题生成)
|
||||||
|
GLM_API_KEY=your_glm_api_key
|
||||||
|
|
||||||
|
# LatentSync 配置
|
||||||
|
LATENTSYNC_GPU_ID=1
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 启动服务
|
||||||
|
|
||||||
|
**开发模式 (热重载)**:
|
||||||
|
```bash
|
||||||
|
uvicorn app.main:app --host 0.0.0.0 --port 8006 --reload
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧩 服务集成指南
|
||||||
|
|
||||||
|
### 集成新模型
|
||||||
|
|
||||||
|
如果需要集成新的 AI 模型 (例如新的 TTS 引擎):
|
||||||
|
|
||||||
|
1. 在 `app/services/` 下创建新的 Service 类 (如 `NewTTSService`)。
|
||||||
|
2. 实现 `generate` 方法,可以使用 subprocess 调用,也可以是 HTTP 请求。
|
||||||
|
3. **重要**: 如果模型占用 GPU,请务必使用 `asyncio.Lock` 进行并发控制,防止 OOM。
|
||||||
|
4. 在 `app/api/` 中添加对应的路由调用。
|
||||||
|
|
||||||
|
### 添加定时任务
|
||||||
|
|
||||||
|
目前推荐使用 **APScheduler** 或 **Crontab** 来管理定时任务。
|
||||||
|
社交媒体的定时发布功能目前依赖 `playwright` 的延迟执行,未来计划迁移到 Celery 队列。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛡️ 错误处理
|
||||||
|
|
||||||
|
全项目统一使用 `Loguru` 进行日志记录。
|
||||||
|
|
||||||
|
```python
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 业务逻辑
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"操作失败: {str(e)}")
|
||||||
|
raise HTTPException(status_code=500, detail="服务器内部错误")
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧪 测试
|
||||||
|
|
||||||
|
运行测试套件:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pytest
|
||||||
|
```
|
||||||
@@ -292,7 +292,17 @@ pm2 save
|
|||||||
curl http://localhost:8009/health
|
curl http://localhost:8009/health
|
||||||
```
|
```
|
||||||
|
|
||||||
### 5. 保存当前列表 (开机自启)
|
### 5. 启动服务看门狗 (Watchdog)
|
||||||
|
|
||||||
|
> 🛡️ **推荐**:监控 Qwen-TTS 和 LatentSync 服务健康状态,卡死时自动重启。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/rongye/ProgramFiles/ViGent2
|
||||||
|
pm2 start ./run_watchdog.sh --name vigent2-watchdog
|
||||||
|
pm2 save
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. 保存当前列表 (开机自启)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pm2 save
|
pm2 save
|
||||||
@@ -357,7 +367,46 @@ server {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 步骤 12: 配置阿里云 Nginx 网关 (关键)
|
---
|
||||||
|
|
||||||
|
## 步骤 13: 部署可选功能 (字幕与文案助手)
|
||||||
|
|
||||||
|
本节介绍如何部署逐字高亮字幕、片头标题以及文案提取助手功能。
|
||||||
|
|
||||||
|
### 13.1 部署字幕系统 (Subtitle System)
|
||||||
|
|
||||||
|
包含 `faster-whisper` (字幕生成) 和 `Remotion` (视频渲染) 组件。
|
||||||
|
|
||||||
|
详细步骤请参考:**[字幕功能部署指南](SUBTITLE_DEPLOY.md)**
|
||||||
|
|
||||||
|
简要步骤:
|
||||||
|
1. 安装 Python 依赖: `faster-whisper`
|
||||||
|
2. 安装 Node.js 依赖: `npm install` (在 `remotion/` 目录)
|
||||||
|
3. 验证: `npx remotion --version`
|
||||||
|
|
||||||
|
### 13.2 部署文案提取助手 (Copywriting Assistant)
|
||||||
|
|
||||||
|
支持 B站/抖音/TikTok 视频链接提取文案与 AI 洗稿。
|
||||||
|
|
||||||
|
1. **安装核心依赖**:
|
||||||
|
```bash
|
||||||
|
cd /home/rongye/ProgramFiles/ViGent2/backend
|
||||||
|
source venv/bin/activate
|
||||||
|
pip install yt-dlp zai-sdk
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **配置 AI 洗稿 (GLM)**:
|
||||||
|
确保 `.env` 中已配置 `GLM_API_KEY`:
|
||||||
|
```ini
|
||||||
|
GLM_API_KEY=your_zhipu_api_key
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **验证**:
|
||||||
|
访问 `http://localhost:8006/docs`,测试 `/api/tools/extract-script` 接口。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 步骤 14: 配置阿里云 Nginx 网关 (关键)
|
||||||
|
|
||||||
> ⚠️ **CRITICAL**: 如果使用 `api.hbyrkj.top` 等域名作为入口,必须在阿里云 (或公网入口) 的 Nginx 配置中解除上传限制。
|
> ⚠️ **CRITICAL**: 如果使用 `api.hbyrkj.top` 等域名作为入口,必须在阿里云 (或公网入口) 的 Nginx 配置中解除上传限制。
|
||||||
> **这是导致 500/413 错误的核心原因。**
|
> **这是导致 500/413 错误的核心原因。**
|
||||||
|
|||||||
119
Docs/DevLogs/Day16.md
Normal file
119
Docs/DevLogs/Day16.md
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 Qwen-TTS Flash Attention 优化 (10:00)
|
||||||
|
|
||||||
|
### 优化背景
|
||||||
|
Qwen3-TTS 1.7B 模型在默认情况下加载速度慢,推理显存占用高。通过引入 Flash Attention 2,可以显著提升模型加载速度和推理效率。
|
||||||
|
|
||||||
|
### 实施方案
|
||||||
|
在 `qwen-tts` Conda 环境中安装 `flash-attn`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
conda activate qwen-tts
|
||||||
|
pip install -U flash-attn --no-build-isolation
|
||||||
|
```
|
||||||
|
|
||||||
|
### 验证结果
|
||||||
|
- **加载速度**: 从 ~60s 提升至 **8.9s** ⚡
|
||||||
|
- **显存占用**: 显著降低,消除 OOM 风险
|
||||||
|
- **代码变动**: 无代码变动,仅环境优化 (自动检测)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛡️ 服务看门狗 Watchdog (10:30)
|
||||||
|
|
||||||
|
### 问题描述
|
||||||
|
常驻服务 (`vigent2-qwen-tts` 和 `vigent2-latentsync`) 可能会因显存碎片或长时间运行出现僵死 (Port open but unresponsive)。
|
||||||
|
|
||||||
|
### 解决方案
|
||||||
|
开发了一个 Python Watchdog 脚本,每 30 秒轮询服务的 `/health` 接口,如果连续 3 次失败则自动重启服务。
|
||||||
|
|
||||||
|
1. **Watchdog 脚本**: `backend/scripts/watchdog.py`
|
||||||
|
2. **启动脚本**: `run_watchdog.sh` (基于 PM2)
|
||||||
|
|
||||||
|
### 核心逻辑
|
||||||
|
```python
|
||||||
|
# 连续 3 次心跳失败触发重启
|
||||||
|
if service["failures"] >= service['threshold']:
|
||||||
|
subprocess.run(["pm2", "restart", service["name"]])
|
||||||
|
```
|
||||||
|
|
||||||
|
### 部署状态
|
||||||
|
- `vigent2-watchdog` 已启动并加入 PM2 列表
|
||||||
|
- 监控对象: `vigent2-qwen-tts` (8009), `vigent2-latentsync` (8007)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚡ LatentSync 性能确认
|
||||||
|
|
||||||
|
经代码审计,LatentSync 1.6 已内置优化:
|
||||||
|
- ✅ **Flash Attention**: 原生使用 `torch.nn.functional.scaled_dot_product_attention`
|
||||||
|
- ✅ **DeepCache**: 已启用 (`cache_interval=3`),提供 ~2.5x 加速
|
||||||
|
- ✅ **GPU 并发**: 双卡流水线 (GPU0 TTS | GPU1 LipSync) 已确认工作正常
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎨 UI 交互体验优化 (15:30)
|
||||||
|
|
||||||
|
### 优化内容
|
||||||
|
- 视频生成完成后,预览优先选中最新输出
|
||||||
|
- 选择项持久化:素材 / 背景音乐 / 历史视频
|
||||||
|
- 列表内滚动定位选中项,避免页面跳动
|
||||||
|
- 刷新回顶部(首页 / 发布页)
|
||||||
|
- 背景音乐试听即选中并自动开启,音量滑块实时影响试听
|
||||||
|
|
||||||
|
### 涉及文件
|
||||||
|
- `frontend/src/app/page.tsx`
|
||||||
|
- `frontend/src/app/publish/page.tsx`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎵 字体与背景音乐资源库接入 (15:50)
|
||||||
|
|
||||||
|
### 资源库
|
||||||
|
- `backend/assets/fonts/`(SuperIPAgent 字体全量导入)
|
||||||
|
- `backend/assets/bgm/`(背景音乐素材)
|
||||||
|
- `backend/assets/styles/{subtitle.json,title.json}`(样式预设)
|
||||||
|
|
||||||
|
### 服务能力
|
||||||
|
- `/api/assets/subtitle-styles`、`/api/assets/title-styles`、`/api/assets/bgm`
|
||||||
|
- `/assets` 静态挂载供前端预览与试听
|
||||||
|
|
||||||
|
### 生成链路调整
|
||||||
|
- 先完成人声与唇形/字幕对齐,再混入 BGM
|
||||||
|
- 修复 FFmpeg shell 解析导致的混音失败
|
||||||
|
- 禁用 amix 归一化,保证配音音量不被压低
|
||||||
|
|
||||||
|
### 关键修改
|
||||||
|
`backend/app/services/video_service.py`
|
||||||
|
```python
|
||||||
|
filter_complex = (
|
||||||
|
"[0:a]volume=1.0[a0];"
|
||||||
|
f"[1:a]volume={volume}[a1];"
|
||||||
|
"[a0][a1]amix=inputs=2:duration=first:dropout_transition=2:normalize=0[aout]"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🖼️ 标题/字幕样式预览 (16:10)
|
||||||
|
|
||||||
|
### 前端
|
||||||
|
- 样式选择 + 预览面板
|
||||||
|
- 字号可调(覆盖样式默认值)
|
||||||
|
- 字体文件动态加载
|
||||||
|
|
||||||
|
### Remotion
|
||||||
|
- 样式参数透传到 `Subtitles` / `Title`
|
||||||
|
- 渲染前临时复制字体到渲染目录
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 文档更新
|
||||||
|
|
||||||
|
- [x] `Docs/QWEN3_TTS_DEPLOY.md`: 添加 Flash Attention 安装指南
|
||||||
|
- [x] `Docs/DEPLOY_MANUAL.md`: 添加 Watchdog 部署说明
|
||||||
|
- [x] `Docs/task_complete.md`: 更新进度至 100% (Day 16)
|
||||||
|
- [x] `README.md`: 新增样式与背景音乐能力说明
|
||||||
|
- [x] `Docs/BACKEND_README.md`: 资产接口与混音链路说明
|
||||||
|
- [x] `Docs/FRONTEND_README.md`: 新增样式预览与BGM试听说明
|
||||||
103
Docs/FRONTEND_README.md
Normal file
103
Docs/FRONTEND_README.md
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
# ViGent2 Frontend
|
||||||
|
|
||||||
|
ViGent2 的前端界面,采用 Next.js 14 + TailwindCSS 构建。
|
||||||
|
|
||||||
|
## ✨ 核心功能
|
||||||
|
|
||||||
|
### 1. 视频生成 (`/`)
|
||||||
|
- **素材管理**: 拖拽上传人物视频,实时预览。
|
||||||
|
- **文案配音**: 集成 EdgeTTS,支持多音色选择 (云溪 / 晓晓)。
|
||||||
|
- **AI 标题/标签**: 一键生成视频标题与标签 (Day 14)。
|
||||||
|
- **标题/字幕样式**: 样式选择 + 预览 + 字号调节 (Day 16)。
|
||||||
|
- **背景音乐**: 试听 + 音量控制 + 选择持久化 (Day 16)。
|
||||||
|
- **交互优化**: 选择项持久化、列表内定位、刷新回顶部 (Day 16)。
|
||||||
|
- **进度追踪**: 实时显示视频生成进度 (10% -> 100%)。
|
||||||
|
- **结果预览**: 生成完成后直接播放下载。
|
||||||
|
- **本地保存**: 文案/标题自动保存,刷新后恢复 (Day 14)。
|
||||||
|
|
||||||
|
### 2. 全自动发布 (`/publish`) [Day 7 新增]
|
||||||
|
- **多平台管理**: 统一管理 B站、抖音、小红书账号状态。
|
||||||
|
- **扫码登录**:
|
||||||
|
- 集成后端 Playwright 生成的 QR Code。
|
||||||
|
- 实时检测扫码状态 (Wait/Success)。
|
||||||
|
- Cookie 自动保存与状态同步。
|
||||||
|
- **发布配置**: 设置视频标题、标签、简介。
|
||||||
|
- **定时任务**: 支持 "立即发布" 或 "定时发布"。
|
||||||
|
|
||||||
|
### 3. 声音克隆 [Day 13 新增]
|
||||||
|
- **TTS 模式选择**: EdgeTTS (预设音色) / 声音克隆 (自定义音色) 切换。
|
||||||
|
- **参考音频管理**: 上传/列表/删除参考音频 (3-20秒 WAV)。
|
||||||
|
- **一键克隆**: 选择参考音频后自动调用 Qwen3-TTS 服务。
|
||||||
|
|
||||||
|
### 4. 字幕与标题 [Day 13 新增]
|
||||||
|
- **片头标题**: 可选输入,视频开头显示 3 秒淡入淡出标题。
|
||||||
|
- **逐字高亮字幕**: 卡拉OK效果,默认开启,可关闭。
|
||||||
|
- **自动对齐**: 基于 faster-whisper 生成字级别时间戳。
|
||||||
|
- **样式预设**: 标题/字幕样式选择 + 预览 + 字号调节 (Day 16)。
|
||||||
|
|
||||||
|
### 5. 背景音乐 [Day 16 新增]
|
||||||
|
- **试听预览**: 点击试听即选中,音量滑块实时生效。
|
||||||
|
- **混音控制**: 仅影响 BGM,配音保持原音量。
|
||||||
|
|
||||||
|
### 6. 账户设置 [Day 15 新增]
|
||||||
|
- **手机号登录**: 11位中国手机号验证登录。
|
||||||
|
- **账户下拉菜单**: 显示有效期 + 修改密码 + 安全退出。
|
||||||
|
- **修改密码**: 弹窗输入当前密码与新密码,修改后强制重新登录。
|
||||||
|
|
||||||
|
### 7. 文案提取助手 (`ScriptExtractionModal`) [Day 15 新增]
|
||||||
|
- **多源提取**: 支持文件拖拽上传与 URL 粘贴 (B站/抖音/TikTok)。
|
||||||
|
- **AI 洗稿**: 集成 GLM-4.7-Flash,自动改写为口播文案。
|
||||||
|
- **一键填入**: 提取结果直接填充至视频生成输入框。
|
||||||
|
- **智能交互**: 实时进度展示,防误触设计。
|
||||||
|
|
||||||
|
## 🛠️ 技术栈
|
||||||
|
|
||||||
|
- **框架**: Next.js 14 (App Router)
|
||||||
|
- **样式**: TailwindCSS
|
||||||
|
- **图标**: Lucide React
|
||||||
|
- **组件**: 自定义现代化组件 (Glassmorphism 风格)
|
||||||
|
- **API**: Axios 实例 `@/lib/axios` (对接后端 FastAPI :8006)
|
||||||
|
|
||||||
|
## 🚀 开发指南
|
||||||
|
|
||||||
|
### 安装依赖
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### 启动开发服务器
|
||||||
|
|
||||||
|
默认运行在 **3002** 端口 (通过 `package.json` 配置):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
# 访问: http://localhost:3002
|
||||||
|
```
|
||||||
|
|
||||||
|
### 目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
src/
|
||||||
|
├── app/
|
||||||
|
│ ├── page.tsx # 视频生成主页
|
||||||
|
│ ├── publish/ # 发布管理页
|
||||||
|
│ │ └── page.tsx
|
||||||
|
│ └── layout.tsx # 全局布局 (导航栏)
|
||||||
|
├── components/ # UI 组件
|
||||||
|
│ ├── VideoUploader.tsx # 视频上传
|
||||||
|
│ ├── StatusBadge.tsx # 状态徽章
|
||||||
|
│ └── ...
|
||||||
|
└── lib/ # 工具函数
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔌 后端对接
|
||||||
|
|
||||||
|
- **Base URL**: `http://localhost:8006`
|
||||||
|
- **代理配置**: Next.js Rewrites (如需) 或直接 CORS。
|
||||||
|
|
||||||
|
## 🎨 设计规范
|
||||||
|
|
||||||
|
- **主色调**: 深紫/黑色系 (Dark Mode)
|
||||||
|
- **交互**: 悬停微动画 (Hover Effects)
|
||||||
|
- **响应式**: 适配桌面端大屏操作
|
||||||
333
Docs/Logs.md
333
Docs/Logs.md
@@ -1,333 +0,0 @@
|
|||||||
rongye@r730-ubuntu:~$ pm2 logs vigent2-qwen-tts
|
|
||||||
[TAILING] Tailing last 15 lines for [vigent2-qwen-tts] process (change the value with --lines option)
|
|
||||||
/home/rongye/.pm2/logs/vigent2-qwen-tts-error.log last 15 lines:
|
|
||||||
13|vigent2 | Setting `pad_token_id` to `eos_token_id`:2150 for open-end generation.
|
|
||||||
|
|
||||||
/home/rongye/.pm2/logs/vigent2-qwen-tts-out.log last 15 lines:
|
|
||||||
13|vigent2 | 🔄 Loading Qwen3-TTS model...
|
|
||||||
13|vigent2 |
|
|
||||||
13|vigent2 | ********
|
|
||||||
13|vigent2 | Warning: flash-attn is not installed. Will only run the manual PyTorch version. Please install flash-attn for faster inference.
|
|
||||||
13|vigent2 | ********
|
|
||||||
13|vigent2 |
|
|
||||||
13|vigent2 | ✅ Qwen3-TTS model loaded in 8.6s
|
|
||||||
13|vigent2 | INFO: 127.0.0.1:56814 - "GET /health HTTP/1.1" 200 OK
|
|
||||||
13|vigent2 | 🎤 Generating: 大家好,欢迎来到我的频道,今天给大家分享一些有趣的内容。...
|
|
||||||
13|vigent2 | 📝 Ref text: 其实生活中有许多美好的瞬间,比如清晨的阳光,或者一杯温热的清茶。希望这次生成的音色能够自然、流畅,完...
|
|
||||||
13|vigent2 | [WARNING] Min value of input waveform signal is -1.006709337234497
|
|
||||||
13|vigent2 | [WARNING] Max value of input waveform signal is 1.0008893013000488
|
|
||||||
13|vigent2 | ✅ Generated in 15.0s, duration: 4.6s
|
|
||||||
13|vigent2 | INFO: 127.0.0.1:36556 - "POST /generate HTTP/1.1" 200 OK
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
rongye@r730-ubuntu:~$ pm2 logs vigent2-backend --lines 400
|
|
||||||
[TAILING] Tailing last 400 lines for [vigent2-backend] process (change the value with --lines option)
|
|
||||||
/home/rongye/.pm2/logs/vigent2-backend-out.log last 400 lines:
|
|
||||||
11|vigent2 | Storage endpoint URL should have a trailing slash.
|
|
||||||
11|vigent2 | Storage endpoint URL should have a trailing slash.
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/materials?t=1769651820268 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/generated HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/generated HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/materials?t=1769651825016 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/publish/accounts HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/generated HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/materials?t=1769651828852 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/generated HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/ref-audios HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/materials?t=1769654501430 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/generated HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/materials?t=1769654987404 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/ref-audios HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/generated HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/ref-audios HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/ref-audios HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "POST /api/ref-audios HTTP/1.1" 500 Internal Server Error
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/ref-audios HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/materials?t=1769655093628 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/generated HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/ref-audios HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "POST /api/ref-audios HTTP/1.1" 500 Internal Server Error
|
|
||||||
11|vigent2 | Storage endpoint URL should have a trailing slash.
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/ref-audios HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/materials?t=1769655569331 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/generated HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "POST /api/ref-audios HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/ref-audios HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "POST /api/videos/generate HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | [Pipeline] TTS completed in 17.7s
|
|
||||||
11|vigent2 | [LipSync] Health check: ready=True
|
|
||||||
11|vigent2 | [LipSync] Starting LatentSync inference...
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | [Pipeline] LipSync completed in 122.8s
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | [Pipeline] Total generation time: 143.1s
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/tasks/bf4760b8-e338-49ee-9777-828c1ef0c855 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/generated HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/publish/accounts HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/generated HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/materials?t=1769655769762 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/generated HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/ref-audios HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/publish/accounts HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/generated HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/materials?t=1769655923194 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/generated HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/ref-audios HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/materials?t=1769655960629 HTTP/1.1" 403 Forbidden
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/ref-audios HTTP/1.1" 403 Forbidden
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/generated HTTP/1.1" 403 Forbidden
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "POST /api/auth/logout HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "POST /api/auth/login HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/materials?t=1769655964287 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/generated HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/ref-audios HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/publish/accounts HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/generated HTTP/1.1" 403 Forbidden
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "POST /api/auth/logout HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/publish/accounts HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/generated HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "POST /api/auth/login HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/materials?t=1769656015718 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/generated HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/ref-audios HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/materials?t=1769656233290 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/generated HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/ref-audios HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "POST /api/ref-audios HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/ref-audios HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/publish/accounts HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/generated HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/materials?t=1769656987465 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/generated HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/ref-audios HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/materials?t=1769657141569 HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/videos/generated HTTP/1.1" 200 OK
|
|
||||||
11|vigent2 | INFO: 27.17.161.128:0 - "GET /api/ref-audios HTTP/1.1" 200 OK
|
|
||||||
|
|
||||||
/home/rongye/.pm2/logs/vigent2-backend-error.log last 400 lines:
|
|
||||||
11|vigent2 | rnPaKCW6D20R7A4QpeumwXIRUkzHtaFASP40bWfE6KL05g4rq6VbZFQ9X4FVBZ2lbwW%2Faa32knjuye8aa1ejtZEGmyfXpfcryezEIy0gmYYjjT7lKB6HAupj9%2FCezQ%3D%3D; rl_trait=RudderEncrypt%3AU2FsdGVkX1%2BpEG8yoPZBpac674EsBSuEU0HhlEZGMLIKNfviY6GGLzzbk6%2BbdfmzJ5s1nr16B0NNWzywMDwDD00Cktdf8N50BWw0Pp7Xuy2cOM6L15tjqobzRZyayXyVA1o%2B5kHPODaa3yg4cjWjee8OqG1qRaX4EwOXc0YzPZI%3D; rl_user_id=RudderEncrypt%3AU2FsdGVkX1%2BRY4oSsXW07D0HdYfXZhDpJS%2Fl%2F%2Bysns8Xand%2BMI7%2FJBIRw1RV%2FIJPzbTSpW8kmvwLCsUosyNPtsZbl3lGRDOM4YJIL%2BaFVjvjAWDo0WA89ezEeTVY9hzd9rwV3A6dbv5vJhrEdjolAkub50ItC47iV1fIGb%2FN3vI%3D; rl_anonymous_id=RudderEncrypt%3AU2FsdGVkX19r9Vr3ov%2BP30OgbarNSaCn6bebg11iU%2B8UV7b%2F116JurvSpJ77d%2FdZ62kjIP%2BMF3h3R9RathLKFQ%3D%3D; rl_page_init_referrer=RudderEncrypt%3AU2FsdGVkX19CE%2F3GmyTsZHCQhdFWdzYnJYPdvCMBFbM%3D; rl_page_init_referring_domain=RudderEncrypt%3AU2FsdGVkX18t2%2FxrnN2HPEqTssR572nq%2FgCim9EQN7E%3D'}
|
|
||||||
11|vigent2 | 2026-01-29 11:06:00.756 | INFO | app.main:dispatch:21 - START Request: GET https://vigent.hbyrkj.top/api/videos/generated
|
|
||||||
11|vigent2 | 2026-01-29 11:06:00.757 | INFO | app.main:dispatch:22 - HEADERS: {'connection': 'upgrade', 'host': 'vigent.hbyrkj.top', 'x-real-ip': '27.17.161.128', 'x-forwarded-for': '27.17.161.128', 'x-forwarded-proto': 'https', 'sec-fetch-dest': 'empty', 'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.2 Mobile/15E148 Safari/604.1', 'accept': 'application/json, text/plain, */*', 'referer': 'https://vigent.hbyrkj.top/', 'sec-fetch-site': 'same-origin', 'sec-fetch-mode': 'cors', 'accept-language': 'en-US,en;q=0.9', 'priority': 'u=3, i', 'accept-encoding': 'gzip, deflate, br', 'cookie': 'access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5NGNkOTFlMy03ZDg5LTQ1ZTgtOWQ4NS1lOGJhMDY2MGQ3NGMiLCJzZXNzaW9uX3Rva2VuIjoiN2JlNWIzNWYtMzQ0Ni00ZTIyLWEzMTktZTc5M2NlNDBmYTRiIiwiZXhwIjoxNzcwMTc4MTE0fQ.pk4sCAkd9hcN6fE5_8RXH42zfMl7YPSV5i1R9QeER4s; ph_phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo_posthog=%7B%22distinct_id%22%3A%22f6a1ba3602218bc1551bb81b48167bf7484eeb86ed8ee9484fa83f1267023264%230d2437ec-d81b-491c-991f-0b6559daa00d%22%2C%22%24sesid%22%3A%5B1760758482696%2C%220199f562-16c1-7fcb-9bef-fdc33838b6a8%22%2C1760758470336%5D%2C%22%24epp%22%3Atrue%2C%22%24initial_person_info%22%3A%7B%22r%22%3A%22%24direct%22%2C%22u%22%3A%22https%3A%2F%2Fn8n.hbyrkj.top%2Fsignin%3Fredirect%3D%25252F%22%7D%7D; rl_session=RudderEncrypt%3AU2FsdGVkX19ssBuVw9hBTDRVrnPaKCW6D20R7A4QpeumwXIRUkzHtaFASP40bWfE6KL05g4rq6VbZFQ9X4FVBZ2lbwW%2Faa32knjuye8aa1ejtZEGmyfXpfcryezEIy0gmYYjjT7lKB6HAupj9%2FCezQ%3D%3D; rl_trait=RudderEncrypt%3AU2FsdGVkX1%2BpEG8yoPZBpac674EsBSuEU0HhlEZGMLIKNfviY6GGLzzbk6%2BbdfmzJ5s1nr16B0NNWzywMDwDD00Cktdf8N50BWw0Pp7Xuy2cOM6L15tjqobzRZyayXyVA1o%2B5kHPODaa3yg4cjWjee8OqG1qRaX4EwOXc0YzPZI%3D; rl_user_id=RudderEncrypt%3AU2FsdGVkX1%2BRY4oSsXW07D0HdYfXZhDpJS%2Fl%2F%2Bysns8Xand%2BMI7%2FJBIRw1RV%2FIJPzbTSpW8kmvwLCsUosyNPtsZbl3lGRDOM4YJIL%2BaFVjvjAWDo0WA89ezEeTVY9hzd9rwV3A6dbv5vJhrEdjolAkub50ItC47iV1fIGb%2FN3vI%3D; rl_anonymous_id=RudderEncrypt%3AU2FsdGVkX19r9Vr3ov%2BP30OgbarNSaCn6bebg11iU%2B8UV7b%2F116JurvSpJ77d%2FdZ62kjIP%2BMF3h3R9RathLKFQ%3D%3D; rl_page_init_referrer=RudderEncrypt%3AU2FsdGVkX19CE%2F3GmyTsZHCQhdFWdzYnJYPdvCMBFbM%3D; rl_page_init_referring_domain=RudderEncrypt%3AU2FsdGVkX18t2%2FxrnN2HPEqTssR572nq%2FgCim9EQN7E%3D'}
|
|
||||||
11|vigent2 | 2026-01-29 11:06:00.765 | INFO | app.main:dispatch:26 - END Request: GET https://vigent.hbyrkj.top/api/ref-audios - Status: 403 - Duration: 0.02s
|
|
||||||
11|vigent2 | 2026-01-29 11:06:00.766 | INFO | app.main:dispatch:26 - END Request: GET https://vigent.hbyrkj.top/api/videos/generated - Status: 403 - Duration: 0.01s
|
|
||||||
11|vigent2 | 2026-01-29 11:06:00.812 | INFO | app.main:dispatch:21 - START Request: POST https://vigent.hbyrkj.top/api/auth/logout
|
|
||||||
11|vigent2 | 2026-01-29 11:06:00.812 | INFO | app.main:dispatch:22 - HEADERS: {'connection': 'upgrade', 'host': 'vigent.hbyrkj.top', 'x-real-ip': '27.17.161.128', 'x-forwarded-for': '27.17.161.128', 'x-forwarded-proto': 'https', 'content-length': '0', 'accept': '*/*', 'sec-fetch-site': 'same-origin', 'origin': 'https://vigent.hbyrkj.top', 'sec-fetch-mode': 'cors', 'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.2 Mobile/15E148 Safari/604.1', 'referer': 'https://vigent.hbyrkj.top/', 'sec-fetch-dest': 'empty', 'accept-language': 'en-US,en;q=0.9', 'priority': 'u=3, i', 'accept-encoding': 'gzip, deflate, br', 'cookie': 'access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5NGNkOTFlMy03ZDg5LTQ1ZTgtOWQ4NS1lOGJhMDY2MGQ3NGMiLCJzZXNzaW9uX3Rva2VuIjoiN2JlNWIzNWYtMzQ0Ni00ZTIyLWEzMTktZTc5M2NlNDBmYTRiIiwiZXhwIjoxNzcwMTc4MTE0fQ.pk4sCAkd9hcN6fE5_8RXH42zfMl7YPSV5i1R9QeER4s; ph_phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo_posthog=%7B%22distinct_id%22%3A%22f6a1ba3602218bc1551bb81b48167bf7484eeb86ed8ee9484fa83f1267023264%230d2437ec-d81b-491c-991f-0b6559daa00d%22%2C%22%24sesid%22%3A%5B1760758482696%2C%220199f562-16c1-7fcb-9bef-fdc33838b6a8%22%2C1760758470336%5D%2C%22%24epp%22%3Atrue%2C%22%24initial_person_info%22%3A%7B%22r%22%3A%22%24direct%22%2C%22u%22%3A%22https%3A%2F%2Fn8n.hbyrkj.top%2Fsignin%3Fredirect%3D%25252F%22%7D%7D; rl_session=RudderEncrypt%3AU2FsdGVkX19ssBuVw9hBTDRVrnPaKCW6D20R7A4QpeumwXIRUkzHtaFASP40bWfE6KL05g4rq6VbZFQ9X4FVBZ2lbwW%2Faa32knjuye8aa1ejtZEGmyfXpfcryezEIy0gmYYjjT7lKB6HAupj9%2FCezQ%3D%3D; rl_trait=RudderEncrypt%3AU2FsdGVkX1%2BpEG8yoPZBpac674EsBSuEU0HhlEZGMLIKNfviY6GGLzzbk6%2BbdfmzJ5s1nr16B0NNWzywMDwDD00Cktdf8N50BWw0Pp7Xuy2cOM6L15tjqobzRZyayXyVA1o%2B5kHPODaa3yg4cjWjee8OqG1qRaX4EwOXc0YzPZI%3D; rl_user_id=RudderEncrypt%3AU2FsdGVkX1%2BRY4oSsXW07D0HdYfXZhDpJS%2Fl%2F%2Bysns8Xand%2BMI7%2FJBIRw1RV%2FIJPzbTSpW8kmvwLCsUosyNPtsZbl3lGRDOM4YJIL%2BaFVjvjAWDo0WA89ezEeTVY9hzd9rwV3A6dbv5vJhrEdjolAkub50ItC47iV1fIGb%2FN3vI%3D; rl_anonymous_id=RudderEncrypt%3AU2FsdGVkX19r9Vr3ov%2BP30OgbarNSaCn6bebg11iU%2B8UV7b%2F116JurvSpJ77d%2FdZ62kjIP%2BMF3h3R9RathLKFQ%3D%3D; rl_page_init_referrer=RudderEncrypt%3AU2FsdGVkX19CE%2F3GmyTsZHCQhdFWdzYnJYPdvCMBFbM%3D; rl_page_init_referring_domain=RudderEncrypt%3AU2FsdGVkX18t2%2FxrnN2HPEqTssR572nq%2FgCim9EQN7E%3D'}
|
|
||||||
11|vigent2 | 2026-01-29 11:06:00.815 | INFO | app.main:dispatch:26 - END Request: POST https://vigent.hbyrkj.top/api/auth/logout - Status: 200 - Duration: 0.00s
|
|
||||||
11|vigent2 | 2026-01-29 11:06:03.694 | INFO | app.main:dispatch:21 - START Request: POST https://vigent.hbyrkj.top/api/auth/login
|
|
||||||
11|vigent2 | 2026-01-29 11:06:03.695 | INFO | app.main:dispatch:22 - HEADERS: {'connection': 'upgrade', 'host': 'vigent.hbyrkj.top', 'x-real-ip': '27.17.161.128', 'x-forwarded-for': '27.17.161.128', 'x-forwarded-proto': 'https', 'content-length': '58', 'accept': '*/*', 'content-type': 'application/json', 'sec-fetch-site': 'same-origin', 'origin': 'https://vigent.hbyrkj.top', 'sec-fetch-mode': 'cors', 'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.2 Mobile/15E148 Safari/604.1', 'referer': 'https://vigent.hbyrkj.top/login', 'sec-fetch-dest': 'empty', 'accept-language': 'en-US,en;q=0.9', 'priority': 'u=3, i', 'accept-encoding': 'gzip, deflate, br', 'cookie': 'ph_phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo_posthog=%7B%22distinct_id%22%3A%22f6a1ba3602218bc1551bb81b48167bf7484eeb86ed8ee9484fa83f1267023264%230d2437ec-d81b-491c-991f-0b6559daa00d%22%2C%22%24sesid%22%3A%5B1760758482696%2C%220199f562-16c1-7fcb-9bef-fdc33838b6a8%22%2C1760758470336%5D%2C%22%24epp%22%3Atrue%2C%22%24initial_person_info%22%3A%7B%22r%22%3A%22%24direct%22%2C%22u%22%3A%22https%3A%2F%2Fn8n.hbyrkj.top%2Fsignin%3Fredirect%3D%25252F%22%7D%7D; rl_session=RudderEncrypt%3AU2FsdGVkX19ssBuVw9hBTDRVrnPaKCW6D20R7A4QpeumwXIRUkzHtaFASP40bWfE6KL05g4rq6VbZFQ9X4FVBZ2lbwW%2Faa32knjuye8aa1ejtZEGmyfXpfcryezEIy0gmYYjjT7lKB6HAupj9%2FCezQ%3D%3D; rl_trait=RudderEncrypt%3AU2FsdGVkX1%2BpEG8yoPZBpac674EsBSuEU0HhlEZGMLIKNfviY6GGLzzbk6%2BbdfmzJ5s1nr16B0NNWzywMDwDD00Cktdf8N50BWw0Pp7Xuy2cOM6L15tjqobzRZyayXyVA1o%2B5kHPODaa3yg4cjWjee8OqG1qRaX4EwOXc0YzPZI%3D; rl_user_id=RudderEncrypt%3AU2FsdGVkX1%2BRY4oSsXW07D0HdYfXZhDpJS%2Fl%2F%2Bysns8Xand%2BMI7%2FJBIRw1RV%2FIJPzbTSpW8kmvwLCsUosyNPtsZbl3lGRDOM4YJIL%2BaFVjvjAWDo0WA89ezEeTVY9hzd9rwV3A6dbv5vJhrEdjolAkub50ItC47iV1fIGb%2FN3vI%3D; rl_anonymous_id=RudderEncrypt%3AU2FsdGVkX19r9Vr3ov%2BP30OgbarNSaCn6bebg11iU%2B8UV7b%2F116JurvSpJ77d%2FdZ62kjIP%2BMF3h3R9RathLKFQ%3D%3D; rl_page_init_referrer=RudderEncrypt%3AU2FsdGVkX19CE%2F3GmyTsZHCQhdFWdzYnJYPdvCMBFbM%3D; rl_page_init_referring_domain=RudderEncrypt%3AU2FsdGVkX18t2%2FxrnN2HPEqTssR572nq%2FgCim9EQN7E%3D'}
|
|
||||||
11|vigent2 | 2026-01-29 11:06:04.185 | INFO | app.api.auth:login:157 - 用户登录: lamnickdavid@gmail.com
|
|
||||||
11|vigent2 | 2026-01-29 11:06:04.185 | INFO | app.main:dispatch:26 - END Request: POST https://vigent.hbyrkj.top/api/auth/login - Status: 200 - Duration: 0.49s
|
|
||||||
11|vigent2 | 2026-01-29 11:06:04.359 | INFO | app.main:dispatch:21 - START Request: GET https://vigent.hbyrkj.top/api/materials?t=1769655964287
|
|
||||||
11|vigent2 | 2026-01-29 11:06:04.359 | INFO | app.main:dispatch:22 - HEADERS: {'connection': 'upgrade', 'host': 'vigent.hbyrkj.top', 'x-real-ip': '27.17.161.128', 'x-forwarded-for': '27.17.161.128', 'x-forwarded-proto': 'https', 'sec-fetch-dest': 'empty', 'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.2 Mobile/15E148 Safari/604.1', 'accept': 'application/json, text/plain, */*', 'referer': 'https://vigent.hbyrkj.top/', 'sec-fetch-site': 'same-origin', 'sec-fetch-mode': 'cors', 'accept-language': 'en-US,en;q=0.9', 'priority': 'u=3, i', 'accept-encoding': 'gzip, deflate, br', 'cookie': 'access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5NGNkOTFlMy03ZDg5LTQ1ZTgtOWQ4NS1lOGJhMDY2MGQ3NGMiLCJzZXNzaW9uX3Rva2VuIjoiMWE0NzczNTktZmMwZS00MjVhLTk3MGUtODc1ZTcyNjFjYWJiIiwiZXhwIjoxNzcwMjYwNzY0fQ.X-nGjaX_gwaJw995Zuw_fnj2oY_K-oM6tgwMDR4pDQk; ph_phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo_posthog=%7B%22distinct_id%22%3A%22f6a1ba3602218bc1551bb81b48167bf7484eeb86ed8ee9484fa83f1267023264%230d2437ec-d81b-491c-991f-0b6559daa00d%22%2C%22%24sesid%22%3A%5B1760758482696%2C%220199f562-16c1-7fcb-9bef-fdc33838b6a8%22%2C1760758470336%5D%2C%22%24epp%22%3Atrue%2C%22%24initial_person_info%22%3A%7B%22r%22%3A%22%24direct%22%2C%22u%22%3A%22https%3A%2F%2Fn8n.hbyrkj.top%2Fsignin%3Fredirect%3D%25252F%22%7D%7D; rl_session=RudderEncrypt%3AU2FsdGVkX19ssBuVw9hBTDRVrnPaKCW6D20R7A4QpeumwXIRUkzHtaFASP40bWfE6KL05g4rq6VbZFQ9X4FVBZ2lbwW%2Faa32knjuye8aa1ejtZEGmyfXpfcryezEIy0gmYYjjT7lKB6HAupj9%2FCezQ%3D%3D; rl_trait=RudderEncrypt%3AU2FsdGVkX1%2BpEG8yoPZBpac674EsBSuEU0HhlEZGMLIKNfviY6GGLzzbk6%2BbdfmzJ5s1nr16B0NNWzywMDwDD00Cktdf8N50BWw0Pp7Xuy2cOM6L15tjqobzRZyayXyVA1o%2B5kHPODaa3yg4cjWjee8OqG1qRaX4EwOXc0YzPZI%3D; rl_user_id=RudderEncrypt%3AU2FsdGVkX1%2BRY4oSsXW07D0HdYfXZhDpJS%2Fl%2F%2Bysns8Xand%2BMI7%2FJBIRw1RV%2FIJPzbTSpW8kmvwLCsUosyNPtsZbl3lGRDOM4YJIL%2BaFVjvjAWDo0WA89ezEeTVY9hzd9rwV3A6dbv5vJhrEdjolAkub50ItC47iV1fIGb%2FN3vI%3D; rl_anonymous_id=RudderEncrypt%3AU2FsdGVkX19r9Vr3ov%2BP30OgbarNSaCn6bebg11iU%2B8UV7b%2F116JurvSpJ77d%2FdZ62kjIP%2BMF3h3R9RathLKFQ%3D%3D; rl_page_init_referrer=RudderEncrypt%3AU2FsdGVkX19CE%2F3GmyTsZHCQhdFWdzYnJYPdvCMBFbM%3D; rl_page_init_referring_domain=RudderEncrypt%3AU2FsdGVkX18t2%2FxrnN2HPEqTssR572nq%2FgCim9EQN7E%3D'}
|
|
||||||
11|vigent2 | 2026-01-29 11:06:04.377 | INFO | app.main:dispatch:21 - START Request: GET https://vigent.hbyrkj.top/api/ref-audios
|
|
||||||
11|vigent2 | 2026-01-29 11:06:04.377 | INFO | app.main:dispatch:22 - HEADERS: {'connection': 'upgrade', 'host': 'vigent.hbyrkj.top', 'x-real-ip': '27.17.161.128', 'x-forwarded-for': '27.17.161.128', 'x-forwarded-proto': 'https', 'sec-fetch-dest': 'empty', 'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.2 Mobile/15E148 Safari/604.1', 'accept': 'application/json, text/plain, */*', 'referer': 'https://vigent.hbyrkj.top/', 'sec-fetch-site': 'same-origin', 'sec-fetch-mode': 'cors', 'accept-language': 'en-US,en;q=0.9', 'priority': 'u=3, i', 'accept-encoding': 'gzip, deflate, br', 'cookie': 'access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5NGNkOTFlMy03ZDg5LTQ1ZTgtOWQ4NS1lOGJhMDY2MGQ3NGMiLCJzZXNzaW9uX3Rva2VuIjoiMWE0NzczNTktZmMwZS00MjVhLTk3MGUtODc1ZTcyNjFjYWJiIiwiZXhwIjoxNzcwMjYwNzY0fQ.X-nGjaX_gwaJw995Zuw_fnj2oY_K-oM6tgwMDR4pDQk; ph_phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo_posthog=%7B%22distinct_id%22%3A%22f6a1ba3602218bc1551bb81b48167bf7484eeb86ed8ee9484fa83f1267023264%230d2437ec-d81b-491c-991f-0b6559daa00d%22%2C%22%24sesid%22%3A%5B1760758482696%2C%220199f562-16c1-7fcb-9bef-fdc33838b6a8%22%2C1760758470336%5D%2C%22%24epp%22%3Atrue%2C%22%24initial_person_info%22%3A%7B%22r%22%3A%22%24direct%22%2C%22u%22%3A%22https%3A%2F%2Fn8n.hbyrkj.top%2Fsignin%3Fredirect%3D%25252F%22%7D%7D; rl_session=RudderEncrypt%3AU2FsdGVkX19ssBuVw9hBTDRVrnPaKCW6D20R7A4QpeumwXIRUkzHtaFASP40bWfE6KL05g4rq6VbZFQ9X4FVBZ2lbwW%2Faa32knjuye8aa1ejtZEGmyfXpfcryezEIy0gmYYjjT7lKB6HAupj9%2FCezQ%3D%3D; rl_trait=RudderEncrypt%3AU2FsdGVkX1%2BpEG8yoPZBpac674EsBSuEU0HhlEZGMLIKNfviY6GGLzzbk6%2BbdfmzJ5s1nr16B0NNWzywMDwDD00Cktdf8N50BWw0Pp7Xuy2cOM6L15tjqobzRZyayXyVA1o%2B5kHPODaa3yg4cjWjee8OqG1qRaX4EwOXc0YzPZI%3D; rl_user_id=RudderEncrypt%3AU2FsdGVkX1%2BRY4oSsXW07D0HdYfXZhDpJS%2Fl%2F%2Bysns8Xand%2BMI7%2FJBIRw1RV%2FIJPzbTSpW8kmvwLCsUosyNPtsZbl3lGRDOM4YJIL%2BaFVjvjAWDo0WA89ezEeTVY9hzd9rwV3A6dbv5vJhrEdjolAkub50ItC47iV1fIGb%2FN3vI%3D; rl_anonymous_id=RudderEncrypt%3AU2FsdGVkX19r9Vr3ov%2BP30OgbarNSaCn6bebg11iU%2B8UV7b%2F116JurvSpJ77d%2FdZ62kjIP%2BMF3h3R9RathLKFQ%3D%3D; rl_page_init_referrer=RudderEncrypt%3AU2FsdGVkX19CE%2F3GmyTsZHCQhdFWdzYnJYPdvCMBFbM%3D; rl_page_init_referring_domain=RudderEncrypt%3AU2FsdGVkX18t2%2FxrnN2HPEqTssR572nq%2FgCim9EQN7E%3D'}
|
|
||||||
11|vigent2 | 2026-01-29 11:06:04.392 | INFO | app.main:dispatch:21 - START Request: GET https://vigent.hbyrkj.top/api/videos/generated
|
|
||||||
11|vigent2 | 2026-01-29 11:06:04.392 | INFO | app.main:dispatch:22 - HEADERS: {'connection': 'upgrade', 'host': 'vigent.hbyrkj.top', 'x-real-ip': '27.17.161.128', 'x-forwarded-for': '27.17.161.128', 'x-forwarded-proto': 'https', 'sec-fetch-dest': 'empty', 'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.2 Mobile/15E148 Safari/604.1', 'accept': 'application/json, text/plain, */*', 'referer': 'https://vigent.hbyrkj.top/', 'sec-fetch-site': 'same-origin', 'sec-fetch-mode': 'cors', 'accept-language': 'en-US,en;q=0.9', 'priority': 'u=3, i', 'accept-encoding': 'gzip, deflate, br', 'cookie': 'access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5NGNkOTFlMy03ZDg5LTQ1ZTgtOWQ4NS1lOGJhMDY2MGQ3NGMiLCJzZXNzaW9uX3Rva2VuIjoiMWE0NzczNTktZmMwZS00MjVhLTk3MGUtODc1ZTcyNjFjYWJiIiwiZXhwIjoxNzcwMjYwNzY0fQ.X-nGjaX_gwaJw995Zuw_fnj2oY_K-oM6tgwMDR4pDQk; ph_phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo_posthog=%7B%22distinct_id%22%3A%22f6a1ba3602218bc1551bb81b48167bf7484eeb86ed8ee9484fa83f1267023264%230d2437ec-d81b-491c-991f-0b6559daa00d%22%2C%22%24sesid%22%3A%5B1760758482696%2C%220199f562-16c1-7fcb-9bef-fdc33838b6a8%22%2C1760758470336%5D%2C%22%24epp%22%3Atrue%2C%22%24initial_person_info%22%3A%7B%22r%22%3A%22%24direct%22%2C%22u%22%3A%22https%3A%2F%2Fn8n.hbyrkj.top%2Fsignin%3Fredirect%3D%25252F%22%7D%7D; rl_session=RudderEncrypt%3AU2FsdGVkX19ssBuVw9hBTDRVrnPaKCW6D20R7A4QpeumwXIRUkzHtaFASP40bWfE6KL05g4rq6VbZFQ9X4FVBZ2lbwW%2Faa32knjuye8aa1ejtZEGmyfXpfcryezEIy0gmYYjjT7lKB6HAupj9%2FCezQ%3D%3D; rl_trait=RudderEncrypt%3AU2FsdGVkX1%2BpEG8yoPZBpac674EsBSuEU0HhlEZGMLIKNfviY6GGLzzbk6%2BbdfmzJ5s1nr16B0NNWzywMDwDD00Cktdf8N50BWw0Pp7Xuy2cOM6L15tjqobzRZyayXyVA1o%2B5kHPODaa3yg4cjWjee8OqG1qRaX4EwOXc0YzPZI%3D; rl_user_id=RudderEncrypt%3AU2FsdGVkX1%2BRY4oSsXW07D0HdYfXZhDpJS%2Fl%2F%2Bysns8Xand%2BMI7%2FJBIRw1RV%2FIJPzbTSpW8kmvwLCsUosyNPtsZbl3lGRDOM4YJIL%2BaFVjvjAWDo0WA89ezEeTVY9hzd9rwV3A6dbv5vJhrEdjolAkub50ItC47iV1fIGb%2FN3vI%3D; rl_anonymous_id=RudderEncrypt%3AU2FsdGVkX19r9Vr3ov%2BP30OgbarNSaCn6bebg11iU%2B8UV7b%2F116JurvSpJ77d%2FdZ62kjIP%2BMF3h3R9RathLKFQ%3D%3D; rl_page_init_referrer=RudderEncrypt%3AU2FsdGVkX19CE%2F3GmyTsZHCQhdFWdzYnJYPdvCMBFbM%3D; rl_page_init_referring_domain=RudderEncrypt%3AU2FsdGVkX18t2%2FxrnN2HPEqTssR572nq%2FgCim9EQN7E%3D'}
|
|
||||||
11|vigent2 | 2026-01-29 11:06:04.478 | INFO | app.main:dispatch:26 - END Request: GET https://vigent.hbyrkj.top/api/materials?t=1769655964287 - Status: 200 - Duration: 0.12s
|
|
||||||
11|vigent2 | 2026-01-29 11:06:04.491 | INFO | app.main:dispatch:26 - END Request: GET https://vigent.hbyrkj.top/api/videos/generated - Status: 200 - Duration: 0.10s
|
|
||||||
11|vigent2 | 2026-01-29 11:06:04.614 | INFO | app.main:dispatch:26 - END Request: GET https://vigent.hbyrkj.top/api/ref-audios - Status: 200 - Duration: 0.24s
|
|
||||||
11|vigent2 | 2026-01-29 11:06:16.329 | INFO | app.main:dispatch:21 - START Request: GET https://vigent.hbyrkj.top/api/publish/accounts
|
|
||||||
11|vigent2 | 2026-01-29 11:06:16.329 | INFO | app.main:dispatch:22 - HEADERS: {'connection': 'upgrade', 'host': 'vigent.hbyrkj.top', 'x-real-ip': '27.17.161.128', 'x-forwarded-for': '27.17.161.128', 'x-forwarded-proto': 'https', 'sec-ch-ua-platform': '"Windows"', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36', 'accept': 'application/json, text/plain, */*', 'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"', 'sec-ch-ua-mobile': '?0', 'sec-fetch-site': 'same-origin', 'sec-fetch-mode': 'cors', 'sec-fetch-dest': 'empty', 'referer': 'https://vigent.hbyrkj.top/publish', 'accept-encoding': 'gzip, deflate, br, zstd', 'accept-language': 'en-US,en;q=0.9,zh;q=0.8,zh-CN;q=0.7', 'priority': 'u=1, i', 'cookie': 'rl_page_init_referrer=RudderEncrypt%3AU2FsdGVkX1%2FRWtsIwIaguDp15em58SDrIwOvRJVXeK4%3D; rl_page_init_referring_domain=RudderEncrypt%3AU2FsdGVkX1%2BVZN6tniQmiO5L2fGVdcrYOkqG%2BRHkNFw%3D; ph_phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo_posthog=%7B%22distinct_id%22%3A%22f6a1ba3602218bc1551bb81b48167bf7484eeb86ed8ee9484fa83f1267023264%230d2437ec-d81b-491c-991f-0b6559daa00d%22%2C%22%24sesid%22%3A%5B1762504332341%2C%22019a5d6c-ae21-7d75-8919-11e9621a135f%22%2C1762503994906%5D%2C%22%24epp%22%3Atrue%2C%22%24initial_person_info%22%3A%7B%22r%22%3A%22%24direct%22%2C%22u%22%3A%22https%3A%2F%2Fn8n.hbyrkj.top%2Fsignin%3Fredirect%3D%25252F%22%7D%7D; rl_anonymous_id=RudderEncrypt%3AU2FsdGVkX19aTpWYcHFt3zhITFSLk1XAMr9V2jBWQwsuLDNLXh93pTlQ%2FUpvwmv6h%2Fl1bW4xH83hrkWPCTkSYg%3D%3D; rl_group_id=RudderEncrypt%3AU2FsdGVkX1%2BhywVlN3t3ypqwAMgqlh7ZRNLMKnFMhxA%3D; rl_group_trait=RudderEncrypt%3AU2FsdGVkX19jAKNOmR%2FnSngsWGVcmYB2qyvsbh3wQc0%3D; rl_user_id=RudderEncrypt%3AU2FsdGVkX180hU8QtHwPe3dPd1o7rEP7efRzFgCIvuIPRwbE3dWE0aEQCCMpQTN%2B7AGEtH6mjRvEuqcbfOdaX4TtJGL2jHbdcZUuA7Mpjf0uvsZ15LToi0zM1NWR7i6wE2z4vcYyFaBdB1uTJq3SxhX2WsqWe4YiT12vld0E%2F5w%3D; rl_trait=RudderEncrypt%3AU2FsdGVkX19tgs8QN46oDejOzAvFyTx%2FIVRu7LAGDzh2eg%2FAhV8eY%2FyjW12D%2BtSOVq6NLF2lSZcY40rlQ%2B1fUc3DAe2euuWhIECOtlxtY5Hho11ZdHGB8lZ4CSLo%2BWmSIjzmkQ33RgkeNF9eYV4AV1PpdZZ%2Fjyl%2BVjCQtaNVV5c%3D; rl_session=RudderEncrypt%3AU2FsdGVkX19jm82pV3xfWHI%2FE6QaUo5xFQZuXuYh%2FkUCBhyJGY7TqzAK3YDkYppIpUipS7LtUSxm6iWAAp3vGhbB58MN7hrVa8imlwsuL7ceFNN%2BR1uTEvKTR8wWKaii2Xzs%2FYnhG3X8kmImIfYZgg%3D%3D; access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5NGNkOTFlMy03ZDg5LTQ1ZTgtOWQ4NS1lOGJhMDY2MGQ3NGMiLCJzZXNzaW9uX3Rva2VuIjoiNDk2N2QwNjMtNjhhZC00NzFkLThhMWQtOGE1MmJhODAxZjBjIiwiZXhwIjoxNzcwMTc4MzM4fQ.k9JOPKwqHrNTTNOsUQlMuA63rOETStl7uWXAIIDLGtA'}
|
|
||||||
11|vigent2 | 2026-01-29 11:06:16.333 | INFO | app.main:dispatch:21 - START Request: GET https://vigent.hbyrkj.top/api/videos/generated
|
|
||||||
11|vigent2 | 2026-01-29 11:06:16.333 | INFO | app.main:dispatch:22 - HEADERS: {'connection': 'upgrade', 'host': 'vigent.hbyrkj.top', 'x-real-ip': '27.17.161.128', 'x-forwarded-for': '27.17.161.128', 'x-forwarded-proto': 'https', 'sec-ch-ua-platform': '"Windows"', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36', 'accept': 'application/json, text/plain, */*', 'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"', 'sec-ch-ua-mobile': '?0', 'sec-fetch-site': 'same-origin', 'sec-fetch-mode': 'cors', 'sec-fetch-dest': 'empty', 'referer': 'https://vigent.hbyrkj.top/publish', 'accept-encoding': 'gzip, deflate, br, zstd', 'accept-language': 'en-US,en;q=0.9,zh;q=0.8,zh-CN;q=0.7', 'priority': 'u=1, i', 'cookie': 'rl_page_init_referrer=RudderEncrypt%3AU2FsdGVkX1%2FRWtsIwIaguDp15em58SDrIwOvRJVXeK4%3D; rl_page_init_referring_domain=RudderEncrypt%3AU2FsdGVkX1%2BVZN6tniQmiO5L2fGVdcrYOkqG%2BRHkNFw%3D; ph_phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo_posthog=%7B%22distinct_id%22%3A%22f6a1ba3602218bc1551bb81b48167bf7484eeb86ed8ee9484fa83f1267023264%230d2437ec-d81b-491c-991f-0b6559daa00d%22%2C%22%24sesid%22%3A%5B1762504332341%2C%22019a5d6c-ae21-7d75-8919-11e9621a135f%22%2C1762503994906%5D%2C%22%24epp%22%3Atrue%2C%22%24initial_person_info%22%3A%7B%22r%22%3A%22%24direct%22%2C%22u%22%3A%22https%3A%2F%2Fn8n.hbyrkj.top%2Fsignin%3Fredirect%3D%25252F%22%7D%7D; rl_anonymous_id=RudderEncrypt%3AU2FsdGVkX19aTpWYcHFt3zhITFSLk1XAMr9V2jBWQwsuLDNLXh93pTlQ%2FUpvwmv6h%2Fl1bW4xH83hrkWPCTkSYg%3D%3D; rl_group_id=RudderEncrypt%3AU2FsdGVkX1%2BhywVlN3t3ypqwAMgqlh7ZRNLMKnFMhxA%3D; rl_group_trait=RudderEncrypt%3AU2FsdGVkX19jAKNOmR%2FnSngsWGVcmYB2qyvsbh3wQc0%3D; rl_user_id=RudderEncrypt%3AU2FsdGVkX180hU8QtHwPe3dPd1o7rEP7efRzFgCIvuIPRwbE3dWE0aEQCCMpQTN%2B7AGEtH6mjRvEuqcbfOdaX4TtJGL2jHbdcZUuA7Mpjf0uvsZ15LToi0zM1NWR7i6wE2z4vcYyFaBdB1uTJq3SxhX2WsqWe4YiT12vld0E%2F5w%3D; rl_trait=RudderEncrypt%3AU2FsdGVkX19tgs8QN46oDejOzAvFyTx%2FIVRu7LAGDzh2eg%2FAhV8eY%2FyjW12D%2BtSOVq6NLF2lSZcY40rlQ%2B1fUc3DAe2euuWhIECOtlxtY5Hho11ZdHGB8lZ4CSLo%2BWmSIjzmkQ33RgkeNF9eYV4AV1PpdZZ%2Fjyl%2BVjCQtaNVV5c%3D; rl_session=RudderEncrypt%3AU2FsdGVkX19jm82pV3xfWHI%2FE6QaUo5xFQZuXuYh%2FkUCBhyJGY7TqzAK3YDkYppIpUipS7LtUSxm6iWAAp3vGhbB58MN7hrVa8imlwsuL7ceFNN%2BR1uTEvKTR8wWKaii2Xzs%2FYnhG3X8kmImIfYZgg%3D%3D; access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5NGNkOTFlMy03ZDg5LTQ1ZTgtOWQ4NS1lOGJhMDY2MGQ3NGMiLCJzZXNzaW9uX3Rva2VuIjoiNDk2N2QwNjMtNjhhZC00NzFkLThhMWQtOGE1MmJhODAxZjBjIiwiZXhwIjoxNzcwMTc4MzM4fQ.k9JOPKwqHrNTTNOsUQlMuA63rOETStl7uWXAIIDLGtA'}
|
|
||||||
11|vigent2 | 2026-01-29 11:06:16.342 | INFO | app.main:dispatch:26 - END Request: GET https://vigent.hbyrkj.top/api/publish/accounts - Status: 200 - Duration: 0.01s
|
|
||||||
11|vigent2 | 2026-01-29 11:06:16.343 | INFO | app.main:dispatch:26 - END Request: GET https://vigent.hbyrkj.top/api/videos/generated - Status: 403 - Duration: 0.01s
|
|
||||||
11|vigent2 | 2026-01-29 11:06:16.397 | INFO | app.main:dispatch:21 - START Request: POST https://vigent.hbyrkj.top/api/auth/logout
|
|
||||||
11|vigent2 | 2026-01-29 11:06:16.397 | INFO | app.main:dispatch:22 - HEADERS: {'connection': 'upgrade', 'host': 'vigent.hbyrkj.top', 'x-real-ip': '27.17.161.128', 'x-forwarded-for': '27.17.161.128', 'x-forwarded-proto': 'https', 'content-length': '0', 'sec-ch-ua-platform': '"Windows"', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36', 'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"', 'sec-ch-ua-mobile': '?0', 'accept': '*/*', 'origin': 'https://vigent.hbyrkj.top', 'sec-fetch-site': 'same-origin', 'sec-fetch-mode': 'cors', 'sec-fetch-dest': 'empty', 'referer': 'https://vigent.hbyrkj.top/publish', 'accept-encoding': 'gzip, deflate, br, zstd', 'accept-language': 'en-US,en;q=0.9,zh;q=0.8,zh-CN;q=0.7', 'priority': 'u=1, i', 'cookie': 'rl_page_init_referrer=RudderEncrypt%3AU2FsdGVkX1%2FRWtsIwIaguDp15em58SDrIwOvRJVXeK4%3D; rl_page_init_referring_domain=RudderEncrypt%3AU2FsdGVkX1%2BVZN6tniQmiO5L2fGVdcrYOkqG%2BRHkNFw%3D; ph_phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo_posthog=%7B%22distinct_id%22%3A%22f6a1ba3602218bc1551bb81b48167bf7484eeb86ed8ee9484fa83f1267023264%230d2437ec-d81b-491c-991f-0b6559daa00d%22%2C%22%24sesid%22%3A%5B1762504332341%2C%22019a5d6c-ae21-7d75-8919-11e9621a135f%22%2C1762503994906%5D%2C%22%24epp%22%3Atrue%2C%22%24initial_person_info%22%3A%7B%22r%22%3A%22%24direct%22%2C%22u%22%3A%22https%3A%2F%2Fn8n.hbyrkj.top%2Fsignin%3Fredirect%3D%25252F%22%7D%7D; rl_anonymous_id=RudderEncrypt%3AU2FsdGVkX19aTpWYcHFt3zhITFSLk1XAMr9V2jBWQwsuLDNLXh93pTlQ%2FUpvwmv6h%2Fl1bW4xH83hrkWPCTkSYg%3D%3D; rl_group_id=RudderEncrypt%3AU2FsdGVkX1%2BhywVlN3t3ypqwAMgqlh7ZRNLMKnFMhxA%3D; rl_group_trait=RudderEncrypt%3AU2FsdGVkX19jAKNOmR%2FnSngsWGVcmYB2qyvsbh3wQc0%3D; rl_user_id=RudderEncrypt%3AU2FsdGVkX180hU8QtHwPe3dPd1o7rEP7efRzFgCIvuIPRwbE3dWE0aEQCCMpQTN%2B7AGEtH6mjRvEuqcbfOdaX4TtJGL2jHbdcZUuA7Mpjf0uvsZ15LToi0zM1NWR7i6wE2z4vcYyFaBdB1uTJq3SxhX2WsqWe4YiT12vld0E%2F5w%3D; rl_trait=RudderEncrypt%3AU2FsdGVkX19tgs8QN46oDejOzAvFyTx%2FIVRu7LAGDzh2eg%2FAhV8eY%2FyjW12D%2BtSOVq6NLF2lSZcY40rlQ%2B1fUc3DAe2euuWhIECOtlxtY5Hho11ZdHGB8lZ4CSLo%2BWmSIjzmkQ33RgkeNF9eYV4AV1PpdZZ%2Fjyl%2BVjCQtaNVV5c%3D; rl_session=RudderEncrypt%3AU2FsdGVkX19jm82pV3xfWHI%2FE6QaUo5xFQZuXuYh%2FkUCBhyJGY7TqzAK3YDkYppIpUipS7LtUSxm6iWAAp3vGhbB58MN7hrVa8imlwsuL7ceFNN%2BR1uTEvKTR8wWKaii2Xzs%2FYnhG3X8kmImIfYZgg%3D%3D; access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5NGNkOTFlMy03ZDg5LTQ1ZTgtOWQ4NS1lOGJhMDY2MGQ3NGMiLCJzZXNzaW9uX3Rva2VuIjoiNDk2N2QwNjMtNjhhZC00NzFkLThhMWQtOGE1MmJhODAxZjBjIiwiZXhwIjoxNzcwMTc4MzM4fQ.k9JOPKwqHrNTTNOsUQlMuA63rOETStl7uWXAIIDLGtA'}
|
|
||||||
11|vigent2 | 2026-01-29 11:06:16.398 | INFO | app.main:dispatch:26 - END Request: POST https://vigent.hbyrkj.top/api/auth/logout - Status: 200 - Duration: 0.00s
|
|
||||||
11|vigent2 | 2026-01-29 11:06:28.685 | INFO | app.main:dispatch:21 - START Request: GET https://vigent.hbyrkj.top/api/videos/generated
|
|
||||||
11|vigent2 | 2026-01-29 11:06:28.686 | INFO | app.main:dispatch:22 - HEADERS: {'connection': 'upgrade', 'host': 'vigent.hbyrkj.top', 'x-real-ip': '27.17.161.128', 'x-forwarded-for': '27.17.161.128', 'x-forwarded-proto': 'https', 'sec-fetch-dest': 'empty', 'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.2 Mobile/15E148 Safari/604.1', 'accept': 'application/json, text/plain, */*', 'referer': 'https://vigent.hbyrkj.top/publish', 'sec-fetch-site': 'same-origin', 'sec-fetch-mode': 'cors', 'accept-language': 'en-US,en;q=0.9', 'priority': 'u=3, i', 'accept-encoding': 'gzip, deflate, br', 'cookie': 'access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5NGNkOTFlMy03ZDg5LTQ1ZTgtOWQ4NS1lOGJhMDY2MGQ3NGMiLCJzZXNzaW9uX3Rva2VuIjoiMWE0NzczNTktZmMwZS00MjVhLTk3MGUtODc1ZTcyNjFjYWJiIiwiZXhwIjoxNzcwMjYwNzY0fQ.X-nGjaX_gwaJw995Zuw_fnj2oY_K-oM6tgwMDR4pDQk; ph_phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo_posthog=%7B%22distinct_id%22%3A%22f6a1ba3602218bc1551bb81b48167bf7484eeb86ed8ee9484fa83f1267023264%230d2437ec-d81b-491c-991f-0b6559daa00d%22%2C%22%24sesid%22%3A%5B1760758482696%2C%220199f562-16c1-7fcb-9bef-fdc33838b6a8%22%2C1760758470336%5D%2C%22%24epp%22%3Atrue%2C%22%24initial_person_info%22%3A%7B%22r%22%3A%22%24direct%22%2C%22u%22%3A%22https%3A%2F%2Fn8n.hbyrkj.top%2Fsignin%3Fredirect%3D%25252F%22%7D%7D; rl_session=RudderEncrypt%3AU2FsdGVkX19ssBuVw9hBTDRVrnPaKCW6D20R7A4QpeumwXIRUkzHtaFASP40bWfE6KL05g4rq6VbZFQ9X4FVBZ2lbwW%2Faa32knjuye8aa1ejtZEGmyfXpfcryezEIy0gmYYjjT7lKB6HAupj9%2FCezQ%3D%3D; rl_trait=RudderEncrypt%3AU2FsdGVkX1%2BpEG8yoPZBpac674EsBSuEU0HhlEZGMLIKNfviY6GGLzzbk6%2BbdfmzJ5s1nr16B0NNWzywMDwDD00Cktdf8N50BWw0Pp7Xuy2cOM6L15tjqobzRZyayXyVA1o%2B5kHPODaa3yg4cjWjee8OqG1qRaX4EwOXc0YzPZI%3D; rl_user_id=RudderEncrypt%3AU2FsdGVkX1%2BRY4oSsXW07D0HdYfXZhDpJS%2Fl%2F%2Bysns8Xand%2BMI7%2FJBIRw1RV%2FIJPzbTSpW8kmvwLCsUosyNPtsZbl3lGRDOM4YJIL%2BaFVjvjAWDo0WA89ezEeTVY9hzd9rwV3A6dbv5vJhrEdjolAkub50ItC47iV1fIGb%2FN3vI%3D; rl_anonymous_id=RudderEncrypt%3AU2FsdGVkX19r9Vr3ov%2BP30OgbarNSaCn6bebg11iU%2B8UV7b%2F116JurvSpJ77d%2FdZ62kjIP%2BMF3h3R9RathLKFQ%3D%3D; rl_page_init_referrer=RudderEncrypt%3AU2FsdGVkX19CE%2F3GmyTsZHCQhdFWdzYnJYPdvCMBFbM%3D; rl_page_init_referring_domain=RudderEncrypt%3AU2FsdGVkX18t2%2FxrnN2HPEqTssR572nq%2FgCim9EQN7E%3D'}
|
|
||||||
11|vigent2 | 2026-01-29 11:06:28.704 | INFO | app.main:dispatch:21 - START Request: GET https://vigent.hbyrkj.top/api/publish/accounts
|
|
||||||
11|vigent2 | 2026-01-29 11:06:28.705 | INFO | app.main:dispatch:22 - HEADERS: {'connection': 'upgrade', 'host': 'vigent.hbyrkj.top', 'x-real-ip': '27.17.161.128', 'x-forwarded-for': '27.17.161.128', 'x-forwarded-proto': 'https', 'sec-fetch-dest': 'empty', 'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.2 Mobile/15E148 Safari/604.1', 'accept': 'application/json, text/plain, */*', 'referer': 'https://vigent.hbyrkj.top/publish', 'sec-fetch-site': 'same-origin', 'sec-fetch-mode': 'cors', 'accept-language': 'en-US,en;q=0.9', 'priority': 'u=3, i', 'accept-encoding': 'gzip, deflate, br', 'cookie': 'access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5NGNkOTFlMy03ZDg5LTQ1ZTgtOWQ4NS1lOGJhMDY2MGQ3NGMiLCJzZXNzaW9uX3Rva2VuIjoiMWE0NzczNTktZmMwZS00MjVhLTk3MGUtODc1ZTcyNjFjYWJiIiwiZXhwIjoxNzcwMjYwNzY0fQ.X-nGjaX_gwaJw995Zuw_fnj2oY_K-oM6tgwMDR4pDQk; ph_phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo_posthog=%7B%22distinct_id%22%3A%22f6a1ba3602218bc1551bb81b48167bf7484eeb86ed8ee9484fa83f1267023264%230d2437ec-d81b-491c-991f-0b6559daa00d%22%2C%22%24sesid%22%3A%5B1760758482696%2C%220199f562-16c1-7fcb-9bef-fdc33838b6a8%22%2C1760758470336%5D%2C%22%24epp%22%3Atrue%2C%22%24initial_person_info%22%3A%7B%22r%22%3A%22%24direct%22%2C%22u%22%3A%22https%3A%2F%2Fn8n.hbyrkj.top%2Fsignin%3Fredirect%3D%25252F%22%7D%7D; rl_session=RudderEncrypt%3AU2FsdGVkX19ssBuVw9hBTDRVrnPaKCW6D20R7A4QpeumwXIRUkzHtaFASP40bWfE6KL05g4rq6VbZFQ9X4FVBZ2lbwW%2Faa32knjuye8aa1ejtZEGmyfXpfcryezEIy0gmYYjjT7lKB6HAupj9%2FCezQ%3D%3D; rl_trait=RudderEncrypt%3AU2FsdGVkX1%2BpEG8yoPZBpac674EsBSuEU0HhlEZGMLIKNfviY6GGLzzbk6%2BbdfmzJ5s1nr16B0NNWzywMDwDD00Cktdf8N50BWw0Pp7Xuy2cOM6L15tjqobzRZyayXyVA1o%2B5kHPODaa3yg4cjWjee8OqG1qRaX4EwOXc0YzPZI%3D; rl_user_id=RudderEncrypt%3AU2FsdGVkX1%2BRY4oSsXW07D0HdYfXZhDpJS%2Fl%2F%2Bysns8Xand%2BMI7%2FJBIRw1RV%2FIJPzbTSpW8kmvwLCsUosyNPtsZbl3lGRDOM4YJIL%2BaFVjvjAWDo0WA89ezEeTVY9hzd9rwV3A6dbv5vJhrEdjolAkub50ItC47iV1fIGb%2FN3vI%3D; rl_anonymous_id=RudderEncrypt%3AU2FsdGVkX19r9Vr3ov%2BP30OgbarNSaCn6bebg11iU%2B8UV7b%2F116JurvSpJ77d%2FdZ62kjIP%2BMF3h3R9RathLKFQ%3D%3D; rl_page_init_referrer=RudderEncrypt%3AU2FsdGVkX19CE%2F3GmyTsZHCQhdFWdzYnJYPdvCMBFbM%3D; rl_page_init_referring_domain=RudderEncrypt%3AU2FsdGVkX18t2%2FxrnN2HPEqTssR572nq%2FgCim9EQN7E%3D'}
|
|
||||||
11|vigent2 | 2026-01-29 11:06:28.710 | INFO | app.main:dispatch:26 - END Request: GET https://vigent.hbyrkj.top/api/publish/accounts - Status: 200 - Duration: 0.01s
|
|
||||||
11|vigent2 | 2026-01-29 11:06:28.745 | INFO | app.main:dispatch:26 - END Request: GET https://vigent.hbyrkj.top/api/videos/generated - Status: 200 - Duration: 0.06s
|
|
||||||
11|vigent2 | 2026-01-29 11:06:51.021 | INFO | app.main:dispatch:21 - START Request: POST https://vigent.hbyrkj.top/api/auth/login
|
|
||||||
11|vigent2 | 2026-01-29 11:06:51.021 | INFO | app.main:dispatch:22 - HEADERS: {'connection': 'upgrade', 'host': 'vigent.hbyrkj.top', 'x-real-ip': '27.17.161.128', 'x-forwarded-for': '27.17.161.128', 'x-forwarded-proto': 'https', 'content-length': '58', 'sec-ch-ua-platform': '"Windows"', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36', 'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"', 'content-type': 'application/json', 'sec-ch-ua-mobile': '?0', 'accept': '*/*', 'origin': 'https://vigent.hbyrkj.top', 'sec-fetch-site': 'same-origin', 'sec-fetch-mode': 'cors', 'sec-fetch-dest': 'empty', 'referer': 'https://vigent.hbyrkj.top/login', 'accept-encoding': 'gzip, deflate, br, zstd', 'accept-language': 'en-US,en;q=0.9,zh;q=0.8,zh-CN;q=0.7', 'priority': 'u=1, i', 'cookie': 'rl_page_init_referrer=RudderEncrypt%3AU2FsdGVkX1%2FRWtsIwIaguDp15em58SDrIwOvRJVXeK4%3D; rl_page_init_referring_domain=RudderEncrypt%3AU2FsdGVkX1%2BVZN6tniQmiO5L2fGVdcrYOkqG%2BRHkNFw%3D; ph_phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo_posthog=%7B%22distinct_id%22%3A%22f6a1ba3602218bc1551bb81b48167bf7484eeb86ed8ee9484fa83f1267023264%230d2437ec-d81b-491c-991f-0b6559daa00d%22%2C%22%24sesid%22%3A%5B1762504332341%2C%22019a5d6c-ae21-7d75-8919-11e9621a135f%22%2C1762503994906%5D%2C%22%24epp%22%3Atrue%2C%22%24initial_person_info%22%3A%7B%22r%22%3A%22%24direct%22%2C%22u%22%3A%22https%3A%2F%2Fn8n.hbyrkj.top%2Fsignin%3Fredirect%3D%25252F%22%7D%7D; rl_anonymous_id=RudderEncrypt%3AU2FsdGVkX19aTpWYcHFt3zhITFSLk1XAMr9V2jBWQwsuLDNLXh93pTlQ%2FUpvwmv6h%2Fl1bW4xH83hrkWPCTkSYg%3D%3D; rl_group_id=RudderEncrypt%3AU2FsdGVkX1%2BhywVlN3t3ypqwAMgqlh7ZRNLMKnFMhxA%3D; rl_group_trait=RudderEncrypt%3AU2FsdGVkX19jAKNOmR%2FnSngsWGVcmYB2qyvsbh3wQc0%3D; rl_user_id=RudderEncrypt%3AU2FsdGVkX180hU8QtHwPe3dPd1o7rEP7efRzFgCIvuIPRwbE3dWE0aEQCCMpQTN%2B7AGEtH6mjRvEuqcbfOdaX4TtJGL2jHbdcZUuA7Mpjf0uvsZ15LToi0zM1NWR7i6wE2z4vcYyFaBdB1uTJq3SxhX2WsqWe4YiT12vld0E%2F5w%3D; rl_trait=RudderEncrypt%3AU2FsdGVkX19tgs8QN46oDejOzAvFyTx%2FIVRu7LAGDzh2eg%2FAhV8eY%2FyjW12D%2BtSOVq6NLF2lSZcY40rlQ%2B1fUc3DAe2euuWhIECOtlxtY5Hho11ZdHGB8lZ4CSLo%2BWmSIjzmkQ33RgkeNF9eYV4AV1PpdZZ%2Fjyl%2BVjCQtaNVV5c%3D; rl_session=RudderEncrypt%3AU2FsdGVkX19jm82pV3xfWHI%2FE6QaUo5xFQZuXuYh%2FkUCBhyJGY7TqzAK3YDkYppIpUipS7LtUSxm6iWAAp3vGhbB58MN7hrVa8imlwsuL7ceFNN%2BR1uTEvKTR8wWKaii2Xzs%2FYnhG3X8kmImIfYZgg%3D%3D'}
|
|
||||||
11|vigent2 | 2026-01-29 11:06:51.624 | INFO | app.api.auth:login:157 - 用户登录: lamnickdavid@gmail.com
|
|
||||||
11|vigent2 | 2026-01-29 11:06:51.625 | INFO | app.main:dispatch:26 - END Request: POST https://vigent.hbyrkj.top/api/auth/login - Status: 200 - Duration: 0.60s
|
|
||||||
11|vigent2 | 2026-01-29 11:06:51.806 | INFO | app.main:dispatch:21 - START Request: GET https://vigent.hbyrkj.top/api/materials?t=1769656015718
|
|
||||||
11|vigent2 | 2026-01-29 11:06:51.806 | INFO | app.main:dispatch:22 - HEADERS: {'connection': 'upgrade', 'host': 'vigent.hbyrkj.top', 'x-real-ip': '27.17.161.128', 'x-forwarded-for': '27.17.161.128', 'x-forwarded-proto': 'https', 'sec-ch-ua-platform': '"Windows"', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36', 'accept': 'application/json, text/plain, */*', 'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"', 'sec-ch-ua-mobile': '?0', 'sec-fetch-site': 'same-origin', 'sec-fetch-mode': 'cors', 'sec-fetch-dest': 'empty', 'referer': 'https://vigent.hbyrkj.top/', 'accept-encoding': 'gzip, deflate, br, zstd', 'accept-language': 'en-US,en;q=0.9,zh;q=0.8,zh-CN;q=0.7', 'priority': 'u=1, i', 'cookie': 'rl_page_init_referrer=RudderEncrypt%3AU2FsdGVkX1%2FRWtsIwIaguDp15em58SDrIwOvRJVXeK4%3D; rl_page_init_referring_domain=RudderEncrypt%3AU2FsdGVkX1%2BVZN6tniQmiO5L2fGVdcrYOkqG%2BRHkNFw%3D; ph_phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo_posthog=%7B%22distinct_id%22%3A%22f6a1ba3602218bc1551bb81b48167bf7484eeb86ed8ee9484fa83f1267023264%230d2437ec-d81b-491c-991f-0b6559daa00d%22%2C%22%24sesid%22%3A%5B1762504332341%2C%22019a5d6c-ae21-7d75-8919-11e9621a135f%22%2C1762503994906%5D%2C%22%24epp%22%3Atrue%2C%22%24initial_person_info%22%3A%7B%22r%22%3A%22%24direct%22%2C%22u%22%3A%22https%3A%2F%2Fn8n.hbyrkj.top%2Fsignin%3Fredirect%3D%25252F%22%7D%7D; rl_anonymous_id=RudderEncrypt%3AU2FsdGVkX19aTpWYcHFt3zhITFSLk1XAMr9V2jBWQwsuLDNLXh93pTlQ%2FUpvwmv6h%2Fl1bW4xH83hrkWPCTkSYg%3D%3D; rl_group_id=RudderEncrypt%3AU2FsdGVkX1%2BhywVlN3t3ypqwAMgqlh7ZRNLMKnFMhxA%3D; rl_group_trait=RudderEncrypt%3AU2FsdGVkX19jAKNOmR%2FnSngsWGVcmYB2qyvsbh3wQc0%3D; rl_user_id=RudderEncrypt%3AU2FsdGVkX180hU8QtHwPe3dPd1o7rEP7efRzFgCIvuIPRwbE3dWE0aEQCCMpQTN%2B7AGEtH6mjRvEuqcbfOdaX4TtJGL2jHbdcZUuA7Mpjf0uvsZ15LToi0zM1NWR7i6wE2z4vcYyFaBdB1uTJq3SxhX2WsqWe4YiT12vld0E%2F5w%3D; rl_trait=RudderEncrypt%3AU2FsdGVkX19tgs8QN46oDejOzAvFyTx%2FIVRu7LAGDzh2eg%2FAhV8eY%2FyjW12D%2BtSOVq6NLF2lSZcY40rlQ%2B1fUc3DAe2euuWhIECOtlxtY5Hho11ZdHGB8lZ4CSLo%2BWmSIjzmkQ33RgkeNF9eYV4AV1PpdZZ%2Fjyl%2BVjCQtaNVV5c%3D; rl_session=RudderEncrypt%3AU2FsdGVkX19jm82pV3xfWHI%2FE6QaUo5xFQZuXuYh%2FkUCBhyJGY7TqzAK3YDkYppIpUipS7LtUSxm6iWAAp3vGhbB58MN7hrVa8imlwsuL7ceFNN%2BR1uTEvKTR8wWKaii2Xzs%2FYnhG3X8kmImIfYZgg%3D%3D; access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5NGNkOTFlMy03ZDg5LTQ1ZTgtOWQ4NS1lOGJhMDY2MGQ3NGMiLCJzZXNzaW9uX3Rva2VuIjoiMjFjMmEwMmItYjY5Ny00MGVjLWIwMmItMjI1YzJjOWUyZGMzIiwiZXhwIjoxNzcwMjYwODExfQ.MpOjnbwllAzarfaoTk1SzYVMqAEXBEMyRt5UyiJ90Qw'}
|
|
||||||
11|vigent2 | 2026-01-29 11:06:51.820 | INFO | app.main:dispatch:21 - START Request: GET https://vigent.hbyrkj.top/api/videos/generated
|
|
||||||
11|vigent2 | 2026-01-29 11:06:51.821 | INFO | app.main:dispatch:22 - HEADERS: {'connection': 'upgrade', 'host': 'vigent.hbyrkj.top', 'x-real-ip': '27.17.161.128', 'x-forwarded-for': '27.17.161.128', 'x-forwarded-proto': 'https', 'sec-ch-ua-platform': '"Windows"', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36', 'accept': 'application/json, text/plain, */*', 'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"', 'sec-ch-ua-mobile': '?0', 'sec-fetch-site': 'same-origin', 'sec-fetch-mode': 'cors', 'sec-fetch-dest': 'empty', 'referer': 'https://vigent.hbyrkj.top/', 'accept-encoding': 'gzip, deflate, br, zstd', 'accept-language': 'en-US,en;q=0.9,zh;q=0.8,zh-CN;q=0.7', 'priority': 'u=1, i', 'cookie': 'rl_page_init_referrer=RudderEncrypt%3AU2FsdGVkX1%2FRWtsIwIaguDp15em58SDrIwOvRJVXeK4%3D; rl_page_init_referring_domain=RudderEncrypt%3AU2FsdGVkX1%2BVZN6tniQmiO5L2fGVdcrYOkqG%2BRHkNFw%3D; ph_phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo_posthog=%7B%22distinct_id%22%3A%22f6a1ba3602218bc1551bb81b48167bf7484eeb86ed8ee9484fa83f1267023264%230d2437ec-d81b-491c-991f-0b6559daa00d%22%2C%22%24sesid%22%3A%5B1762504332341%2C%22019a5d6c-ae21-7d75-8919-11e9621a135f%22%2C1762503994906%5D%2C%22%24epp%22%3Atrue%2C%22%24initial_person_info%22%3A%7B%22r%22%3A%22%24direct%22%2C%22u%22%3A%22https%3A%2F%2Fn8n.hbyrkj.top%2Fsignin%3Fredirect%3D%25252F%22%7D%7D; rl_anonymous_id=RudderEncrypt%3AU2FsdGVkX19aTpWYcHFt3zhITFSLk1XAMr9V2jBWQwsuLDNLXh93pTlQ%2FUpvwmv6h%2Fl1bW4xH83hrkWPCTkSYg%3D%3D; rl_group_id=RudderEncrypt%3AU2FsdGVkX1%2BhywVlN3t3ypqwAMgqlh7ZRNLMKnFMhxA%3D; rl_group_trait=RudderEncrypt%3AU2FsdGVkX19jAKNOmR%2FnSngsWGVcmYB2qyvsbh3wQc0%3D; rl_user_id=RudderEncrypt%3AU2FsdGVkX180hU8QtHwPe3dPd1o7rEP7efRzFgCIvuIPRwbE3dWE0aEQCCMpQTN%2B7AGEtH6mjRvEuqcbfOdaX4TtJGL2jHbdcZUuA7Mpjf0uvsZ15LToi0zM1NWR7i6wE2z4vcYyFaBdB1uTJq3SxhX2WsqWe4YiT12vld0E%2F5w%3D; rl_trait=RudderEncrypt%3AU2FsdGVkX19tgs8QN46oDejOzAvFyTx%2FIVRu7LAGDzh2eg%2FAhV8eY%2FyjW12D%2BtSOVq6NLF2lSZcY40rlQ%2B1fUc3DAe2euuWhIECOtlxtY5Hho11ZdHGB8lZ4CSLo%2BWmSIjzmkQ33RgkeNF9eYV4AV1PpdZZ%2Fjyl%2BVjCQtaNVV5c%3D; rl_session=RudderEncrypt%3AU2FsdGVkX19jm82pV3xfWHI%2FE6QaUo5xFQZuXuYh%2FkUCBhyJGY7TqzAK3YDkYppIpUipS7LtUSxm6iWAAp3vGhbB58MN7hrVa8imlwsuL7ceFNN%2BR1uTEvKTR8wWKaii2Xzs%2FYnhG3X8kmImIfYZgg%3D%3D; access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5NGNkOTFlMy03ZDg5LTQ1ZTgtOWQ4NS1lOGJhMDY2MGQ3NGMiLCJzZXNzaW9uX3Rva2VuIjoiMjFjMmEwMmItYjY5Ny00MGVjLWIwMmItMjI1YzJjOWUyZGMzIiwiZXhwIjoxNzcwMjYwODExfQ.MpOjnbwllAzarfaoTk1SzYVMqAEXBEMyRt5UyiJ90Qw'}
|
|
||||||
11|vigent2 | 2026-01-29 11:06:51.834 | INFO | app.main:dispatch:21 - START Request: GET https://vigent.hbyrkj.top/api/ref-audios
|
|
||||||
11|vigent2 | 2026-01-29 11:06:51.834 | INFO | app.main:dispatch:22 - HEADERS: {'connection': 'upgrade', 'host': 'vigent.hbyrkj.top', 'x-real-ip': '27.17.161.128', 'x-forwarded-for': '27.17.161.128', 'x-forwarded-proto': 'https', 'sec-ch-ua-platform': '"Windows"', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36', 'accept': 'application/json, text/plain, */*', 'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"', 'sec-ch-ua-mobile': '?0', 'sec-fetch-site': 'same-origin', 'sec-fetch-mode': 'cors', 'sec-fetch-dest': 'empty', 'referer': 'https://vigent.hbyrkj.top/', 'accept-encoding': 'gzip, deflate, br, zstd', 'accept-language': 'en-US,en;q=0.9,zh;q=0.8,zh-CN;q=0.7', 'priority': 'u=1, i', 'cookie': 'rl_page_init_referrer=RudderEncrypt%3AU2FsdGVkX1%2FRWtsIwIaguDp15em58SDrIwOvRJVXeK4%3D; rl_page_init_referring_domain=RudderEncrypt%3AU2FsdGVkX1%2BVZN6tniQmiO5L2fGVdcrYOkqG%2BRHkNFw%3D; ph_phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo_posthog=%7B%22distinct_id%22%3A%22f6a1ba3602218bc1551bb81b48167bf7484eeb86ed8ee9484fa83f1267023264%230d2437ec-d81b-491c-991f-0b6559daa00d%22%2C%22%24sesid%22%3A%5B1762504332341%2C%22019a5d6c-ae21-7d75-8919-11e9621a135f%22%2C1762503994906%5D%2C%22%24epp%22%3Atrue%2C%22%24initial_person_info%22%3A%7B%22r%22%3A%22%24direct%22%2C%22u%22%3A%22https%3A%2F%2Fn8n.hbyrkj.top%2Fsignin%3Fredirect%3D%25252F%22%7D%7D; rl_anonymous_id=RudderEncrypt%3AU2FsdGVkX19aTpWYcHFt3zhITFSLk1XAMr9V2jBWQwsuLDNLXh93pTlQ%2FUpvwmv6h%2Fl1bW4xH83hrkWPCTkSYg%3D%3D; rl_group_id=RudderEncrypt%3AU2FsdGVkX1%2BhywVlN3t3ypqwAMgqlh7ZRNLMKnFMhxA%3D; rl_group_trait=RudderEncrypt%3AU2FsdGVkX19jAKNOmR%2FnSngsWGVcmYB2qyvsbh3wQc0%3D; rl_user_id=RudderEncrypt%3AU2FsdGVkX180hU8QtHwPe3dPd1o7rEP7efRzFgCIvuIPRwbE3dWE0aEQCCMpQTN%2B7AGEtH6mjRvEuqcbfOdaX4TtJGL2jHbdcZUuA7Mpjf0uvsZ15LToi0zM1NWR7i6wE2z4vcYyFaBdB1uTJq3SxhX2WsqWe4YiT12vld0E%2F5w%3D; rl_trait=RudderEncrypt%3AU2FsdGVkX19tgs8QN46oDejOzAvFyTx%2FIVRu7LAGDzh2eg%2FAhV8eY%2FyjW12D%2BtSOVq6NLF2lSZcY40rlQ%2B1fUc3DAe2euuWhIECOtlxtY5Hho11ZdHGB8lZ4CSLo%2BWmSIjzmkQ33RgkeNF9eYV4AV1PpdZZ%2Fjyl%2BVjCQtaNVV5c%3D; rl_session=RudderEncrypt%3AU2FsdGVkX19jm82pV3xfWHI%2FE6QaUo5xFQZuXuYh%2FkUCBhyJGY7TqzAK3YDkYppIpUipS7LtUSxm6iWAAp3vGhbB58MN7hrVa8imlwsuL7ceFNN%2BR1uTEvKTR8wWKaii2Xzs%2FYnhG3X8kmImIfYZgg%3D%3D; access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5NGNkOTFlMy03ZDg5LTQ1ZTgtOWQ4NS1lOGJhMDY2MGQ3NGMiLCJzZXNzaW9uX3Rva2VuIjoiMjFjMmEwMmItYjY5Ny00MGVjLWIwMmItMjI1YzJjOWUyZGMzIiwiZXhwIjoxNzcwMjYwODExfQ.MpOjnbwllAzarfaoTk1SzYVMqAEXBEMyRt5UyiJ90Qw'}
|
|
||||||
11|vigent2 | 2026-01-29 11:06:51.865 | INFO | app.main:dispatch:26 - END Request: GET https://vigent.hbyrkj.top/api/materials?t=1769656015718 - Status: 200 - Duration: 0.06s
|
|
||||||
11|vigent2 | 2026-01-29 11:06:51.941 | INFO | app.main:dispatch:26 - END Request: GET https://vigent.hbyrkj.top/api/videos/generated - Status: 200 - Duration: 0.12s
|
|
||||||
11|vigent2 | 2026-01-29 11:06:52.076 | INFO | app.main:dispatch:26 - END Request: GET https://vigent.hbyrkj.top/api/ref-audios - Status: 200 - Duration: 0.24s
|
|
||||||
11|vigent2 | 2026-01-29 11:10:29.354 | INFO | app.main:dispatch:21 - START Request: GET https://vigent.hbyrkj.top/api/materials?t=1769656233290
|
|
||||||
11|vigent2 | 2026-01-29 11:10:29.354 | INFO | app.main:dispatch:22 - HEADERS: {'connection': 'upgrade', 'host': 'vigent.hbyrkj.top', 'x-real-ip': '27.17.161.128', 'x-forwarded-for': '27.17.161.128', 'x-forwarded-proto': 'https', 'sec-ch-ua-platform': '"Windows"', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36', 'accept': 'application/json, text/plain, */*', 'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"', 'sec-ch-ua-mobile': '?0', 'sec-fetch-site': 'same-origin', 'sec-fetch-mode': 'cors', 'sec-fetch-dest': 'empty', 'referer': 'https://vigent.hbyrkj.top/', 'accept-encoding': 'gzip, deflate, br, zstd', 'accept-language': 'en-US,en;q=0.9,zh;q=0.8,zh-CN;q=0.7', 'priority': 'u=1, i', 'cookie': 'rl_page_init_referrer=RudderEncrypt%3AU2FsdGVkX1%2FRWtsIwIaguDp15em58SDrIwOvRJVXeK4%3D; rl_page_init_referring_domain=RudderEncrypt%3AU2FsdGVkX1%2BVZN6tniQmiO5L2fGVdcrYOkqG%2BRHkNFw%3D; ph_phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo_posthog=%7B%22distinct_id%22%3A%22f6a1ba3602218bc1551bb81b48167bf7484eeb86ed8ee9484fa83f1267023264%230d2437ec-d81b-491c-991f-0b6559daa00d%22%2C%22%24sesid%22%3A%5B1762504332341%2C%22019a5d6c-ae21-7d75-8919-11e9621a135f%22%2C1762503994906%5D%2C%22%24epp%22%3Atrue%2C%22%24initial_person_info%22%3A%7B%22r%22%3A%22%24direct%22%2C%22u%22%3A%22https%3A%2F%2Fn8n.hbyrkj.top%2Fsignin%3Fredirect%3D%25252F%22%7D%7D; rl_anonymous_id=RudderEncrypt%3AU2FsdGVkX19aTpWYcHFt3zhITFSLk1XAMr9V2jBWQwsuLDNLXh93pTlQ%2FUpvwmv6h%2Fl1bW4xH83hrkWPCTkSYg%3D%3D; rl_group_id=RudderEncrypt%3AU2FsdGVkX1%2BhywVlN3t3ypqwAMgqlh7ZRNLMKnFMhxA%3D; rl_group_trait=RudderEncrypt%3AU2FsdGVkX19jAKNOmR%2FnSngsWGVcmYB2qyvsbh3wQc0%3D; rl_user_id=RudderEncrypt%3AU2FsdGVkX180hU8QtHwPe3dPd1o7rEP7efRzFgCIvuIPRwbE3dWE0aEQCCMpQTN%2B7AGEtH6mjRvEuqcbfOdaX4TtJGL2jHbdcZUuA7Mpjf0uvsZ15LToi0zM1NWR7i6wE2z4vcYyFaBdB1uTJq3SxhX2WsqWe4YiT12vld0E%2F5w%3D; rl_trait=RudderEncrypt%3AU2FsdGVkX19tgs8QN46oDejOzAvFyTx%2FIVRu7LAGDzh2eg%2FAhV8eY%2FyjW12D%2BtSOVq6NLF2lSZcY40rlQ%2B1fUc3DAe2euuWhIECOtlxtY5Hho11ZdHGB8lZ4CSLo%2BWmSIjzmkQ33RgkeNF9eYV4AV1PpdZZ%2Fjyl%2BVjCQtaNVV5c%3D; rl_session=RudderEncrypt%3AU2FsdGVkX19jm82pV3xfWHI%2FE6QaUo5xFQZuXuYh%2FkUCBhyJGY7TqzAK3YDkYppIpUipS7LtUSxm6iWAAp3vGhbB58MN7hrVa8imlwsuL7ceFNN%2BR1uTEvKTR8wWKaii2Xzs%2FYnhG3X8kmImIfYZgg%3D%3D; access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5NGNkOTFlMy03ZDg5LTQ1ZTgtOWQ4NS1lOGJhMDY2MGQ3NGMiLCJzZXNzaW9uX3Rva2VuIjoiMjFjMmEwMmItYjY5Ny00MGVjLWIwMmItMjI1YzJjOWUyZGMzIiwiZXhwIjoxNzcwMjYwODExfQ.MpOjnbwllAzarfaoTk1SzYVMqAEXBEMyRt5UyiJ90Qw'}
|
|
||||||
11|vigent2 | 2026-01-29 11:10:29.405 | INFO | app.main:dispatch:21 - START Request: GET https://vigent.hbyrkj.top/api/ref-audios
|
|
||||||
11|vigent2 | 2026-01-29 11:10:29.406 | INFO | app.main:dispatch:22 - HEADERS: {'connection': 'upgrade', 'host': 'vigent.hbyrkj.top', 'x-real-ip': '27.17.161.128', 'x-forwarded-for': '27.17.161.128', 'x-forwarded-proto': 'https', 'sec-ch-ua-platform': '"Windows"', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36', 'accept': 'application/json, text/plain, */*', 'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"', 'sec-ch-ua-mobile': '?0', 'sec-fetch-site': 'same-origin', 'sec-fetch-mode': 'cors', 'sec-fetch-dest': 'empty', 'referer': 'https://vigent.hbyrkj.top/', 'accept-encoding': 'gzip, deflate, br, zstd', 'accept-language': 'en-US,en;q=0.9,zh;q=0.8,zh-CN;q=0.7', 'priority': 'u=1, i', 'cookie': 'rl_page_init_referrer=RudderEncrypt%3AU2FsdGVkX1%2FRWtsIwIaguDp15em58SDrIwOvRJVXeK4%3D; rl_page_init_referring_domain=RudderEncrypt%3AU2FsdGVkX1%2BVZN6tniQmiO5L2fGVdcrYOkqG%2BRHkNFw%3D; ph_phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo_posthog=%7B%22distinct_id%22%3A%22f6a1ba3602218bc1551bb81b48167bf7484eeb86ed8ee9484fa83f1267023264%230d2437ec-d81b-491c-991f-0b6559daa00d%22%2C%22%24sesid%22%3A%5B1762504332341%2C%22019a5d6c-ae21-7d75-8919-11e9621a135f%22%2C1762503994906%5D%2C%22%24epp%22%3Atrue%2C%22%24initial_person_info%22%3A%7B%22r%22%3A%22%24direct%22%2C%22u%22%3A%22https%3A%2F%2Fn8n.hbyrkj.top%2Fsignin%3Fredirect%3D%25252F%22%7D%7D; rl_anonymous_id=RudderEncrypt%3AU2FsdGVkX19aTpWYcHFt3zhITFSLk1XAMr9V2jBWQwsuLDNLXh93pTlQ%2FUpvwmv6h%2Fl1bW4xH83hrkWPCTkSYg%3D%3D; rl_group_id=RudderEncrypt%3AU2FsdGVkX1%2BhywVlN3t3ypqwAMgqlh7ZRNLMKnFMhxA%3D; rl_group_trait=RudderEncrypt%3AU2FsdGVkX19jAKNOmR%2FnSngsWGVcmYB2qyvsbh3wQc0%3D; rl_user_id=RudderEncrypt%3AU2FsdGVkX180hU8QtHwPe3dPd1o7rEP7efRzFgCIvuIPRwbE3dWE0aEQCCMpQTN%2B7AGEtH6mjRvEuqcbfOdaX4TtJGL2jHbdcZUuA7Mpjf0uvsZ15LToi0zM1NWR7i6wE2z4vcYyFaBdB1uTJq3SxhX2WsqWe4YiT12vld0E%2F5w%3D; rl_trait=RudderEncrypt%3AU2FsdGVkX19tgs8QN46oDejOzAvFyTx%2FIVRu7LAGDzh2eg%2FAhV8eY%2FyjW12D%2BtSOVq6NLF2lSZcY40rlQ%2B1fUc3DAe2euuWhIECOtlxtY5Hho11ZdHGB8lZ4CSLo%2BWmSIjzmkQ33RgkeNF9eYV4AV1PpdZZ%2Fjyl%2BVjCQtaNVV5c%3D; rl_session=RudderEncrypt%3AU2FsdGVkX19jm82pV3xfWHI%2FE6QaUo5xFQZuXuYh%2FkUCBhyJGY7TqzAK3YDkYppIpUipS7LtUSxm6iWAAp3vGhbB58MN7hrVa8imlwsuL7ceFNN%2BR1uTEvKTR8wWKaii2Xzs%2FYnhG3X8kmImIfYZgg%3D%3D; access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5NGNkOTFlMy03ZDg5LTQ1ZTgtOWQ4NS1lOGJhMDY2MGQ3NGMiLCJzZXNzaW9uX3Rva2VuIjoiMjFjMmEwMmItYjY5Ny00MGVjLWIwMmItMjI1YzJjOWUyZGMzIiwiZXhwIjoxNzcwMjYwODExfQ.MpOjnbwllAzarfaoTk1SzYVMqAEXBEMyRt5UyiJ90Qw'}
|
|
||||||
11|vigent2 | 2026-01-29 11:10:29.423 | INFO | app.main:dispatch:21 - START Request: GET https://vigent.hbyrkj.top/api/videos/generated
|
|
||||||
11|vigent2 | 2026-01-29 11:10:29.423 | INFO | app.main:dispatch:22 - HEADERS: {'connection': 'upgrade', 'host': 'vigent.hbyrkj.top', 'x-real-ip': '27.17.161.128', 'x-forwarded-for': '27.17.161.128', 'x-forwarded-proto': 'https', 'sec-ch-ua-platform': '"Windows"', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36', 'accept': 'application/json, text/plain, */*', 'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"', 'sec-ch-ua-mobile': '?0', 'sec-fetch-site': 'same-origin', 'sec-fetch-mode': 'cors', 'sec-fetch-dest': 'empty', 'referer': 'https://vigent.hbyrkj.top/', 'accept-encoding': 'gzip, deflate, br, zstd', 'accept-language': 'en-US,en;q=0.9,zh;q=0.8,zh-CN;q=0.7', 'priority': 'u=1, i', 'cookie': 'rl_page_init_referrer=RudderEncrypt%3AU2FsdGVkX1%2FRWtsIwIaguDp15em58SDrIwOvRJVXeK4%3D; rl_page_init_referring_domain=RudderEncrypt%3AU2FsdGVkX1%2BVZN6tniQmiO5L2fGVdcrYOkqG%2BRHkNFw%3D; ph_phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo_posthog=%7B%22distinct_id%22%3A%22f6a1ba3602218bc1551bb81b48167bf7484eeb86ed8ee9484fa83f1267023264%230d2437ec-d81b-491c-991f-0b6559daa00d%22%2C%22%24sesid%22%3A%5B1762504332341%2C%22019a5d6c-ae21-7d75-8919-11e9621a135f%22%2C1762503994906%5D%2C%22%24epp%22%3Atrue%2C%22%24initial_person_info%22%3A%7B%22r%22%3A%22%24direct%22%2C%22u%22%3A%22https%3A%2F%2Fn8n.hbyrkj.top%2Fsignin%3Fredirect%3D%25252F%22%7D%7D; rl_anonymous_id=RudderEncrypt%3AU2FsdGVkX19aTpWYcHFt3zhITFSLk1XAMr9V2jBWQwsuLDNLXh93pTlQ%2FUpvwmv6h%2Fl1bW4xH83hrkWPCTkSYg%3D%3D; rl_group_id=RudderEncrypt%3AU2FsdGVkX1%2BhywVlN3t3ypqwAMgqlh7ZRNLMKnFMhxA%3D; rl_group_trait=RudderEncrypt%3AU2FsdGVkX19jAKNOmR%2FnSngsWGVcmYB2qyvsbh3wQc0%3D; rl_user_id=RudderEncrypt%3AU2FsdGVkX180hU8QtHwPe3dPd1o7rEP7efRzFgCIvuIPRwbE3dWE0aEQCCMpQTN%2B7AGEtH6mjRvEuqcbfOdaX4TtJGL2jHbdcZUuA7Mpjf0uvsZ15LToi0zM1NWR7i6wE2z4vcYyFaBdB1uTJq3SxhX2WsqWe4YiT12vld0E%2F5w%3D; rl_trait=RudderEncrypt%3AU2FsdGVkX19tgs8QN46oDejOzAvFyTx%2FIVRu7LAGDzh2eg%2FAhV8eY%2FyjW12D%2BtSOVq6NLF2lSZcY40rlQ%2B1fUc3DAe2euuWhIECOtlxtY5Hho11ZdHGB8lZ4CSLo%2BWmSIjzmkQ33RgkeNF9eYV4AV1PpdZZ%2Fjyl%2BVjCQtaNVV5c%3D; rl_session=RudderEncrypt%3AU2FsdGVkX19jm82pV3xfWHI%2FE6QaUo5xFQZuXuYh%2FkUCBhyJGY7TqzAK3YDkYppIpUipS7LtUSxm6iWAAp3vGhbB58MN7hrVa8imlwsuL7ceFNN%2BR1uTEvKTR8wWKaii2Xzs%2FYnhG3X8kmImIfYZgg%3D%3D; access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5NGNkOTFlMy03ZDg5LTQ1ZTgtOWQ4NS1lOGJhMDY2MGQ3NGMiLCJzZXNzaW9uX3Rva2VuIjoiMjFjMmEwMmItYjY5Ny00MGVjLWIwMmItMjI1YzJjOWUyZGMzIiwiZXhwIjoxNzcwMjYwODExfQ.MpOjnbwllAzarfaoTk1SzYVMqAEXBEMyRt5UyiJ90Qw'}
|
|
||||||
11|vigent2 | 2026-01-29 11:10:29.474 | INFO | app.main:dispatch:26 - END Request: GET https://vigent.hbyrkj.top/api/materials?t=1769656233290 - Status: 200 - Duration: 0.12s
|
|
||||||
11|vigent2 | 2026-01-29 11:10:29.535 | INFO | app.main:dispatch:26 - END Request: GET https://vigent.hbyrkj.top/api/videos/generated - Status: 200 - Duration: 0.11s
|
|
||||||
11|vigent2 | 2026-01-29 11:10:29.653 | INFO | app.main:dispatch:26 - END Request: GET https://vigent.hbyrkj.top/api/ref-audios - Status: 200 - Duration: 0.25s
|
|
||||||
11|vigent2 | 2026-01-29 11:11:20.032 | INFO | app.main:dispatch:21 - START Request: POST https://vigent.hbyrkj.top/api/ref-audios
|
|
||||||
11|vigent2 | 2026-01-29 11:11:20.032 | INFO | app.main:dispatch:22 - HEADERS: {'connection': 'upgrade', 'host': 'vigent.hbyrkj.top', 'x-real-ip': '27.17.161.128', 'x-forwarded-for': '27.17.161.128', 'x-forwarded-proto': 'https', 'content-length': '204514', 'sec-ch-ua-platform': '"Windows"', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36', 'accept': 'application/json, text/plain, */*', 'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"', 'content-type': 'multipart/form-data; boundary=----WebKitFormBoundaryBGjf99CuOGlQdB7a', 'sec-ch-ua-mobile': '?0', 'origin': 'https://vigent.hbyrkj.top', 'sec-fetch-site': 'same-origin', 'sec-fetch-mode': 'cors', 'sec-fetch-dest': 'empty', 'referer': 'https://vigent.hbyrkj.top/', 'accept-encoding': 'gzip, deflate, br, zstd', 'accept-language': 'en-US,en;q=0.9,zh;q=0.8,zh-CN;q=0.7', 'priority': 'u=1, i', 'cookie': 'rl_page_init_referrer=RudderEncrypt%3AU2FsdGVkX1%2FRWtsIwIaguDp15em58SDrIwOvRJVXeK4%3D; rl_page_init_referring_domain=RudderEncrypt%3AU2FsdGVkX1%2BVZN6tniQmiO5L2fGVdcrYOkqG%2BRHkNFw%3D; ph_phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo_posthog=%7B%22distinct_id%22%3A%22f6a1ba3602218bc1551bb81b48167bf7484eeb86ed8ee9484fa83f1267023264%230d2437ec-d81b-491c-991f-0b6559daa00d%22%2C%22%24sesid%22%3A%5B1762504332341%2C%22019a5d6c-ae21-7d75-8919-11e9621a135f%22%2C1762503994906%5D%2C%22%24epp%22%3Atrue%2C%22%24initial_person_info%22%3A%7B%22r%22%3A%22%24direct%22%2C%22u%22%3A%22https%3A%2F%2Fn8n.hbyrkj.top%2Fsignin%3Fredirect%3D%25252F%22%7D%7D; rl_anonymous_id=RudderEncrypt%3AU2FsdGVkX19aTpWYcHFt3zhITFSLk1XAMr9V2jBWQwsuLDNLXh93pTlQ%2FUpvwmv6h%2Fl1bW4xH83hrkWPCTkSYg%3D%3D; rl_group_id=RudderEncrypt%3AU2FsdGVkX1%2BhywVlN3t3ypqwAMgqlh7ZRNLMKnFMhxA%3D; rl_group_trait=RudderEncrypt%3AU2FsdGVkX19jAKNOmR%2FnSngsWGVcmYB2qyvsbh3wQc0%3D; rl_user_id=RudderEncrypt%3AU2FsdGVkX180hU8QtHwPe3dPd1o7rEP7efRzFgCIvuIPRwbE3dWE0aEQCCMpQTN%2B7AGEtH6mjRvEuqcbfOdaX4TtJGL2jHbdcZUuA7Mpjf0uvsZ15LToi0zM1NWR7i6wE2z4vcYyFaBdB1uTJq3SxhX2WsqWe4YiT12vld0E%2F5w%3D; rl_trait=RudderEncrypt%3AU2FsdGVkX19tgs8QN46oDejOzAvFyTx%2FIVRu7LAGDzh2eg%2FAhV8eY%2FyjW12D%2BtSOVq6NLF2lSZcY40rlQ%2B1fUc3DAe2euuWhIECOtlxtY5Hho11ZdHGB8lZ4CSLo%2BWmSIjzmkQ33RgkeNF9eYV4AV1PpdZZ%2Fjyl%2BVjCQtaNVV5c%3D; rl_session=RudderEncrypt%3AU2FsdGVkX19jm82pV3xfWHI%2FE6QaUo5xFQZuXuYh%2FkUCBhyJGY7TqzAK3YDkYppIpUipS7LtUSxm6iWAAp3vGhbB58MN7hrVa8imlwsuL7ceFNN%2BR1uTEvKTR8wWKaii2Xzs%2FYnhG3X8kmImIfYZgg%3D%3D; access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5NGNkOTFlMy03ZDg5LTQ1ZTgtOWQ4NS1lOGJhMDY2MGQ3NGMiLCJzZXNzaW9uX3Rva2VuIjoiMjFjMmEwMmItYjY5Ny00MGVjLWIwMmItMjI1YzJjOWUyZGMzIiwiZXhwIjoxNzcwMjYwODExfQ.MpOjnbwllAzarfaoTk1SzYVMqAEXBEMyRt5UyiJ90Qw'}
|
|
||||||
11|vigent2 | 2026-01-29 11:11:20.536 | INFO | app.services.storage:upload_file:97 - Storage upload success: 94cd91e3-7d89-45e8-9d85-e8ba0660d74c/1769656280_myvoice.wav
|
|
||||||
11|vigent2 | 2026-01-29 11:11:20.576 | INFO | app.services.storage:upload_file:97 - Storage upload success: 94cd91e3-7d89-45e8-9d85-e8ba0660d74c/1769656280_myvoice.json
|
|
||||||
11|vigent2 | 2026-01-29 11:11:20.584 | INFO | app.main:dispatch:26 - END Request: POST https://vigent.hbyrkj.top/api/ref-audios - Status: 200 - Duration: 0.55s
|
|
||||||
11|vigent2 | 2026-01-29 11:11:20.638 | INFO | app.main:dispatch:21 - START Request: GET https://vigent.hbyrkj.top/api/ref-audios
|
|
||||||
11|vigent2 | 2026-01-29 11:11:20.638 | INFO | app.main:dispatch:22 - HEADERS: {'connection': 'upgrade', 'host': 'vigent.hbyrkj.top', 'x-real-ip': '27.17.161.128', 'x-forwarded-for': '27.17.161.128', 'x-forwarded-proto': 'https', 'sec-ch-ua-platform': '"Windows"', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36', 'accept': 'application/json, text/plain, */*', 'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"', 'sec-ch-ua-mobile': '?0', 'sec-fetch-site': 'same-origin', 'sec-fetch-mode': 'cors', 'sec-fetch-dest': 'empty', 'referer': 'https://vigent.hbyrkj.top/', 'accept-encoding': 'gzip, deflate, br, zstd', 'accept-language': 'en-US,en;q=0.9,zh;q=0.8,zh-CN;q=0.7', 'priority': 'u=1, i', 'cookie': 'rl_page_init_referrer=RudderEncrypt%3AU2FsdGVkX1%2FRWtsIwIaguDp15em58SDrIwOvRJVXeK4%3D; rl_page_init_referring_domain=RudderEncrypt%3AU2FsdGVkX1%2BVZN6tniQmiO5L2fGVdcrYOkqG%2BRHkNFw%3D; ph_phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo_posthog=%7B%22distinct_id%22%3A%22f6a1ba3602218bc1551bb81b48167bf7484eeb86ed8ee9484fa83f1267023264%230d2437ec-d81b-491c-991f-0b6559daa00d%22%2C%22%24sesid%22%3A%5B1762504332341%2C%22019a5d6c-ae21-7d75-8919-11e9621a135f%22%2C1762503994906%5D%2C%22%24epp%22%3Atrue%2C%22%24initial_person_info%22%3A%7B%22r%22%3A%22%24direct%22%2C%22u%22%3A%22https%3A%2F%2Fn8n.hbyrkj.top%2Fsignin%3Fredirect%3D%25252F%22%7D%7D; rl_anonymous_id=RudderEncrypt%3AU2FsdGVkX19aTpWYcHFt3zhITFSLk1XAMr9V2jBWQwsuLDNLXh93pTlQ%2FUpvwmv6h%2Fl1bW4xH83hrkWPCTkSYg%3D%3D; rl_group_id=RudderEncrypt%3AU2FsdGVkX1%2BhywVlN3t3ypqwAMgqlh7ZRNLMKnFMhxA%3D; rl_group_trait=RudderEncrypt%3AU2FsdGVkX19jAKNOmR%2FnSngsWGVcmYB2qyvsbh3wQc0%3D; rl_user_id=RudderEncrypt%3AU2FsdGVkX180hU8QtHwPe3dPd1o7rEP7efRzFgCIvuIPRwbE3dWE0aEQCCMpQTN%2B7AGEtH6mjRvEuqcbfOdaX4TtJGL2jHbdcZUuA7Mpjf0uvsZ15LToi0zM1NWR7i6wE2z4vcYyFaBdB1uTJq3SxhX2WsqWe4YiT12vld0E%2F5w%3D; rl_trait=RudderEncrypt%3AU2FsdGVkX19tgs8QN46oDejOzAvFyTx%2FIVRu7LAGDzh2eg%2FAhV8eY%2FyjW12D%2BtSOVq6NLF2lSZcY40rlQ%2B1fUc3DAe2euuWhIECOtlxtY5Hho11ZdHGB8lZ4CSLo%2BWmSIjzmkQ33RgkeNF9eYV4AV1PpdZZ%2Fjyl%2BVjCQtaNVV5c%3D; rl_session=RudderEncrypt%3AU2FsdGVkX19jm82pV3xfWHI%2FE6QaUo5xFQZuXuYh%2FkUCBhyJGY7TqzAK3YDkYppIpUipS7LtUSxm6iWAAp3vGhbB58MN7hrVa8imlwsuL7ceFNN%2BR1uTEvKTR8wWKaii2Xzs%2FYnhG3X8kmImIfYZgg%3D%3D; access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5NGNkOTFlMy03ZDg5LTQ1ZTgtOWQ4NS1lOGJhMDY2MGQ3NGMiLCJzZXNzaW9uX3Rva2VuIjoiMjFjMmEwMmItYjY5Ny00MGVjLWIwMmItMjI1YzJjOWUyZGMzIiwiZXhwIjoxNzcwMjYwODExfQ.MpOjnbwllAzarfaoTk1SzYVMqAEXBEMyRt5UyiJ90Qw'}
|
|
||||||
11|vigent2 | 2026-01-29 11:11:21.086 | INFO | app.main:dispatch:26 - END Request: GET https://vigent.hbyrkj.top/api/ref-audios - Status: 200 - Duration: 0.45s
|
|
||||||
11|vigent2 | 2026-01-29 11:22:58.683 | INFO | app.main:dispatch:21 - START Request: GET https://vigent.hbyrkj.top/api/videos/generated
|
|
||||||
11|vigent2 | 2026-01-29 11:22:58.684 | INFO | app.main:dispatch:22 - HEADERS: {'connection': 'upgrade', 'host': 'vigent.hbyrkj.top', 'x-real-ip': '27.17.161.128', 'x-forwarded-for': '27.17.161.128', 'x-forwarded-proto': 'https', 'sec-ch-ua-platform': '"Windows"', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36', 'accept': 'application/json, text/plain, */*', 'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"', 'sec-ch-ua-mobile': '?0', 'sec-fetch-site': 'same-origin', 'sec-fetch-mode': 'cors', 'sec-fetch-dest': 'empty', 'referer': 'https://vigent.hbyrkj.top/publish', 'accept-encoding': 'gzip, deflate, br, zstd', 'accept-language': 'en-US,en;q=0.9,zh;q=0.8,zh-CN;q=0.7', 'priority': 'u=1, i', 'cookie': 'rl_page_init_referrer=RudderEncrypt%3AU2FsdGVkX1%2FRWtsIwIaguDp15em58SDrIwOvRJVXeK4%3D; rl_page_init_referring_domain=RudderEncrypt%3AU2FsdGVkX1%2BVZN6tniQmiO5L2fGVdcrYOkqG%2BRHkNFw%3D; ph_phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo_posthog=%7B%22distinct_id%22%3A%22f6a1ba3602218bc1551bb81b48167bf7484eeb86ed8ee9484fa83f1267023264%230d2437ec-d81b-491c-991f-0b6559daa00d%22%2C%22%24sesid%22%3A%5B1762504332341%2C%22019a5d6c-ae21-7d75-8919-11e9621a135f%22%2C1762503994906%5D%2C%22%24epp%22%3Atrue%2C%22%24initial_person_info%22%3A%7B%22r%22%3A%22%24direct%22%2C%22u%22%3A%22https%3A%2F%2Fn8n.hbyrkj.top%2Fsignin%3Fredirect%3D%25252F%22%7D%7D; rl_anonymous_id=RudderEncrypt%3AU2FsdGVkX19aTpWYcHFt3zhITFSLk1XAMr9V2jBWQwsuLDNLXh93pTlQ%2FUpvwmv6h%2Fl1bW4xH83hrkWPCTkSYg%3D%3D; rl_group_id=RudderEncrypt%3AU2FsdGVkX1%2BhywVlN3t3ypqwAMgqlh7ZRNLMKnFMhxA%3D; rl_group_trait=RudderEncrypt%3AU2FsdGVkX19jAKNOmR%2FnSngsWGVcmYB2qyvsbh3wQc0%3D; rl_user_id=RudderEncrypt%3AU2FsdGVkX180hU8QtHwPe3dPd1o7rEP7efRzFgCIvuIPRwbE3dWE0aEQCCMpQTN%2B7AGEtH6mjRvEuqcbfOdaX4TtJGL2jHbdcZUuA7Mpjf0uvsZ15LToi0zM1NWR7i6wE2z4vcYyFaBdB1uTJq3SxhX2WsqWe4YiT12vld0E%2F5w%3D; rl_trait=RudderEncrypt%3AU2FsdGVkX19tgs8QN46oDejOzAvFyTx%2FIVRu7LAGDzh2eg%2FAhV8eY%2FyjW12D%2BtSOVq6NLF2lSZcY40rlQ%2B1fUc3DAe2euuWhIECOtlxtY5Hho11ZdHGB8lZ4CSLo%2BWmSIjzmkQ33RgkeNF9eYV4AV1PpdZZ%2Fjyl%2BVjCQtaNVV5c%3D; rl_session=RudderEncrypt%3AU2FsdGVkX19jm82pV3xfWHI%2FE6QaUo5xFQZuXuYh%2FkUCBhyJGY7TqzAK3YDkYppIpUipS7LtUSxm6iWAAp3vGhbB58MN7hrVa8imlwsuL7ceFNN%2BR1uTEvKTR8wWKaii2Xzs%2FYnhG3X8kmImIfYZgg%3D%3D; access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5NGNkOTFlMy03ZDg5LTQ1ZTgtOWQ4NS1lOGJhMDY2MGQ3NGMiLCJzZXNzaW9uX3Rva2VuIjoiMjFjMmEwMmItYjY5Ny00MGVjLWIwMmItMjI1YzJjOWUyZGMzIiwiZXhwIjoxNzcwMjYwODExfQ.MpOjnbwllAzarfaoTk1SzYVMqAEXBEMyRt5UyiJ90Qw'}
|
|
||||||
11|vigent2 | 2026-01-29 11:22:58.742 | INFO | app.main:dispatch:21 - START Request: GET https://vigent.hbyrkj.top/api/publish/accounts
|
|
||||||
11|vigent2 | 2026-01-29 11:22:58.743 | INFO | app.main:dispatch:22 - HEADERS: {'connection': 'upgrade', 'host': 'vigent.hbyrkj.top', 'x-real-ip': '27.17.161.128', 'x-forwarded-for': '27.17.161.128', 'x-forwarded-proto': 'https', 'sec-ch-ua-platform': '"Windows"', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36', 'accept': 'application/json, text/plain, */*', 'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"', 'sec-ch-ua-mobile': '?0', 'sec-fetch-site': 'same-origin', 'sec-fetch-mode': 'cors', 'sec-fetch-dest': 'empty', 'referer': 'https://vigent.hbyrkj.top/publish', 'accept-encoding': 'gzip, deflate, br, zstd', 'accept-language': 'en-US,en;q=0.9,zh;q=0.8,zh-CN;q=0.7', 'priority': 'u=1, i', 'cookie': 'rl_page_init_referrer=RudderEncrypt%3AU2FsdGVkX1%2FRWtsIwIaguDp15em58SDrIwOvRJVXeK4%3D; rl_page_init_referring_domain=RudderEncrypt%3AU2FsdGVkX1%2BVZN6tniQmiO5L2fGVdcrYOkqG%2BRHkNFw%3D; ph_phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo_posthog=%7B%22distinct_id%22%3A%22f6a1ba3602218bc1551bb81b48167bf7484eeb86ed8ee9484fa83f1267023264%230d2437ec-d81b-491c-991f-0b6559daa00d%22%2C%22%24sesid%22%3A%5B1762504332341%2C%22019a5d6c-ae21-7d75-8919-11e9621a135f%22%2C1762503994906%5D%2C%22%24epp%22%3Atrue%2C%22%24initial_person_info%22%3A%7B%22r%22%3A%22%24direct%22%2C%22u%22%3A%22https%3A%2F%2Fn8n.hbyrkj.top%2Fsignin%3Fredirect%3D%25252F%22%7D%7D; rl_anonymous_id=RudderEncrypt%3AU2FsdGVkX19aTpWYcHFt3zhITFSLk1XAMr9V2jBWQwsuLDNLXh93pTlQ%2FUpvwmv6h%2Fl1bW4xH83hrkWPCTkSYg%3D%3D; rl_group_id=RudderEncrypt%3AU2FsdGVkX1%2BhywVlN3t3ypqwAMgqlh7ZRNLMKnFMhxA%3D; rl_group_trait=RudderEncrypt%3AU2FsdGVkX19jAKNOmR%2FnSngsWGVcmYB2qyvsbh3wQc0%3D; rl_user_id=RudderEncrypt%3AU2FsdGVkX180hU8QtHwPe3dPd1o7rEP7efRzFgCIvuIPRwbE3dWE0aEQCCMpQTN%2B7AGEtH6mjRvEuqcbfOdaX4TtJGL2jHbdcZUuA7Mpjf0uvsZ15LToi0zM1NWR7i6wE2z4vcYyFaBdB1uTJq3SxhX2WsqWe4YiT12vld0E%2F5w%3D; rl_trait=RudderEncrypt%3AU2FsdGVkX19tgs8QN46oDejOzAvFyTx%2FIVRu7LAGDzh2eg%2FAhV8eY%2FyjW12D%2BtSOVq6NLF2lSZcY40rlQ%2B1fUc3DAe2euuWhIECOtlxtY5Hho11ZdHGB8lZ4CSLo%2BWmSIjzmkQ33RgkeNF9eYV4AV1PpdZZ%2Fjyl%2BVjCQtaNVV5c%3D; rl_session=RudderEncrypt%3AU2FsdGVkX19jm82pV3xfWHI%2FE6QaUo5xFQZuXuYh%2FkUCBhyJGY7TqzAK3YDkYppIpUipS7LtUSxm6iWAAp3vGhbB58MN7hrVa8imlwsuL7ceFNN%2BR1uTEvKTR8wWKaii2Xzs%2FYnhG3X8kmImIfYZgg%3D%3D; access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5NGNkOTFlMy03ZDg5LTQ1ZTgtOWQ4NS1lOGJhMDY2MGQ3NGMiLCJzZXNzaW9uX3Rva2VuIjoiMjFjMmEwMmItYjY5Ny00MGVjLWIwMmItMjI1YzJjOWUyZGMzIiwiZXhwIjoxNzcwMjYwODExfQ.MpOjnbwllAzarfaoTk1SzYVMqAEXBEMyRt5UyiJ90Qw'}
|
|
||||||
11|vigent2 | 2026-01-29 11:22:58.747 | INFO | app.main:dispatch:26 - END Request: GET https://vigent.hbyrkj.top/api/publish/accounts - Status: 200 - Duration: 0.01s
|
|
||||||
11|vigent2 | 2026-01-29 11:22:58.798 | INFO | app.main:dispatch:26 - END Request: GET https://vigent.hbyrkj.top/api/videos/generated - Status: 200 - Duration: 0.11s
|
|
||||||
11|vigent2 | 2026-01-29 11:23:03.509 | INFO | app.main:dispatch:21 - START Request: GET https://vigent.hbyrkj.top/api/materials?t=1769656987465
|
|
||||||
11|vigent2 | 2026-01-29 11:23:03.510 | INFO | app.main:dispatch:22 - HEADERS: {'connection': 'upgrade', 'host': 'vigent.hbyrkj.top', 'x-real-ip': '27.17.161.128', 'x-forwarded-for': '27.17.161.128', 'x-forwarded-proto': 'https', 'sec-ch-ua-platform': '"Windows"', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36', 'accept': 'application/json, text/plain, */*', 'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"', 'sec-ch-ua-mobile': '?0', 'sec-fetch-site': 'same-origin', 'sec-fetch-mode': 'cors', 'sec-fetch-dest': 'empty', 'referer': 'https://vigent.hbyrkj.top/', 'accept-encoding': 'gzip, deflate, br, zstd', 'accept-language': 'en-US,en;q=0.9,zh;q=0.8,zh-CN;q=0.7', 'priority': 'u=1, i', 'cookie': 'rl_page_init_referrer=RudderEncrypt%3AU2FsdGVkX1%2FRWtsIwIaguDp15em58SDrIwOvRJVXeK4%3D; rl_page_init_referring_domain=RudderEncrypt%3AU2FsdGVkX1%2BVZN6tniQmiO5L2fGVdcrYOkqG%2BRHkNFw%3D; ph_phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo_posthog=%7B%22distinct_id%22%3A%22f6a1ba3602218bc1551bb81b48167bf7484eeb86ed8ee9484fa83f1267023264%230d2437ec-d81b-491c-991f-0b6559daa00d%22%2C%22%24sesid%22%3A%5B1762504332341%2C%22019a5d6c-ae21-7d75-8919-11e9621a135f%22%2C1762503994906%5D%2C%22%24epp%22%3Atrue%2C%22%24initial_person_info%22%3A%7B%22r%22%3A%22%24direct%22%2C%22u%22%3A%22https%3A%2F%2Fn8n.hbyrkj.top%2Fsignin%3Fredirect%3D%25252F%22%7D%7D; rl_anonymous_id=RudderEncrypt%3AU2FsdGVkX19aTpWYcHFt3zhITFSLk1XAMr9V2jBWQwsuLDNLXh93pTlQ%2FUpvwmv6h%2Fl1bW4xH83hrkWPCTkSYg%3D%3D; rl_group_id=RudderEncrypt%3AU2FsdGVkX1%2BhywVlN3t3ypqwAMgqlh7ZRNLMKnFMhxA%3D; rl_group_trait=RudderEncrypt%3AU2FsdGVkX19jAKNOmR%2FnSngsWGVcmYB2qyvsbh3wQc0%3D; rl_user_id=RudderEncrypt%3AU2FsdGVkX180hU8QtHwPe3dPd1o7rEP7efRzFgCIvuIPRwbE3dWE0aEQCCMpQTN%2B7AGEtH6mjRvEuqcbfOdaX4TtJGL2jHbdcZUuA7Mpjf0uvsZ15LToi0zM1NWR7i6wE2z4vcYyFaBdB1uTJq3SxhX2WsqWe4YiT12vld0E%2F5w%3D; rl_trait=RudderEncrypt%3AU2FsdGVkX19tgs8QN46oDejOzAvFyTx%2FIVRu7LAGDzh2eg%2FAhV8eY%2FyjW12D%2BtSOVq6NLF2lSZcY40rlQ%2B1fUc3DAe2euuWhIECOtlxtY5Hho11ZdHGB8lZ4CSLo%2BWmSIjzmkQ33RgkeNF9eYV4AV1PpdZZ%2Fjyl%2BVjCQtaNVV5c%3D; rl_session=RudderEncrypt%3AU2FsdGVkX19jm82pV3xfWHI%2FE6QaUo5xFQZuXuYh%2FkUCBhyJGY7TqzAK3YDkYppIpUipS7LtUSxm6iWAAp3vGhbB58MN7hrVa8imlwsuL7ceFNN%2BR1uTEvKTR8wWKaii2Xzs%2FYnhG3X8kmImIfYZgg%3D%3D; access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5NGNkOTFlMy03ZDg5LTQ1ZTgtOWQ4NS1lOGJhMDY2MGQ3NGMiLCJzZXNzaW9uX3Rva2VuIjoiMjFjMmEwMmItYjY5Ny00MGVjLWIwMmItMjI1YzJjOWUyZGMzIiwiZXhwIjoxNzcwMjYwODExfQ.MpOjnbwllAzarfaoTk1SzYVMqAEXBEMyRt5UyiJ90Qw'}
|
|
||||||
11|vigent2 | 2026-01-29 11:23:03.535 | INFO | app.main:dispatch:21 - START Request: GET https://vigent.hbyrkj.top/api/videos/generated
|
|
||||||
11|vigent2 | 2026-01-29 11:23:03.535 | INFO | app.main:dispatch:22 - HEADERS: {'connection': 'upgrade', 'host': 'vigent.hbyrkj.top', 'x-real-ip': '27.17.161.128', 'x-forwarded-for': '27.17.161.128', 'x-forwarded-proto': 'https', 'sec-ch-ua-platform': '"Windows"', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36', 'accept': 'application/json, text/plain, */*', 'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"', 'sec-ch-ua-mobile': '?0', 'sec-fetch-site': 'same-origin', 'sec-fetch-mode': 'cors', 'sec-fetch-dest': 'empty', 'referer': 'https://vigent.hbyrkj.top/', 'accept-encoding': 'gzip, deflate, br, zstd', 'accept-language': 'en-US,en;q=0.9,zh;q=0.8,zh-CN;q=0.7', 'priority': 'u=1, i', 'cookie': 'rl_page_init_referrer=RudderEncrypt%3AU2FsdGVkX1%2FRWtsIwIaguDp15em58SDrIwOvRJVXeK4%3D; rl_page_init_referring_domain=RudderEncrypt%3AU2FsdGVkX1%2BVZN6tniQmiO5L2fGVdcrYOkqG%2BRHkNFw%3D; ph_phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo_posthog=%7B%22distinct_id%22%3A%22f6a1ba3602218bc1551bb81b48167bf7484eeb86ed8ee9484fa83f1267023264%230d2437ec-d81b-491c-991f-0b6559daa00d%22%2C%22%24sesid%22%3A%5B1762504332341%2C%22019a5d6c-ae21-7d75-8919-11e9621a135f%22%2C1762503994906%5D%2C%22%24epp%22%3Atrue%2C%22%24initial_person_info%22%3A%7B%22r%22%3A%22%24direct%22%2C%22u%22%3A%22https%3A%2F%2Fn8n.hbyrkj.top%2Fsignin%3Fredirect%3D%25252F%22%7D%7D; rl_anonymous_id=RudderEncrypt%3AU2FsdGVkX19aTpWYcHFt3zhITFSLk1XAMr9V2jBWQwsuLDNLXh93pTlQ%2FUpvwmv6h%2Fl1bW4xH83hrkWPCTkSYg%3D%3D; rl_group_id=RudderEncrypt%3AU2FsdGVkX1%2BhywVlN3t3ypqwAMgqlh7ZRNLMKnFMhxA%3D; rl_group_trait=RudderEncrypt%3AU2FsdGVkX19jAKNOmR%2FnSngsWGVcmYB2qyvsbh3wQc0%3D; rl_user_id=RudderEncrypt%3AU2FsdGVkX180hU8QtHwPe3dPd1o7rEP7efRzFgCIvuIPRwbE3dWE0aEQCCMpQTN%2B7AGEtH6mjRvEuqcbfOdaX4TtJGL2jHbdcZUuA7Mpjf0uvsZ15LToi0zM1NWR7i6wE2z4vcYyFaBdB1uTJq3SxhX2WsqWe4YiT12vld0E%2F5w%3D; rl_trait=RudderEncrypt%3AU2FsdGVkX19tgs8QN46oDejOzAvFyTx%2FIVRu7LAGDzh2eg%2FAhV8eY%2FyjW12D%2BtSOVq6NLF2lSZcY40rlQ%2B1fUc3DAe2euuWhIECOtlxtY5Hho11ZdHGB8lZ4CSLo%2BWmSIjzmkQ33RgkeNF9eYV4AV1PpdZZ%2Fjyl%2BVjCQtaNVV5c%3D; rl_session=RudderEncrypt%3AU2FsdGVkX19jm82pV3xfWHI%2FE6QaUo5xFQZuXuYh%2FkUCBhyJGY7TqzAK3YDkYppIpUipS7LtUSxm6iWAAp3vGhbB58MN7hrVa8imlwsuL7ceFNN%2BR1uTEvKTR8wWKaii2Xzs%2FYnhG3X8kmImIfYZgg%3D%3D; access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5NGNkOTFlMy03ZDg5LTQ1ZTgtOWQ4NS1lOGJhMDY2MGQ3NGMiLCJzZXNzaW9uX3Rva2VuIjoiMjFjMmEwMmItYjY5Ny00MGVjLWIwMmItMjI1YzJjOWUyZGMzIiwiZXhwIjoxNzcwMjYwODExfQ.MpOjnbwllAzarfaoTk1SzYVMqAEXBEMyRt5UyiJ90Qw'}
|
|
||||||
11|vigent2 | 2026-01-29 11:23:03.551 | INFO | app.main:dispatch:21 - START Request: GET https://vigent.hbyrkj.top/api/ref-audios
|
|
||||||
11|vigent2 | 2026-01-29 11:23:03.552 | INFO | app.main:dispatch:22 - HEADERS: {'connection': 'upgrade', 'host': 'vigent.hbyrkj.top', 'x-real-ip': '27.17.161.128', 'x-forwarded-for': '27.17.161.128', 'x-forwarded-proto': 'https', 'sec-ch-ua-platform': '"Windows"', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36', 'accept': 'application/json, text/plain, */*', 'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"', 'sec-ch-ua-mobile': '?0', 'sec-fetch-site': 'same-origin', 'sec-fetch-mode': 'cors', 'sec-fetch-dest': 'empty', 'referer': 'https://vigent.hbyrkj.top/', 'accept-encoding': 'gzip, deflate, br, zstd', 'accept-language': 'en-US,en;q=0.9,zh;q=0.8,zh-CN;q=0.7', 'priority': 'u=1, i', 'cookie': 'rl_page_init_referrer=RudderEncrypt%3AU2FsdGVkX1%2FRWtsIwIaguDp15em58SDrIwOvRJVXeK4%3D; rl_page_init_referring_domain=RudderEncrypt%3AU2FsdGVkX1%2BVZN6tniQmiO5L2fGVdcrYOkqG%2BRHkNFw%3D; ph_phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo_posthog=%7B%22distinct_id%22%3A%22f6a1ba3602218bc1551bb81b48167bf7484eeb86ed8ee9484fa83f1267023264%230d2437ec-d81b-491c-991f-0b6559daa00d%22%2C%22%24sesid%22%3A%5B1762504332341%2C%22019a5d6c-ae21-7d75-8919-11e9621a135f%22%2C1762503994906%5D%2C%22%24epp%22%3Atrue%2C%22%24initial_person_info%22%3A%7B%22r%22%3A%22%24direct%22%2C%22u%22%3A%22https%3A%2F%2Fn8n.hbyrkj.top%2Fsignin%3Fredirect%3D%25252F%22%7D%7D; rl_anonymous_id=RudderEncrypt%3AU2FsdGVkX19aTpWYcHFt3zhITFSLk1XAMr9V2jBWQwsuLDNLXh93pTlQ%2FUpvwmv6h%2Fl1bW4xH83hrkWPCTkSYg%3D%3D; rl_group_id=RudderEncrypt%3AU2FsdGVkX1%2BhywVlN3t3ypqwAMgqlh7ZRNLMKnFMhxA%3D; rl_group_trait=RudderEncrypt%3AU2FsdGVkX19jAKNOmR%2FnSngsWGVcmYB2qyvsbh3wQc0%3D; rl_user_id=RudderEncrypt%3AU2FsdGVkX180hU8QtHwPe3dPd1o7rEP7efRzFgCIvuIPRwbE3dWE0aEQCCMpQTN%2B7AGEtH6mjRvEuqcbfOdaX4TtJGL2jHbdcZUuA7Mpjf0uvsZ15LToi0zM1NWR7i6wE2z4vcYyFaBdB1uTJq3SxhX2WsqWe4YiT12vld0E%2F5w%3D; rl_trait=RudderEncrypt%3AU2FsdGVkX19tgs8QN46oDejOzAvFyTx%2FIVRu7LAGDzh2eg%2FAhV8eY%2FyjW12D%2BtSOVq6NLF2lSZcY40rlQ%2B1fUc3DAe2euuWhIECOtlxtY5Hho11ZdHGB8lZ4CSLo%2BWmSIjzmkQ33RgkeNF9eYV4AV1PpdZZ%2Fjyl%2BVjCQtaNVV5c%3D; rl_session=RudderEncrypt%3AU2FsdGVkX19jm82pV3xfWHI%2FE6QaUo5xFQZuXuYh%2FkUCBhyJGY7TqzAK3YDkYppIpUipS7LtUSxm6iWAAp3vGhbB58MN7hrVa8imlwsuL7ceFNN%2BR1uTEvKTR8wWKaii2Xzs%2FYnhG3X8kmImIfYZgg%3D%3D; access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5NGNkOTFlMy03ZDg5LTQ1ZTgtOWQ4NS1lOGJhMDY2MGQ3NGMiLCJzZXNzaW9uX3Rva2VuIjoiMjFjMmEwMmItYjY5Ny00MGVjLWIwMmItMjI1YzJjOWUyZGMzIiwiZXhwIjoxNzcwMjYwODExfQ.MpOjnbwllAzarfaoTk1SzYVMqAEXBEMyRt5UyiJ90Qw'}
|
|
||||||
11|vigent2 | 2026-01-29 11:23:03.569 | INFO | app.main:dispatch:26 - END Request: GET https://vigent.hbyrkj.top/api/materials?t=1769656987465 - Status: 200 - Duration: 0.06s
|
|
||||||
11|vigent2 | 2026-01-29 11:23:03.658 | INFO | app.main:dispatch:26 - END Request: GET https://vigent.hbyrkj.top/api/videos/generated - Status: 200 - Duration: 0.12s
|
|
||||||
11|vigent2 | 2026-01-29 11:23:03.996 | INFO | app.main:dispatch:26 - END Request: GET https://vigent.hbyrkj.top/api/ref-audios - Status: 200 - Duration: 0.44s
|
|
||||||
11|vigent2 | 2026-01-29 11:25:37.605 | INFO | app.main:dispatch:21 - START Request: GET https://vigent.hbyrkj.top/api/ref-audios
|
|
||||||
11|vigent2 | 2026-01-29 11:25:37.605 | INFO | app.main:dispatch:22 - HEADERS: {'connection': 'upgrade', 'host': 'vigent.hbyrkj.top', 'x-real-ip': '27.17.161.128', 'x-forwarded-for': '27.17.161.128', 'x-forwarded-proto': 'https', 'sec-ch-ua-platform': '"Windows"', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36', 'accept': 'application/json, text/plain, */*', 'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"', 'sec-ch-ua-mobile': '?0', 'sec-fetch-site': 'same-origin', 'sec-fetch-mode': 'cors', 'sec-fetch-dest': 'empty', 'referer': 'https://vigent.hbyrkj.top/', 'accept-encoding': 'gzip, deflate, br, zstd', 'accept-language': 'en-US,en;q=0.9,zh;q=0.8,zh-CN;q=0.7', 'priority': 'u=1, i', 'cookie': 'rl_page_init_referrer=RudderEncrypt%3AU2FsdGVkX1%2FRWtsIwIaguDp15em58SDrIwOvRJVXeK4%3D; rl_page_init_referring_domain=RudderEncrypt%3AU2FsdGVkX1%2BVZN6tniQmiO5L2fGVdcrYOkqG%2BRHkNFw%3D; ph_phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo_posthog=%7B%22distinct_id%22%3A%22f6a1ba3602218bc1551bb81b48167bf7484eeb86ed8ee9484fa83f1267023264%230d2437ec-d81b-491c-991f-0b6559daa00d%22%2C%22%24sesid%22%3A%5B1762504332341%2C%22019a5d6c-ae21-7d75-8919-11e9621a135f%22%2C1762503994906%5D%2C%22%24epp%22%3Atrue%2C%22%24initial_person_info%22%3A%7B%22r%22%3A%22%24direct%22%2C%22u%22%3A%22https%3A%2F%2Fn8n.hbyrkj.top%2Fsignin%3Fredirect%3D%25252F%22%7D%7D; rl_anonymous_id=RudderEncrypt%3AU2FsdGVkX19aTpWYcHFt3zhITFSLk1XAMr9V2jBWQwsuLDNLXh93pTlQ%2FUpvwmv6h%2Fl1bW4xH83hrkWPCTkSYg%3D%3D; rl_group_id=RudderEncrypt%3AU2FsdGVkX1%2BhywVlN3t3ypqwAMgqlh7ZRNLMKnFMhxA%3D; rl_group_trait=RudderEncrypt%3AU2FsdGVkX19jAKNOmR%2FnSngsWGVcmYB2qyvsbh3wQc0%3D; rl_user_id=RudderEncrypt%3AU2FsdGVkX180hU8QtHwPe3dPd1o7rEP7efRzFgCIvuIPRwbE3dWE0aEQCCMpQTN%2B7AGEtH6mjRvEuqcbfOdaX4TtJGL2jHbdcZUuA7Mpjf0uvsZ15LToi0zM1NWR7i6wE2z4vcYyFaBdB1uTJq3SxhX2WsqWe4YiT12vld0E%2F5w%3D; rl_trait=RudderEncrypt%3AU2FsdGVkX19tgs8QN46oDejOzAvFyTx%2FIVRu7LAGDzh2eg%2FAhV8eY%2FyjW12D%2BtSOVq6NLF2lSZcY40rlQ%2B1fUc3DAe2euuWhIECOtlxtY5Hho11ZdHGB8lZ4CSLo%2BWmSIjzmkQ33RgkeNF9eYV4AV1PpdZZ%2Fjyl%2BVjCQtaNVV5c%3D; rl_session=RudderEncrypt%3AU2FsdGVkX19jm82pV3xfWHI%2FE6QaUo5xFQZuXuYh%2FkUCBhyJGY7TqzAK3YDkYppIpUipS7LtUSxm6iWAAp3vGhbB58MN7hrVa8imlwsuL7ceFNN%2BR1uTEvKTR8wWKaii2Xzs%2FYnhG3X8kmImIfYZgg%3D%3D; access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5NGNkOTFlMy03ZDg5LTQ1ZTgtOWQ4NS1lOGJhMDY2MGQ3NGMiLCJzZXNzaW9uX3Rva2VuIjoiMjFjMmEwMmItYjY5Ny00MGVjLWIwMmItMjI1YzJjOWUyZGMzIiwiZXhwIjoxNzcwMjYwODExfQ.MpOjnbwllAzarfaoTk1SzYVMqAEXBEMyRt5UyiJ90Qw'}
|
|
||||||
11|vigent2 | 2026-01-29 11:25:37.653 | INFO | app.main:dispatch:21 - START Request: GET https://vigent.hbyrkj.top/api/materials?t=1769657141569
|
|
||||||
11|vigent2 | 2026-01-29 11:25:37.653 | INFO | app.main:dispatch:22 - HEADERS: {'connection': 'upgrade', 'host': 'vigent.hbyrkj.top', 'x-real-ip': '27.17.161.128', 'x-forwarded-for': '27.17.161.128', 'x-forwarded-proto': 'https', 'sec-ch-ua-platform': '"Windows"', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36', 'accept': 'application/json, text/plain, */*', 'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"', 'sec-ch-ua-mobile': '?0', 'sec-fetch-site': 'same-origin', 'sec-fetch-mode': 'cors', 'sec-fetch-dest': 'empty', 'referer': 'https://vigent.hbyrkj.top/', 'accept-encoding': 'gzip, deflate, br, zstd', 'accept-language': 'en-US,en;q=0.9,zh;q=0.8,zh-CN;q=0.7', 'priority': 'u=1, i', 'cookie': 'rl_page_init_referrer=RudderEncrypt%3AU2FsdGVkX1%2FRWtsIwIaguDp15em58SDrIwOvRJVXeK4%3D; rl_page_init_referring_domain=RudderEncrypt%3AU2FsdGVkX1%2BVZN6tniQmiO5L2fGVdcrYOkqG%2BRHkNFw%3D; ph_phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo_posthog=%7B%22distinct_id%22%3A%22f6a1ba3602218bc1551bb81b48167bf7484eeb86ed8ee9484fa83f1267023264%230d2437ec-d81b-491c-991f-0b6559daa00d%22%2C%22%24sesid%22%3A%5B1762504332341%2C%22019a5d6c-ae21-7d75-8919-11e9621a135f%22%2C1762503994906%5D%2C%22%24epp%22%3Atrue%2C%22%24initial_person_info%22%3A%7B%22r%22%3A%22%24direct%22%2C%22u%22%3A%22https%3A%2F%2Fn8n.hbyrkj.top%2Fsignin%3Fredirect%3D%25252F%22%7D%7D; rl_anonymous_id=RudderEncrypt%3AU2FsdGVkX19aTpWYcHFt3zhITFSLk1XAMr9V2jBWQwsuLDNLXh93pTlQ%2FUpvwmv6h%2Fl1bW4xH83hrkWPCTkSYg%3D%3D; rl_group_id=RudderEncrypt%3AU2FsdGVkX1%2BhywVlN3t3ypqwAMgqlh7ZRNLMKnFMhxA%3D; rl_group_trait=RudderEncrypt%3AU2FsdGVkX19jAKNOmR%2FnSngsWGVcmYB2qyvsbh3wQc0%3D; rl_user_id=RudderEncrypt%3AU2FsdGVkX180hU8QtHwPe3dPd1o7rEP7efRzFgCIvuIPRwbE3dWE0aEQCCMpQTN%2B7AGEtH6mjRvEuqcbfOdaX4TtJGL2jHbdcZUuA7Mpjf0uvsZ15LToi0zM1NWR7i6wE2z4vcYyFaBdB1uTJq3SxhX2WsqWe4YiT12vld0E%2F5w%3D; rl_trait=RudderEncrypt%3AU2FsdGVkX19tgs8QN46oDejOzAvFyTx%2FIVRu7LAGDzh2eg%2FAhV8eY%2FyjW12D%2BtSOVq6NLF2lSZcY40rlQ%2B1fUc3DAe2euuWhIECOtlxtY5Hho11ZdHGB8lZ4CSLo%2BWmSIjzmkQ33RgkeNF9eYV4AV1PpdZZ%2Fjyl%2BVjCQtaNVV5c%3D; rl_session=RudderEncrypt%3AU2FsdGVkX19jm82pV3xfWHI%2FE6QaUo5xFQZuXuYh%2FkUCBhyJGY7TqzAK3YDkYppIpUipS7LtUSxm6iWAAp3vGhbB58MN7hrVa8imlwsuL7ceFNN%2BR1uTEvKTR8wWKaii2Xzs%2FYnhG3X8kmImIfYZgg%3D%3D; access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5NGNkOTFlMy03ZDg5LTQ1ZTgtOWQ4NS1lOGJhMDY2MGQ3NGMiLCJzZXNzaW9uX3Rva2VuIjoiMjFjMmEwMmItYjY5Ny00MGVjLWIwMmItMjI1YzJjOWUyZGMzIiwiZXhwIjoxNzcwMjYwODExfQ.MpOjnbwllAzarfaoTk1SzYVMqAEXBEMyRt5UyiJ90Qw'}
|
|
||||||
11|vigent2 | 2026-01-29 11:25:37.673 | INFO | app.main:dispatch:21 - START Request: GET https://vigent.hbyrkj.top/api/videos/generated
|
|
||||||
11|vigent2 | 2026-01-29 11:25:37.674 | INFO | app.main:dispatch:22 - HEADERS: {'connection': 'upgrade', 'host': 'vigent.hbyrkj.top', 'x-real-ip': '27.17.161.128', 'x-forwarded-for': '27.17.161.128', 'x-forwarded-proto': 'https', 'sec-ch-ua-platform': '"Windows"', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36', 'accept': 'application/json, text/plain, */*', 'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"', 'sec-ch-ua-mobile': '?0', 'sec-fetch-site': 'same-origin', 'sec-fetch-mode': 'cors', 'sec-fetch-dest': 'empty', 'referer': 'https://vigent.hbyrkj.top/', 'accept-encoding': 'gzip, deflate, br, zstd', 'accept-language': 'en-US,en;q=0.9,zh;q=0.8,zh-CN;q=0.7', 'priority': 'u=1, i', 'cookie': 'rl_page_init_referrer=RudderEncrypt%3AU2FsdGVkX1%2FRWtsIwIaguDp15em58SDrIwOvRJVXeK4%3D; rl_page_init_referring_domain=RudderEncrypt%3AU2FsdGVkX1%2BVZN6tniQmiO5L2fGVdcrYOkqG%2BRHkNFw%3D; ph_phc_4URIAm1uYfJO7j8kWSe0J8lc8IqnstRLS7Jx8NcakHo_posthog=%7B%22distinct_id%22%3A%22f6a1ba3602218bc1551bb81b48167bf7484eeb86ed8ee9484fa83f1267023264%230d2437ec-d81b-491c-991f-0b6559daa00d%22%2C%22%24sesid%22%3A%5B1762504332341%2C%22019a5d6c-ae21-7d75-8919-11e9621a135f%22%2C1762503994906%5D%2C%22%24epp%22%3Atrue%2C%22%24initial_person_info%22%3A%7B%22r%22%3A%22%24direct%22%2C%22u%22%3A%22https%3A%2F%2Fn8n.hbyrkj.top%2Fsignin%3Fredirect%3D%25252F%22%7D%7D; rl_anonymous_id=RudderEncrypt%3AU2FsdGVkX19aTpWYcHFt3zhITFSLk1XAMr9V2jBWQwsuLDNLXh93pTlQ%2FUpvwmv6h%2Fl1bW4xH83hrkWPCTkSYg%3D%3D; rl_group_id=RudderEncrypt%3AU2FsdGVkX1%2BhywVlN3t3ypqwAMgqlh7ZRNLMKnFMhxA%3D; rl_group_trait=RudderEncrypt%3AU2FsdGVkX19jAKNOmR%2FnSngsWGVcmYB2qyvsbh3wQc0%3D; rl_user_id=RudderEncrypt%3AU2FsdGVkX180hU8QtHwPe3dPd1o7rEP7efRzFgCIvuIPRwbE3dWE0aEQCCMpQTN%2B7AGEtH6mjRvEuqcbfOdaX4TtJGL2jHbdcZUuA7Mpjf0uvsZ15LToi0zM1NWR7i6wE2z4vcYyFaBdB1uTJq3SxhX2WsqWe4YiT12vld0E%2F5w%3D; rl_trait=RudderEncrypt%3AU2FsdGVkX19tgs8QN46oDejOzAvFyTx%2FIVRu7LAGDzh2eg%2FAhV8eY%2FyjW12D%2BtSOVq6NLF2lSZcY40rlQ%2B1fUc3DAe2euuWhIECOtlxtY5Hho11ZdHGB8lZ4CSLo%2BWmSIjzmkQ33RgkeNF9eYV4AV1PpdZZ%2Fjyl%2BVjCQtaNVV5c%3D; rl_session=RudderEncrypt%3AU2FsdGVkX19jm82pV3xfWHI%2FE6QaUo5xFQZuXuYh%2FkUCBhyJGY7TqzAK3YDkYppIpUipS7LtUSxm6iWAAp3vGhbB58MN7hrVa8imlwsuL7ceFNN%2BR1uTEvKTR8wWKaii2Xzs%2FYnhG3X8kmImIfYZgg%3D%3D; access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5NGNkOTFlMy03ZDg5LTQ1ZTgtOWQ4NS1lOGJhMDY2MGQ3NGMiLCJzZXNzaW9uX3Rva2VuIjoiMjFjMmEwMmItYjY5Ny00MGVjLWIwMmItMjI1YzJjOWUyZGMzIiwiZXhwIjoxNzcwMjYwODExfQ.MpOjnbwllAzarfaoTk1SzYVMqAEXBEMyRt5UyiJ90Qw'}
|
|
||||||
11|vigent2 | 2026-01-29 11:25:37.781 | INFO | app.main:dispatch:26 - END Request: GET https://vigent.hbyrkj.top/api/materials?t=1769657141569 - Status: 200 - Duration: 0.13s
|
|
||||||
11|vigent2 | 2026-01-29 11:25:37.792 | INFO | app.main:dispatch:26 - END Request: GET https://vigent.hbyrkj.top/api/videos/generated - Status: 200 - Duration: 0.12s
|
|
||||||
11|vigent2 | 2026-01-29 11:25:38.087 | INFO | app.main:dispatch:26 - END Request: GET https://vigent.hbyrkj.top/api/ref-audios - Status: 200 - Duration: 0.48s
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
rongye@r730-ubuntu:~$ pm2 logs vigent2-latentsync
|
|
||||||
[TAILING] Tailing last 15 lines for [vigent2-latentsync] process (change the value with --lines option)
|
|
||||||
/home/rongye/.pm2/logs/vigent2-latentsync-out.log last 15 lines:
|
|
||||||
/home/rongye/.pm2/logs/vigent2-latentsync-error.log last 15 lines:
|
|
||||||
@@ -55,9 +55,9 @@ pip install -e .
|
|||||||
conda install -y -c conda-forge sox
|
conda install -y -c conda-forge sox
|
||||||
```
|
```
|
||||||
|
|
||||||
### 可选: 安装 FlashAttention (推荐)
|
### 可选: 安装 FlashAttention (强烈推荐)
|
||||||
|
|
||||||
FlashAttention 可以显著提升推理速度并减少显存占用:
|
FlashAttention 可以显著提升推理速度 (加载时间减少 85%) 并减少显存占用:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install -U flash-attn --no-build-isolation
|
pip install -U flash-attn --no-build-isolation
|
||||||
|
|||||||
@@ -348,6 +348,15 @@ cp -r SuperIPAgent/social-auto-upload backend/social_upload
|
|||||||
- [x] 前端登录/注册页面更新
|
- [x] 前端登录/注册页面更新
|
||||||
- [x] 数据库迁移脚本 (migrate_to_phone.sql)
|
- [x] 数据库迁移脚本 (migrate_to_phone.sql)
|
||||||
|
|
||||||
|
### 阶段十九:深度性能优化与服务守护 (Day 16) ✅
|
||||||
|
|
||||||
|
> **目标**:提升系统响应速度与服务稳定性
|
||||||
|
|
||||||
|
- [x] Flash Attention 2 集成 (Qwen3-TTS 加速 5x)
|
||||||
|
- [x] LatentSync 性能调优 (OMP 线程限制 + 原生 Flash Attn)
|
||||||
|
- [x] Watchdog 服务守护 (自动重启僵死服务)
|
||||||
|
- [x] 文档体系更新 (部署手册与运维指南)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 项目目录结构 (最终)
|
## 项目目录结构 (最终)
|
||||||
|
|||||||
@@ -1,220 +0,0 @@
|
|||||||
# Qwen3-TTS 声音克隆集成到 ViGent2
|
|
||||||
|
|
||||||
## 需求概述
|
|
||||||
1. 前端支持上传/在线录制参考音频(wav, mp3, m4a 等)
|
|
||||||
2. EdgeTTS 音色保留,增加 Qwen3-TTS 声音克隆界面
|
|
||||||
3. 两种 TTS 方式做成统一界面(Tab 切换)
|
|
||||||
4. 声音克隆使用相同的口播文案输入
|
|
||||||
|
|
||||||
## 架构设计
|
|
||||||
|
|
||||||
### GPU 分配
|
|
||||||
| GPU | 服务 | 模型 |
|
|
||||||
|-----|------|------|
|
|
||||||
| GPU0 | Qwen3-TTS | 0.6B-Base (声音克隆) |
|
|
||||||
| GPU1 | LatentSync | 1.6 (唇形同步) |
|
|
||||||
|
|
||||||
### 存储
|
|
||||||
- 新增 Supabase bucket: `ref_audios`
|
|
||||||
- 路径格式: `{user_id}/{timestamp}_{filename}.wav`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 实现步骤
|
|
||||||
|
|
||||||
### 1. 后端:新建声音克隆服务
|
|
||||||
**文件**: `backend/app/services/voice_clone_service.py`
|
|
||||||
|
|
||||||
```python
|
|
||||||
class VoiceCloneService:
|
|
||||||
def __init__(self):
|
|
||||||
self.gpu_id = 0
|
|
||||||
self.model_path = "models/Qwen3-TTS/checkpoints/0.6B-Base"
|
|
||||||
self._model = None
|
|
||||||
self._lock = asyncio.Lock()
|
|
||||||
|
|
||||||
async def generate_audio(self, text, ref_audio_path, ref_text, output_path, language="Chinese"):
|
|
||||||
# 使用 Qwen3TTSModel.generate_voice_clone()
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 后端:新建参考音频 API
|
|
||||||
**文件**: `backend/app/api/ref_audios.py`
|
|
||||||
|
|
||||||
| 接口 | 方法 | 功能 |
|
|
||||||
|------|------|------|
|
|
||||||
| `/api/ref-audios` | POST | 上传参考音频 + ref_text |
|
|
||||||
| `/api/ref-audios` | GET | 列出用户的参考音频 |
|
|
||||||
| `/api/ref-audios/{id}` | DELETE | 删除参考音频 |
|
|
||||||
|
|
||||||
上传时自动转换为 wav (16kHz mono),存储 ref_text 元数据。
|
|
||||||
|
|
||||||
### 3. 后端:修改视频生成 API
|
|
||||||
**文件**: `backend/app/api/videos.py`
|
|
||||||
|
|
||||||
扩展 GenerateRequest:
|
|
||||||
```python
|
|
||||||
class GenerateRequest(BaseModel):
|
|
||||||
text: str
|
|
||||||
voice: str = "zh-CN-YunxiNeural"
|
|
||||||
material_path: str
|
|
||||||
# 新增
|
|
||||||
tts_mode: str = "edgetts" # "edgetts" | "voiceclone"
|
|
||||||
ref_audio_id: Optional[str] = None
|
|
||||||
ref_text: Optional[str] = None
|
|
||||||
```
|
|
||||||
|
|
||||||
修改 `_process_video_generation()`:
|
|
||||||
```python
|
|
||||||
if req.tts_mode == "voiceclone":
|
|
||||||
await voice_clone_service.generate_audio(...)
|
|
||||||
else:
|
|
||||||
await tts_service.generate_audio(...)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. 后端:注册路由
|
|
||||||
**文件**: `backend/app/main.py`
|
|
||||||
|
|
||||||
```python
|
|
||||||
from app.api import ref_audios
|
|
||||||
app.include_router(ref_audios.router, prefix="/api/ref-audios", tags=["ref-audios"])
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. 前端:改造音色选择区域
|
|
||||||
**文件**: `frontend/src/app/page.tsx`
|
|
||||||
|
|
||||||
**新增状态**:
|
|
||||||
```typescript
|
|
||||||
const [ttsMode, setTtsMode] = useState<'edgetts' | 'voiceclone'>('edgetts');
|
|
||||||
const [refAudios, setRefAudios] = useState<RefAudio[]>([]);
|
|
||||||
const [selectedRefAudio, setSelectedRefAudio] = useState<RefAudio | null>(null);
|
|
||||||
const [refText, setRefText] = useState('');
|
|
||||||
|
|
||||||
// 在线录音相关
|
|
||||||
const [isRecording, setIsRecording] = useState(false);
|
|
||||||
const [recordedBlob, setRecordedBlob] = useState<Blob | null>(null);
|
|
||||||
const [recordingTime, setRecordingTime] = useState(0);
|
|
||||||
const mediaRecorderRef = useRef<MediaRecorder | null>(null);
|
|
||||||
```
|
|
||||||
|
|
||||||
**UI 结构**:
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────┐
|
|
||||||
│ 🎙️ 选择配音方式 │
|
|
||||||
├─────────────────────────────────────┤
|
|
||||||
│ [EdgeTTS 音色] [声音克隆] ← Tab │
|
|
||||||
├─────────────────────────────────────┤
|
|
||||||
│ Tab 1: 现有音色 2x3 网格 │
|
|
||||||
│ │
|
|
||||||
│ Tab 2: 声音克隆 │
|
|
||||||
│ ┌───────────────────────────────┐ │
|
|
||||||
│ │ 📁 我的参考音频 │ │
|
|
||||||
│ │ [ref1] [ref2] [+上传] │ │
|
|
||||||
│ └───────────────────────────────┘ │
|
|
||||||
│ ┌───────────────────────────────┐ │
|
|
||||||
│ │ 🎤 或在线录音 │ │
|
|
||||||
│ │ [开始录音] [停止] 时长: 0:05 │ │
|
|
||||||
│ │ (录音完成后显示试听和使用按钮) │ │
|
|
||||||
│ └───────────────────────────────┘ │
|
|
||||||
│ ┌───────────────────────────────┐ │
|
|
||||||
│ │ 📝 参考音频文字 (必填) │ │
|
|
||||||
│ │ [textarea] │ │
|
|
||||||
│ └───────────────────────────────┘ │
|
|
||||||
└─────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
**在线录音逻辑**:
|
|
||||||
```typescript
|
|
||||||
const startRecording = async () => {
|
|
||||||
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
||||||
const mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/webm' });
|
|
||||||
const chunks: BlobPart[] = [];
|
|
||||||
|
|
||||||
mediaRecorder.ondataavailable = (e) => chunks.push(e.data);
|
|
||||||
mediaRecorder.onstop = () => {
|
|
||||||
const blob = new Blob(chunks, { type: 'audio/webm' });
|
|
||||||
setRecordedBlob(blob);
|
|
||||||
stream.getTracks().forEach(track => track.stop());
|
|
||||||
};
|
|
||||||
|
|
||||||
mediaRecorder.start();
|
|
||||||
setIsRecording(true);
|
|
||||||
mediaRecorderRef.current = mediaRecorder;
|
|
||||||
};
|
|
||||||
|
|
||||||
const stopRecording = () => {
|
|
||||||
mediaRecorderRef.current?.stop();
|
|
||||||
setIsRecording(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const useRecording = async () => {
|
|
||||||
// 将录音 Blob 上传到后端
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append('file', recordedBlob, 'recording.webm');
|
|
||||||
formData.append('ref_text', refText);
|
|
||||||
const { data } = await api.post('/api/ref-audios', formData);
|
|
||||||
// 上传成功后刷新列表并选中
|
|
||||||
fetchRefAudios();
|
|
||||||
setSelectedRefAudio(data);
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### 6. 前端:修改生成请求
|
|
||||||
```typescript
|
|
||||||
const handleGenerate = async () => {
|
|
||||||
const payload = {
|
|
||||||
material_path: materialObj.path,
|
|
||||||
text: text,
|
|
||||||
tts_mode: ttsMode,
|
|
||||||
...(ttsMode === 'edgetts'
|
|
||||||
? { voice }
|
|
||||||
: { ref_audio_id: selectedRefAudio.id, ref_text: refText })
|
|
||||||
};
|
|
||||||
await api.post('/api/videos/generate', payload);
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 文件清单
|
|
||||||
|
|
||||||
### 新建
|
|
||||||
| 文件 | 描述 |
|
|
||||||
|------|------|
|
|
||||||
| `backend/app/services/voice_clone_service.py` | 声音克隆服务 |
|
|
||||||
| `backend/app/api/ref_audios.py` | 参考音频管理 API |
|
|
||||||
|
|
||||||
### 修改
|
|
||||||
| 文件 | 修改内容 |
|
|
||||||
|------|----------|
|
|
||||||
| `backend/app/api/videos.py` | 扩展 GenerateRequest,修改 TTS 调用逻辑 |
|
|
||||||
| `backend/app/main.py` | 注册 ref_audios 路由 |
|
|
||||||
| `backend/app/services/storage.py` | 添加 BUCKET_REF_AUDIOS |
|
|
||||||
| `frontend/src/app/page.tsx` | Tab 切换 UI、参考音频选择、refText 输入 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 验证方法
|
|
||||||
|
|
||||||
1. **后端测试**:
|
|
||||||
```bash
|
|
||||||
# 启动后端
|
|
||||||
cd backend && uvicorn app.main:app --port 8006
|
|
||||||
|
|
||||||
# 测试参考音频上传
|
|
||||||
curl -X POST http://localhost:8006/api/ref-audios \
|
|
||||||
-F "file=@test.wav" -F "ref_text=测试文字"
|
|
||||||
|
|
||||||
# 测试声音克隆生成
|
|
||||||
curl -X POST http://localhost:8006/api/videos/generate \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{"text":"测试文案","tts_mode":"voiceclone","ref_audio_id":"xxx","ref_text":"参考文字","material_path":"..."}'
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **前端测试**:
|
|
||||||
- 打开首页,确认 Tab 切换正常
|
|
||||||
- 上传参考音频,确认列表显示
|
|
||||||
- 选择声音克隆模式,填写参考文字,点击生成
|
|
||||||
- 确认生成的视频使用克隆的声音
|
|
||||||
|
|
||||||
3. **端到端测试**:
|
|
||||||
- 上传参考音频 → 选择声音克隆 → 输入口播文案 → 生成视频 → 播放验证声音
|
|
||||||
@@ -1,422 +1,95 @@
|
|||||||
# ViGent 数字人口播系统 - 开发任务清单
|
# ViGent2 开发任务清单 (Task Log)
|
||||||
|
|
||||||
**项目**:ViGent2 数字人口播视频生成系统
|
**项目**: ViGent2 数字人口播视频生成系统
|
||||||
**服务器**:Dell R730 (2× RTX 3090 24GB)
|
**进度**: 100% (Day 16 - 深度优化完成)
|
||||||
**更新时间**:2026-02-02
|
**更新时间**: 2026-02-03
|
||||||
**整体进度**:100%(Day 15 手机号登录迁移 + 账户设置功能完成)
|
|
||||||
|
|
||||||
## 📖 快速导航
|
|
||||||
|
|
||||||
| 章节 | 说明 |
|
|
||||||
|------|------|
|
|
||||||
| [已完成任务](#-已完成任务) | Day 1-13 完成的功能 |
|
|
||||||
| [后续规划](#️-后续规划) | 待办项目 |
|
|
||||||
| [进度统计](#-进度统计) | 各模块完成度 |
|
|
||||||
| [里程碑](#-里程碑) | 关键节点 |
|
|
||||||
| [时间线](#-时间线) | 开发历程 |
|
|
||||||
|
|
||||||
**相关文档**:
|
|
||||||
- [Day 日志](file:///d:/CodingProjects/Antigravity/ViGent2/Docs/DevLogs/) (Day1-Day15)
|
|
||||||
- [部署指南](file:///d:/CodingProjects/Antigravity/ViGent2/Docs/DEPLOY_MANUAL.md)
|
|
||||||
- [Qwen3-TTS 部署](file:///d:/CodingProjects/Antigravity/ViGent2/Docs/QWEN3_TTS_DEPLOY.md)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ✅ 已完成任务
|
## 📅 对话历史与开发日志
|
||||||
|
|
||||||
### 阶段一:核心功能验证
|
> 这里记录了每一天的核心开发内容与 milestone。
|
||||||
- [x] EdgeTTS 配音集成
|
|
||||||
- [x] FFmpeg 视频合成
|
|
||||||
- [x] MuseTalk 唇形同步 (代码集成)
|
|
||||||
- [x] 端到端流程验证
|
|
||||||
|
|
||||||
### 阶段二:后端 API 开发
|
### Day 16: 深度性能优化 (Current) 🚀
|
||||||
- [x] FastAPI 项目搭建
|
- [x] **Qwen-TTS 加速**: 集成 Flash Attention 2,模型加载速度提升至 8.9s。
|
||||||
- [x] 视频生成 API
|
- [x] **服务守护**: 开发 `Watchdog` 看门狗机制,自动监控并重启僵死服务。
|
||||||
- [x] 素材管理 API
|
- [x] **LatentSync 性能确认**: 验证 DeepCache + 原生 Flash Attn 生效。
|
||||||
- [x] 文件存储管理
|
- [x] **文档重构**: 全面更新 README、部署手册及后端文档。
|
||||||
|
- [x] **UI 交互优化**: 选择项持久化、列表内定位、刷新回顶部。
|
||||||
|
- [x] **样式与预览**: 标题/字幕样式选择 + 预览 + 字号调节。
|
||||||
|
- [x] **背景音乐**: 试听 + 音量控制 + 混音稳定性修复。
|
||||||
|
- [x] **资产库接入**: 字体/BGM 资源库 + `/api/assets` 资源接口。
|
||||||
|
|
||||||
### 阶段三:前端 Web UI
|
### Day 15: 手机号认证迁移
|
||||||
- [x] Next.js 项目初始化
|
- [x] **认证系统升级**: 从邮箱迁移至 11 位手机号注册/登录。
|
||||||
- [x] 视频生成页面
|
- [x] **账户管理**: 新增修改密码、有效期显示、安全退出功能。
|
||||||
- [x] 发布管理页面
|
- [x] **AI 文案助手**: 升级 GLM-4.7-Flash,支持 B站/抖音链接提取与洗稿。
|
||||||
- [x] 任务状态展示
|
|
||||||
|
|
||||||
### 阶段四:社交媒体发布
|
### Day 14: AI 增强与体验优化
|
||||||
- [x] Playwright 自动化框架
|
- [x] **AI 标题/标签**: 集成 GLM-4API 自动生成视频元数据。
|
||||||
- [x] Cookie 管理功能
|
- [x] **字幕升级**: Remotion 逐字高亮字幕 (卡拉OK效果) 及动画片头。
|
||||||
- [x] 多平台发布 UI
|
- [x] **模型升级**: Qwen3-TTS 升级至 1.7B-Base 版本。
|
||||||
- [x] 定时发布功能 (Day 7)
|
|
||||||
- [x] QR码自动登录 (Day 7)
|
|
||||||
|
|
||||||
### 阶段五:部署与文档
|
### Day 13: 声音克隆集成
|
||||||
- [x] 手动部署指南 (DEPLOY_MANUAL.md)
|
- [x] **声音克隆微服务**: 封装 Qwen3-TTS 为独立 API (8009端口)。
|
||||||
- [x] 一键部署脚本 (deploy.sh)
|
- [x] **参考音频管理**: Supabase 存储桶配置与管理接口。
|
||||||
- [x] 环境配置模板 (.env.example)
|
- [x] **多模态 TTS**: 前端支持 EdgeTTS / Clone Voice 切换。
|
||||||
- [x] 项目文档 (README.md)
|
|
||||||
- [x] 端口配置 (8006/3002)
|
|
||||||
|
|
||||||
### 阶段六:MuseTalk 服务器部署 (Day 2-3)
|
### Day 12: 移动端适配
|
||||||
- [x] conda 环境配置 (musetalk)
|
- [x] **iOS 兼容**: 修复 Safari 安全区域、状态栏颜色、Cookie 拦截问题。
|
||||||
- [x] 模型权重下载 (~7GB)
|
- [x] **响应式 UI**: 移动端 Header 与发布页重构。
|
||||||
- [x] subprocess 调用方式实现
|
|
||||||
- [x] 健康检查功能
|
|
||||||
- [x] 实际推理调用验证 (Day 3 修复)
|
|
||||||
|
|
||||||
### 阶段七:MuseTalk 完整修复 (Day 4)
|
### Day 11: 上传架构重构
|
||||||
- [x] 权重检测路径修复 (软链接)
|
- [x] **直传优化**: 前端直传 Supabase Storage,解决 Nginx 30s 超时问题。
|
||||||
- [x] 音视频长度不匹配修复 (audio_processor.py)
|
- [x] **数据隔离**: 用户素材/视频按 UserID 物理隔离。
|
||||||
- [x] 推理脚本错误日志增强 (inference.py)
|
|
||||||
- [x] 视频合成 MP4 生成验证
|
|
||||||
- [x] 端到端流程完整测试
|
|
||||||
|
|
||||||
### 阶段八:前端功能增强 (Day 5)
|
### Day 10: HTTPS 与安全
|
||||||
- [x] Web 视频上传功能
|
- [x] **HTTPS 部署**: 配置 SSL 证书与 Nginx 反向代理。
|
||||||
- [x] 上传进度显示
|
- [x] **安全加固**: Supabase Studio 增加 Basic Auth 保护。
|
||||||
- [x] 自动刷新素材列表
|
|
||||||
|
|
||||||
### 阶段九:唇形同步模型升级 (Day 6)
|
### Day 9: 认证系统与发布闭环
|
||||||
- [x] MuseTalk → LatentSync 1.6 迁移
|
- [x] **用户系统**: 基于 Supabase Auth 实现 JWT 认证。
|
||||||
- [x] 后端代码适配 (config.py, lipsync_service.py)
|
- [x] **发布闭环**: 验证 B站/抖音/小红书 自动发布流程。
|
||||||
- [x] Conda 环境配置 (latentsync)
|
- [x] **服务自愈**: 配置 PM2 进程守护。
|
||||||
- [x] 模型权重部署指南
|
|
||||||
- [x] 服务器端到端验证
|
|
||||||
|
|
||||||
### 阶段十:性能优化 (Day 6)
|
### Day 1-8: 核心功能构建
|
||||||
- [x] 视频预压缩优化 (高分辨率自动压缩到720p)
|
- [x] **Day 8**: 历史记录持久化与文件管理。
|
||||||
- [x] 进度更新细化 (5% → 10% → 25% → ... → 100%)
|
- [x] **Day 7**: 社交媒体自动登录与多平台发布。
|
||||||
- [x] LipSync 服务单例缓存
|
- [x] **Day 6**: **LatentSync 1.6** 升级与服务器部署。
|
||||||
- [x] 健康检查缓存 (5分钟)
|
- [x] **Day 5**: 前端视频上传与进度反馈。
|
||||||
- [x] 异步子进程修复 (subprocess.run → asyncio)
|
- [x] **Day 4**: MuseTalk (旧版) 口型同步修复。
|
||||||
- [x] 预加载模型服务 (常驻 Server + FastAPI)
|
- [x] **Day 3**: 服务器环境配置与模型权重下载。
|
||||||
- [x] 批量队列处理 (GPU 并发控制)
|
- [x] **Day 1-2**: 项目基础框架 (FastAPI + Next.js) 搭建。
|
||||||
|
|
||||||
### 阶段十一:社交媒体发布完善 (Day 7)
|
|
||||||
- [x] QR码自动登录 (Playwright headless)
|
|
||||||
- [x] 多平台上传器架构 (B站/抖音/小红书)
|
|
||||||
- [x] B站发布 (biliup官方库)
|
|
||||||
- [x] 抖音/小红书发布 (Playwright)
|
|
||||||
- [x] 定时发布功能
|
|
||||||
- [x] 前端发布UI优化
|
|
||||||
- [x] Cookie自动管理
|
|
||||||
- [x] UI一致性修复 (导航栏对齐、滚动条隐藏)
|
|
||||||
- [x] QR登录超时修复 (Stealth模式、多选择器fallback)
|
|
||||||
- [x] 文档规则优化 (智能修改标准、工具使用规范)
|
|
||||||
|
|
||||||
### 阶段十二:用户体验优化 (Day 8)
|
|
||||||
- [x] 文件名保留 (时间戳前缀 + 原始名称)
|
|
||||||
- [x] 视频持久化 (从文件系统读取历史)
|
|
||||||
- [x] 历史视频列表组件
|
|
||||||
- [x] 素材/视频删除功能
|
|
||||||
- [x] 登出功能 (Logout API + 前端按钮)
|
|
||||||
- [x] 前端 SWR 轮询优化
|
|
||||||
- [x] QR 登录状态检测修复
|
|
||||||
|
|
||||||
### 阶段十三:发布模块优化 (Day 9)
|
|
||||||
- [x] B站/抖音发布验证通过
|
|
||||||
- [x] 资源清理保障 (try-finally)
|
|
||||||
- [x] 超时保护 (消除无限循环)
|
|
||||||
- [x] 小红书 headless 模式修复
|
|
||||||
- [x] API 输入验证
|
|
||||||
- [x] 完整类型提示
|
|
||||||
- [x] 扫码登录等待界面 (加载动画)
|
|
||||||
- [x] 抖音/B站登录策略优化 (Text优先)
|
|
||||||
- [x] 发布成功审核提示
|
|
||||||
|
|
||||||
### 阶段十四:用户认证系统 (Day 9)
|
|
||||||
- [x] Supabase 数据库表设计与部署
|
|
||||||
- [x] JWT 认证 (HttpOnly Cookie)
|
|
||||||
- [x] 用户注册/登录/登出 API
|
|
||||||
- [x] 管理员权限控制 (is_active)
|
|
||||||
- [x] 单设备登录限制 (Session Token)
|
|
||||||
- [x] 防止 Supabase 暂停 (GitHub Actions/Crontab)
|
|
||||||
- [x] 认证部署文档 (AUTH_DEPLOY.md)
|
|
||||||
|
|
||||||
### 阶段十五:部署稳定性优化 (Day 9)
|
|
||||||
- [x] 后端依赖修复 (bcrypt/email-validator)
|
|
||||||
- [x] 前端生产环境构建修复 (npm run build)
|
|
||||||
- [x] LatentSync 性能卡顿修复 (OMP_NUM_THREADS限制)
|
|
||||||
- [x] 部署服务自愈 (PM2 配置优化)
|
|
||||||
- [x] 部署手册全量更新 (DEPLOY_MANUAL.md)
|
|
||||||
|
|
||||||
### 阶段十六:HTTPS 部署与细节完善 (Day 10)
|
|
||||||
- [x] 隧道访问修复 (StaticFiles 挂载 + Rewrite)
|
|
||||||
- [x] 平台账号列表 500 错误修复 (paths.py)
|
|
||||||
- [x] Nginx HTTPS 配置 (反向代理 + SSL)
|
|
||||||
- [x] 浏览器标题修改 (ViGent)
|
|
||||||
- [x] 代码自适应 HTTPS 验证
|
|
||||||
- [x] **Supabase 自托管部署** (Docker, 3003/8008端口)
|
|
||||||
- [x] **安全加固** (Basic Auth 保护后台)
|
|
||||||
- [x] **端口冲突解决** (迁移 Analytics/Kong)
|
|
||||||
|
|
||||||
### 阶段十七:上传架构重构 (Day 11)
|
|
||||||
- [x] **直传改造** (前端直接上传 Supabase,绕过后端代理)
|
|
||||||
- [x] **后端适配** (Signed URL 签名生成)
|
|
||||||
- [x] **RLS 策略部署** (SQL 脚本自动化权限配置)
|
|
||||||
- [x] **超时问题根治** (彻底解决 Nginx/FRP 30s 限制)
|
|
||||||
- [x] **前端依赖更新** (@supabase/supabase-js 集成)
|
|
||||||
|
|
||||||
### 阶段十八:用户隔离与存储优化 (Day 11)
|
|
||||||
- [x] **用户数据隔离** (素材/视频/Cookie 按用户ID目录隔离)
|
|
||||||
- [x] **Storage URL 修复** (SUPABASE_PUBLIC_URL 配置,修复 localhost 问题)
|
|
||||||
- [x] **发布服务优化** (直接读取本地 Supabase Storage 文件,跳过 HTTP 下载)
|
|
||||||
- [x] **Supabase Studio 配置** (公网访问配置)
|
|
||||||
|
|
||||||
### 阶段十九:iOS 兼容与移动端 UI 优化 (Day 12)
|
|
||||||
- [x] **Axios 全局拦截器** (401/403 自动跳转登录,防重复跳转)
|
|
||||||
- [x] **iOS Safari 安全区域修复** (viewport-fit: cover, themeColor, 渐变背景统一)
|
|
||||||
- [x] **移动端 Header 优化** (按钮紧凑布局,响应式间距)
|
|
||||||
- [x] **发布页面 UI 重构** (立即发布/定时发布按钮分离,防误触设计)
|
|
||||||
- [x] **Qwen3-TTS 1.7B 部署** (声音克隆模型,GPU0,更高质量)
|
|
||||||
|
|
||||||
### 阶段二十:声音克隆功能集成 (Day 13)
|
|
||||||
- [x] **Qwen3-TTS HTTP 服务** (独立 FastAPI 服务,端口 8009)
|
|
||||||
- [x] **声音克隆服务** (voice_clone_service.py,HTTP 调用封装)
|
|
||||||
- [x] **参考音频管理 API** (上传/列表/删除)
|
|
||||||
- [x] **前端 TTS 模式选择** (EdgeTTS / 声音克隆切换)
|
|
||||||
- [x] **Supabase ref-audios Bucket** (参考音频存储桶 + RLS 策略)
|
|
||||||
- [x] **端到端测试验证** (声音克隆完整流程测试通过)
|
|
||||||
|
|
||||||
### 阶段二十一:逐字高亮字幕 + 片头标题 (Day 13)
|
|
||||||
- [x] **faster-whisper 字幕对齐** (字级别时间戳生成)
|
|
||||||
- [x] **Remotion 视频渲染** (React 视频合成框架)
|
|
||||||
- [x] **逐字高亮字幕** (卡拉OK效果)
|
|
||||||
- [x] **片头标题** (淡入淡出动画)
|
|
||||||
- [x] **前端标题/字幕设置 UI**
|
|
||||||
- [x] **降级机制** (Remotion 失败时回退 FFmpeg)
|
|
||||||
|
|
||||||
### 阶段二十二:AI 标题标签 + 前端稳定性修复 (Day 14)
|
|
||||||
- [x] **Qwen3-TTS 1.7B 模型升级** (0.6B → 1.7B-Base)
|
|
||||||
- [x] **字幕样式与标题动画优化** (Remotion 视觉增强)
|
|
||||||
- [x] **AI 标题/标签生成** (GLM-4-Flash API)
|
|
||||||
- [x] **生成结果同步到发布页** (localStorage 对齐)
|
|
||||||
- [x] **文案/标题本地保存修复** (刷新后恢复)
|
|
||||||
- [x] **登录页刷新循环修复** (公开路由跳转豁免)
|
|
||||||
|
|
||||||
### 阶段二十三:手机号登录迁移 (Day 15)
|
|
||||||
- [x] **认证迁移** (邮箱 → 11位手机号)
|
|
||||||
- [x] **后端 API 适配** (auth.py/admin.py 手机号验证)
|
|
||||||
- [x] **修改密码功能** (/api/auth/change-password 接口)
|
|
||||||
- [x] **账户设置菜单** (首页下拉菜单:修改密码 + 有效期显示 + 退出登录)
|
|
||||||
- [x] **有效期显示** (expires_at 字段显示在账户菜单)
|
|
||||||
- [x] **点击外部关闭菜单** (useRef + useEffect 监听)
|
|
||||||
- [x] **前端页面更新** (登录/注册/管理员页面)
|
|
||||||
- [x] **数据库迁移脚本** (migrate_to_phone.sql)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🛤️ 后续规划
|
## 🛤️ 后续规划 (Roadmap)
|
||||||
|
|
||||||
### 🔴 优先待办
|
### 🔴 优先待办
|
||||||
- [ ] 批量视频生成架构设计
|
- [ ] **批量生成架构**: 支持 Excel 导入,批量生产视频。
|
||||||
|
- [ ] **定时任务后台化**: 迁移前端触发的定时发布到后端 APScheduler。
|
||||||
### 🟠 功能完善
|
|
||||||
- [x] Qwen3-TTS 集成到 ViGent2 ✅ Day 13 完成
|
|
||||||
- [x] 定时发布功能 ✅ Day 7 完成
|
|
||||||
- [x] 逐字高亮字幕 ✅ Day 13 完成
|
|
||||||
- [ ] **后端定时发布** - 替代平台端定时,使用 APScheduler 实现任务调度
|
|
||||||
- [ ] 批量视频生成
|
|
||||||
- [ ] 字幕样式编辑器
|
|
||||||
|
|
||||||
### 🔵 长期探索
|
### 🔵 长期探索
|
||||||
- [ ] Docker 容器化
|
- [ ] **容器化交付**: 提供完整的 Docker Compose 一键部署包。
|
||||||
- [ ] Celery 分布式任务队列
|
- [ ] **分布式队列**: 引入 Celery + Redis 处理超高并发任务。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📊 进度统计
|
## 📊 模块完成度
|
||||||
|
|
||||||
### 总体进度
|
|
||||||
```
|
|
||||||
████████████████████ 100%
|
|
||||||
```
|
|
||||||
|
|
||||||
### 各模块进度
|
|
||||||
|
|
||||||
| 模块 | 进度 | 状态 |
|
| 模块 | 进度 | 状态 |
|
||||||
|------|------|------|
|
|------|------|------|
|
||||||
| 后端 API | 100% | ✅ 完成 |
|
| **核心 API** | 100% | ✅ 稳定 |
|
||||||
| 前端 UI | 100% | ✅ 完成 |
|
| **Web UI** | 100% | ✅ 稳定 (移动端适配) |
|
||||||
| TTS 配音 | 100% | ✅ 完成 |
|
| **唇形同步** | 100% | ✅ LatentSync 1.6 |
|
||||||
| 视频合成 | 100% | ✅ 完成 |
|
| **TTS 配音** | 100% | ✅ EdgeTTS + Qwen3 |
|
||||||
| 唇形同步 | 100% | ✅ LatentSync 1.6 升级完成 |
|
| **自动发布** | 100% | ✅ B站/抖音/小红书 |
|
||||||
| 社交发布 | 100% | ✅ Day 9 验证通过 |
|
| **用户认证** | 100% | ✅ 手机号 + JWT |
|
||||||
| 用户认证 | 100% | ✅ Day 9 Supabase+JWT |
|
| **部署运维** | 100% | ✅ PM2 + Watchdog |
|
||||||
| 服务器部署 | 100% | ✅ Day 9 稳定性优化完成 |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🎯 里程碑
|
## 📎 相关文档
|
||||||
|
|
||||||
### Milestone 1: 项目框架搭建 ✅
|
|
||||||
**完成时间**: Day 1
|
|
||||||
**成果**:
|
|
||||||
- FastAPI 后端 + Next.js 前端
|
|
||||||
- EdgeTTS + FFmpeg 集成
|
|
||||||
- 视频生成端到端验证
|
|
||||||
|
|
||||||
### Milestone 2: 服务器部署 ✅
|
|
||||||
**完成时间**: Day 3
|
|
||||||
**成果**:
|
|
||||||
- PyTorch 2.0.1 + MMLab 环境修复
|
|
||||||
- 模型目录重组与权重补全
|
|
||||||
- MuseTalk 推理成功运行
|
|
||||||
|
|
||||||
### Milestone 3: 口型同步完整修复 ✅
|
|
||||||
**完成时间**: Day 4
|
|
||||||
**成果**:
|
|
||||||
- 权重检测路径修复 (软链接)
|
|
||||||
- 音视频长度不匹配修复
|
|
||||||
- 视频合成 MP4 验证通过 (28MB → 3.8MB)
|
|
||||||
|
|
||||||
### Milestone 4: LatentSync 1.6 升级 ✅
|
|
||||||
**完成时间**: Day 6
|
|
||||||
**成果**:
|
|
||||||
- MuseTalk → LatentSync 1.6 迁移
|
|
||||||
- 512×512 高分辨率唇形同步
|
|
||||||
- Latent Diffusion 架构升级
|
|
||||||
- 性能优化 (视频预压缩、进度更新)
|
|
||||||
|
|
||||||
### Milestone 5: 用户认证系统 ✅
|
|
||||||
**完成时间**: Day 9
|
|
||||||
**成果**:
|
|
||||||
- Supabase 云数据库集成
|
|
||||||
- 安全的 JWT + HttpOnly Cookie 认证
|
|
||||||
- 管理员后台与用户隔离
|
|
||||||
- 完善的部署与保活方案
|
|
||||||
|
|
||||||
### Milestone 6: 生产环境部署稳定化 ✅
|
|
||||||
**完成时间**: Day 9
|
|
||||||
**成果**:
|
|
||||||
- 修复了后端 (bcrypt) 和前端 (build) 的启动崩溃问题
|
|
||||||
- 解决了 LatentSync 占用全量 CPU 导致服务器卡顿的严重问题
|
|
||||||
- 完善了部署手册,记录了关键的 Troubleshooting 步骤
|
|
||||||
- 实现了服务 Long-term 稳定运行 (Reset PM2 counter)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📅 时间线
|
|
||||||
|
|
||||||
Day 1: 项目初始化 + 核心功能 ✅ 完成
|
|
||||||
- 后端 API 框架
|
|
||||||
- 前端 UI
|
|
||||||
- TTS + 视频合成
|
|
||||||
- 社交发布框架
|
|
||||||
- 部署文档
|
|
||||||
|
|
||||||
Day 2: 服务器部署 + MuseTalk ✅ 完成
|
|
||||||
- 端口配置 (8006/3002)
|
|
||||||
- MuseTalk conda 环境初始化
|
|
||||||
- subprocess 调用实现
|
|
||||||
- 健康检查验证
|
|
||||||
|
|
||||||
Day 3: 环境修复与验证 ✅ 完成
|
|
||||||
- PyTorch 降级 (2.5 -> 2.0.1)
|
|
||||||
- MMLab 依赖全量安装
|
|
||||||
- 模型权重补全 (dwpose, syncnet)
|
|
||||||
- 目录结构修复 (symlinks)
|
|
||||||
- 推理脚本验证 (生成593帧)
|
|
||||||
|
|
||||||
Day 4: 口型同步完整修复 ✅ 完成
|
|
||||||
- 权重检测路径修复 (软链接)
|
|
||||||
- audio_processor.py 音视频长度修复
|
|
||||||
- inference.py 错误日志增强
|
|
||||||
- MP4 视频合成验证通过
|
|
||||||
|
|
||||||
Day 5: 前端功能增强 ✅ 完成
|
|
||||||
- Web 视频上传功能
|
|
||||||
- 上传进度显示
|
|
||||||
- 自动刷新素材列表
|
|
||||||
|
|
||||||
Day 6: LatentSync 1.6 升级 ✅ 完成
|
|
||||||
- MuseTalk → LatentSync 迁移
|
|
||||||
- 后端代码适配
|
|
||||||
- 模型部署指南
|
|
||||||
- 服务器部署验证
|
|
||||||
- 性能优化 (视频预压缩、进度更新)
|
|
||||||
|
|
||||||
Day 7: 社交媒体发布完善 ✅ 完成
|
|
||||||
- QR码自动登录 (B站/抖音验证通过)
|
|
||||||
- 智能定位策略 (CSS/Text并行)
|
|
||||||
- 多平台发布 (B站/抖音/小红书)
|
|
||||||
- UI 一致性优化
|
|
||||||
- 文档规则体系优化
|
|
||||||
|
|
||||||
Day 8: 用户体验优化 ✅ 完成
|
|
||||||
- 文件名保留 (时间戳前缀)
|
|
||||||
- 视频持久化 (历史视频API)
|
|
||||||
- 历史视频列表组件
|
|
||||||
- 素材/视频删除功能
|
|
||||||
|
|
||||||
Day 9: 发布模块优化 ✅ 完成
|
|
||||||
- B站/抖音登录+发布验证通过
|
|
||||||
- 资源清理保障 (try-finally)
|
|
||||||
- 超时保护 (消除无限循环)
|
|
||||||
- 小红书 headless 模式修复
|
|
||||||
- 扫码登录等待界面 (加载动画)
|
|
||||||
- 抖音/B站登录策略优化 (Text优先)
|
|
||||||
- 发布成功审核提示
|
|
||||||
- 用户认证系统规划 (FastAPI+Supabase)
|
|
||||||
- Supabase 表结构设计 (users/sessions)
|
|
||||||
- 后端 JWT 认证实现 (auth.py/deps.py)
|
|
||||||
- 数据库配置与 SQL 部署
|
|
||||||
- 独立认证部署文档 (AUTH_DEPLOY.md)
|
|
||||||
- 自动保活机制 (Crontab/Actions)
|
|
||||||
- 部署稳定性优化 (Backend依赖修复)
|
|
||||||
- 前端生产构建流程修复
|
|
||||||
- LatentSync 严重卡顿修复 (线程数限制)
|
|
||||||
- 部署手册全量更新
|
|
||||||
|
|
||||||
Day 10: HTTPS 部署与细节完善 ✅ 完成
|
|
||||||
- 隧道访问视频修正 (挂载 uploads)
|
|
||||||
- 账号列表 Bug 修复 (paths.py 白名单)
|
|
||||||
- 阿里云 Nginx HTTPS 部署
|
|
||||||
- UI 细节优化 (Title 更新)
|
|
||||||
|
|
||||||
Day 11: 上传架构重构 ✅ 完成
|
|
||||||
- **核心修复**: Aliyun Nginx `client_max_body_size 0` 配置
|
|
||||||
- 500 错误根治 (Direct Upload + Gateway Config)
|
|
||||||
- Supabase RLS 权限策略部署
|
|
||||||
- 前端集成 supabase-js
|
|
||||||
- 彻底解决大文件上传超时 (30s 限制)
|
|
||||||
- **用户数据隔离** (素材/视频/Cookie 按用户目录存储)
|
|
||||||
- **Storage URL 修复** (SUPABASE_PUBLIC_URL 公网地址配置)
|
|
||||||
- **发布服务优化** (本地文件直读,跳过 HTTP 下载)
|
|
||||||
|
|
||||||
Day 12: iOS 兼容与移动端优化 ✅ 完成
|
|
||||||
- Axios 全局拦截器 (401/403 自动跳转登录)
|
|
||||||
- iOS Safari 安全区域白边修复 (viewport-fit: cover)
|
|
||||||
- themeColor 配置 (状态栏颜色适配)
|
|
||||||
- 渐变背景统一 (body 全局渐变,消除分层)
|
|
||||||
- 移动端 Header 响应式优化 (按钮紧凑布局)
|
|
||||||
- 发布页面 UI 重构 (立即发布 3/4 + 定时 1/4)
|
|
||||||
- **Qwen3-TTS 1.7B 部署** (声音克隆模型,GPU0)
|
|
||||||
- **部署文档** (QWEN3_TTS_DEPLOY.md)
|
|
||||||
|
|
||||||
Day 13: 声音克隆 + 字幕功能 ✅ 完成
|
|
||||||
- Qwen3-TTS HTTP 服务 (独立 FastAPI,端口 8009)
|
|
||||||
- 声音克隆服务 (voice_clone_service.py)
|
|
||||||
- 参考音频管理 API (上传/列表/删除)
|
|
||||||
- 前端 TTS 模式选择 (EdgeTTS / 声音克隆)
|
|
||||||
- Supabase ref-audios Bucket 配置
|
|
||||||
- 端到端测试验证通过
|
|
||||||
- **faster-whisper 字幕对齐** (字级别时间戳)
|
|
||||||
- **Remotion 视频渲染** (逐字高亮字幕 + 片头标题)
|
|
||||||
- **前端标题/字幕设置 UI**
|
|
||||||
- **部署文档** (SUBTITLE_DEPLOY.md)
|
|
||||||
|
|
||||||
Day 14: 模型升级 + AI 标题标签 + 前端修复 ✅ 完成
|
|
||||||
- Qwen3-TTS 1.7B 模型升级 (0.6B → 1.7B-Base)
|
|
||||||
- 字幕样式与标题动画优化 (Remotion)
|
|
||||||
- AI 标题/标签生成接口 + 前端同步
|
|
||||||
- 文案/标题本地保存修复 (刷新后恢复)
|
|
||||||
- 登录页刷新循环修复 (公开路由跳转豁免)
|
|
||||||
|
|
||||||
Day 15: 手机号登录迁移 + 账户设置 ✅ 完成
|
|
||||||
- **认证系统迁移** (邮箱 → 11位手机号)
|
|
||||||
- **账户设置** (修改密码 + 退出登录 + 有效期显示)
|
|
||||||
- **GLM-4.7 模型升级** (文案洗稿效果提升)
|
|
||||||
- **文案提取助手** (支持 B站/抖音/URL 提取 + 自动洗稿)
|
|
||||||
- **视频预览功能** (素材列表预览 + 交互优化)
|
|
||||||
- **前端交互优化** (滚动条美化、弹窗误触修复)
|
|
||||||
|
|
||||||
|
- [详细开发日志 (DevLogs)](file:///d:/CodingProjects/Antigravity/ViGent2/Docs/DevLogs/)
|
||||||
|
- [部署手册 (DEPLOY_MANUAL)](file:///d:/CodingProjects/Antigravity/ViGent2/Docs/DEPLOY_MANUAL.md)
|
||||||
|
|||||||
227
README.md
227
README.md
@@ -1,44 +1,64 @@
|
|||||||
# ViGent2 - 数字人口播视频生成系统
|
# ViGent2 - 数字人口播视频生成系统
|
||||||
|
|
||||||
基于 **LatentSync 1.6 + EdgeTTS** 的开源数字人口播视频生成系统。
|
<div align="center">
|
||||||
|
|
||||||
> 📹 上传静态人物视频 → 🎙️ 输入口播文案 → 🎬 自动生成唇形同步视频
|
> 📹 **上传人物** · 🎙️ **输入文案** · 🎬 **一键成片**
|
||||||
|
|
||||||
|
基于 **LatentSync 1.6 + EdgeTTS** 的开源数字人口播视频生成系统。
|
||||||
|
集成 **Qwen3-TTS** 声音克隆与自动社交媒体发布功能。
|
||||||
|
|
||||||
|
[功能特性](#-功能特性) • [技术栈](#-技术栈) • [文档中心](#-文档中心) • [部署指南](Docs/DEPLOY_MANUAL.md)
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ✨ 功能特性
|
## ✨ 功能特性
|
||||||
|
|
||||||
- 🎬 **唇形同步** - LatentSync 1.6 驱动,512×512 高分辨率 Diffusion 模型
|
### 核心能力
|
||||||
- 🎙️ **TTS 配音** - EdgeTTS 多音色支持(云溪、晓晓等)
|
- 🎬 **高清唇形同步** - LatentSync 1.6 驱动,512×512 高分辨率 Latent Diffusion 模型。
|
||||||
- 🔊 **声音克隆** - Qwen3-TTS 1.7B,3秒参考音频快速克隆(更高质量)
|
- 🎙️ **多模态配音** - 支持 **EdgeTTS** (微软超自然语音) 和 **Qwen3-TTS** (3秒极速声音克隆)。
|
||||||
- 📝 **逐字高亮字幕** - faster-whisper + Remotion,卡拉OK效果 🆕
|
- 📝 **智能字幕** - 集成 faster-whisper + Remotion,自动生成逐字高亮 (卡拉OK效果) 字幕。
|
||||||
- 🎬 **片头标题** - 淡入淡出动画,可自定义 🆕
|
- 🎨 **样式预设** - 标题/字幕样式选择 + 预览 + 字号调节,支持自定义字体库。
|
||||||
- 🤖 **AI 标题/标签生成** - GLM-4.7-Flash 自动生成标题与标签 (升级版) 🆕
|
- 🎵 **背景音乐** - 试听 + 音量控制 + 混音,保持配音音量稳定。
|
||||||
- 📜 **文案提取助手** - 支持 B站/抖音/TikTok 视频链接提取与 AI 洗稿 🆕
|
- 🤖 **AI 辅助创作** - 内置 GLM-4.7-Flash,支持 B站/抖音链接文案提取、AI 洗稿、标题/标签自动生成。
|
||||||
- 📽️ **上传视频预览** - 素材列表支持直接预览播放 🆕
|
|
||||||
- 📱 **全自动发布** - 扫码登录 + Cookie持久化,支持多平台(B站/抖音/小红书)定时发布
|
### 平台化功能
|
||||||
- 🖥️ **Web UI** - Next.js 现代化界面,iOS/Android 移动端适配
|
- 📱 **全自动发布** - 支持 B站、抖音、小红书定时发布,扫码登录 + Cookie 持久化。
|
||||||
- 🔐 **用户系统** - Supabase + JWT 认证,**手机号登录** + 管理员后台 🆕
|
- 🔐 **企业级认证** - 完善的用户隔离系统 (Supabase),支持手机号注册/登录、密码管理。
|
||||||
- ⚙️ **账户设置** - 修改密码 + 有效期显示 + 安全退出 🆕
|
- 🛡️ **服务守护** - 内置 Watchdog 看门狗机制,自动监控并重启僵死服务,确保 7x24h 稳定运行。
|
||||||
- 👥 **多用户隔离** - 素材/视频/Cookie 按用户独立存储,数据完全隔离
|
- 🚀 **极致性能** - 视频预压缩、模型常驻服务 (0s加载)、双 GPU 流水线并发。
|
||||||
- 🚀 **性能优化** - 视频预压缩、常驻模型服务 (0s加载)、本地文件直读、并发控制
|
|
||||||
- 🌐 **全局任务管理** - 跨页面任务状态同步,实时进度显示
|
---
|
||||||
|
|
||||||
## 🛠️ 技术栈
|
## 🛠️ 技术栈
|
||||||
|
|
||||||
| 模块 | 技术 |
|
| 领域 | 核心技术 | 说明 |
|
||||||
|------|------|
|
|------|----------|------|
|
||||||
| 前端 | Next.js 14 + TypeScript + TailwindCSS |
|
| **前端** | Next.js 14 | TypeScript, TailwindCSS, SWR |
|
||||||
| 后端 | FastAPI + Python 3.10 |
|
| **后端** | FastAPI | Python 3.10, AsyncIO, PM2 |
|
||||||
| 数据库 | **Supabase** (PostgreSQL) 自托管 Docker |
|
| **数据库** | Supabase | PostgreSQL, Storage (本地/S3), Auth |
|
||||||
| 存储 | **Supabase Storage** (本地文件系统) |
|
| **唇形同步** | LatentSync 1.6 | PyTorch 2.5, Diffusers, DeepCache |
|
||||||
| 认证 | **JWT** + HttpOnly Cookie |
|
| **声音克隆** | Qwen3-TTS | 1.7B 参数量,Flash Attention 2 加速 |
|
||||||
| 唇形同步 | **LatentSync 1.6** (Latent Diffusion, 512×512) |
|
| **自动化** | Playwright | 社交媒体无头浏览器自动化 |
|
||||||
| TTS | EdgeTTS |
|
| **部署** | Docker & PM2 | 混合部署架构 |
|
||||||
| 声音克隆 | **Qwen3-TTS 1.7B** |
|
|
||||||
| 字幕渲染 | **faster-whisper + Remotion** |
|
---
|
||||||
| 视频处理 | FFmpeg |
|
|
||||||
| 自动发布 | Playwright |
|
## 📖 文档中心
|
||||||
|
|
||||||
|
我们提供了详尽的开发与部署文档:
|
||||||
|
|
||||||
|
### 部署运维
|
||||||
|
- **[部署手册 (DEPLOY_MANUAL.md)](Docs/DEPLOY_MANUAL.md)** - 👈 **部署请看这里**!包含完整的环境搭建步骤。
|
||||||
|
- [参考音频服务部署 (QWEN3_TTS_DEPLOY.md)](Docs/QWEN3_TTS_DEPLOY.md) - 声音克隆模型部署指南。
|
||||||
|
- [LatentSync 部署指南](models/LatentSync/DEPLOY.md) - 唇形同步模型独立部署。
|
||||||
|
- [用户认证部署 (AUTH_DEPLOY.md)](Docs/AUTH_DEPLOY.md) - Supabase 与 Auth 系统配置。
|
||||||
|
|
||||||
|
### 开发文档
|
||||||
|
- [后端开发指南](Docs/BACKEND_README.md) - 接口规范与开发流程。
|
||||||
|
- [前端开发指南](Docs/FRONTEND_DEV.md) - UI 组件与页面规范。
|
||||||
|
- [开发日志 (DevLogs)](Docs/DevLogs/) - 每日开发进度与技术决策记录。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -46,140 +66,33 @@
|
|||||||
|
|
||||||
```
|
```
|
||||||
ViGent2/
|
ViGent2/
|
||||||
├── backend/ # FastAPI 后端
|
├── backend/ # FastAPI 后端服务
|
||||||
│ ├── app/
|
│ ├── app/ # 核心业务逻辑
|
||||||
│ │ ├── api/ # API 路由
|
│ ├── scripts/ # 运维脚本 (Watchdog 等)
|
||||||
│ │ ├── services/ # 核心服务 (TTS, LipSync, Video)
|
│ └── tests/ # 测试用例
|
||||||
│ │ └── core/ # 配置
|
├── frontend/ # Next.js 前端应用
|
||||||
│ ├── requirements.txt
|
├── models/ # AI 模型仓库
|
||||||
│ └── .env.example
|
│ ├── LatentSync/ # 唇形同步服务
|
||||||
├── frontend/ # Next.js 前端
|
│ └── Qwen3-TTS/ # 声音克隆服务
|
||||||
│ └── src/app/
|
└── Docs/ # 项目文档
|
||||||
├── models/ # AI 模型
|
|
||||||
│ └── LatentSync/ # 唇形同步模型
|
|
||||||
│ └── DEPLOY.md # LatentSync 部署指南
|
|
||||||
└── Docs/ # 文档
|
|
||||||
├── DEPLOY_MANUAL.md # 部署手册
|
|
||||||
├── AUTH_DEPLOY.md # 认证部署指南
|
|
||||||
├── task_complete.md
|
|
||||||
└── DevLogs/
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🚀 快速开始
|
## 🌐 服务架构
|
||||||
|
|
||||||
### 1. 克隆项目
|
系统采用微服务架构设计,各组件独立运行:
|
||||||
|
|
||||||
```bash
|
| 服务名称 | 端口 | 用途 |
|
||||||
git clone <仓库地址> /home/rongye/ProgramFiles/ViGent2
|
|----------|------|------|
|
||||||
cd /home/rongye/ProgramFiles/ViGent2
|
| **Web UI** | 3002 | 用户访问入口 (Next.js) |
|
||||||
```
|
| **Backend API** | 8006 | 核心业务接口 (FastAPI) |
|
||||||
|
| **LatentSync** | 8007 | 唇形同步推理服务 |
|
||||||
### 2. 安装后端
|
| **Qwen3-TTS** | 8009 | 声音克隆推理服务 |
|
||||||
|
| **Supabase** | 8008 | 数据库与认证网关 |
|
||||||
```bash
|
|
||||||
cd backend
|
|
||||||
python -m venv venv
|
|
||||||
source venv/bin/activate # Windows: venv\Scripts\activate
|
|
||||||
pip install -r requirements.txt
|
|
||||||
cp .env.example .env
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 安装前端
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd frontend
|
|
||||||
npm install
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. 安装 LatentSync (服务器)
|
|
||||||
|
|
||||||
详见 [models/LatentSync/DEPLOY.md](models/LatentSync/DEPLOY.md)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 创建独立 Conda 环境
|
|
||||||
conda create -n latentsync python=3.10.13
|
|
||||||
conda activate latentsync
|
|
||||||
|
|
||||||
# 安装依赖并下载权重
|
|
||||||
cd models/LatentSync
|
|
||||||
pip install -r requirements.txt
|
|
||||||
huggingface-cli download ByteDance/LatentSync-1.6 --local-dir checkpoints
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. 启动服务
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 终端 1: 后端 (端口 8006)
|
|
||||||
cd backend && source venv/bin/activate
|
|
||||||
uvicorn app.main:app --host 0.0.0.0 --port 8006
|
|
||||||
|
|
||||||
# 终端 2: 前端 (端口 3002)
|
|
||||||
cd frontend
|
|
||||||
npm run dev -- -p 3002
|
|
||||||
|
|
||||||
# 终端 3: LatentSync 服务 (端口 8007, 推荐启动)
|
|
||||||
cd models/LatentSync
|
|
||||||
nohup python -m scripts.server > server.log 2>&1 &
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🖥️ 服务器配置
|
## ⚖️ License
|
||||||
|
|
||||||
**目标服务器**: Dell PowerEdge R730
|
[MIT License](LICENSE) © 2026 ViGent Team
|
||||||
|
|
||||||
| 配置 | 规格 |
|
|
||||||
|------|------|
|
|
||||||
| CPU | 2× Intel Xeon E5-2680 v4 (56 线程) |
|
|
||||||
| 内存 | 192GB DDR4 |
|
|
||||||
| GPU | 2× NVIDIA RTX 3090 24GB |
|
|
||||||
| 存储 | 4.47TB |
|
|
||||||
|
|
||||||
**GPU 分配**:
|
|
||||||
- GPU 0: 其他服务
|
|
||||||
- GPU 1: **LatentSync** 唇形同步 (~18GB VRAM)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🌐 访问地址
|
|
||||||
|
|
||||||
| 服务 | 地址 | 说明 |
|
|
||||||
|------|------|------|
|
|
||||||
| **视频生成 (UI)** | `https://vigent.hbyrkj.top` | 用户访问入口 |
|
|
||||||
| **API 服务** | `http://<服务器IP>:8006` | 后端 Swagger |
|
|
||||||
| **认证管理 (Studio)** | `https://supabase.hbyrkj.top` | 需要 Basic Auth |
|
|
||||||
| **认证 API (Kong)** | `https://api.hbyrkj.top` | Supabase 接口 |
|
|
||||||
| **唇形同步服务** | `http://<服务器IP>:8007` | LatentSync |
|
|
||||||
| **声音克隆服务** | `http://<服务器IP>:8009` | Qwen3-TTS |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📖 文档
|
|
||||||
|
|
||||||
- [手动部署指南](Docs/DEPLOY_MANUAL.md)
|
|
||||||
- [Supabase 部署指南](Docs/SUPABASE_DEPLOY.md)
|
|
||||||
- [Qwen3-TTS 部署指南](Docs/QWEN3_TTS_DEPLOY.md)
|
|
||||||
- [字幕功能部署指南](Docs/SUBTITLE_DEPLOY.md)
|
|
||||||
- [LatentSync 部署指南](models/LatentSync/DEPLOY.md)
|
|
||||||
- [开发日志](Docs/DevLogs/)
|
|
||||||
- [Day 15 - 手机号登录 + 账户设置](Docs/DevLogs/Day15.md) 🆕
|
|
||||||
- [任务进度](Docs/task_complete.md)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🆚 与 ViGent 的区别
|
|
||||||
|
|
||||||
| 特性 | ViGent (v1) | ViGent2 |
|
|
||||||
|------|-------------|---------|
|
|
||||||
| 唇形同步模型 | MuseTalk v1.5 | **LatentSync 1.6** |
|
|
||||||
| 分辨率 | 256×256 | **512×512** |
|
|
||||||
| 架构 | GAN | **Latent Diffusion** |
|
|
||||||
| 视频预处理 | 无 | **自动压缩优化** |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📄 License
|
|
||||||
|
|
||||||
MIT
|
|
||||||
|
|||||||
22
backend/app/api/assets.py
Normal file
22
backend/app/api/assets.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
from fastapi import APIRouter, Depends
|
||||||
|
|
||||||
|
from app.core.deps import get_current_user
|
||||||
|
from app.services.assets_service import list_styles, list_bgm
|
||||||
|
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/subtitle-styles")
|
||||||
|
async def list_subtitle_styles(current_user: dict = Depends(get_current_user)):
|
||||||
|
return {"styles": list_styles("subtitle")}
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/title-styles")
|
||||||
|
async def list_title_styles(current_user: dict = Depends(get_current_user)):
|
||||||
|
return {"styles": list_styles("title")}
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/bgm")
|
||||||
|
async def list_bgm_items(current_user: dict = Depends(get_current_user)):
|
||||||
|
return {"bgm": list_bgm()}
|
||||||
@@ -127,7 +127,60 @@ async def upload_ref_audio(
|
|||||||
if duration > 60.0:
|
if duration > 60.0:
|
||||||
raise HTTPException(status_code=400, detail="音频时长过长,最多 60 秒")
|
raise HTTPException(status_code=400, detail="音频时长过长,最多 60 秒")
|
||||||
|
|
||||||
# 生成存储路径
|
|
||||||
|
# 3. 处理重名逻辑 (Friendly Display Name)
|
||||||
|
original_name = file.filename
|
||||||
|
|
||||||
|
# 获取用户现有的所有参考音频列表 (为了检查文件名冲突)
|
||||||
|
# 注意: 这种列表方式在文件极多时性能一般,但考虑到单用户参考音频数量有限,目前可行
|
||||||
|
existing_files = await storage_service.list_files(BUCKET_REF_AUDIOS, user_id)
|
||||||
|
existing_names = set()
|
||||||
|
|
||||||
|
# 预加载所有现有的 display name
|
||||||
|
# 这里需要并发请求 metadata 可能会慢,优化: 仅检查 metadata 文件并解析
|
||||||
|
# 简易方案: 仅在 metadata 中读取 original_filename
|
||||||
|
# 但 list_files 返回的是 name,我们需要 metadata
|
||||||
|
# 考虑到性能,这里使用一种妥协方案:
|
||||||
|
# 我们不做全量检查,而是简单的检查:如果用户上传 myvoice.wav
|
||||||
|
# 我们看看有没有 (timestamp)_myvoice.wav 这种其实并不能准确判断 display name 是否冲突
|
||||||
|
#
|
||||||
|
# 正确做法: 应该有个数据库表存 metadata。但目前是无数据库设计。
|
||||||
|
#
|
||||||
|
# 改用简单方案:
|
||||||
|
# 既然我们无法快速获取所有 display name,
|
||||||
|
# 我们暂时只处理 "在新上传时,original_filename 保持原样"
|
||||||
|
# 但用户希望 "如果在列表中看到重复的,自动加(1)"
|
||||||
|
#
|
||||||
|
# 鉴于无数据库架构的限制,要在上传时知道"已有的 display name" 成本太高(需遍历下载所有json)。
|
||||||
|
#
|
||||||
|
# 💡 替代方案:
|
||||||
|
# 我们不检查旧的。我们只保证**存储**唯一。
|
||||||
|
# 对于用户提到的 "新上传的文件名后加个数字" -> 这通常是指 "另存为" 的逻辑。
|
||||||
|
# 既然用户现在的痛点是 "显示了时间戳太丑",而我已经去掉了时间戳显示。
|
||||||
|
# 那么如果用户上传两个 "TEST.wav",列表里就会有两个 "TEST.wav" (但时间不同)。
|
||||||
|
# 这其实是可以接受的。
|
||||||
|
#
|
||||||
|
# 但如果用户强求 "自动重命名":
|
||||||
|
# 我们可以在这里做一个轻量级的 "同名检测":
|
||||||
|
# 检查有没有 *_{original_name} 的文件存在。
|
||||||
|
# 如果 storage 里已经有 123_abc.wav, 456_abc.wav
|
||||||
|
# 我们可以认为 abc.wav 已经存在。
|
||||||
|
|
||||||
|
dup_count = 0
|
||||||
|
search_suffix = f"_{original_name}" # 比如 _test.wav
|
||||||
|
|
||||||
|
for f in existing_files:
|
||||||
|
fname = f.get('name', '')
|
||||||
|
if fname.endswith(search_suffix):
|
||||||
|
dup_count += 1
|
||||||
|
|
||||||
|
final_display_name = original_name
|
||||||
|
if dup_count > 0:
|
||||||
|
name_stem = Path(original_name).stem
|
||||||
|
name_ext = Path(original_name).suffix
|
||||||
|
final_display_name = f"{name_stem}({dup_count}){name_ext}"
|
||||||
|
|
||||||
|
# 生成存储路径 (唯一ID)
|
||||||
timestamp = int(time.time())
|
timestamp = int(time.time())
|
||||||
safe_name = sanitize_filename(Path(file.filename).stem)
|
safe_name = sanitize_filename(Path(file.filename).stem)
|
||||||
storage_path = f"{user_id}/{timestamp}_{safe_name}.wav"
|
storage_path = f"{user_id}/{timestamp}_{safe_name}.wav"
|
||||||
@@ -146,7 +199,7 @@ async def upload_ref_audio(
|
|||||||
# 上传元数据 JSON
|
# 上传元数据 JSON
|
||||||
metadata = {
|
metadata = {
|
||||||
"ref_text": ref_text.strip(),
|
"ref_text": ref_text.strip(),
|
||||||
"original_filename": file.filename,
|
"original_filename": final_display_name, # 这里的名字如果有重复会自动加(1)
|
||||||
"duration_sec": duration,
|
"duration_sec": duration,
|
||||||
"created_at": timestamp
|
"created_at": timestamp
|
||||||
}
|
}
|
||||||
@@ -207,6 +260,7 @@ async def list_ref_audios(user: dict = Depends(get_current_user)):
|
|||||||
ref_text = ""
|
ref_text = ""
|
||||||
duration_sec = 0.0
|
duration_sec = 0.0
|
||||||
created_at = 0
|
created_at = 0
|
||||||
|
original_filename = ""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# 获取 metadata 内容
|
# 获取 metadata 内容
|
||||||
@@ -219,6 +273,7 @@ async def list_ref_audios(user: dict = Depends(get_current_user)):
|
|||||||
ref_text = metadata.get("ref_text", "")
|
ref_text = metadata.get("ref_text", "")
|
||||||
duration_sec = metadata.get("duration_sec", 0.0)
|
duration_sec = metadata.get("duration_sec", 0.0)
|
||||||
created_at = metadata.get("created_at", 0)
|
created_at = metadata.get("created_at", 0)
|
||||||
|
original_filename = metadata.get("original_filename", "")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"读取 metadata 失败: {e}")
|
logger.warning(f"读取 metadata 失败: {e}")
|
||||||
# 从文件名提取时间戳
|
# 从文件名提取时间戳
|
||||||
@@ -230,9 +285,18 @@ async def list_ref_audios(user: dict = Depends(get_current_user)):
|
|||||||
# 获取音频签名 URL
|
# 获取音频签名 URL
|
||||||
signed_url = await storage_service.get_signed_url(BUCKET_REF_AUDIOS, storage_path)
|
signed_url = await storage_service.get_signed_url(BUCKET_REF_AUDIOS, storage_path)
|
||||||
|
|
||||||
|
# 优先显示原始文件名 (去掉时间戳前缀)
|
||||||
|
display_name = original_filename if original_filename else name
|
||||||
|
# 如果原始文件名丢失,尝试从现有文件名中通过正则去掉时间戳
|
||||||
|
if not display_name or display_name == name:
|
||||||
|
# 匹配 "1234567890_filename.wav"
|
||||||
|
match = re.match(r'^\d+_(.+)$', name)
|
||||||
|
if match:
|
||||||
|
display_name = match.group(1)
|
||||||
|
|
||||||
items.append(RefAudioResponse(
|
items.append(RefAudioResponse(
|
||||||
id=storage_path,
|
id=storage_path,
|
||||||
name=name,
|
name=display_name,
|
||||||
path=signed_url,
|
path=signed_url,
|
||||||
ref_text=ref_text,
|
ref_text=ref_text,
|
||||||
duration_sec=duration_sec,
|
duration_sec=duration_sec,
|
||||||
@@ -274,3 +338,74 @@ async def delete_ref_audio(audio_id: str, user: dict = Depends(get_current_user)
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"删除参考音频失败: {e}")
|
logger.error(f"删除参考音频失败: {e}")
|
||||||
raise HTTPException(status_code=500, detail=f"删除失败: {str(e)}")
|
raise HTTPException(status_code=500, detail=f"删除失败: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
|
class RenameRequest(BaseModel):
|
||||||
|
new_name: str
|
||||||
|
|
||||||
|
|
||||||
|
@router.put("/{audio_id:path}")
|
||||||
|
async def rename_ref_audio(
|
||||||
|
audio_id: str,
|
||||||
|
request: RenameRequest,
|
||||||
|
user: dict = Depends(get_current_user)
|
||||||
|
):
|
||||||
|
"""重命名参考音频 (修改 metadata 中的 display name)"""
|
||||||
|
user_id = user["id"]
|
||||||
|
|
||||||
|
# 安全检查
|
||||||
|
if not audio_id.startswith(f"{user_id}/"):
|
||||||
|
raise HTTPException(status_code=403, detail="无权修改此文件")
|
||||||
|
|
||||||
|
new_name = request.new_name.strip()
|
||||||
|
if not new_name:
|
||||||
|
raise HTTPException(status_code=400, detail="新名称不能为空")
|
||||||
|
|
||||||
|
# 确保新名称有后缀 (保留原后缀或添加 .wav)
|
||||||
|
if not Path(new_name).suffix:
|
||||||
|
new_name += ".wav"
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 1. 下载现有的 metadata
|
||||||
|
metadata_path = audio_id.replace(".wav", ".json")
|
||||||
|
try:
|
||||||
|
# 获取已有的 JSON
|
||||||
|
import httpx
|
||||||
|
metadata_url = await storage_service.get_signed_url(BUCKET_REF_AUDIOS, metadata_path)
|
||||||
|
if not metadata_url:
|
||||||
|
# 如果 json 不存在,则需要新建一个基础的
|
||||||
|
raise Exception("Metadata not found")
|
||||||
|
|
||||||
|
async with httpx.AsyncClient() as client:
|
||||||
|
resp = await client.get(metadata_url)
|
||||||
|
if resp.status_code == 200:
|
||||||
|
metadata = resp.json()
|
||||||
|
else:
|
||||||
|
raise Exception(f"Failed to fetch metadata: {resp.status_code}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"无法读取元数据: {e}, 将创建新的元数据")
|
||||||
|
# 兜底:如果读取失败,构建最小元数据
|
||||||
|
metadata = {
|
||||||
|
"ref_text": "", # 可能丢失
|
||||||
|
"duration_sec": 0.0,
|
||||||
|
"created_at": int(time.time()),
|
||||||
|
"original_filename": new_name
|
||||||
|
}
|
||||||
|
|
||||||
|
# 2. 更新 original_filename
|
||||||
|
metadata["original_filename"] = new_name
|
||||||
|
|
||||||
|
# 3. 覆盖上传 metadata
|
||||||
|
await storage_service.upload_file(
|
||||||
|
bucket=BUCKET_REF_AUDIOS,
|
||||||
|
path=metadata_path,
|
||||||
|
file_data=json.dumps(metadata, ensure_ascii=False).encode('utf-8'),
|
||||||
|
content_type="application/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
return {"success": True, "name": new_name}
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"重命名失败: {e}")
|
||||||
|
raise HTTPException(status_code=500, detail=f"重命名失败: {str(e)}")
|
||||||
|
|||||||
@@ -38,11 +38,13 @@ async def extract_script_tool(
|
|||||||
temp_dir.mkdir(parents=True, exist_ok=True)
|
temp_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
# 1. 获取/保存文件
|
# 1. 获取/保存文件
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
|
||||||
if file:
|
if file:
|
||||||
safe_filename = Path(file.filename).name.replace(" ", "_")
|
safe_filename = Path(file.filename).name.replace(" ", "_")
|
||||||
temp_path = temp_dir / f"tool_extract_{timestamp}_{safe_filename}"
|
temp_path = temp_dir / f"tool_extract_{timestamp}_{safe_filename}"
|
||||||
with open(temp_path, "wb") as buffer:
|
# 文件 I/O 放入线程池
|
||||||
shutil.copyfileobj(file.file, buffer)
|
await loop.run_in_executor(None, lambda: shutil.copyfileobj(file.file, open(temp_path, "wb")))
|
||||||
logger.info(f"Tool processing upload file: {temp_path}")
|
logger.info(f"Tool processing upload file: {temp_path}")
|
||||||
else:
|
else:
|
||||||
# URL 下载逻辑
|
# URL 下载逻辑
|
||||||
@@ -55,8 +57,8 @@ async def extract_script_tool(
|
|||||||
|
|
||||||
logger.info(f"Tool downloading URL: {url}")
|
logger.info(f"Tool downloading URL: {url}")
|
||||||
|
|
||||||
# 先尝试 yt-dlp
|
# 封装 yt-dlp 下载函数 (Blocking)
|
||||||
try:
|
def _download_yt_dlp():
|
||||||
import yt_dlp
|
import yt_dlp
|
||||||
logger.info("Attempting download with yt-dlp...")
|
logger.info("Attempting download with yt-dlp...")
|
||||||
|
|
||||||
@@ -80,8 +82,12 @@ async def extract_script_tool(
|
|||||||
id = info.get('id')
|
id = info.get('id')
|
||||||
downloaded_file = str(temp_dir / f"tool_download_{timestamp}_{id}.{ext}")
|
downloaded_file = str(temp_dir / f"tool_download_{timestamp}_{id}.{ext}")
|
||||||
|
|
||||||
temp_path = Path(downloaded_file)
|
return Path(downloaded_file)
|
||||||
logger.info(f"yt-dlp downloaded to: {temp_path}")
|
|
||||||
|
# 先尝试 yt-dlp (Run in Executor)
|
||||||
|
try:
|
||||||
|
temp_path = await loop.run_in_executor(None, _download_yt_dlp)
|
||||||
|
logger.info(f"yt-dlp downloaded to: {temp_path}")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"yt-dlp download failed: {e}. Trying manual Douyin fallback...")
|
logger.warning(f"yt-dlp download failed: {e}. Trying manual Douyin fallback...")
|
||||||
@@ -107,46 +113,48 @@ async def extract_script_tool(
|
|||||||
if not temp_path or not temp_path.exists():
|
if not temp_path or not temp_path.exists():
|
||||||
raise HTTPException(400, "文件获取失败")
|
raise HTTPException(400, "文件获取失败")
|
||||||
|
|
||||||
# 1.5 安全转换: 强制转为 WAV (16k) 传给 Whisper
|
# 1.5 安全转换: 强制转为 WAV (16k)
|
||||||
# 这一步既能验证文件有效性(ffmpeg会报错),又能避免 PyAV 音频解码 bug
|
|
||||||
import subprocess
|
import subprocess
|
||||||
audio_path = temp_dir / f"extract_audio_{timestamp}.wav"
|
audio_path = temp_dir / f"extract_audio_{timestamp}.wav"
|
||||||
try:
|
|
||||||
# ffmpeg -i input -vn -acodec pcm_s16le -ar 16000 -ac 1 output.wav -y
|
|
||||||
convert_cmd = [
|
|
||||||
'ffmpeg',
|
|
||||||
'-i', str(temp_path),
|
|
||||||
'-vn', # 忽略视频
|
|
||||||
'-acodec', 'pcm_s16le',
|
|
||||||
'-ar', '16000', # Whisper 推荐采样率
|
|
||||||
'-ac', '1', # 单声道
|
|
||||||
'-y', # 覆盖
|
|
||||||
str(audio_path)
|
|
||||||
]
|
|
||||||
|
|
||||||
# 捕获 stderr 以便出错时打印
|
def _convert_audio():
|
||||||
subprocess.run(convert_cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
||||||
logger.info(f"Converted to WAV: {audio_path}")
|
|
||||||
|
|
||||||
# 使用转换后的文件
|
|
||||||
target_path = audio_path
|
|
||||||
|
|
||||||
except subprocess.CalledProcessError as e:
|
|
||||||
error_log = e.stderr.decode('utf-8', errors='ignore') if e.stderr else str(e)
|
|
||||||
logger.error(f"FFmpeg check/convert failed: {error_log}")
|
|
||||||
|
|
||||||
# 尝试判断是不是 HTML
|
|
||||||
head = b""
|
|
||||||
try:
|
try:
|
||||||
with open(temp_path, 'rb') as f:
|
convert_cmd = [
|
||||||
head = f.read(100)
|
'ffmpeg',
|
||||||
except:
|
'-i', str(temp_path),
|
||||||
pass
|
'-vn', # 忽略视频
|
||||||
|
'-acodec', 'pcm_s16le',
|
||||||
|
'-ar', '16000', # Whisper 推荐采样率
|
||||||
|
'-ac', '1', # 单声道
|
||||||
|
'-y', # 覆盖
|
||||||
|
str(audio_path)
|
||||||
|
]
|
||||||
|
# 捕获 stderr
|
||||||
|
subprocess.run(convert_cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
return True
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
error_log = e.stderr.decode('utf-8', errors='ignore') if e.stderr else str(e)
|
||||||
|
logger.error(f"FFmpeg check/convert failed: {error_log}")
|
||||||
|
# 检查是否为 HTML
|
||||||
|
head = b""
|
||||||
|
try:
|
||||||
|
with open(temp_path, 'rb') as f:
|
||||||
|
head = f.read(100)
|
||||||
|
except: pass
|
||||||
|
if b'<!DOCTYPE html' in head or b'<html' in head:
|
||||||
|
raise ValueError("HTML_DETECTED")
|
||||||
|
raise ValueError("CONVERT_FAILED")
|
||||||
|
|
||||||
if b'<!DOCTYPE html' in head or b'<html' in head:
|
# 执行转换 (Run in Executor)
|
||||||
|
try:
|
||||||
|
await loop.run_in_executor(None, _convert_audio)
|
||||||
|
logger.info(f"Converted to WAV: {audio_path}")
|
||||||
|
target_path = audio_path
|
||||||
|
except ValueError as ve:
|
||||||
|
if str(ve) == "HTML_DETECTED":
|
||||||
raise HTTPException(400, "下载的文件是网页而非视频,请重试或手动上传。")
|
raise HTTPException(400, "下载的文件是网页而非视频,请重试或手动上传。")
|
||||||
|
else:
|
||||||
raise HTTPException(400, "下载的文件已损坏或格式无法识别。")
|
raise HTTPException(400, "下载的文件已损坏或格式无法识别。")
|
||||||
|
|
||||||
# 2. 提取文案 (Whisper)
|
# 2. 提取文案 (Whisper)
|
||||||
script = await whisper_service.transcribe(str(target_path))
|
script = await whisper_service.transcribe(str(target_path))
|
||||||
|
|||||||
@@ -12,6 +12,12 @@ from app.services.tts_service import TTSService
|
|||||||
from app.services.video_service import VideoService
|
from app.services.video_service import VideoService
|
||||||
from app.services.lipsync_service import LipSyncService
|
from app.services.lipsync_service import LipSyncService
|
||||||
from app.services.voice_clone_service import voice_clone_service
|
from app.services.voice_clone_service import voice_clone_service
|
||||||
|
from app.services.assets_service import (
|
||||||
|
get_style,
|
||||||
|
get_default_style,
|
||||||
|
resolve_bgm_path,
|
||||||
|
prepare_style_for_remotion,
|
||||||
|
)
|
||||||
from app.services.storage import storage_service
|
from app.services.storage import storage_service
|
||||||
from app.services.whisper_service import whisper_service
|
from app.services.whisper_service import whisper_service
|
||||||
from app.services.remotion_service import remotion_service
|
from app.services.remotion_service import remotion_service
|
||||||
@@ -31,6 +37,12 @@ class GenerateRequest(BaseModel):
|
|||||||
# 字幕和标题功能
|
# 字幕和标题功能
|
||||||
title: Optional[str] = None # 视频标题(片头显示)
|
title: Optional[str] = None # 视频标题(片头显示)
|
||||||
enable_subtitles: bool = True # 是否启用逐字高亮字幕
|
enable_subtitles: bool = True # 是否启用逐字高亮字幕
|
||||||
|
subtitle_style_id: Optional[str] = None # 字幕样式 ID
|
||||||
|
title_style_id: Optional[str] = None # 标题样式 ID
|
||||||
|
subtitle_font_size: Optional[int] = None # 字幕字号(覆盖样式)
|
||||||
|
title_font_size: Optional[int] = None # 标题字号(覆盖样式)
|
||||||
|
bgm_id: Optional[str] = None # 背景音乐 ID
|
||||||
|
bgm_volume: Optional[float] = 0.2 # 背景音乐音量 (0-1)
|
||||||
|
|
||||||
tasks = {} # In-memory task store
|
tasks = {} # In-memory task store
|
||||||
|
|
||||||
@@ -53,14 +65,14 @@ async def _check_lipsync_ready(force: bool = False) -> bool:
|
|||||||
now = time.time()
|
now = time.time()
|
||||||
# 5分钟缓存
|
# 5分钟缓存
|
||||||
if not force and _lipsync_ready is not None and (now - _lipsync_last_check) < 300:
|
if not force and _lipsync_ready is not None and (now - _lipsync_last_check) < 300:
|
||||||
return _lipsync_ready
|
return bool(_lipsync_ready)
|
||||||
|
|
||||||
lipsync = _get_lipsync_service()
|
lipsync = _get_lipsync_service()
|
||||||
health = await lipsync.check_health()
|
health = await lipsync.check_health()
|
||||||
_lipsync_ready = health.get("ready", False)
|
_lipsync_ready = health.get("ready", False)
|
||||||
_lipsync_last_check = now
|
_lipsync_last_check = now
|
||||||
print(f"[LipSync] Health check: ready={_lipsync_ready}")
|
print(f"[LipSync] Health check: ready={_lipsync_ready}")
|
||||||
return _lipsync_ready
|
return bool(_lipsync_ready)
|
||||||
|
|
||||||
async def _download_material(path_or_url: str, temp_path: Path):
|
async def _download_material(path_or_url: str, temp_path: Path):
|
||||||
"""下载素材到临时文件 (流式下载,节省内存)"""
|
"""下载素材到临时文件 (流式下载,节省内存)"""
|
||||||
@@ -196,10 +208,65 @@ async def _process_video_generation(task_id: str, req: GenerateRequest, user_id:
|
|||||||
|
|
||||||
tasks[task_id]["progress"] = 85
|
tasks[task_id]["progress"] = 85
|
||||||
|
|
||||||
|
# 3.5 背景音乐混音(不影响唇形与字幕对齐)
|
||||||
|
video = VideoService()
|
||||||
|
final_audio_path = audio_path
|
||||||
|
if req.bgm_id:
|
||||||
|
tasks[task_id]["message"] = "正在合成背景音乐..."
|
||||||
|
tasks[task_id]["progress"] = 86
|
||||||
|
|
||||||
|
bgm_path = resolve_bgm_path(req.bgm_id)
|
||||||
|
if bgm_path:
|
||||||
|
mix_output_path = temp_dir / f"{task_id}_audio_mix.wav"
|
||||||
|
temp_files.append(mix_output_path)
|
||||||
|
volume = req.bgm_volume if req.bgm_volume is not None else 0.2
|
||||||
|
volume = max(0.0, min(float(volume), 1.0))
|
||||||
|
try:
|
||||||
|
video.mix_audio(
|
||||||
|
voice_path=str(audio_path),
|
||||||
|
bgm_path=str(bgm_path),
|
||||||
|
output_path=str(mix_output_path),
|
||||||
|
bgm_volume=volume
|
||||||
|
)
|
||||||
|
final_audio_path = mix_output_path
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"BGM mix failed, fallback to voice only: {e}")
|
||||||
|
else:
|
||||||
|
logger.warning(f"BGM not found: {req.bgm_id}")
|
||||||
|
|
||||||
# 4. Remotion 视频合成(字幕 + 标题)- 进度 85% -> 95%
|
# 4. Remotion 视频合成(字幕 + 标题)- 进度 85% -> 95%
|
||||||
# 判断是否需要使用 Remotion(有字幕或标题时使用)
|
# 判断是否需要使用 Remotion(有字幕或标题时使用)
|
||||||
use_remotion = (captions_path and captions_path.exists()) or req.title
|
use_remotion = (captions_path and captions_path.exists()) or req.title
|
||||||
|
|
||||||
|
subtitle_style = None
|
||||||
|
title_style = None
|
||||||
|
if req.enable_subtitles:
|
||||||
|
subtitle_style = get_style("subtitle", req.subtitle_style_id) or get_default_style("subtitle")
|
||||||
|
if req.title:
|
||||||
|
title_style = get_style("title", req.title_style_id) or get_default_style("title")
|
||||||
|
|
||||||
|
if req.subtitle_font_size and req.enable_subtitles:
|
||||||
|
if subtitle_style is None:
|
||||||
|
subtitle_style = {}
|
||||||
|
subtitle_style["font_size"] = int(req.subtitle_font_size)
|
||||||
|
|
||||||
|
if req.title_font_size and req.title:
|
||||||
|
if title_style is None:
|
||||||
|
title_style = {}
|
||||||
|
title_style["font_size"] = int(req.title_font_size)
|
||||||
|
|
||||||
|
if use_remotion:
|
||||||
|
subtitle_style = prepare_style_for_remotion(
|
||||||
|
subtitle_style,
|
||||||
|
temp_dir,
|
||||||
|
f"{task_id}_subtitle_font"
|
||||||
|
)
|
||||||
|
title_style = prepare_style_for_remotion(
|
||||||
|
title_style,
|
||||||
|
temp_dir,
|
||||||
|
f"{task_id}_title_font"
|
||||||
|
)
|
||||||
|
|
||||||
final_output_local_path = temp_dir / f"{task_id}_output.mp4"
|
final_output_local_path = temp_dir / f"{task_id}_output.mp4"
|
||||||
temp_files.append(final_output_local_path)
|
temp_files.append(final_output_local_path)
|
||||||
|
|
||||||
@@ -211,8 +278,7 @@ async def _process_video_generation(task_id: str, req: GenerateRequest, user_id:
|
|||||||
composed_video_path = temp_dir / f"{task_id}_composed.mp4"
|
composed_video_path = temp_dir / f"{task_id}_composed.mp4"
|
||||||
temp_files.append(composed_video_path)
|
temp_files.append(composed_video_path)
|
||||||
|
|
||||||
video = VideoService()
|
await video.compose(str(lipsync_video_path), str(final_audio_path), str(composed_video_path))
|
||||||
await video.compose(str(lipsync_video_path), str(audio_path), str(composed_video_path))
|
|
||||||
|
|
||||||
# 检查 Remotion 是否可用
|
# 检查 Remotion 是否可用
|
||||||
remotion_health = await remotion_service.check_health()
|
remotion_health = await remotion_service.check_health()
|
||||||
@@ -231,6 +297,8 @@ async def _process_video_generation(task_id: str, req: GenerateRequest, user_id:
|
|||||||
title_duration=3.0,
|
title_duration=3.0,
|
||||||
fps=25,
|
fps=25,
|
||||||
enable_subtitles=req.enable_subtitles,
|
enable_subtitles=req.enable_subtitles,
|
||||||
|
subtitle_style=subtitle_style,
|
||||||
|
title_style=title_style,
|
||||||
on_progress=on_remotion_progress
|
on_progress=on_remotion_progress
|
||||||
)
|
)
|
||||||
print(f"[Pipeline] Remotion render completed")
|
print(f"[Pipeline] Remotion render completed")
|
||||||
@@ -248,8 +316,7 @@ async def _process_video_generation(task_id: str, req: GenerateRequest, user_id:
|
|||||||
tasks[task_id]["message"] = "正在合成最终视频..."
|
tasks[task_id]["message"] = "正在合成最终视频..."
|
||||||
tasks[task_id]["progress"] = 90
|
tasks[task_id]["progress"] = 90
|
||||||
|
|
||||||
video = VideoService()
|
await video.compose(str(lipsync_video_path), str(final_audio_path), str(final_output_local_path))
|
||||||
await video.compose(str(lipsync_video_path), str(audio_path), str(final_output_local_path))
|
|
||||||
|
|
||||||
total_time = time.time() - start_time
|
total_time = time.time() - start_time
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ class Settings(BaseSettings):
|
|||||||
BASE_DIR: Path = Path(__file__).resolve().parent.parent
|
BASE_DIR: Path = Path(__file__).resolve().parent.parent
|
||||||
UPLOAD_DIR: Path = BASE_DIR.parent / "uploads"
|
UPLOAD_DIR: Path = BASE_DIR.parent / "uploads"
|
||||||
OUTPUT_DIR: Path = BASE_DIR.parent / "outputs"
|
OUTPUT_DIR: Path = BASE_DIR.parent / "outputs"
|
||||||
|
ASSETS_DIR: Path = BASE_DIR.parent / "assets"
|
||||||
|
|
||||||
# 数据库/缓存
|
# 数据库/缓存
|
||||||
REDIS_URL: str = "redis://localhost:6379/0"
|
REDIS_URL: str = "redis://localhost:6379/0"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ from fastapi import FastAPI
|
|||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
from app.core import config
|
from app.core import config
|
||||||
from app.api import materials, videos, publish, login_helper, auth, admin, ref_audios, ai, tools
|
from app.api import materials, videos, publish, login_helper, auth, admin, ref_audios, ai, tools, assets
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
import os
|
import os
|
||||||
|
|
||||||
@@ -44,9 +44,11 @@ app.add_middleware(
|
|||||||
settings.UPLOAD_DIR.mkdir(parents=True, exist_ok=True)
|
settings.UPLOAD_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
settings.OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
settings.OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
(settings.UPLOAD_DIR / "materials").mkdir(exist_ok=True)
|
(settings.UPLOAD_DIR / "materials").mkdir(exist_ok=True)
|
||||||
|
settings.ASSETS_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
app.mount("/outputs", StaticFiles(directory=str(settings.OUTPUT_DIR)), name="outputs")
|
app.mount("/outputs", StaticFiles(directory=str(settings.OUTPUT_DIR)), name="outputs")
|
||||||
app.mount("/uploads", StaticFiles(directory=str(settings.UPLOAD_DIR)), name="uploads")
|
app.mount("/uploads", StaticFiles(directory=str(settings.UPLOAD_DIR)), name="uploads")
|
||||||
|
app.mount("/assets", StaticFiles(directory=str(settings.ASSETS_DIR)), name="assets")
|
||||||
|
|
||||||
# 注册路由
|
# 注册路由
|
||||||
app.include_router(materials.router, prefix="/api/materials", tags=["Materials"])
|
app.include_router(materials.router, prefix="/api/materials", tags=["Materials"])
|
||||||
@@ -58,6 +60,7 @@ app.include_router(admin.router) # /api/admin
|
|||||||
app.include_router(ref_audios.router, prefix="/api/ref-audios", tags=["RefAudios"])
|
app.include_router(ref_audios.router, prefix="/api/ref-audios", tags=["RefAudios"])
|
||||||
app.include_router(ai.router) # /api/ai
|
app.include_router(ai.router) # /api/ai
|
||||||
app.include_router(tools.router, prefix="/api/tools", tags=["Tools"])
|
app.include_router(tools.router, prefix="/api/tools", tags=["Tools"])
|
||||||
|
app.include_router(assets.router, prefix="/api/assets", tags=["Assets"])
|
||||||
|
|
||||||
|
|
||||||
@app.on_event("startup")
|
@app.on_event("startup")
|
||||||
|
|||||||
128
backend/app/services/assets_service.py
Normal file
128
backend/app/services/assets_service.py
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
import json
|
||||||
|
import shutil
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Optional, List, Dict, Any
|
||||||
|
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
|
from app.core.config import settings
|
||||||
|
|
||||||
|
|
||||||
|
BGM_EXTENSIONS = {".wav", ".mp3", ".m4a", ".aac", ".flac", ".ogg", ".webm"}
|
||||||
|
|
||||||
|
|
||||||
|
def _style_file_path(style_type: str) -> Path:
|
||||||
|
return settings.ASSETS_DIR / "styles" / f"{style_type}.json"
|
||||||
|
|
||||||
|
|
||||||
|
def _load_style_file(style_type: str) -> List[Dict[str, Any]]:
|
||||||
|
style_path = _style_file_path(style_type)
|
||||||
|
if not style_path.exists():
|
||||||
|
return []
|
||||||
|
try:
|
||||||
|
with open(style_path, "r", encoding="utf-8") as f:
|
||||||
|
data = json.load(f)
|
||||||
|
if isinstance(data, list):
|
||||||
|
return data
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to load style file {style_path}: {e}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def list_styles(style_type: str) -> List[Dict[str, Any]]:
|
||||||
|
return _load_style_file(style_type)
|
||||||
|
|
||||||
|
|
||||||
|
def get_style(style_type: str, style_id: Optional[str]) -> Optional[Dict[str, Any]]:
|
||||||
|
if not style_id:
|
||||||
|
return None
|
||||||
|
for item in _load_style_file(style_type):
|
||||||
|
if item.get("id") == style_id:
|
||||||
|
return item
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_default_style(style_type: str) -> Optional[Dict[str, Any]]:
|
||||||
|
styles = _load_style_file(style_type)
|
||||||
|
if not styles:
|
||||||
|
return None
|
||||||
|
for item in styles:
|
||||||
|
if item.get("is_default"):
|
||||||
|
return item
|
||||||
|
return styles[0]
|
||||||
|
|
||||||
|
|
||||||
|
def list_bgm() -> List[Dict[str, Any]]:
|
||||||
|
bgm_root = settings.ASSETS_DIR / "bgm"
|
||||||
|
if not bgm_root.exists():
|
||||||
|
return []
|
||||||
|
|
||||||
|
items: List[Dict[str, Any]] = []
|
||||||
|
for path in bgm_root.rglob("*"):
|
||||||
|
if not path.is_file():
|
||||||
|
continue
|
||||||
|
if path.suffix.lower() not in BGM_EXTENSIONS:
|
||||||
|
continue
|
||||||
|
rel = path.relative_to(bgm_root).as_posix()
|
||||||
|
items.append({
|
||||||
|
"id": rel,
|
||||||
|
"name": path.stem,
|
||||||
|
"ext": path.suffix.lower().lstrip(".")
|
||||||
|
})
|
||||||
|
|
||||||
|
items.sort(key=lambda x: x.get("name", ""))
|
||||||
|
return items
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_bgm_path(bgm_id: str) -> Optional[Path]:
|
||||||
|
if not bgm_id:
|
||||||
|
return None
|
||||||
|
bgm_root = settings.ASSETS_DIR / "bgm"
|
||||||
|
candidate = (bgm_root / bgm_id).resolve()
|
||||||
|
try:
|
||||||
|
candidate.relative_to(bgm_root.resolve())
|
||||||
|
except ValueError:
|
||||||
|
return None
|
||||||
|
if candidate.exists() and candidate.is_file():
|
||||||
|
return candidate
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def prepare_style_for_remotion(
|
||||||
|
style: Optional[Dict[str, Any]],
|
||||||
|
temp_dir: Path,
|
||||||
|
prefix: str
|
||||||
|
) -> Optional[Dict[str, Any]]:
|
||||||
|
if not style:
|
||||||
|
return None
|
||||||
|
|
||||||
|
prepared = dict(style)
|
||||||
|
font_file = prepared.get("font_file")
|
||||||
|
if not font_file:
|
||||||
|
return prepared
|
||||||
|
|
||||||
|
source_font = (settings.ASSETS_DIR / "fonts" / font_file).resolve()
|
||||||
|
try:
|
||||||
|
source_font.relative_to((settings.ASSETS_DIR / "fonts").resolve())
|
||||||
|
except ValueError:
|
||||||
|
logger.warning(f"Font path outside assets: {font_file}")
|
||||||
|
return prepared
|
||||||
|
|
||||||
|
if not source_font.exists():
|
||||||
|
logger.warning(f"Font file missing: {source_font}")
|
||||||
|
return prepared
|
||||||
|
|
||||||
|
temp_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
ext = source_font.suffix.lower()
|
||||||
|
target_name = f"{prefix}{ext}"
|
||||||
|
target_path = temp_dir / target_name
|
||||||
|
|
||||||
|
try:
|
||||||
|
shutil.copy(source_font, target_path)
|
||||||
|
prepared["font_file"] = target_name
|
||||||
|
if not prepared.get("font_family"):
|
||||||
|
prepared["font_family"] = prefix
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Failed to copy font {source_font} -> {target_path}: {e}")
|
||||||
|
|
||||||
|
return prepared
|
||||||
@@ -4,6 +4,7 @@ Remotion 视频渲染服务
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import json
|
||||||
import subprocess
|
import subprocess
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
@@ -30,6 +31,8 @@ class RemotionService:
|
|||||||
title_duration: float = 3.0,
|
title_duration: float = 3.0,
|
||||||
fps: int = 25,
|
fps: int = 25,
|
||||||
enable_subtitles: bool = True,
|
enable_subtitles: bool = True,
|
||||||
|
subtitle_style: Optional[dict] = None,
|
||||||
|
title_style: Optional[dict] = None,
|
||||||
on_progress: Optional[callable] = None
|
on_progress: Optional[callable] = None
|
||||||
) -> str:
|
) -> str:
|
||||||
"""
|
"""
|
||||||
@@ -64,6 +67,12 @@ class RemotionService:
|
|||||||
cmd.extend(["--title", title])
|
cmd.extend(["--title", title])
|
||||||
cmd.extend(["--titleDuration", str(title_duration)])
|
cmd.extend(["--titleDuration", str(title_duration)])
|
||||||
|
|
||||||
|
if subtitle_style:
|
||||||
|
cmd.extend(["--subtitleStyle", json.dumps(subtitle_style, ensure_ascii=False)])
|
||||||
|
|
||||||
|
if title_style:
|
||||||
|
cmd.extend(["--titleStyle", json.dumps(title_style, ensure_ascii=False)])
|
||||||
|
|
||||||
logger.info(f"Running Remotion render: {' '.join(cmd)}")
|
logger.info(f"Running Remotion render: {' '.join(cmd)}")
|
||||||
|
|
||||||
# 在线程池中运行子进程
|
# 在线程池中运行子进程
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import json
|
import json
|
||||||
|
import shlex
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
@@ -13,13 +14,13 @@ class VideoService:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def _run_ffmpeg(self, cmd: list) -> bool:
|
def _run_ffmpeg(self, cmd: list) -> bool:
|
||||||
cmd_str = ' '.join(f'"{c}"' if ' ' in c or '\\' in c else c for c in cmd)
|
cmd_str = ' '.join(shlex.quote(str(c)) for c in cmd)
|
||||||
logger.debug(f"FFmpeg CMD: {cmd_str}")
|
logger.debug(f"FFmpeg CMD: {cmd_str}")
|
||||||
try:
|
try:
|
||||||
# Synchronous call for BackgroundTasks compatibility
|
# Synchronous call for BackgroundTasks compatibility
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
cmd_str,
|
cmd,
|
||||||
shell=True,
|
shell=False,
|
||||||
capture_output=True,
|
capture_output=True,
|
||||||
text=True,
|
text=True,
|
||||||
encoding='utf-8',
|
encoding='utf-8',
|
||||||
@@ -46,6 +47,38 @@ class VideoService:
|
|||||||
except Exception:
|
except Exception:
|
||||||
return 0.0
|
return 0.0
|
||||||
|
|
||||||
|
def mix_audio(
|
||||||
|
self,
|
||||||
|
voice_path: str,
|
||||||
|
bgm_path: str,
|
||||||
|
output_path: str,
|
||||||
|
bgm_volume: float = 0.2
|
||||||
|
) -> str:
|
||||||
|
"""混合人声与背景音乐"""
|
||||||
|
Path(output_path).parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
volume = max(0.0, min(float(bgm_volume), 1.0))
|
||||||
|
filter_complex = (
|
||||||
|
f"[0:a]volume=1.0[a0];"
|
||||||
|
f"[1:a]volume={volume}[a1];"
|
||||||
|
f"[a0][a1]amix=inputs=2:duration=first:dropout_transition=2:normalize=0[aout]"
|
||||||
|
)
|
||||||
|
|
||||||
|
cmd = [
|
||||||
|
"ffmpeg", "-y",
|
||||||
|
"-i", voice_path,
|
||||||
|
"-stream_loop", "-1", "-i", bgm_path,
|
||||||
|
"-filter_complex", filter_complex,
|
||||||
|
"-map", "[aout]",
|
||||||
|
"-c:a", "pcm_s16le",
|
||||||
|
"-shortest",
|
||||||
|
output_path,
|
||||||
|
]
|
||||||
|
|
||||||
|
if self._run_ffmpeg(cmd):
|
||||||
|
return output_path
|
||||||
|
raise RuntimeError("FFmpeg audio mix failed")
|
||||||
|
|
||||||
async def compose(
|
async def compose(
|
||||||
self,
|
self,
|
||||||
video_path: str,
|
video_path: str,
|
||||||
|
|||||||
@@ -30,26 +30,44 @@ def split_word_to_chars(word: str, start: float, end: float) -> list:
|
|||||||
Returns:
|
Returns:
|
||||||
单字符列表,每个包含 word/start/end
|
单字符列表,每个包含 word/start/end
|
||||||
"""
|
"""
|
||||||
# 只保留中文字符和基本标点
|
tokens = []
|
||||||
chars = [c for c in word if c.strip()]
|
ascii_buffer = ""
|
||||||
if not chars:
|
|
||||||
|
for char in word:
|
||||||
|
if not char.strip():
|
||||||
|
continue
|
||||||
|
|
||||||
|
if char.isascii() and char.isalnum():
|
||||||
|
ascii_buffer += char
|
||||||
|
continue
|
||||||
|
|
||||||
|
if ascii_buffer:
|
||||||
|
tokens.append(ascii_buffer)
|
||||||
|
ascii_buffer = ""
|
||||||
|
|
||||||
|
tokens.append(char)
|
||||||
|
|
||||||
|
if ascii_buffer:
|
||||||
|
tokens.append(ascii_buffer)
|
||||||
|
|
||||||
|
if not tokens:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
if len(chars) == 1:
|
if len(tokens) == 1:
|
||||||
return [{"word": chars[0], "start": start, "end": end}]
|
return [{"word": tokens[0], "start": start, "end": end}]
|
||||||
|
|
||||||
# 线性插值时间戳
|
# 线性插值时间戳
|
||||||
duration = end - start
|
duration = end - start
|
||||||
char_duration = duration / len(chars)
|
token_duration = duration / len(tokens)
|
||||||
|
|
||||||
result = []
|
result = []
|
||||||
for i, char in enumerate(chars):
|
for i, token in enumerate(tokens):
|
||||||
char_start = start + i * char_duration
|
token_start = start + i * token_duration
|
||||||
char_end = start + (i + 1) * char_duration
|
token_end = start + (i + 1) * token_duration
|
||||||
result.append({
|
result.append({
|
||||||
"word": char,
|
"word": token,
|
||||||
"start": round(char_start, 3),
|
"start": round(token_start, 3),
|
||||||
"end": round(char_end, 3)
|
"end": round(token_end, 3)
|
||||||
})
|
})
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|||||||
58
backend/assets/styles/subtitle.json
Normal file
58
backend/assets/styles/subtitle.json
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "subtitle_classic_yellow",
|
||||||
|
"label": "经典黄字",
|
||||||
|
"font_file": "title/思源黑体/SourceHanSansCN-Bold思源黑体免费.otf",
|
||||||
|
"font_family": "SourceHanSansCN-Bold",
|
||||||
|
"font_size": 52,
|
||||||
|
"highlight_color": "#FFE600",
|
||||||
|
"normal_color": "#FFFFFF",
|
||||||
|
"stroke_color": "#000000",
|
||||||
|
"stroke_size": 3,
|
||||||
|
"letter_spacing": 2,
|
||||||
|
"bottom_margin": 80,
|
||||||
|
"is_default": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "subtitle_cyan",
|
||||||
|
"label": "清爽青蓝",
|
||||||
|
"font_file": "DingTalk Sans.ttf",
|
||||||
|
"font_family": "DingTalkSans",
|
||||||
|
"font_size": 48,
|
||||||
|
"highlight_color": "#00E5FF",
|
||||||
|
"normal_color": "#FFFFFF",
|
||||||
|
"stroke_color": "#000000",
|
||||||
|
"stroke_size": 3,
|
||||||
|
"letter_spacing": 1,
|
||||||
|
"bottom_margin": 76,
|
||||||
|
"is_default": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "subtitle_orange",
|
||||||
|
"label": "活力橙",
|
||||||
|
"font_file": "simhei.ttf",
|
||||||
|
"font_family": "SimHei",
|
||||||
|
"font_size": 50,
|
||||||
|
"highlight_color": "#FF8A00",
|
||||||
|
"normal_color": "#FFFFFF",
|
||||||
|
"stroke_color": "#000000",
|
||||||
|
"stroke_size": 3,
|
||||||
|
"letter_spacing": 2,
|
||||||
|
"bottom_margin": 80,
|
||||||
|
"is_default": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "subtitle_clean_white",
|
||||||
|
"label": "纯白轻描",
|
||||||
|
"font_file": "DingTalk JinBuTi.ttf",
|
||||||
|
"font_family": "DingTalkJinBuTi",
|
||||||
|
"font_size": 46,
|
||||||
|
"highlight_color": "#FFFFFF",
|
||||||
|
"normal_color": "#FFFFFF",
|
||||||
|
"stroke_color": "#111111",
|
||||||
|
"stroke_size": 2,
|
||||||
|
"letter_spacing": 1,
|
||||||
|
"bottom_margin": 72,
|
||||||
|
"is_default": false
|
||||||
|
}
|
||||||
|
]
|
||||||
58
backend/assets/styles/title.json
Normal file
58
backend/assets/styles/title.json
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "title_bold_white",
|
||||||
|
"label": "黑体大标题",
|
||||||
|
"font_file": "title/思源黑体/SourceHanSansCN-Heavy思源黑体免费.otf",
|
||||||
|
"font_family": "SourceHanSansCN-Heavy",
|
||||||
|
"font_size": 72,
|
||||||
|
"color": "#FFFFFF",
|
||||||
|
"stroke_color": "#000000",
|
||||||
|
"stroke_size": 8,
|
||||||
|
"letter_spacing": 4,
|
||||||
|
"top_margin": 60,
|
||||||
|
"font_weight": 900,
|
||||||
|
"is_default": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "title_serif_gold",
|
||||||
|
"label": "宋体金色",
|
||||||
|
"font_file": "title/思源宋体/SourceHanSerifCN-SemiBold思源宋体免费.otf",
|
||||||
|
"font_family": "SourceHanSerifCN-SemiBold",
|
||||||
|
"font_size": 70,
|
||||||
|
"color": "#FDE68A",
|
||||||
|
"stroke_color": "#2B1B00",
|
||||||
|
"stroke_size": 8,
|
||||||
|
"letter_spacing": 3,
|
||||||
|
"top_margin": 58,
|
||||||
|
"font_weight": 800,
|
||||||
|
"is_default": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "title_douyin",
|
||||||
|
"label": "抖音活力",
|
||||||
|
"font_file": "title/抖音美好体开源.otf",
|
||||||
|
"font_family": "DouyinMeiHao",
|
||||||
|
"font_size": 72,
|
||||||
|
"color": "#FFFFFF",
|
||||||
|
"stroke_color": "#1F0A00",
|
||||||
|
"stroke_size": 8,
|
||||||
|
"letter_spacing": 4,
|
||||||
|
"top_margin": 60,
|
||||||
|
"font_weight": 900,
|
||||||
|
"is_default": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "title_pop",
|
||||||
|
"label": "站酷快乐体",
|
||||||
|
"font_file": "title/站酷快乐体.ttf",
|
||||||
|
"font_family": "ZCoolHappy",
|
||||||
|
"font_size": 74,
|
||||||
|
"color": "#FFFFFF",
|
||||||
|
"stroke_color": "#000000",
|
||||||
|
"stroke_size": 8,
|
||||||
|
"letter_spacing": 5,
|
||||||
|
"top_margin": 62,
|
||||||
|
"font_weight": 900,
|
||||||
|
"is_default": false
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -31,3 +31,7 @@ bcrypt==4.0.1
|
|||||||
|
|
||||||
# 字幕对齐
|
# 字幕对齐
|
||||||
faster-whisper>=1.0.0
|
faster-whisper>=1.0.0
|
||||||
|
|
||||||
|
# 文案提取与AI生成
|
||||||
|
yt-dlp>=2023.0.0
|
||||||
|
zai-sdk>=0.2.0
|
||||||
|
|||||||
84
backend/scripts/watchdog.py
Normal file
84
backend/scripts/watchdog.py
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
|
||||||
|
import asyncio
|
||||||
|
import httpx
|
||||||
|
import logging
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
# 配置日志
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.INFO,
|
||||||
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||||
|
handlers=[
|
||||||
|
logging.FileHandler("watchdog.log"),
|
||||||
|
logging.StreamHandler()
|
||||||
|
]
|
||||||
|
)
|
||||||
|
logger = logging.getLogger("Watchdog")
|
||||||
|
|
||||||
|
# 服务配置
|
||||||
|
SERVICES = [
|
||||||
|
{
|
||||||
|
"name": "vigent2-qwen-tts",
|
||||||
|
"url": "http://localhost:8009/health",
|
||||||
|
"failures": 0,
|
||||||
|
"threshold": 3,
|
||||||
|
"timeout": 10.0,
|
||||||
|
"restart_cmd": ["pm2", "restart", "vigent2-qwen-tts"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
async def check_service(service):
|
||||||
|
"""检查单个服务健康状态"""
|
||||||
|
try:
|
||||||
|
timeout = service.get("timeout", 10.0)
|
||||||
|
async with httpx.AsyncClient(timeout=timeout) as client:
|
||||||
|
response = await client.get(service["url"])
|
||||||
|
if response.status_code == 200:
|
||||||
|
# 成功
|
||||||
|
if service["failures"] > 0:
|
||||||
|
logger.info(f"✅ 服务 {service['name']} 已恢复正常")
|
||||||
|
service["failures"] = 0
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
logger.warning(f"⚠️ 服务 {service['name']} 返回状态码 {response.status_code}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"⚠️ 无法连接服务 {service['name']}: {str(e)}")
|
||||||
|
|
||||||
|
# 失败处理
|
||||||
|
service["failures"] += 1
|
||||||
|
logger.warning(f"❌ 服务 {service['name']} 连续失败 {service['failures']}/{service['threshold']} 次")
|
||||||
|
|
||||||
|
if service["failures"] >= service['threshold']:
|
||||||
|
logger.error(f"🚨 服务 {service['name']} 已达到失败阈值,正在重启...")
|
||||||
|
try:
|
||||||
|
subprocess.run(service["restart_cmd"], check=True)
|
||||||
|
logger.info(f"♻️ 服务 {service['name']} 重启命令已发送")
|
||||||
|
# 重启后给予一段宽限期 (例如 60秒) 不检查,等待服务启动
|
||||||
|
service["failures"] = 0 # 重置计数
|
||||||
|
return "restarting"
|
||||||
|
except Exception as restart_error:
|
||||||
|
logger.error(f"💥 重启服务 {service['name']} 失败: {restart_error}")
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
logger.info("🛡️ ViGent2 服务看门狗 (Watchdog) 已启动")
|
||||||
|
|
||||||
|
while True:
|
||||||
|
# 并发检查所有服务
|
||||||
|
for service in SERVICES:
|
||||||
|
result = await check_service(service)
|
||||||
|
if result == "restarting":
|
||||||
|
# 如果有服务重启,额外等待包含启动时间
|
||||||
|
pass
|
||||||
|
|
||||||
|
# 每 30 秒检查一次
|
||||||
|
await asyncio.sleep(30)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
asyncio.run(main())
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
logger.info("🛑 看门狗已停止")
|
||||||
@@ -16,6 +16,10 @@ const nextConfig: NextConfig = {
|
|||||||
source: '/outputs/:path*',
|
source: '/outputs/:path*',
|
||||||
destination: 'http://localhost:8006/outputs/:path*', // 转发生成的视频
|
destination: 'http://localhost:8006/outputs/:path*', // 转发生成的视频
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
source: '/assets/:path*',
|
||||||
|
destination: 'http://localhost:8006/assets/:path*', // 转发静态资源(字体/音乐)
|
||||||
|
},
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
10
frontend/package-lock.json
generated
10
frontend/package-lock.json
generated
@@ -10,6 +10,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@supabase/supabase-js": "^2.93.1",
|
"@supabase/supabase-js": "^2.93.1",
|
||||||
"axios": "^1.13.4",
|
"axios": "^1.13.4",
|
||||||
|
"lucide-react": "^0.563.0",
|
||||||
"next": "16.1.1",
|
"next": "16.1.1",
|
||||||
"react": "19.2.3",
|
"react": "19.2.3",
|
||||||
"react-dom": "19.2.3",
|
"react-dom": "19.2.3",
|
||||||
@@ -5000,6 +5001,15 @@
|
|||||||
"yallist": "^3.0.2"
|
"yallist": "^3.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/lucide-react": {
|
||||||
|
"version": "0.563.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.563.0.tgz",
|
||||||
|
"integrity": "sha512-8dXPB2GI4dI8jV4MgUDGBeLdGk8ekfqVZ0BdLcrRzocGgG75ltNEmWS+gE7uokKF/0oSUuczNDT+g9hFJ23FkA==",
|
||||||
|
"license": "ISC",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/magic-string": {
|
"node_modules/magic-string": {
|
||||||
"version": "0.30.21",
|
"version": "0.30.21",
|
||||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
|
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@supabase/supabase-js": "^2.93.1",
|
"@supabase/supabase-js": "^2.93.1",
|
||||||
"axios": "^1.13.4",
|
"axios": "^1.13.4",
|
||||||
|
"lucide-react": "^0.563.0",
|
||||||
"next": "16.1.1",
|
"next": "16.1.1",
|
||||||
"react": "19.2.3",
|
"react": "19.2.3",
|
||||||
"react-dom": "19.2.3",
|
"react-dom": "19.2.3",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,15 @@ import useSWR from 'swr';
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import api from "@/lib/axios";
|
import api from "@/lib/axios";
|
||||||
import { useAuth } from "@/contexts/AuthContext";
|
import { useAuth } from "@/contexts/AuthContext";
|
||||||
|
import AccountSettingsDropdown from "@/components/AccountSettingsDropdown";
|
||||||
|
import {
|
||||||
|
ArrowLeft,
|
||||||
|
RotateCcw,
|
||||||
|
LogOut,
|
||||||
|
QrCode,
|
||||||
|
Rocket,
|
||||||
|
Clock,
|
||||||
|
} from "lucide-react";
|
||||||
|
|
||||||
// SWR fetcher 使用 axios(自动处理 401/403)
|
// SWR fetcher 使用 axios(自动处理 401/403)
|
||||||
const fetcher = (url: string) => api.get(url).then((res) => res.data);
|
const fetcher = (url: string) => api.get(url).then((res) => res.data);
|
||||||
@@ -63,6 +72,14 @@ export default function PublishPage() {
|
|||||||
fetchVideos();
|
fetchVideos();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (typeof window === 'undefined') return;
|
||||||
|
if ('scrollRestoration' in window.history) {
|
||||||
|
window.history.scrollRestoration = 'manual';
|
||||||
|
}
|
||||||
|
window.scrollTo({ top: 0, left: 0, behavior: 'auto' });
|
||||||
|
}, []);
|
||||||
|
|
||||||
// 获取存储 key 的前缀(登录用户使用 userId,未登录使用 guest)
|
// 获取存储 key 的前缀(登录用户使用 userId,未登录使用 guest)
|
||||||
const storageKey = userId || 'guest';
|
const storageKey = userId || 'guest';
|
||||||
|
|
||||||
@@ -296,7 +313,7 @@ export default function PublishPage() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Header - 统一样式 */}
|
{/* Header - 统一样式 */}
|
||||||
<header className="border-b border-white/10 bg-black/20 backdrop-blur-sm">
|
<header className="border-b border-white/10 bg-black/20 backdrop-blur-sm relative z-[100]">
|
||||||
<div className="max-w-6xl mx-auto px-4 sm:px-6 py-3 sm:py-4 flex items-center justify-between">
|
<div className="max-w-6xl mx-auto px-4 sm:px-6 py-3 sm:py-4 flex items-center justify-between">
|
||||||
<Link href="/" className="text-xl sm:text-2xl font-bold text-white flex items-center gap-2 sm:gap-3 hover:opacity-80 transition-opacity">
|
<Link href="/" className="text-xl sm:text-2xl font-bold text-white flex items-center gap-2 sm:gap-3 hover:opacity-80 transition-opacity">
|
||||||
<span className="text-3xl sm:text-4xl">🎬</span>
|
<span className="text-3xl sm:text-4xl">🎬</span>
|
||||||
@@ -305,26 +322,15 @@ export default function PublishPage() {
|
|||||||
<div className="flex items-center gap-1 sm:gap-4">
|
<div className="flex items-center gap-1 sm:gap-4">
|
||||||
<Link
|
<Link
|
||||||
href="/"
|
href="/"
|
||||||
className="px-2 sm:px-4 py-1 sm:py-2 text-sm sm:text-base bg-white/10 hover:bg-white/20 text-white rounded-lg transition-colors"
|
className="px-2 sm:px-4 py-1 sm:py-2 text-sm sm:text-base bg-white/10 hover:bg-white/20 text-white rounded-lg transition-colors flex items-center gap-1"
|
||||||
>
|
>
|
||||||
|
<ArrowLeft className="h-4 w-4" />
|
||||||
返回创作
|
返回创作
|
||||||
</Link>
|
</Link>
|
||||||
<span className="px-2 sm:px-4 py-1 sm:py-2 text-sm sm:text-base bg-gradient-to-r from-purple-600 to-pink-600 text-white rounded-lg font-semibold">
|
<span className="px-2 sm:px-4 py-1 sm:py-2 text-sm sm:text-base bg-gradient-to-r from-purple-600 to-pink-600 text-white rounded-lg font-semibold">
|
||||||
发布管理
|
发布管理
|
||||||
</span>
|
</span>
|
||||||
<button
|
<AccountSettingsDropdown />
|
||||||
onClick={async () => {
|
|
||||||
if (confirm('确定要退出登录吗?')) {
|
|
||||||
try {
|
|
||||||
await api.post('/api/auth/logout');
|
|
||||||
} catch (e) { }
|
|
||||||
window.location.href = '/login';
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
className="px-2 sm:px-4 py-1 sm:py-2 text-sm sm:text-base bg-red-500/10 hover:bg-red-500/20 text-red-200 rounded-lg transition-colors"
|
|
||||||
>
|
|
||||||
退出
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
@@ -367,23 +373,26 @@ export default function PublishPage() {
|
|||||||
<>
|
<>
|
||||||
<button
|
<button
|
||||||
onClick={() => handleLogin(account.platform)}
|
onClick={() => handleLogin(account.platform)}
|
||||||
className="px-3 py-1 bg-white/10 hover:bg-white/20 text-white text-sm rounded-lg transition-colors"
|
className="px-3 py-1 bg-white/10 hover:bg-white/20 text-white text-sm rounded-lg transition-colors flex items-center gap-1"
|
||||||
>
|
>
|
||||||
↻ 重新登录
|
<RotateCcw className="h-3.5 w-3.5" />
|
||||||
|
重新登录
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => handleLogout(account.platform)}
|
onClick={() => handleLogout(account.platform)}
|
||||||
className="px-3 py-1 bg-red-500/80 hover:bg-red-600 text-white text-sm rounded-lg transition-colors"
|
className="px-3 py-1 bg-red-500/80 hover:bg-red-600 text-white text-sm rounded-lg transition-colors flex items-center gap-1"
|
||||||
>
|
>
|
||||||
|
<LogOut className="h-3.5 w-3.5" />
|
||||||
注销
|
注销
|
||||||
</button>
|
</button>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<button
|
<button
|
||||||
onClick={() => handleLogin(account.platform)}
|
onClick={() => handleLogin(account.platform)}
|
||||||
className="px-3 py-1 bg-purple-600 hover:bg-purple-700 text-white text-sm rounded-lg transition-colors"
|
className="px-3 py-1 bg-purple-600 hover:bg-purple-700 text-white text-sm rounded-lg transition-colors flex items-center gap-1"
|
||||||
>
|
>
|
||||||
🔐 扫码登录
|
<QrCode className="h-3.5 w-3.5" />
|
||||||
|
扫码登录
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -496,25 +505,33 @@ export default function PublishPage() {
|
|||||||
handlePublish();
|
handlePublish();
|
||||||
}}
|
}}
|
||||||
disabled={isPublishing || selectedPlatforms.length === 0}
|
disabled={isPublishing || selectedPlatforms.length === 0}
|
||||||
className={`flex-[3] py-4 rounded-xl font-bold text-lg transition-all ${isPublishing || selectedPlatforms.length === 0
|
className={`flex-[3] py-4 rounded-xl font-bold text-lg transition-all flex items-center justify-center gap-2 ${isPublishing || selectedPlatforms.length === 0
|
||||||
? "bg-gray-600 cursor-not-allowed text-gray-400"
|
? "bg-gray-600 cursor-not-allowed text-gray-400"
|
||||||
: "bg-gradient-to-r from-green-600 to-teal-600 hover:from-green-700 hover:to-teal-700 text-white"
|
: "bg-gradient-to-r from-green-600 to-teal-600 hover:from-green-700 hover:to-teal-700 text-white"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{isPublishing && scheduleMode === "now" ? "发布中..." : "🚀 立即发布"}
|
{isPublishing && scheduleMode === "now" ? (
|
||||||
|
"发布中..."
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<Rocket className="h-5 w-5" />
|
||||||
|
立即发布
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</button>
|
</button>
|
||||||
{/* 定时发布 - 占 1/4 */}
|
{/* 定时发布 - 占 1/4 */}
|
||||||
<button
|
<button
|
||||||
onClick={() => setScheduleMode(scheduleMode === "scheduled" ? "now" : "scheduled")}
|
onClick={() => setScheduleMode(scheduleMode === "scheduled" ? "now" : "scheduled")}
|
||||||
disabled={isPublishing || selectedPlatforms.length === 0}
|
disabled={isPublishing || selectedPlatforms.length === 0}
|
||||||
className={`flex-1 py-4 rounded-xl font-bold text-base transition-all ${isPublishing || selectedPlatforms.length === 0
|
className={`flex-1 py-4 rounded-xl font-bold text-base transition-all flex items-center justify-center gap-2 ${isPublishing || selectedPlatforms.length === 0
|
||||||
? "bg-gray-600 cursor-not-allowed text-gray-400"
|
? "bg-gray-600 cursor-not-allowed text-gray-400"
|
||||||
: scheduleMode === "scheduled"
|
: scheduleMode === "scheduled"
|
||||||
? "bg-purple-600 text-white"
|
? "bg-purple-600 text-white"
|
||||||
: "bg-white/10 hover:bg-white/20 text-white"
|
: "bg-white/10 hover:bg-white/20 text-white"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
⏰ 定时
|
<Clock className="h-5 w-5" />
|
||||||
|
定时
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
15
run_watchdog.sh
Normal file
15
run_watchdog.sh
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# 启动 ViGent2 服务看门狗
|
||||||
|
# 监控 Qwen-TTS and LatentSync 服务健康状态
|
||||||
|
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
|
||||||
|
# 使用 backend 的虚拟环境 Python (包含 httpx 等依赖)
|
||||||
|
PYTHON_PATH="./backend/venv/bin/python"
|
||||||
|
|
||||||
|
if [ -f "$PYTHON_PATH" ]; then
|
||||||
|
"$PYTHON_PATH" backend/scripts/watchdog.py
|
||||||
|
else
|
||||||
|
echo "❌ 错误: 找不到 Python 解释器: $PYTHON_PATH"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
Reference in New Issue
Block a user