Tailwind CSS 实战:基于 Kooboo 构建 AI 对话框页面(五):语音合成输出与交互增强

news2025/6/2 2:41:25
Tailwind CSS 实战,基于Kooboo构建AI对话框页面(一)
Tailwind CSS 实战,基于Kooboo构建AI对话框页面(二):实现交互功能
Tailwind CSS 实战,基于 Kooboo 构建 AI 对话框页面(三):实现暗黑模式主题切换
Tailwind CSS 实战,基于 Kooboo 构建 AI 对话框页面(四):语音识别输入功能

继前几篇实现语音识别功能后,本文将聚焦于语音合成输出的落地,结合 Web Speech Synthesis API 与 Tailwind CSS,构建「语音输入→AI 处理→语音输出」的完整交互闭环,并通过 UI 优化增强操作反馈。

一、关于语音合成

语音合成(Text-to-Speech, TTS)就是把文字变成声音。在 AI 对话框里加上这个功能,能让 AI “开口说话”,比如用户打字提问后,AI 不仅显示文字回复,还能读出答案。这对习惯听语音的用户或双手忙碌的场景非常友好,让交互更自然。

核心技术:Web Speech Synthesis API

这是浏览器自带的 API,不需要额外安装库,直接用 JavaScript 就能调用。它支持多语言(如中文、英文),还能调整语速、音调等参数,非常适合前端开发。

二、一步一步实现语音合成功能

1. 准备工作:初始化语音合成对象

首先,在 JavaScript 里创建一个语音合成实例,并定义一些变量来跟踪当前播放状态:

const synth = window.speechSynthesis; // 语音合成对象  
let currentUtterance = null; // 当前正在播放的语音实例  
let lastPlayedText = ''; // 最后播放的文本,用于全局播放控制  

2. 播放语音的核心函数:speak ()

这个函数负责把文本转为语音并播放,还会更新按钮和状态指示器的样式。

function speak(text, button = null) {  
  // 先停止当前正在播放的语音  
  if (currentUtterance) {  
    synth.cancel();  
  }  
  
  // 创建语音实例  
  const utterance = new SpeechSynthesisUtterance(text);  
  
  // 设置语音参数(从全局设置中获取)  
  utterance.rate = speechSettings.rate; // 语速(0.5倍最慢,2倍最快)  
  utterance.pitch = speechSettings.pitch; // 音调(0最低,2最高)  
  utterance.volume = speechSettings.volume; // 音量(0-1)  
  utterance.lang = speechSettings.lang; // 语言,如'zh-CN'(中文)或'en-US'(英文)  
  
  // 播放时更新UI:按钮变绿,显示加载动画  
  if (button) {  
    button.classList.add('active'); // 添加激活态样式(绿色背景)  
    button.innerHTML = '<i class="fa fa-pause"></i>'; // 切换为暂停图标  
    const indicator = button.parentElement.querySelector('.voice-indicator');  
    indicator?.classList.add('active'); // 显示动态脉冲效果  
  }  
  
  // 绑定播放结束事件:播放完后重置按钮状态  
  utterance.onend = () => {  
    if (button) {  
      button.classList.remove('active');  
      button.innerHTML = '<i class="fa fa-play"></i>';  
      indicator?.classList.remove('active');  
    }  
  };  
  
  // 开始播放  
  synth.speak(utterance);  
  currentUtterance = utterance; // 记录当前播放的实例  
  lastPlayedText = text; // 记录最后播放的文本  
}  

3. 添加播放按钮到 AI 消息气泡

在 AI 回复的 HTML 里,每个消息气泡右侧加一个播放按钮。点击按钮时,调用上面的speak函数:

<div class="max-w-[70%] relative">  
  <div class="bg-[var(--chat-bubble-ai)] p-4 rounded-lg">  
    <p>您好!这是AI的语音回复。</p>  
  </div>  
  <!-- 播放按钮:点击时调用speak函数,传入文本和当前按钮 -->  
  <button  
    class="play-button absolute right-4 top-4"  
    onclick="speak('您好!这是AI的语音回复。', this)"  
  >  
    <i class="fa fa-play text-gray-500"></i>  
  </button>  
  <!-- 语音状态指示器:播放时显示绿色脉冲 -->  
  <div class="voice-indicator absolute right-12 top-5"></div>  
