AI Agent项目实战(03)-利用TTS技术让你的AI Agent发声

1 语音逻辑设计

一个AI Agent应用的语音逻辑设计流程图。

1.1 基本流程

复制代码
- 用户 -> Agent -> 文本回答

最基础的交互模式。用户输入被传递给Agent,Agent生成文本回答。

1.2 添加语音功能

markdown 复制代码
- 用户 -> Agent -> 文本回答
           |
           v
        TTS服务 -> MSTTS -> 语音回答

基本流程基础上,增加文本转语音(TTS)服务。Agent生成的文本回答被发送到TTS服务,然后通过MSTTS(Microsoft Text-to-Speech)转换为语音回答。

1.3 完整流程

markdown 复制代码
- 用户 -> Agent -> 文本回答
           |
           v (异步)
        TTS服务 -> MSTTS -> 语音回答

文本回答和语音回答是并行处理的。Agent生成文本回答后,同时开始TTS转换过程,这个过程被标记为"异步"。

1.4 设计思路

  • 模块化:将文本处理和语音转换分离,便于独立开发和维护。
  • 异步处理:文本回答可以立即呈现,而语音转换在后台进行,提高响应速度。
  • 灵活性:可以根据需求选择只使用文本回答或同时使用语音回答。
  • 技术整合:利用MSTTS等成熟技术,提高语音质量。

这种设计允许AI Agent应用在保持高效文本交互的同时,提供更丰富的语音交互体验。

2 TTS能力介绍

以 Google Cloud Text-To-Speech 服务为例说明。

开发人员可用 Text-to-Speech 创建可播放音频格式的自然发音的合成人类语音。可用由 Text-to-Speech 创建的音频数据文件来丰富应用功能或者扩大视频或录音等媒体。

Text-to-Speech 会将文本或语音合成标记语言 (SSML) 输入转换为音频数据,例如 MP3 或 LINEAR16(WAV 文件中使用的编码)。

2.1 基本示例

Text-to-Speech 适用于向用户播放人类语音音频的任何应用。您可以使用它将任意字符串、字词和句子转换为表述相同内容的人的语音。

设想您有一个语音辅助应用,可以通过可播放音频文件,向您的用户提供自然语言反馈。您的应用可能会执行某个操作,然后向用户提供人类语音作为反馈。

例如,您的应用可能想要报告它已成功将某项活动添加到用户的日历中。您的应用会构建一个响应字符串向用户报告操作已成功,例如"我已将活动添加到您的日历中"。

使用 Text-to-Speech,您可以将该响应字符串转换为实际的人类语音以播放给用户,类似于下面提供的示例。

示例 1:Text-to-Speech 生成的音频文件

要创建音频文件,请向 Text-to-Speech 发送请求,如:

bash 复制代码
curl -H "Authorization: Bearer "$(gcloud auth print-access-token) -H "x-goog-user-project: <var>PROJECT_ID</var>" -H "Content-Type: application/json; charset=utf-8" --data "{
  'input':{
    'text':'I\'ve added the event to your calendar.'
  },
  'voice':{
    'languageCode':'en-gb',
    'name':'en-GB-Standard-A',
    'ssmlGender':'FEMALE'
  },
  'audioConfig':{
    'audioEncoding':'MP3'
  }
}" "https://texttospeech.googleapis.com/v1/text:synthesize"

2.2 语音合成

将文本输入转换为音频数据的过程称为合成,而输出合成则称为合成语音。 Text-to-Speech 采用两种类型的输入:原始文本或 SSML 格式的数据(下文详解)。要创建新的音频文件,可调用 API 的 synthesize 端点。

语音合成过程会生成原始音频数据,格式为 base64 编码字符串。您必须先将 base64 编码字符串解码为音频文件,应用才可以播放相应文件。大多数平台和操作系统都具备将 base64 文本解码为可播放媒体文件的工具。

2.3 语音

Text-to-Speech 生成自然人类语音的原始音频数据。也就是说,它生成的音频听上去像人在说话。当您向 Text-to-Speech 发送合成请求时,您必须指定"说出"字词的语音

Text-to-Speech 有多种自定义语音供您选择。语音因语言、性别和口音(适用于某些语言)而异。例如,你可以创建模仿带有英国口音的女性说英语的声音音频,如以上示例 1您也可以将同一文本转换为不同的语音,比方说有澳大利亚口音的男性说英语的声音。

