跳到主要内容
极客日志极客日志
首页博客AI提示词GitHub精选代理工具
搜索
|注册
博客列表
PythonAI

基于 Coze 构建 AI 应用:从智能体开发到 Web 部署

综述由AI生成Coze 平台提供低代码 AI 应用开发能力,涵盖智能体构建、工作流编排及知识库集成。如何从零搭建智能体,利用插件与数据库增强功能,并通过 API 与 Python SDK 将工作流封装为 Web 服务。结合实际案例演示了视频生成应用的完整部署流程,包括后端逻辑、前端交互及环境配置,帮助开发者快速实现 AI 业务落地。

Ne0发布于 2026/3/16更新于 2026/4/251 浏览
基于 Coze 构建 AI 应用:从智能体开发到 Web 部署

一、Coze 简介

1.1 什么是 Coze?

Coze 是字节跳动开发的 AI Agent 平台,作为一款人工智能开发工具,它可以帮助开发者通过低代码甚至零代码的方式快速构建应用程序。此外还提供了相关的 API 和 SDK,可以集成到自己开发的项目业务中。

1.2 核心概念

  • 智能体:用户以对话的方式与 AI 进行交互,它根据用户输入,利用大模型自动调用相关的工具或流程完成特定任务,例如,可以将其构建为类似人工智能客服的对话应用。
  • 应用:在智能体的基础上包装一层外壳,即多了一个 web 页面或移动端界面。
  • 大模型:是一种基于海量数据和巨量参数构建的人工智能模型,类似一个'超级大脑'。智能体和应用的实现依赖于大模型。

大模型的缺陷

  1. 没有数据实时性:比如它无法知道今天的天气情况,无法知道今天道路的拥堵情况,无法社会的实时热点等等。
  2. '幻觉'问题:生成看似合理但完全错误或虚构的信息,包括捏造事实、引用不存在的文献、给出错误答案。
  3. 推理能力有限:在复杂逻辑推理、数学计算、因果推断和规划任务上表现不稳定,容易犯低级错误。

此外大模型还依赖于提示词,提示词的详细程度和设计质量直接影响模型输出结果是否符合预期。

Coze 的核心价值,在于为原始大模型装备了一套功能强大的'外骨骼'与'操作系统'。这个'操作系统'通过一系列工程化手段(工具扩展、流程固化、知识增强、角色设定)来引导、约束、放大和聚焦大模型的通用能力,最终创造出能够可靠、自主、高效地解决特定领域问题的智能体(AI Agent)。将大模型的'通用能力'设计成'特定能力'。

二、Coze 产品生态

  • 扣子开发平台:如同餐厅的菜谱研发部门,负责设计新菜品(智能体功能)、制定烹饪流程(工作流)和食材搭配(插件/知识库集成)。
  • 扣子罗盘:相当于餐厅的运营管理系统,实时监控订单流量(用户交互)、分析菜品受欢迎程度(智能体性能指标)、优化供应链(模型调用成本)。
  • Eino 框架:相当于餐厅的厨房基础设施,包括炉灶(核心引擎)、冷藏系统(数据存储)和排烟管道(数据流处理)。
  • 扣子空间:相当于顾客在餐厅就餐,可直接与'厨师团队'(专家 Agent)交互,直接看到后厨做菜到上菜的全过程。

扣子官方网站:https://www.coze.cn/home

三、智能体开发基础

接下来我们试着开发一个智能体,基本步骤是:创建 - 开发 - 调试 - 发布 - 优化。

图片

图片

模式选择

智能体的三种模式:

图片