</div>  

4. 全局播放按钮:一键控制所有语音

在页面右下角加一个固定按钮,方便用户暂停 / 继续所有语音,或重播最后一条:

<button id="globalPlayButton" class="fixed bottom-4 right-4 w-12 h-12 rounded-full bg-blue-500 text-white">  
  <i class="fa fa-play"></i>  
</button>  

点击事件逻辑:

globalPlayButton.addEventListener('click', () => {  
  if (synth.speaking) {  
    // 如果正在播放,切换暂停/继续  
    synth.paused ? synth.resume() : synth.pause();  
  } else if (lastPlayedText) {  
    // 如果没有播放,重播最后一条消息  
    speak(lastPlayedText);  
  }  
});  

三、设计语音设置面板:让用户自定义声音

为什么需要设置面板?

不同用户对语音的偏好不同,比如有人喜欢快语速,有人喜欢低沉的声音。设置面板允许用户调整参数,并保存设置到本地,下次打开页面时自动应用。

面板里有什么?

  1. 语速滑动条:控制语音速度(0.5x 到 2x)。
  2. 音调滑动条:调整声音高低(0 到 2)。
  3. 音量滑动条:设置音量大小(0% 到 100%)。
  4. 自动播放开关:AI 回复生成后是否自动播放语音。
  5. 测试按钮:用当前设置播放测试语音。

HTML 结构:

<div id="voiceSettings" class="voice-settings">  
  <h3>语音设置</h3>  
  <label>语速</label>  
  <input type="range" id="rateSlider" min="0.5" max="2" step="0.1" value="1">  
  <span id="rateValue">1.0x</span>  
  
  <label>音调</label>  
  <input type="range" id="pitchSlider" min="0.5" max="2" step="0.1" value="1">  
  <span id="pitchValue">1.0x</span>  
  
  <label>音量</label>  
  <input type="range" id="volumeSlider" min="0" max="1" step="0.1" value="1">  
  <span id="volumeValue">100%</span>  
  
  <label>  
    <input type="checkbox" id="autoPlayToggle" checked>  
    自动播放AI回复  
  </label>  
  <button id="testVoiceButton">测试语音</button>  
</div>  

保存设置到本地:

localStorage存储用户设置,页面刷新后不会丢失:

// 监听滑动条变化,更新设置并保存  
rateSlider.addEventListener('input', (e) => {  
  speechSettings.rate = parseFloat(e.target.value);  
  rateValue.textContent = `${speechSettings.rate.toFixed(1)}x`;  
  localStorage.setItem('speechSettings', JSON.stringify(speechSettings));  
});  

// 页面加载时读取本地设置  
const savedSettings = localStorage.getItem('speechSettings');  
if (savedSettings) {  
  speechSettings = JSON.parse(savedSettings);  
  rateSlider.value = speechSettings.rate;  
  // 同步更新其他滑动条和开关  
}  

四、完整代码:从 HTML 到 JavaScript

HTML 部分:

包含暗黑模式切换、语音设置按钮、消息容器、输入框和全局播放按钮。注意 AI 消息里的播放按钮和状态指示器:

<body>  
  <!-- 暗黑模式切换按钮 -->  
  <button id="darkModeToggle">...</button>  
  
  <!-- 语音设置按钮 -->  
  <button id="voiceSettingsToggle"><i class="fa fa-sliders"></i></button>  
  
  <!-- 语音设置面板 -->  
  <div id="voiceSettings" class="voice-settings">  
    <!-- 滑动条和开关 -->  
  </div>  
  
  <!-- 聊天窗口 -->  
  <div id="messageContainer">  
    <!-- AI初始消息,包含播放按钮和状态指示器 -->   
  </div>  
  
  <!-- 输入框和发送按钮 -->  
  <div class="input-wrapper">  
    <button id="voiceButton"><i class="fa fa-microphone"></i></button>  
    <input id="messageInput" placeholder="输入消息...">  
  </div>  
  
  <!-- 全局播放按钮 -->  
  <button id="globalPlayButton"><i class="fa fa-play"></i></button>  
