Files
ViGent2/Docs/DevLogs/Day14.md
Kevin Wong e226224119 更新
2026-02-08 19:54:11 +08:00

9.6 KiB
Raw Blame History

Day 14 - 模型升级 + 标题标签生成 + 前端修复

日期2026-01-30


🚀 Qwen3-TTS 模型升级 (0.6B → 1.7B)

背景

为提升声音克隆质量,将 Qwen3-TTS 模型从 0.6B-Base 升级到 1.7B-Base。

变更内容

项目 升级前 升级后
模型 0.6B-Base 1.7B-Base
大小 2.4GB 6.8GB
质量 基础 更高质量

代码修改

文件: models/Qwen3-TTS/qwen_tts_server.py

# 升级前
MODEL_PATH = Path(__file__).parent / "checkpoints" / "0.6B-Base"

# 升级后
MODEL_PATH = Path(__file__).parent / "checkpoints" / "1.7B-Base"

模型下载

cd /home/rongye/ProgramFiles/ViGent2/models/Qwen3-TTS

# 下载 1.7B-Base 模型 (6.8GB)
modelscope download --model Qwen/Qwen3-TTS-12Hz-1.7B-Base --local_dir ./checkpoints/1.7B-Base

结果

  • 模型加载正常 (GPU0, bfloat16)
  • 声音克隆质量提升
  • 推理速度可接受

🎨 标题和字幕显示优化

字幕组件优化 (Subtitles.tsx)

文件: remotion/src/components/Subtitles.tsx

优化内容:

  • 调整高亮颜色配置
  • 优化文字描边效果(多层阴影)
  • 调整字间距和行高
export const Subtitles: React.FC<SubtitlesProps> = ({
  captions,
  highlightColor = '#FFFF00',  // 高亮颜色
  normalColor = '#FFFFFF',      // 普通文字颜色
  fontSize = 52,
}) => {
  // 样式优化
  const style = {
    textShadow: `
      2px 2px 4px rgba(0,0,0,0.8),
      -2px -2px 4px rgba(0,0,0,0.8),
      ...
    `,
    letterSpacing: '2px',
    lineHeight: 1.4,
    maxWidth: '90%',
  };
};

标题组件优化 (Title.tsx)

文件: remotion/src/components/Title.tsx

优化内容:

  • 淡入淡出动画效果
  • 下滑入场动画
  • 可配置显示时长
interface TitleProps {
  title: string;
  duration?: number;        // 标题显示时长默认3秒
  fadeOutStart?: number;    // 开始淡出的时间默认2秒
}

// 动画效果
// 淡入0-0.5 秒
// 淡出2-3 秒
// 下滑0-0.5 秒,-20px → 0px

结果

  • 字幕显示更清晰
  • 标题动画更流畅

🤖 标题标签自动生成功能

功能描述

使用 AI智谱 GLM-4-Flash根据口播文案自动生成视频标题和标签。

后端实现

1. GLM 服务 (glm_service.py)

文件: backend/app/services/glm_service.py

class GLMService:
    """智谱 GLM AI 服务"""

    async def generate_meta(self, text: str) -> dict:
        """根据文案生成标题和标签"""

        prompt = """根据以下口播文案生成一个吸引人的短视频标题和3个相关标签。

要求:
1. 标题要简洁有力能吸引观众点击不超过10个字
2. 标签要与内容相关便于搜索和推荐只要3个

返回格式:{"title": "标题", "tags": ["标签1", "标签2", "标签3"]}
"""
        # 调用 GLM-4-Flash API
        response = await self._call_api(prompt + text)
        return self._parse_json(response)