目录

  1. 一、Coze 简介
  2. 1.1 什么是 Coze?
  3. 1.2 核心概念
  4. 二、Coze 产品生态
  5. 三、智能体开发基础
  6. 四、Coze 资源
  7. 4.1 插件
  8. 4.2 扣子知识库
  9. 4.3 数据库资源
  10. 五、工作流开发与发布
  11. 六、应用开发与发布
  12. 七、Coze 的 API 与 SDK
  13. 八、实战案例
  14. 加载环境变量
  15. 调用工作流生成视频
  16. 声明接口路由
  17. 访问首页
  • 💰 8折买阿里云服务器限时8折了解详情
  • 单 Agent(自主规划模式):单个智能体独立完成任务,架构简单,适用于流程固定、逻辑单一的场景。
  • 单 Agent(对话流模式):通过预设多轮对话流程引导用户完成任务,支持条件分支、上下文记忆和动态交互。它像电话里的语音客服,严格按脚本提问,引导你一步步提供信息,最后给出结果。适合流程标准化、需要引导用户的场景。
  • 多 Agents:多个智能体协同工作,从不同角度评估问题,通过协作或辩论得出更全面、更平衡的方案。适合极其复杂的任务。

提示词

  • 系统提示词:在创建智能体时由开发者设定,告诉大模型这个智能体是用来做什么的,以及设定一些技能和规则等等。
  • 用户提示词(个性化的):也在使用智能体时用户的输入,在系统提示词规则范围内才被处理。

系统提示词与用户提示词测试:

图片

这里系统提示词提供了 AI 润色,我们还可以根据需要进行修改。

开场白设置

图片

最后进行发布即可。

四、Coze 资源

4.1 插件

在 Coze 中,插件是扩展智能体功能的模块化工具,通过调用外部服务、数据接口或预设逻辑,使智能体具备实时交互、动态决策和场景化服务能力。

示例:出行规划智能体

图片

效果测试:

图片

从这个例子可以看出,AI 插件是为智能体赋予'实际行动能力'的工具,就像 AI 的'手和脚',让智能体拥有了对外执行操作的实体能力。它能打破智能体仅停留在聊天与文本生成的局限,连接真实的外部世界,执行各类具体任务。

插件分类:

  • 数据查询类:获取外部实时数据,墨迹天气、微博热点
  • 业务工具类:执行特定的功能,如生成视频、生成图片

注:有的插件可能付费,可能需要到第三方平台申请。

4.2 扣子知识库

一些私有的数据大模型是无法获取到的,如一个公司的入职指南、人员信息、财务信息,又或是老师上课做的 PPT,家里的 WiFi 密码,自己做的学习笔记等等。

而 Coze 支持导入自己私有的数据给大模型。这有什么应用场景呢?比如,新员工入职一家公司,会有一大堆问重复性的问题:

  • '公司的 Wi-Fi 密码是多少?'
  • '报销流程怎么走?需要哪些票据?'
  • '年假是怎么计算的?'
  • '公司附近有什么好吃的推荐吗?'
  • '技术文档的模板在哪里下载?'

我们可以把这些问题和答案整合一下做成一个文档,然后导入给智能体,到时候新员工直接去问智能体即可。

Coze 平台内置并深度集成了RAG能力,RAG 的全称是检索增强生成。它是一种将信息检索与大语言模型相结合的架构范式。RAG 功能主要通过'知识库'功能模块来体现。

简单来说,RAG 的工作原理就像学生在写论文前先去图书馆查资料:

  • 检索:根据问题,从一个外部知识库(如数据库、文档等)中查找最相关的信息片段。
  • 增强:将这些检索到的信息作为'参考资料'或'上下文',与用户的原始问题一起输入给大语言模型。
  • 生成:大语言模型基于这些提供的可靠'参考资料',生成更准确、更可靠的回答。

示例:这里模拟做了一个新员工入职指南

图片

新创建智能体,并把数据导入知识库,再把知识库的内容导入到智能体中。

图片

图片

此外,还可以将个人学习资料导入知识库,构建一个能够答疑和检索资料的专属学习助手。

4.3 数据库资源

Coze 数据库是字节跳动扣子平台提供的结构化数据存储服务,采用类 NoSQL 的文档模型,支持通过自然语言或 SQL 语句进行数据的增删改查操作。作为智能体的'长期记忆'组件,它能够持久化存储用户交互数据、业务配置信息和应用状态,是构建复杂 AI 应用的核心基础设施。