</body>  

JavaScript 部分:

核心逻辑包括语音合成、语音识别、设置管理和 UI 交互。这里重点看speak函数和设置面板的逻辑:

// 语音设置参数  
let speechSettings = {  
  rate: 1,  
  pitch: 1,  
  volume: 1,  
  autoPlay: true,  
  lang: 'zh-CN'  
};  

// 播放语音函数  
function speak(text, button) {  
  // 停止当前播放  
  synth.cancel();  
  
  // 创建语音实例并设置参数  
  const utterance = new SpeechSynthesisUtterance(text);  
  Object.assign(utterance, speechSettings);  
  
  // 更新按钮和指示器状态  
  if (button) {  
    button.classList.add('active');  
    button.querySelector('.fa').classList.remove('fa-play').add('fa-pause');  
    button.nextElementSibling.classList.add('active');  
  }  
  
  // 播放结束后重置状态  
  utterance.onend = () => {  
    if (button) {  
      button.classList.remove('active');  
      button.querySelector('.fa').classList.remove('fa-pause').add('fa-play');  
      button.nextElementSibling.classList.remove('active');  
    }  
  };  
  
  synth.speak(utterance);  
}  

// 自动播放AI回复  
function addAIResponse(response) {  
  // 添加消息到页面  
  messageContainer.innerHTML += `...`;  
  
  // 如果开启自动播放,调用speak函数  
  if (speechSettings.autoPlay) {  
    speak(response, messageContainer.lastElementChild.querySelector('.play-button'));  
  }  
}  

五、常见问题(初学者必看)

1. 为什么语音不播放?

  • 检查浏览器支持:Web Speech Synthesis API 在 Chrome、Edge 等现代浏览器中支持较好,IE 不支持
  • 权限问题:浏览器可能需要用户交互(如点击按钮)才能播放声音,直接在页面加载时播放可能被阻止。
  • 网络问题:部分浏览器需要联网才能使用语音合成。

2. 如何添加更多语言?

修改speechSettings.lang的值即可,比如:

speechSettings.lang = 'en-US'; // 美式英语  
speechSettings.lang = 'ja-JP'; // 日语  

注意:浏览器需要支持该语言的语音引擎,可能需要安装语音包。

3. 按钮样式不生效怎么办?

  • 确保 Tailwind CSS 的类名正确,比如rounded-fullbg-green-500是否存在。
  • 检查 CSS 变量是否定义,如--voice-playing是否在:root.dark中声明。

4. 如何调试?

  • 使用浏览器开发者工具(F12),在控制台查看错误信息。
  • speak函数中添加console.log('播放语音:', text),确认函数是否被正确调用。

最终效果:

  1. 用户输入文字或语音,AI 回复文本并自动播放语音(若开启自动播放)。
  2. 点击消息气泡旁的播放按钮,可手动播放 / 暂停。
  3. 拖动设置面板的滑动条,实时调整语速、音调、音量。
  4. 点击全局播放按钮,快速控制所有语音。

结语

通过这篇教程,你学会了如何用 Web Speech Synthesis API 实现语音合成,结合 Tailwind CSS 设计交互界面,并通过设置面板提升用户体验。现在,你的 AI 对话框已经具备 “听” 和 “说” 的能力,形成完整的语音交互闭环。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2393120.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

职业本科院校无人机专业人才培养解决方案

2023年的中央经济工作会议强调了以科技创新推动现代化产业体系构建的重要性&#xff0c;并提出发展生物制造、商业航天、低空经济等战略性新兴产业。低空经济&#xff0c;依托民用无人机等低空飞行器&#xff0c;在多场景低空飞行活动的牵引下&#xff0c;正逐步形成一个辐射广…