2.4 WaveNet 语音

Text-to-Speech 还同其他传统合成语音一起,提供优质的 WaveNet 生成语音。用户发现 Wavenet 生成语音比其他合成语音更温暖,更像人声。

WaveNet 语音的主要不同之处在于生成语音所用的 WaveNet 模型。WaveNet 模型一直在使用真人发声的原始音频样本进行训练。因此,这些模型生成的合成语音,其音节、音位和字词的重音与音调更像人类。

2.5 其他音频输出设置

除了语音之外,您还可以配置语音合成创建的音频数据输出的其他方面。Text-to-Speech 支持您配置语速、音高、音量和采样率(单位为赫兹)。

2.6 语音合成标记语言 (SSML) 支持

可通过语音合成标记语言 (SSML) 对文本进行标记来增强 Text-to-Speech 生成的合成语音。SSML 可让您在 Text-to-Speech 生成的音频数据中插入暂停、首字母缩写词发音或其他细节。

注意:Text-to-Speech 不支持特定可用语言的部分 SSML 元素。

例如,您可以通过提供具有标记序数词的 SSML 输入的 Text-to-Speech 来确保合成语音正确地读出序数词。

创建服务账号:

为其创建密钥:

添加密钥:

新建 json 类型密钥:

下载该 json 密钥存储到项目路径下:

项目配置该密钥:

为项目启用 API 服务

3 Voice函数的实现

python 复制代码
@app.post("/chat")
def chat(query: str, background_tasks: BackgroundTasks):
    master = Master()
    msg = master.run(query)
    unique_id = str(uuid.uuid4())
    background_tasks.add_task(master.background_voice_synthesis, msg, unique_id)
    return {"msg": msg, "id": unique_id}
python 复制代码
def background_voice_synthesis(self, text: str, uid: str):
    # 无返回值,只是触发语音合成
    asyncio.run(self.get_voice(text, uid))
python 复制代码
    # text 要转换为语音的文本
    async def get_voice(self, text: str, uid: str):
        print("text2speech", text)
        print("uid", uid)
        print("当前Edge大师应该的语气是:", self.emotion)
        # 默认 grpc 会报 503 错误,必须 rest 请求
        client = texttospeech.TextToSpeechClient(transport="rest")
        input_text = texttospeech.SynthesisInput(text="fsfsdfsd")
        print("input_text=", input_text)
        # Note: the voice can also be specified by name.
        # Names of voices can be retrieved with client.list_voices().
        voice = texttospeech.VoiceSelectionParams(
            language_code="en-US",
            name="en-US-Studio-O",
        )

        audio_config = texttospeech.AudioConfig(
            audio_encoding=texttospeech.AudioEncoding.LINEAR16,
            speaking_rate=1
        )

        response = client.synthesize_speech(
            request={"input": input_text, "voice": voice, "audio_config": audio_config}
        )
        print("response=", response)
        # The response's audio_content is binary.
        with open("output.mp3", "wb") as out:
            out.write(response.audio_content)
            print('Audio content written to file "output.mp3"')

终端输出:

生成文件:

4 语音克隆+TTS增强

4.1 Bark

直达官网,第二代Bark声音克隆 🐶 & 全新中文声音克隆:

4.2 阿里Sambert语音合成

提供SAMBERT+NSFGAN深度神经网络算法与传统领域知识深度结合的文字转语音服务,兼具读音准确,韵律自然,声音还原度高,表现力强的特点。

语音合成API基于达摩院改良的自回归韵律模型,具有推理速度快,合成效果佳的特点。开发者可以通过以下链接,了解如何通过大模型服务平台调用Sambert语音合成API:

Sambert语音合成API基于达摩院改良的自回归韵律模型,支持文本至语音的实时流式合成。可被应用于:

  • 智能设备/机器人播报的语音内容,如智能客服机器人、智能音箱、数字人等。
  • 音视频创作中需要将文字转为语音播报的场景,如小说阅读、新闻播报、影视解说、配音等。
① 将合成音频保存为文件

以下代码展示了将流式返回的二进制音频,保存为本地文件。

python 复制代码
import os

from dotenv import load_dotenv

load_dotenv("qwen.env")
python 复制代码
import sys
from dashscope.audio.tts import SpeechSynthesizer

