# 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` ```python # 升级前 MODEL_PATH = Path(__file__).parent / "checkpoints" / "0.6B-Base" # 升级后 MODEL_PATH = Path(__file__).parent / "checkpoints" / "1.7B-Base" ``` ### 模型下载 ```bash 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` 优化内容: - 调整高亮颜色配置 - 优化文字描边效果(多层阴影) - 调整字间距和行高 ```typescript export const Subtitles: React.FC = ({ 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` 优化内容: - 淡入淡出动画效果 - 下滑入场动画 - 可配置显示时长 ```typescript 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` ```python 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` ```python 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 按钮 ```tsx ``` #### 处理逻辑 ```typescript 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 生成的标题和标签: ```typescript // 恢复标题和标签 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. 认证状态恢复失败时,`userId` 为 `null` 2. 原代码判断 `!userId` 后用默认值覆盖 localStorage 数据 3. 导致已保存的用户数据被清空 ### 解决方案 **文件**: `frontend/src/app/page.tsx` #### 1. 添加恢复完成标志 ```typescript const [isRestored, setIsRestored] = useState(false); ``` #### 2. 等待认证完成后恢复数据 ```typescript 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. 恢复完成后才保存 ```typescript useEffect(() => { if (isRestored) { localStorage.setItem(`vigent_${storageKey}_text`, text); } }, [text, storageKey, isRestored]); ``` ### 用户隔离机制 ```typescript 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/lib/axios.ts` 在拦截器中对公开路由跳过重定向,仅在受保护页面触发登录跳转: ```typescript 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/lib/axios.ts` | 修改 | 公开路由跳过 401/403 登录重定向 | --- ## 🔗 相关文档 - [task_complete.md](../task_complete.md) - 任务总览 - [Day13.md](./Day13.md) - 声音克隆功能集成 + 字幕功能 - [QWEN3_TTS_DEPLOY.md](../QWEN3_TTS_DEPLOY.md) - Qwen3-TTS 1.7B 部署指南