软件评测机构如何保障质量?检测资质、技术实力缺一不可

软件评测机构在保障软件质量上起着关键作用&#xff0c;对软件行业的健康发展极为关键。它们采用专业的技术手段和严格的评估流程&#xff0c;对软件的运行效果、功能等多方面进行细致的审查&#xff0c;为开发者和使用者提供了客观、公正的参考依据。 检测资质正规软件评测机…

Linux多线程(六)之线程控制4【线程ID及进程地址空间布局】

文章目录 线程ID及进程地址空间布局线程局部存储 线程ID及进程地址空间布局 pthread_ create函数会产生一个线程ID&#xff0c;存放在第一个参数指向的地址中。 该线程ID和前面说的线程ID不是一回事。 前面讲的线程ID属于进程调度的范畴。 ​ 因为线程是轻量级进程&#xff…

1.什么是node.js、npm、vue

一、Node.js 是什么&#xff1f; &#x1f63a; 定义&#xff1a; Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时环境&#xff0c;让你可以在浏览器之外运行 JavaScript 代码&#xff0c;主要用于服务端开发。 &#x1f63a;从计算机底层说&#xff1a;什么是“运…

Xamarin入门笔记(Xamarin已经被MAUI取代)

初级代码游戏的专栏介绍与文章目录-CSDN博客 Xamarin入门 概述 环境 Android开发环境比较简单&#xff0c;自带模拟器&#xff0c;实体机打开开发者模式即可。 iOS开发环境比较复杂&#xff0c;必须搭配Mac电脑&#xff0c;Windows连接Mac开发可能有问题&#xff08;比如发…

排查Oracle文件打开数过多

Oracle数据库在运行过程中&#xff0c;会打开大量的文件以执行其操作&#xff0c;包括数据文件、控制文件、日志文件等。如果Oracle用户打开的文件数过多&#xff0c;可能会引起系统性能下降。下面将深入分析Oracle用户文件打开数的优化策略&#xff0c;以帮助数据库管理员&…

应用层协议http(无代码版)

目录 认识URL urlencode 和 urldecode HTTP 协议请求与响应格式 HTTP 的请求方法 GET 方法 POST 方法 HTTP 的状态码 HTTP 常见 Header Location 关于 connection 报头 HTTP版本 远程连接服务器工具 setsockopt 我们来学习应用层协议http。 虽然我们说, 应用层协…

8.5 Q1|广州医科大学CHARLS发文 甘油三酯葡萄糖指数累积变化与 0-3期心血管-肾脏-代谢综合征人群中风发生率的相关性

1.第一段-文章基本信息 文章题目&#xff1a;Association between cumulative changes of the triglyceride glucose index and incidence of stroke in a population with cardiovascular-kidney-metabolic syndrome stage 0-3: a nationwide prospective cohort study 中文标…

无人机停机坪运行技术分析!

一、运行方式 1. 自动折叠与展开 部分停机坪采用二次折叠设计&#xff0c;通过传动组件实现自动折叠&#xff0c;缩小体积便于运输&#xff1b;展开后最大化停机面积&#xff0c;适应不同任务需求。例如&#xff0c;珠海双捷科技的专利通过两次折叠使停机坪体积最小化&#x…

【Java Web】速通HTML

参考笔记: JavaWeb 速通HTML_java html页面-CSDN博客 目录 一、前言 1.网页组成 1 结构 2 表现 3 行为 2.HTML入门 1 基本介绍 2 基本结构 3. HTML标签 1 基本说明 2 注意事项 4. HTML概念名词解释 二、HTML常用标签汇总 + 案例演示 1. 字体标签 font (1)定义 (2)案例 2…

在线制作幼教早教行业自适应网站教程

你想知道怎么做自适应网站吗&#xff1f;今天就来教你在线用模板做个幼教早教行业的网站哦。 首先得了解啥是自适应网站。简单说呢&#xff0c;自适应网站就是能自动匹配不同终端设备的网站&#xff0c;像手机、平板、电脑等。那如何做幼早教自适应网站呢&#xff1f; 在乔拓云…