JSON 解析容错

  • 支持直接 JSON 解析
  • 支持提取 JSON 块
  • 支持 ```json 代码块提取

2. API 端点 (ai.py)

文件: backend/app/api/ai.py

from pydantic import BaseModel

class GenerateMetaRequest(BaseModel):
    text: str  # 口播文案

class GenerateMetaResponse(BaseModel):
    title: str        # 生成的标题
    tags: list[str]   # 生成的标签列表

@router.post("/generate-meta", response_model=GenerateMetaResponse)
async def generate_meta(request: GenerateMetaRequest):
    """AI 生成标题和标签"""
    result = await glm_service.generate_meta(request.text)
    return result

前端实现

文件: frontend/src/app/page.tsx

UI 按钮

<button
  onClick={handleGenerateMeta}
  disabled={isGeneratingMeta || !text.trim()}
  className="px-2 py-1 text-xs rounded transition-all whitespace-nowrap"
>
  {isGeneratingMeta ? "⏳ 生成中..." : "🤖 AI生成标题标签"}
</button>

处理逻辑

const handleGenerateMeta = async () => {
  if (!text.trim()) {
    alert("请先输入口播文案");
    return;
  }

  setIsGeneratingMeta(true);
  try {
    const { data } = await api.post('/api/ai/generate-meta', { text: text.trim() });

    // 更新首页标题
    setVideoTitle(data.title || "");

    // 同步到发布页 localStorage
    localStorage.setItem(`vigent_${storageKey}_publish_title`, data.title || "");
    localStorage.setItem(`vigent_${storageKey}_publish_tags`, JSON.stringify(data.tags || []));
  } catch (err: any) {
    alert(`AI 生成失败: ${err.message}`);
  } finally {
    setIsGeneratingMeta(false);
  }
};

发布页集成

文件: frontend/src/app/publish/page.tsx

从 localStorage 恢复 AI 生成的标题和标签:

// 恢复标题和标签
const savedTitle = localStorage.getItem(`vigent_${storageKey}_publish_title`);
const savedTags = localStorage.getItem(`vigent_${storageKey}_publish_tags`);

if (savedTags) {
  try {
    const parsed = JSON.parse(savedTags);
    if (Array.isArray(parsed)) {
      setTags(parsed.join(', '));  // 数组转逗号分隔字符串
    } else {
      setTags(savedTags);
    }
  } catch {
    setTags(savedTags);
  }
}

结果

  • AI 生成标题和标签功能正常
  • 数据自动同步到发布页
  • 支持 JSON 数组和字符串格式兼容

🐛 前端文本保存问题修复

问题描述

现象:页面刷新后,用户输入的文案、标题等数据丢失

原因

  1. 认证状态恢复失败时,userIdnull
  2. 原代码判断 !userId 后用默认值覆盖 localStorage 数据
  3. 导致已保存的用户数据被清空

解决方案

文件: frontend/src/app/page.tsx

1. 添加恢复完成标志

const [isRestored, setIsRestored] = useState(false);

2. 等待认证完成后恢复数据

useEffect(() => {
  if (isAuthLoading) return;  // 等待认证完成

  // 使用 userId 或 'guest' 作为 key
  const key = userId || 'guest';

  // 从 localStorage 恢复数据
  const savedText = localStorage.getItem(`vigent_${key}_text`);
  if (savedText) setText(savedText);

  // ... 恢复其他数据

  setIsRestored(true);  // 标记恢复完成
}, [userId, isAuthLoading]);

3. 恢复完成后才保存

useEffect(() => {
  if (isRestored) {
    localStorage.setItem(`vigent_${storageKey}_text`, text);
  }
}, [text, storageKey, isRestored]);

用户隔离机制

const storageKey = userId || 'guest';
用户状态 storageKey 说明
已登录 user_xxx 数据按用户隔离
未登录/认证失败 guest 使用统一 key

数据恢复流程

1. 页面加载
   ↓
2. 检查 isAuthLoading
   ├─ true: 等待认证完成
   └─ false: 继续
   ↓
3. 确定 storageKey (userId || 'guest')
   ↓
4. 从 localStorage 读取数据
   ├─ 有保存数据: 恢复到状态
   └─ 无保存数据: 使用默认值
   ↓
5. 设置 isRestored = true
   ↓
6. 后续状态变化时保存到 localStorage

保存的数据项

Key 说明
vigent_${key}_text 口播文案
vigent_${key}_title 视频标题
vigent_${key}_subtitles 字幕开关
vigent_${key}_ttsMode TTS 模式
vigent_${key}_voice 选择的音色
vigent_${key}_material 选择的素材
vigent_${key}_publish_title 发布标题
vigent_${key}_publish_tags 发布标签

结果

  • 页面刷新后数据正常恢复
  • 认证失败时不会覆盖已保存数据
  • 多用户数据隔离正常

🐛 登录页刷新循环修复

问题描述

现象:登录页未登录时不断刷新,无法停留在表单页面。

原因

  1. AuthProvider 初始化时调用 /api/auth/me
  2. 未登录返回 401
  3. axios 全局拦截器遇到 401/403 重定向 /login
  4. 登录页本身也在 Provider 中,导致循环刷新

解决方案

文件: frontend/src/shared/api/axios.ts

在拦截器中对公开路由跳过重定向,仅在受保护页面触发登录跳转:

const PUBLIC_PATHS = new Set(['/login', '/register']);
const isPublicPath = typeof window !== 'undefined' && PUBLIC_PATHS.has(window.location.pathname);

if ((status === 401 || status === 403) && !isRedirecting && !isPublicPath) {
  // ... 保持原有重定向逻辑
}

结果

  • 登录页不再刷新,表单可正常输入
  • 受保护页面仍会在 401/403 时跳转登录页

📁 今日修改文件清单

文件 变更类型 说明
models/Qwen3-TTS/qwen_tts_server.py 修改 模型路径升级到 1.7B-Base
Docs/QWEN3_TTS_DEPLOY.md 修改 更新部署文档为 1.7B 版本
remotion/src/components/Subtitles.tsx 修改 优化字幕显示效果
remotion/src/components/Title.tsx 修改 优化标题动画效果
backend/app/services/glm_service.py 新增 GLM AI 服务
backend/app/api/ai.py 新增 AI 生成标题标签 API
backend/app/main.py 修改 注册 ai 路由
frontend/src/app/page.tsx 修改 AI 生成按钮 + localStorage 修复
frontend/src/app/publish/page.tsx 修改 恢复 AI 生成的标签
frontend/src/shared/api/axios.ts 修改 公开路由跳过 401/403 登录重定向

🔗 相关文档