尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

3小时用GLM-5全栈长任务复刻TikTok视频生成SaaS平台

3小时用GLM-5全栈长任务复刻TikTok视频生成SaaS平台 1. 项目缘起当“全栈长任务”遇上“视频生成SaaS”最近GLM-5的“全栈长任务”能力在开发者圈子里讨论得挺火。简单来说它不再是一个只能帮你写几行代码或者润色一段文案的“小助手”而是能理解一个复杂的、多步骤的工程目标并自主规划、调用工具、编写代码最终交付一个可运行的项目。这听起来有点像给了一个能独立完成外包项目的“数字员工”。正好我手头有个一直想验证的想法能不能快速搭建一个类似TikTok风格的短视频生成SaaS平台不是那种简单的模板套用而是包含用户上传素材、AI脚本生成、视频剪辑合成、任务队列管理、用户订阅付费等完整前后端逻辑的“玩具级”但“全功能”系统。传统的做法从技术选型、架构设计、前后端开发、第三方API集成到部署上线一个熟练的全栈工程师也得花上几天甚至一周。这次我想用GLM-5的“全栈长任务”能力来挑战一下看看它能否在3小时内从零开始帮我“复刻”出这个SaaS的核心骨架。我选择的武器库是当前非常流行的技术栈前端用Next.js兼顾SEO和开发体验后端用FastAPIPython异步框架适合AI应用数据库用PostgreSQL视频处理用FFmpeg再结合一些AI服务API。整个过程我将扮演“产品经理”和“架构评审”的角色主要向GLM-5描述需求、审核代码、解决它遇到的“卡点”。下面我就把这3小时的实战过程、核心代码、踩过的坑以及最终的成果完整地记录下来。2. 任务拆解与GLM-5的“思考”过程一开始我并没有直接扔给GLM-5一个“做个TikTok SaaS”的模糊指令。根据以往与AI协作的经验任务的拆解质量直接决定了最终输出的质量。我首先用自然语言向GLM-5描述了项目的核心目标“请构建一个短视频生成SaaS平台的最小可行产品MVP。核心功能包括1. 用户可注册登录并管理订阅套餐基础版、高级版。2. 用户上传图片/短视频片段作为素材并输入文本描述如‘生成一个关于夏日旅行的快节奏视频’。3. 后端接收任务后将其放入队列模拟调用AI服务实际可接入如GPT for script Stable Diffusion for image, 或RunwayML for video生成视频脚本并调用FFmpeg将用户素材与生成的元素如字幕、背景音乐合成为新视频。4. 用户可在前端查看任务列表、状态及下载生成的视频。技术栈前端Next.js 14 (App Router), Tailwind CSS后端FastAPI数据库PostgreSQL with SQLAlchemy消息队列Redis用于Celery对象存储模拟使用本地目录。请从项目初始化开始生成完整的、可运行的代码目录结构、关键逻辑代码、数据库模型、API接口以及基础的UI组件。”发出这个指令后我观察了GLM-5的“思考”过程在一些平台上会显示它的推理链。它并没有立即开始写代码而是先输出了一个项目架构规划整体架构前后端分离。Next.js应用作为前端兼API路由可处理简单逻辑核心后端服务为FastAPI。两者通过RESTful API通信。数据流用户从前端提交任务 - FastAPI创建任务记录并发送到Redis队列 - Celery worker从队列取出任务执行“视频生成”模拟逻辑 - 更新任务状态和结果文件路径 - 前端通过轮询或WebSocket获取状态更新。核心目录结构video-saas-platform/ ├── frontend/ # Next.js 14 应用 │ ├── app/ # App Router │ ├── components/ # 可复用组件 │ ├── lib/ # 工具函数API客户端 │ └── ... ├── backend/ # FastAPI 应用 │ ├── app/ │ │ ├── api/ # 路由端点 │ │ ├── core/ # 配置、安全 │ │ ├── models/ # SQLAlchemy 模型 │ │ ├── schemas/ # Pydantic 模型 │ │ ├── services/ # 业务逻辑 │ │ └── workers/ # Celery 任务定义 │ ├── requirements.txt │ └── ... ├── docker-compose.yml # 用于启动PostgreSQL, Redis └── README.md分阶段实施它建议先搭建后端核心数据模型和API再实现Celery异步任务最后开发前端页面并与后端联调。这个规划相当专业甚至考虑到了开发顺序减少了模块间的耦合。我认可了这个方案并让它开始执行。3. 后端核心FastAPI模型、API与异步任务搭建GLM-5首先从后端开始。它并没有一次性生成所有文件而是按模块生成并附上简要说明。3.1 数据模型与Pydantic模式定义它首先创建了backend/app/models.py和backend/app/schemas.py。模型设计紧扣我们的需求# backend/app/models.py from sqlalchemy import Column, Integer, String, Boolean, DateTime, Enum, ForeignKey from sqlalchemy.orm import relationship from sqlalchemy.sql import func import enum from app.core.database import Base class SubscriptionTier(str, enum.Enum): BASIC basic PREMIUM premium class User(Base): __tablename__ users id Column(Integer, primary_keyTrue, indexTrue) email Column(String, uniqueTrue, indexTrue, nullableFalse) hashed_password Column(String, nullableFalse) subscription_tier Column(Enum(SubscriptionTier), defaultSubscriptionTier.BASIC) is_active Column(Boolean, defaultTrue) created_at Column(DateTime(timezoneTrue), server_defaultfunc.now()) tasks relationship(VideoTask, back_populatesowner) class VideoTaskStatus(str, enum.Enum): PENDING pending PROCESSING processing COMPLETED completed FAILED failed class VideoTask(Base): __tablename__ video_tasks id Column(Integer, primary_keyTrue, indexTrue) user_id Column(Integer, ForeignKey(users.id)) title Column(String, indexTrue) description Column(String) # 用户输入的描述 status Column(Enum(VideoTaskStatus), defaultVideoTaskStatus.PENDING) source_files_path Column(String) # 上传的素材路径JSON字符串存储 output_video_path Column(String, nullableTrue) error_message Column(String, nullableTrue) created_at Column(DateTime(timezoneTrue), server_defaultfunc.now()) updated_at Column(DateTime(timezoneTrue), onupdatefunc.now()) owner relationship(User, back_populatestasks)同时它生成了对应的Pydantic模式用于API请求/响应验证并巧妙地处理了关系字段和枚举。例如在VideoTaskCreate模式中它排除了user_id从token获取和status等字段确保了API的安全性。3.2 核心API端点实现接下来是backend/app/api/endpoints下的路由。GLM-5生成的代码不仅结构清晰还包含了JWT认证、依赖注入等生产级实践。以创建视频任务端点为例# backend/app/api/endpoints/tasks.py from fastapi import APIRouter, Depends, HTTPException, BackgroundTasks from sqlalchemy.orm import Session from app import crud, schemas, models from app.api import deps from app.workers.tasks import process_video_task router APIRouter() router.post(/, response_modelschemas.VideoTask) def create_video_task( *, db: Session Depends(deps.get_db), task_in: schemas.VideoTaskCreate, current_user: models.User Depends(deps.get_current_active_user), background_tasks: BackgroundTasks, ): 创建新的视频生成任务。 1. 检查用户订阅状态是否允许创建新任务此处简化。 2. 将任务信息存入数据库状态为PENDING。 3. 将任务ID加入后台处理队列。 # 此处可添加业务逻辑如检查用户套餐并发任务数限制 task crud.video_task.create_with_owner(dbdb, obj_intask_in, owner_idcurrent_user.id) # 使用BackgroundTasks实现简易异步适用于轻量任务生产环境应用Celery # background_tasks.add_task(process_video_task, task_idtask.id) # 但我们计划用Celery所以这里仅记录日志并通过API触发Celery任务 return task这里出现了一个关键决策点GLM-5最初使用了FastAPI的BackgroundTasks但我在审核时指出视频生成是重CPU/IO操作BackgroundTasks适用于短时任务且与进程绑定不适合生产环境。GLM-5立刻理解了问题并修改了方案转向实现Celery。3.3 Celery异步任务与“视频生成”模拟这是后端最核心的部分。GLM-5创建了backend/app/workers/celery_app.py来配置Celery以及backend/app/workers/tasks.py来定义任务。# backend/app/workers/tasks.py import time import json import subprocess import shutil from pathlib import Path from celery import Celery from app.core.config import settings from app.core.database import SessionLocal from app import crud, models celery_app Celery(worker, brokersettings.REDIS_URL, backendsettings.REDIS_URL) celery_app.task(bindTrue, nameprocess_video_task) def process_video_task(self, task_id: int): 模拟视频生成任务。 实际场景中这里会 1. 调用AI API生成脚本/图/视频。 2. 使用FFmpeg进行复杂的音视频合成。 此处我们模拟耗时过程并生成一个假的视频文件。 db SessionLocal() try: task crud.video_task.get(db, idtask_id) if not task: self.update_state(stateFAILED, meta{error: Task not found}) return # 更新状态为处理中 task crud.video_task.update_status(db, db_objtask, statusmodels.VideoTaskStatus.PROCESSING) db.commit() # 模拟AI处理时间 time.sleep(10) # 模拟调用AI服务生成脚本 # 模拟视频合成这里只是用FFmpeg创建一个简单的测试视频 # 假设用户上传的素材路径是一个包含文件路径的JSON数组 source_files json.loads(task.source_files_path) if task.source_files_path else [] output_dir Path(settings.OUTPUT_VIDEO_DIR) / str(task.user_id) output_dir.mkdir(parentsTrue, exist_okTrue) output_path output_dir / ftask_{task_id}_output.mp4 # 使用FFmpeg创建一个带字幕的测试视频如果系统安装了ffmpeg # 这是一个非常简化的示例实际合成逻辑极其复杂 test_video_path /tmp/test_input.mp4 # 先创建一个测试用的视频文件如果没有的话 if not Path(test_video_path).exists(): # 使用FFmpeg生成一个5秒的测试视频 cmd [ ffmpeg, -f, lavfi, -i, testsrcduration5:size640x480:rate30, -vf, drawtexttextGenerated by SaaS:fontcolorwhite:fontsize24:x(w-text_w)/2:y(h-text_h)/2, -c:v, libx264, -pix_fmt, yuv420p, str(test_video_path) ] subprocess.run(cmd, capture_outputTrue) # 模拟复制“生成”的视频到输出目录 shutil.copy(test_video_path, output_path) # 更新任务状态和输出路径 task crud.video_task.update_on_success( db, db_objtask, statusmodels.VideoTaskStatus.COMPLETED, output_video_pathstr(output_path) ) db.commit() return {task_id: task.id, status: task.status, output_path: task.output_video_path} except Exception as e: # 更新任务状态为失败 if task in locals() and task: task crud.video_task.update_on_failure(db, db_objtask, error_messagestr(e)) db.commit() self.update_state(stateFAILED, meta{error: str(e)}) raise finally: db.close()这段代码的亮点在于它没有停留在“打印日志”的模拟层面而是真实地使用了FFmpeg命令来生成一个带测试图案和文字的视频文件并将文件保存到指定目录。这极大地提升了Demo的真实感也为我后续接入真正的AI视频生成API铺平了道路。同时它完整实现了任务状态的生命周期管理PENDING - PROCESSING - COMPLETED/FAILED并考虑了异常处理和数据回滚。4. 前端实现Next.js与Tailwind构建用户界面后端API就绪后GLM-5开始转向前端。它使用Next.js 14的App Router并采用了服务端组件Server Components和客户端组件Client Components混合的模式这是当前比较推荐的做法。4.1 项目初始化与API客户端它首先生成了frontend/lib/api-client.ts使用axios封装了与后端的通信并统一处理了错误和请求头如添加JWT Token。// frontend/lib/api-client.ts import axios from axios; const apiClient axios.create({ baseURL: process.env.NEXT_PUBLIC_API_URL || http://localhost:8000/api/v1, headers: { Content-Type: application/json, }, }); // 请求拦截器用于添加认证token apiClient.interceptors.request.use( (config) { const token localStorage.getItem(access_token); // 注意服务端组件中不能直接用localStorage if (token) { config.headers.Authorization Bearer ${token}; } return config; }, (error) { return Promise.reject(error); } ); // ... 响应拦截器处理错误这里它留下了一个注意点在Next.js服务端组件中无法直接访问localStorage。它随后在需要认证的客户端组件中通过useEffect和状态来安全地获取token。4.2 核心页面任务创建与列表任务创建页面 (frontend/app/dashboard/tasks/new/page.tsx) 被设计为一个客户端组件。GLM-5生成了一个包含文件上传使用input typefile并配合FormData、标题和描述输入的表单。// 部分代码示例 use client; import { useState } from react; import { useRouter } from next/navigation; export default function NewTaskPage() { const [files, setFiles] useStateFile[]([]); const [uploading, setUploading] useState(false); const router useRouter(); const handleFileChange (e: React.ChangeEventHTMLInputElement) { if (e.target.files) { setFiles(Array.from(e.target.files)); } }; const handleSubmit async (formData: FormData) { setUploading(true); try { // 1. 先上传文件到后端的上传接口获取文件路径 const filePaths await uploadFiles(files); // 2. 创建任务将文件路径等信息提交 const taskData { title: formData.get(title), description: formData.get(description), source_files_path: JSON.stringify(filePaths) }; await apiClient.post(/tasks/, taskData); router.push(/dashboard/tasks); } catch (error) { alert(创建失败); } finally { setUploading(false); } }; // ... JSX渲染表单 }任务列表页面 (frontend/app/dashboard/tasks/page.tsx) 则被设计为服务端组件初始数据在服务端获取以提高首屏加载速度。同时它包含了一个客户端组件TaskList用于实现轮询以更新任务状态。// frontend/app/dashboard/tasks/page.tsx (服务端组件) import { apiClient } from /lib/api-client; import TaskList from ./TaskList; // 客户端组件 export default async function TasksPage() { // 在服务端获取初始任务列表 const initialTasks await getTasksFromServer(); return ( div h1我的视频任务/h1 {/* 将初始数据传递给客户端组件 */} TaskList initialTasks{initialTasks} / /div ); } // frontend/app/dashboard/tasks/TaskList.tsx (客户端组件) use client; import { useEffect, useState } from react; import { pollTaskStatus } from ./actions; // 模拟轮询动作 export default function TaskList({ initialTasks }) { const [tasks, setTasks] useState(initialTasks); useEffect(() { const intervalId setInterval(async () { // 仅轮询处理中的任务 const processingTasks tasks.filter(t t.status processing); for (const task of processingTasks) { const updatedTask await pollTaskStatus(task.id); // 更新状态... } }, 5000); // 每5秒轮询一次 return () clearInterval(intervalId); }, [tasks]); // ... 渲染任务列表 }这种混合架构的运用显示了GLM-5对现代前端框架最佳实践的了解。4.3 文件上传与“模拟对象存储”文件上传是一个关键且容易出错的点。GLM-5在后端实现了一个专门的上传端点接收multipart/form-data将文件保存到服务器本地目录模拟对象存储并返回文件的访问路径。它甚至考虑了文件类型验证、大小限制和防止文件名冲突。# backend/app/api/endpoints/uploads.py router.post(/) async def upload_file( file: UploadFile File(...), current_user: models.User Depends(deps.get_current_active_user), ): # 检查文件类型 allowed_types [image/jpeg, image/png, video/mp4, video/quicktime] if file.content_type not in allowed_types: raise HTTPException(status_code400, detailFile type not allowed) # 生成唯一文件名 file_extension Path(file.filename).suffix unique_filename f{uuid.uuid4()}{file_extension} user_upload_dir UPLOAD_DIR / str(current_user.id) user_upload_dir.mkdir(parentsTrue, exist_okTrue) file_location user_upload_dir / unique_filename # 异步写入文件 async with aiofiles.open(file_location, wb) as f: content await file.read() await f.write(content) # 返回相对路径便于存储到数据库 return {file_path: str(file_location.relative_to(UPLOAD_DIR))}5. 集成、部署与实测中的“坑”当所有代码生成完毕GLM-5还生成了docker-compose.yml用于一键启动PostgreSQL和Redis以及详细的README.md说明如何安装依赖、设置环境变量和运行项目。在按照指引启动服务后我进行了一次端到端的测试。整个过程基本顺畅但也遇到了几个需要人工干预的“坑”环境变量缺失GLM-5生成的.env.example文件很全但.env需要自己创建并填写。它没有自动生成包含随机密钥的.env文件。这是一个安全上的好习惯但需要手动操作。FFmpeg依赖后端Celery任务中使用了FFmpeg命令。如果宿主机没有安装FFmpeg任务会失败。GLM-5在README中提到了这一点但更好的做法是在Dockerfile中安装FFmpeg或者使用包含FFmpeg的Python基础镜像。跨域问题CORS前端运行在localhost:3000后端在localhost:8000直接请求会触发CORS错误。GLM-5在后端代码中已经配置了CORS中间件但需要我确认前端NEXT_PUBLIC_API_URL环境变量设置正确并且后端CORS允许了前端的源。前端Token管理如前所述服务端组件中无法使用localStorage。GLM-5的解决方案是在客户端组件中通过useEffect获取这可行。但对于更复杂的应用可能需要引入状态管理如Zustand或考虑使用Next.js的中间件进行服务端认证。在解决了上述问题后我成功完成了整个流程注册用户 - 登录 - 上传一个视频片段 - 创建视频生成任务 - 在任务列表看到任务状态从“pending”变为“processing”最后变为“completed” - 点击下载链接成功获取到那个由FFmpeg生成的、带有“Generated by SaaS”文字的水印测试视频。6. 总结与对“全栈长任务”能力的思考整个项目从发出指令到最终跑通耗时大约2小时50分钟基本符合“3小时复刻”的目标。最终得到的不是一个“玩具”而是一个架构清晰、代码规范、具备核心业务流程、可扩展的SaaS平台原型。它包含了用户系统、异步任务队列、文件上传、基础的前后端交互甚至还有简单的“视频生成”模拟。通过这次实测我对GLM-5的“全栈长任务”能力有了几点深刻体会优势明显宏观架构能力它能理解一个复杂项目的全貌并做出合理的技术选型和模块划分。代码生成质量高生成的代码不仅仅是语法正确还遵循了常见的框架最佳实践如FastAPI的依赖注入、SQLAlchemy ORM模式、Next.js的混合渲染。上下文关联性强在编写前端组件时它能记住并调用之前生成的后端API接口和数据模式保持前后端数据格式的一致性。解决问题的能力当我在审核中指出使用BackgroundTasks的局限性时它能迅速理解问题并切换到更合适的Celery方案。当前的局限与人的价值环境与部署细节它擅长生成应用代码但对运行环境的具体配置如系统级依赖FFmpeg、Docker网络配置、生产环境Web服务器配置考虑不够周全需要开发者查漏补缺。复杂业务逻辑对于极其复杂的业务规则如不同订阅套餐的精确算费、视频合成的复杂算法它只能生成框架和模拟代码核心算法仍需人工实现或集成专业服务。调试与排错当集成运行出现错误时如上述的CORS问题它无法主动运行和调试需要开发者根据错误信息定位问题并可能需要对它生成的代码进行微调。总而言之GLM-5的“全栈长任务”能力像一个经验丰富、出活极快、但需要明确指导和最终质量把关的高级编程助手。它极大地压缩了从想法到原型的时间将开发者从大量的样板代码和基础架构搭建中解放出来使其能更专注于核心业务创新和复杂问题解决。对于想快速验证想法、构建MVP的独立开发者或小团队来说这无疑是一个革命性的工具。这次“3小时复刻TikTok视频生成SaaS”的挑战成功验证了这一点。下一步我可以在这个原型的基础上轻松地替换掉模拟的FFmpeg命令接入真正的AI视频生成API比如RunwayML或Pika Labs的接口一个真正的AI视频生成SaaS就初具雏形了。
返回列表