智能体本身有一部分记忆功能,也就是在编排中的携带上下文轮数,轮数上限通常为 100 轮,且会消耗积分,这对于需要长期记忆的应用场景来说并不方便。如下:

图片

使用数据库资源,我们就可以把数据做持久的储存,分别做分析。

示例:比如一个健身教练智能体,需要将你做的运动记录或身体状态记录下来,几个星期的,几个月的,甚至几年,这样才方便为你做出健身规划。

创建健身教练智能体

图片

图片

测试示例:

图片

除此之外数据库还有缓存的功能,把问题和答案记录下来,下次问相同的问题就不用做思考,直接从数据库中查看。

五、工作流开发与发布

什么是工作流?

是完成特定目标,而设计的一系列结构化、自动化(或半自动化)的步骤和规则。节点是工作流的最小拆分单位,它的核心包括开始节点、结束节点、大模型节点、插件节点、工作流节点,是系列指令的集合,能够处理复杂的场景。

注:可以将其理解为编程中的'函数调用',即一个工作流可以嵌套调用另一个工作流。

工作流分类

  • Workflow(工作流):面向数据自动化处理场景,通过顺序执行节点链实现特定功能,适用于标准化、批量化任务。
  • Chatflow(对话流):基于对话场景的特殊工作流,通过多轮交互动态调整流程逻辑。

创建工作流:

图片

加入并连接节点:

图片

设置节点:

图片

测试运行:

图片

在智能体中使用工作流:

图片

六、应用开发与发布

相比智能体,应用开发多了一个前端页面,主要依赖于工作流,操作也十分简单,接下来我们使用上面的工作流封装出一个应用:

图片

组件设置:

图片

业务逻辑设置:

图片

最后可以添加一些展示组件,使得它更美观。

图片

七、Coze 的 API 与 SDK

Coze 支持将 AI 智能体和扣子应用发布为 API 服务,可以通过 HTTP 方式与其进行交互。有编程基础的情况下,能够给用户更多的自定义开发空间。扣子 API 通过访问令牌(Access Token)进行 API 请求的鉴权。所有的 API 请求都必须在请求头的 Authorization 参数中包含访问令牌(Access Token)。

图片

注意:Access Token 仅首次生成时显示,请务必妥善保存,丢失后需要重新生成。

在 API 方面,Coze 主要提供了 Bot 调用接口,允许通过 HTTP 请求与指定的 Bot 进行交互。用户只需提供 Bot ID 和访问令牌,即可向接口发送用户输入,并接收 Bot 生成的文本、卡片或其他结构化响应。该 API 支持流式输出,适用于需要实时反馈的场景,同时也允许传递自定义参数以控制 Bot 的行为,例如调整回复风格或启用特定插件。此外,Coze 还提供了管理 API,用于查询 Bot 信息、管理会话历史或处理文件上传等操作,为集成提供了更全面的控制能力。

在 SDK 支持上,Coze 目前主要提供了 Python SDK,简化了在 Python 项目中的集成流程。SDK 封装了 API 调用的细节,提供了直观的类与方法,让开发者能够更便捷地初始化客户端、发送消息并处理响应。无论是同步调用还是异步流式响应,SDK 都提供了相应的支持,大幅降低了开发门槛。

八、实战案例

图片

子流程:

图片

循环体内的代码用来提取 url,如下:

async def main(args: Args) -> Output:
    params = args.params
    # 构建输出对象
    ret: Output = {"key0": params['input'][0]["url"]}
    return ret

同样的最终结果处理用来提取 url:

async def main(args: Args) -> Output:
    params = args.params
    # 构建输出对象
    ret: Output = {"key0": params['input'][0]}
    return ret

主流程中的代码,整理并构建最终结果:

async def main(args: Args) -> Output:
    params = args.params
    result = ''
    # 1 input 和 db 都是空的
    if not params.get('db') and not params.get('input'):
        result = '比特就业课'
    # 2 db 为空
    elif not params.get('db'):
        result = params['input']
    # 3 input 为空
    elif not params.get('input'):
        result = params['db'][0].get('video_url')
    # 核心修复:移除所有空白字符(空格、制表符、换行等)
    result = result.replace(" ", "")
    # 构建输出对象
    ret: Output = {"key0": result}
    return ret
  • 注意:因为使用的阿里云 OSS 插件生成的 URL 可能包含换行符或空白字符,因此我们在代码中增加了去除空白字符的处理逻辑。