Apptrace:APP安全加速解决方案

2021 年&#xff0c;某知名电商平台在 “618” 大促期间遭遇 DDoS 攻击&#xff0c;支付系统瘫痪近 2 小时&#xff1b;2022 年&#xff0c;一款热门手游在新版本上线时因 CC 攻击导致服务器崩溃。观察发现&#xff0c;电商大促、暑期流量高峰和年末结算期等关键商业周期&#…

Web攻防-SQL注入增删改查HTTP头UAXFFRefererCookie无回显报错

知识点&#xff1a; 1、Web攻防-SQL注入-操作方法&增删改查 2、Web攻防-SQL注入-HTTP头&UA&Cookie 3、Web攻防-SQL注入-HTTP头&XFF&Referer 案例说明&#xff1a; 在应用中&#xff0c;存在增删改查数据的操作&#xff0c;其中SQL语句结构不一导致注入语句…

GoldenDB管理节点zk部署

目录 1、准备阶段 1.1、部署规划 1.2、硬件准备 1.3、软件准备 1.4、网络端口开通 1.5、环境清理 2、实施阶段 2.1、操作系统配置 2.1.1、主机名修改 2.1.2、修改hosts文件 2.1.3、禁用防火墙 2.1.4、禁用selinux 2.1.5、禁用透明大页 2.1.6、资源限制调整 2.1.…

mac mini m4命令行管理员密码设置

附上系统版本图 初次使用命令行管理员&#xff0c;让输入密码&#xff0c;无论是输入登录密码还是账号密码&#xff0c;都是错的&#xff0c;百思不得其解&#xff0c;去网上搜说就是登录密码啊 直到后来看到了苹果官方的文档 https://support.apple.com/zh-cn/102367 https…

计算机网络之差错控制中的 CRC(循环冗余校验码)

文章目录 1 概述1.1 简介1.2 特点1.3 基本原则 2 实现步骤3 例题 1 概述 1.1 简介 CRC&#xff1a;Cyclic Redundancy Check&#xff08;循环冗余校验&#xff09;是计算机网络中常用的一种差错控制编码方法&#xff0c;用于检测数据传输或存储过程中可能出现的错误。 1.2 特…

【深度学习】7. 深度卷积神经网络架构:从 ILSVRC、LeNet 到 AlexNet、ZFNet、VGGNet,含pytorch代码结构

深度卷积神经网络架构&#xff1a;从 ILSVRC 到 AlexNet 在2012年Alex出现之前&#xff0c;主要还是依赖于SVM&#xff0c;同时数据工程成为分类任务中很大的一个部分&#xff0c;对数据处理的专家依赖性高。 一、ILSVRC 与图像分类任务背景 ILSVRC 简介 ILSVRC&#xff08…

基于cornerstone3D的dicom影像浏览器 第二十七章 设置vr相机,复位视图

文章目录 前言一、VR视图设置相机位置1. 相机位置参数2. 修改mprvr.js3. 调用流程1) 修改Toolbar3D.vue2) 修改View3d.vue3) 修改DisplayerArea3D.vue 二、所有视图复位1.复位流程说明2. 调用流程1) Toolbar3D中添加"复位"按钮&#xff0c;发送reset事件2) View3d.vu…

2025年渗透测试面试题总结-匿名[校招]高级安全工程师(代码审计安全评估)(题目+回答)

安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。、 目录 匿名[校招]高级安全工程师(代码审计安全评估) 渗透基础 1. 自我介绍 2. SQL注入写Shell&#xff08;分数…

Jenkins实践(7):Publish over SSH功能

在 Jenkins 中使用Publish over SSH功能,需要安装对应的插件。以下是详细步骤: 1. 安装 Publish over SSH 插件 进入 Jenkins 管理界面 → Manage Jenkins → Manage Plugins。切换到 Available 选项卡,搜索 "Publish Over SSH"。勾选插件并点击 Install without…