result = SpeechSynthesizer.call(model='sambert-zhichu-v1',
                                text='今天天气怎么样',
                                sample_rate=48000)
if result.get_audio_data() is not None:
    with open('output.wav', 'wb') as f:
        f.write(result.get_audio_data())
    print('SUCCESS: get audio data: %dbytes in output.wav' %
          (sys.getsizeof(result.get_audio_data())))
else:
    print('ERROR: response is %s' % (result.get_response()))
② 将合成音频通过设备播放

调用成功后,通过本地设备播放实时返回的音频内容。

运行示例前,需要通过pip安装第三方音频播放套件。

python 复制代码
# Installation instructions for pyaudio:
# APPLE Mac OS X
#   brew install portaudio 
#   pip install pyaudio
# Debian/Ubuntu
#   sudo apt-get install python-pyaudio python3-pyaudio
#   or
#   pip install pyaudio
# CentOS
#   sudo yum install -y portaudio portaudio-devel && pip install pyaudio
# Microsoft Windows
#   python -m pip install pyaudio
python 复制代码
import dashscope
import sys
import pyaudio
from dashscope.api_entities.dashscope_response import SpeechSynthesisResponse
from dashscope.audio.tts import ResultCallback, SpeechSynthesizer, SpeechSynthesisResult

dashscope.api_key='sk-xxx'

class Callback(ResultCallback):
    _player = None
    _stream = None

    def on_open(self):
        print('Speech synthesizer is opened.')
        self._player = pyaudio.PyAudio()
        self._stream = self._player.open(
            format=pyaudio.paInt16,
            channels=1,
            rate=48000,
            output=True)

    def on_complete(self):
        print('Speech synthesizer is completed.')

    def on_error(self, response: SpeechSynthesisResponse):
        print('Speech synthesizer failed, response is %s' % (str(response)))

    def on_close(self):
        print('Speech synthesizer is closed.')
        self._stream.stop_stream()
        self._stream.close()
        self._player.terminate()

    def on_event(self, result: SpeechSynthesisResult):
        if result.get_audio_frame() is not None:
            print('audio result length:', sys.getsizeof(result.get_audio_frame()))
            self._stream.write(result.get_audio_frame())

        if result.get_timestamp() is not None:
            print('timestamp result:', str(result.get_timestamp()))

callback = Callback()
SpeechSynthesizer.call(model='sambert-zhichu-v1',
                       text='你是睿智的JavaEdge',
                       sample_rate=48000,
                       format='pcm',
                       callback=callback)

执行完后,你就能听到系统语音播放内容了!

关注我,紧跟本系列专栏文章,咱们下篇再续!

作者简介:魔都架构师,多家大厂后端一线研发经验,在分布式系统设计、数据平台架构和AI应用开发等领域都有丰富实践经验。

各大技术社区头部专家博主。具有丰富的引领团队经验,深厚业务架构和解决方案的积累。

负责:

  • 中央/分销预订系统性能优化

  • 活动&券等营销中台建设

  • 交易平台及数据中台等架构和开发设计

  • 车联网核心平台-物联网连接平台、大数据平台架构设计及优化

  • LLM应用开发

    目前主攻降低软件复杂性设计、构建高可用系统方向。

参考:

相关推荐
李慕婉学姐2 小时前
【开题答辩过程】以《基于JAVA的校园即时配送系统的设计与实现》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
java·开发语言·数据库
奋进的芋圆4 小时前
Java 延时任务实现方案详解(适用于 Spring Boot 3)
java·spring boot·redis·rabbitmq
sxlishaobin4 小时前
设计模式之桥接模式
java·设计模式·桥接模式
model20054 小时前
alibaba linux3 系统盘网站迁移数据盘
java·服务器·前端
荒诞硬汉4 小时前
JavaBean相关补充
java·开发语言
提笔忘字的帝国4 小时前
【教程】macOS 如何完全卸载 Java 开发环境
java·开发语言·macos
2501_941882485 小时前
从灰度发布到流量切分的互联网工程语法控制与多语言实现实践思路随笔分享
java·开发语言
華勳全栈5 小时前
两天开发完成智能体平台
java·spring·go
alonewolf_995 小时前
Spring MVC重点功能底层源码深度解析
java·spring·mvc
沛沛老爹5 小时前
Java泛型擦除:原理、实践与应对策略
java·开发语言·人工智能·企业开发·发展趋势·技术原理