阿里云 OSS(对象存储服务)的使用:

阿里云官网:https://www.aliyun.com/?spm=5176.29463013.J_4VYgf18xNlTAyFFbOuOQe.d_logo.5fb793a1t16gRU

  1. 登录阿里云官网搜索并创建免费的对象存储 oss
  2. 点击个人头像点击找到 AccessKey,点击进入使用云账号创建 AccessKey 并保存好信息。
  3. 进入对象存储 OSS 控制台,创建 Bucket 列表。
  4. 在工作流中搜索插件阿里云文件上传 oss,并设置

图片

在创建好工作流后,我们可以像之前一样将其用于智能体或应用开发。接下来,我们将进一步把它封装成 SDK,并集成到一个独立的 Web 应用中。

首先创建.env 环境变量,设置相关信息

COZE_API_TOKEN="填入用户令牌信息"
WORKFLOW_ID="填入需要使用的工作流 id"
USER_ID="填入用户 id"

图片

封装 SDK 并做 web 开发

import os
import json
from dotenv import load_dotenv
from cozepy import Coze, TokenAuth, COZE_CN_BASE_URL
from flask import Flask, request, jsonify, send_file
from flask_cors import CORS

# 加载环境变量
load_dotenv()
app = Flask(__name__)
CORS(app)  # 允许跨域请求

# 调用工作流生成视频
def create_video(animal_description):
    try:
        api_token = os.getenv('COZE_API_TOKEN')
        workflow_id = os.getenv('WORKFLOW_ID')
        # 初始化 coze 客户端
        coze = Coze(
            auth=TokenAuth(token=api_token),
            base_url=COZE_CN_BASE_URL
        )
        # 执行工作流
        workflow = coze.workflows.runs.create(
            workflow_id=workflow_id,
            parameters={"input": animal_description}
        )
        # 接收返回的内容
        video_url = json.loads(workflow.data)['output']
        return video_url
    except Exception as e:
        return None

# 声明接口路由
@app.route("/generate-video", methods=['POST'])
def generate_video():
    # 获取请求参数
    data = request.get_json()
    animal_description = data.get('input', '').strip()
    video_url = create_video(animal_description)
    return jsonify({'success': True, 'video_url': video_url, 'description': animal_description})

# 访问首页
@app.route('/')
def index():
    return send_file('index.html')

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=5000)

使用 AI 生成 html 页面,即 index.html 文件,运行 Python 程序。效果如下:

图片

index.html 文件:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>动物世界视频生成器</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
}
body {
    background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);
    background-size: 400% 400%;
    animation: gradientBG 15s ease infinite;
    min-height: 100vh;
    color: #333;
    padding: 20px;
}
@keyframes gradientBG {
    0% { background-position: 0% 50%; }
    50% { background-position: 100% 50%; }
    100% { background-position: 0% 50%; }
}
.container {
    max-width: 1200px;
    margin: 0 auto;
    padding: 20px;
}
.header {
    text-align: center;
    margin-bottom: 30px;
    color: white;
    text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
}
.header h1 {
    font-size: 3rem;
    margin-bottom: 10px;
    background: linear-gradient(45deg, #FFD700, #FF8C00);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}
.header p {
    font-size: 1.2rem;
    max-width: 800px;
    margin: 0 auto;
    line-height: 1.6;
    color: rgba(255, 255, 255, 0.9);
}
.main-content {
    display: flex;
    flex-direction: column;
    gap: 30px;
}
@media (min-width: 992px) {
    .main-content {
        flex-direction: row;
    }
}
.input-section, .output-section {
    background: rgba(255, 255, 255, 0.95);
    border-radius: 20px;
    padding: 30px;
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
    backdrop-filter: blur(10px);
    flex: 1;
}
.input-section {
    display: flex;
    flex-direction: column;
}
.section-title {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 1.8rem;
    margin-bottom: 20px;
    color: #2c3e50;
    padding-bottom: 10px;
    border-bottom: 2px solid #3498db;
}
.section-title i {
    color: #3498db;
}
.animal-description {
    flex: 1;
    min-height: 200px;
    padding: 20px;
    font-size: 1.1rem;
    border: 2px solid #e0e0e0;
    border-radius: 15px;
    resize: vertical;
    margin-bottom: 20px;
    transition: border 0.3s;
}
.animal-description:focus {
    outline: none;
    border-color: #3498db;
    box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.2);
}
.examples {
    margin-top: 15px;
    margin-bottom: 25px;
}
.examples h3 {
    color: #2c3e50;
    margin-bottom: 10px;
    font-size: 1.2rem;
}
.example-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}
.example-tag {
    background: #e3f2fd;
    padding: 8px 16px;
    border-radius: 20px;
    cursor: pointer;
    transition: all 0.3s;
    border: 1px solid #bbdefb;
    font-size: 0.95rem;
}
.example-tag:hover {
    background: #bbdefb;
    transform: translateY(-3px);
    box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1);
}
.buttons {
    display: flex;
    gap: 15px;
    margin-top: 20px;
}
.btn {
    padding: 15px 30px;
    border: none;
    border-radius: 12px;
    font-size: 1.1rem;
    font-weight: 600;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    transition: all 0.3s;
    flex: 1;
}
.generate-btn {
    background: linear-gradient(45deg, #3498db, #2ecc71);
    color: white;
}
.generate-btn:hover {
    transform: translateY(-3px);
    box-shadow: 0 7px 15px rgba(52, 152, 219, 0.4);
}
.generate-btn:active {
    transform: translateY(0);
}
.clear-btn {
    background: #f5f5f5;
    color: #555;
    border: 1px solid #ddd;
}
.clear-btn:hover {
    background: #e0e0e0;
    transform: translateY(-3px);
}
.output-section {
    display: flex;
    flex-direction: column;
}
.video-container {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #f8f9fa;
    border-radius: 15px;
    overflow: hidden;
    margin-bottom: 20px;
    min-height: 300px;
    position: relative;
}
.video-placeholder {
    text-align: center;
    color: #7f8c8d;
    padding: 40px;
}
.video-placeholder i {
    font-size: 4rem;
    margin-bottom: 20px;
    color: #bdc3c7;
}
.video-placeholder h3 {
    font-size: 1.5rem;
    margin-bottom: 10px;
}
.video-player {
    width: 100%;
    height: 100%;
    border-radius: 15px;
}
.loading {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(255, 255, 255, 0.9);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    z-index: 10;
    border-radius: 15px;
}
.spinner {
    width: 70px;
    height: 70px;
    border: 8px solid #f3f3f3;
    border-top: 8px solid #3498db;
    border-radius: 50%;
    animation: spin 1.5s linear infinite;
    margin-bottom: 20px;
}
@keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
}
.video-info {
    background: #f8f9fa;
    padding: 20px;
    border-radius: 15px;
    margin-top: 20px;
}
.video-info h3 {
    color: #2c3e50;
    margin-bottom: 10px;
    display: flex;
    align-items: center;
    gap: 10px;
}
.description-text {
    line-height: 1.6;
    color: #555;
}
.action-buttons {
    display: flex;
    gap: 15px;
    margin-top: 20px;
}
.action-btn {
    padding: 12px 25px;
    border-radius: 10px;
    border: none;
    font-size: 1rem;
    font-weight: 600;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    transition: all 0.3s;
    flex: 1;
}
.download-btn {
    background: linear-gradient(45deg, #2ecc71, #27ae60);
    color: white;
}
.download-btn:hover {
    transform: translateY(-3px);
    box-shadow: 0 5px 15px rgba(46, 204, 113, 0.4);
}
.share-btn {
    background: linear-gradient(45deg, #9b59b6, #8e44ad);
    color: white;
}
.share-btn:hover {
    transform: translateY(-3px);
    box-shadow: 0 5px 15px rgba(155, 89, 182, 0.4);
}
.footer {
    text-align: center;
    margin-top: 40px;
    color: rgba(255, 255, 255, 0.8);
    font-size: 0.9rem;
    padding: 20px;
}
.footer a {
    color: #FFD700;
    text-decoration: none;
}
.footer a:hover {
    text-decoration: underline;
}
.notification {
    position: fixed;
    top: 30px;
    right: 30px;
    padding: 15px 25px;
    border-radius: 10px;
    color: white;
    font-weight: 600;
    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
    z-index: 1000;
    display: flex;
    align-items: center;
    gap: 10px;
    transform: translateX(150%);
    transition: transform 0.5s ease;
}
.notification.show {
    transform: translateX(0);
}
.success {
    background: linear-gradient(45deg, #2ecc71, #27ae60);
}
.error {
    background: linear-gradient(45deg, #e74c3c, #c0392b);
}
@media (max-width: 768px) {
    .header h1 {
        font-size: 2.2rem;
    }
    .input-section, .output-section {
        padding: 20px;
    }
    .buttons, .action-buttons {
        flex-direction: column;
    }
    .btn, .action-btn {
        width: 100%;
    }
}
</style>
</head>
<body>
<div class="container">
    <div class="header">
        <h1><i class="fas fa-paw"></i> 动物世界视频生成器</h1>
        <p>描述你想象中的动物,AI 将为你生成独特的动物视频。从可爱的小猫到神奇的神兽,一切皆有可能!</p>
    </div>
    <div class="main-content">
        <div class="input-section">
            <div class="section-title">
                <i class="fas fa-edit"></i>
                <h2>描述你的动物</h2>
            </div>
            <textarea class="animal-description" id="animalDescription" placeholder="描述你想要生成的动物视频...例如:一只蓝色的狐狸在雪地中奔跑,毛发如丝般顺滑,眼睛像蓝宝石一样闪耀。"></textarea>
            <div class="examples">
                <h3>试试这些例子:</h3>
                <div class="example-tags">
                    <div class="example-tag" data-example="一只会说话的熊猫,戴着草帽,在竹林中跳舞">会说话的熊猫</div>
                    <div class="example-tag" data-example="一只彩虹色的独角兽,在星空中飞翔,身后留下七彩光芒">彩虹独角兽</div>
                    <div class="example-tag" data-example="一只机械狮子,在未来的城市中巡逻,眼睛发出红色光芒">机械狮子</div>
                    <div class="example-tag" data-example="一只透明的水母,在深海发光,触手轻轻摆动">发光水母</div>
                    <div class="example-tag" data-example="一只长着翅膀的小猫,在云朵间嬉戏">飞天小猫</div>
                </div>
            </div>
            <div class="buttons">
                <button class="btn generate-btn" id="generateBtn"><i class="fas fa-video"></i> 生成视频</button>
                <button class="btn clear-btn" id="clearBtn"><i class="fas fa-eraser"></i> 清空内容</button>
            </div>
        </div>
        <div class="output-section">
            <div class="section-title">
                <i class="fas fa-film"></i>
                <h2>生成的视频</h2>
            </div>
            <div class="video-container" id="videoContainer">
                <div class="video-placeholder" id="videoPlaceholder">
                    <i class="fas fa-play-circle"></i>
                    <h3>视频将在这里显示</h3>
                    <p>描述一个动物,然后点击'生成视频'按钮</p>
                </div>
                <div class="loading" id="loadingIndicator" style="display: none;">
                    <div class="spinner"></div>
                    <h3>正在生成视频...</h3>
                    <p>这可能需要一些时间,请耐心等待</p>
                </div>
                <video class="video-player" id="videoPlayer" controls style="display: none;"></video>
            </div>
            <div class="video-info" id="videoInfo" style="display: none;">
                <h3><i class="fas fa-info-circle"></i> 描述</h3>
                <p class="description-text" id="descriptionText"></p>
                <div class="action-buttons">
                    <button class="action-btn download-btn" id="downloadBtn"><i class="fas fa-download"></i> 下载视频</button>
                    <button class="action-btn share-btn" id="shareBtn"><i class="fas fa-share-alt"></i> 分享视频</button>
                </div>
            </div>
        </div>
    </div>
    <div class="footer">
        <p>Powered by Coze AI • 视频生成可能需要 30 秒到 1 分钟时间 • <a href="#" id="refreshLink">刷新页面</a></p>
    </div>
</div>
<div class="notification" id="notification"></div>
<script>
// DOM 元素
const animalDescription = document.getElementById('animalDescription');
const generateBtn = document.getElementById('generateBtn');
const clearBtn = document.getElementById('clearBtn');
const videoContainer = document.getElementById('videoContainer');
const videoPlaceholder = document.getElementById('videoPlaceholder');
const videoPlayer = document.getElementById('videoPlayer');
const videoInfo = document.getElementById('videoInfo');
const descriptionText = document.getElementById('descriptionText');
const loadingIndicator = document.getElementById('loadingIndicator');
const downloadBtn = document.getElementById('downloadBtn');
const shareBtn = document.getElementById('shareBtn');
const exampleTags = document.querySelectorAll('.example-tag');
const notification = document.();
 refreshLink = .();


exampleTags.( {
    tag.(,  {
        animalDescription. = tag.();
    });
});


clearBtn.(,  {
    animalDescription. = ;
    animalDescription.();
});


generateBtn.(, generateVideo);


animalDescription.(,  {
     ((e. || e.) && e. === ) {
        ();
    }
});


  () {
     description = animalDescription..();
     (!description) {
        (, );
        animalDescription.();
        ;
    }
    
    loadingIndicator.. = ;
    videoPlaceholder.. = ;
    videoPlayer.. = ;
    videoInfo.. = ;
    
    generateBtn. = ;
    generateBtn. = ;
     {
        
         response =  (, {
            : ,
            : {
                : ,
            },
            : .({ : description })
        });
         data =  response.();
         (data. && data.) {
            
            videoPlayer. = data.;
            videoPlayer.. = ;
            
            descriptionText. = data.;
            videoInfo.. = ;
            
            (, );
            
            videoPlayer. =  {
                loadingIndicator.. = ;
            };
            
            videoPlayer. =  {
                loadingIndicator.. = ;
                (, );
            };
        }  {
              (data. || );
        }
    }  (error) {
        .(, error);
        ( + error., );
        videoPlaceholder.. = ;
        loadingIndicator.. = ;
    }  {
        
        generateBtn. = ;
        generateBtn. = ;
    }
}


downloadBtn.(,  {
     (videoPlayer.) {
         link = .();
        link. = videoPlayer.;
        link. =  + .() + ;
        ..(link);
        link.();
        ..(link);
        (, );
    }  {
        (, );
    }
});


shareBtn.(,  {
     (videoPlayer.) {
         (navigator.) {
            navigator.({
                : ,
                : animalDescription.,
                : ..,
            }).( (, )).( ( + error., ));
        }  {
            
            navigator..(videoPlayer.).( (, )).( (, ));
        }
    }  {
        (, );
    }
});


refreshLink.(,  {
    e.();
    ..();
});


 () {
    notification. = message;
    notification. =  + type;
    notification..();
    ( {
        notification..();
    }, );
}


.(,  {
    animalDescription.();
});
</script>
</body>
</html>
getElementById
'notification'
const
document
getElementById
'refreshLink'
// 示例标签点击事件
forEach
tag =>
addEventListener
'click'
() =>
value
getAttribute
'data-example'
// 清空按钮事件
addEventListener
'click'
() =>
value
''
focus
// 生成视频按钮事件
addEventListener
'click'
// 按 Enter 键生成视频(Ctrl+Enter 或 Cmd+Enter)
addEventListener
'keydown'
(e) =>
if
ctrlKey
metaKey
key
'Enter'
generateVideo
// 生成视频函数
async
function
generateVideo
const
value
trim
if
showNotification
'请输入动物描述'
'error'
focus
return
// 显示加载指示器
style
display
'flex'
style
display
'none'
style
display
'none'
style
display
'none'
// 禁用生成按钮
disabled
true
innerHTML
'<i></i> 生成中...'
try
// 调用后端 API
const
await
fetch
'/generate-video'
method
'POST'
headers
'Content-Type'
'application/json'
body
JSON
stringify
input
const
await
json
if
success
video_url
// 显示视频
src
video_url
style
display
'block'
// 显示描述信息
textContent
description
style
display
'block'
// 显示成功通知
showNotification
'视频生成成功!'
'success'
// 视频加载后隐藏加载指示器
onloadeddata
() =>
style
display
'none'
// 如果视频加载失败,也隐藏加载指示器
onerror
() =>
style
display
'none'
showNotification
'视频加载失败,请检查链接'
'error'
else
throw
new
Error
error
'视频生成失败'
catch
console
error
'生成视频时出错:'
showNotification
'视频生成失败:'
message
'error'
style
display
'block'
style
display
'none'
finally
// 恢复生成按钮状态
disabled
false
innerHTML
'<i></i> 生成视频'
// 下载视频按钮事件
addEventListener
'click'
() =>
if
src
const
document
createElement
'a'
href
src
download
'动物视频_'
Date
now
'.mp4'
document
body
appendChild
click
document
body
removeChild
showNotification
'视频下载已开始'
'success'
else
showNotification
'没有可下载的视频'
'error'
// 分享视频按钮事件
addEventListener
'click'
() =>
if
src
if
share
share
title
'我生成的动物视频'
text
value
url
window
location
href
then
() =>
showNotification
'分享成功'
'success'
catch
(error) =>
showNotification
'分享失败:'
message
'error'
else
// 如果不支持 Web Share API,则复制链接到剪贴板
clipboard
writeText
src
then
() =>
showNotification
'视频链接已复制到剪贴板'
'success'
catch
() =>
showNotification
'复制失败,请手动复制链接'
'error'
else
showNotification
'没有可分享的视频'
'error'
// 刷新链接事件
addEventListener
'click'
(e) =>
preventDefault
window
location
reload
// 显示通知函数
function
showNotification
message, type
textContent
className
'notification '
classList
add
'show'
setTimeout
() =>
classList
remove
'show'
3000
// 页面加载时聚焦到描述框
window
addEventListener
'load'
() =>
focus
  • 💰 8折买阿里云服务器限时8折购买
  • 🦞 5分钟部署阿里云小龙虾了解详情
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • C++ 多态详解:虚函数、重写机制与底层原理
  • 图数据结构详解:存储结构、遍历与核心算法
  • 鸿蒙 ArkTS 与 Java 跨平台 Socket 通信实战
  • 基于 FastGPT 与 MCP 协议构建工具增强型智能体
  • Python Pandas 核心数据结构与操作实战指南
  • Kubernetes 与云原生开发:.NET Core 和 Java 的对比与实践
  • 位运算实战:判断字符唯一性与查找缺失数字
  • Python 处理 Excel:openpyxl 与 pandas 实战指南
  • FastGPT 结合 MCP 协议构建工具增强型智能体实践
  • DeepSeek 深度使用指南:提示词工程与本地知识库搭建
  • 移动前端与 Web 前端开发的核心差异解析
  • 近端策略优化算法 (PPO) 详解与 PyTorch 实战
  • Java 泛型核心机制与实战指南
  • DeepSeek 云电脑部署实测:ToDesk、顺网与海马云横向对比
  • Spring Boot RESTful API 开发与测试
  • jQuery 核心 API 与实战应用指南
  • Python 入门:30 天零基础学习规划(每日 1 小时)
  • MCPHost:命令行下大模型与外部工具交互的实践
  • 基于 brpc+MinIO 的分布式文件存储架构设计与实战
  • MySQL 表操作实战:创建、修改与删除详解

相关免费在线工具

  • RSA密钥对生成器

    生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online

  • Mermaid 预览与可视化编辑

    基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online

  • 随机西班牙地址生成器

    随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online

  • curl 转代码

    解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online