前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >利用OpenAI和NVIDIA Riva,在Jetson上搭建一个AI聊天机器人

利用OpenAI和NVIDIA Riva,在Jetson上搭建一个AI聊天机器人

作者头像
GPUS Lady
发布2023-09-07 08:38:35
5520
发布2023-09-07 08:38:35
举报
文章被收录于专栏:GPUS开发者GPUS开发者

今天小编介绍一个开发者项目:

背景知识

探索 Riva:借助 NVIDIA 技术赋能语音应用

在尖端语音处理领域,Riva 是一款由 NVIDIA 开发的强大平台,使开发人员能够创建强大的语音应用。该平台提供了一系列复杂的语音处理能力,包括自动语音识别(ASR)、文本转语音(TTS)、自然语言处理(NLP)、神经机器翻译(NMT)和语音合成。Riva 的一个关键优势在于其利用了 NVIDIA 的 GPU 加速技术,确保在处理高负载时仍能保持最佳性能。通过用户友好的 API 接口和 SDK 工具,Riva 简化了开发人员构建语音应用的过程。此外,Riva 还在 NVIDIA NGC™ 存储库中提供了预训练的语音模型,这些模型可以在自定义数据集上使用 NVIDIA NeMo 进行进一步优化,从而将专业模型的开发加速了 10 倍。

了解 Riva 的 ASR(自动语音识别)

Riva 的 ASR 是 NVIDIA 开发的一项先进技术,它使用先进的深度学习模型和算法,将口语转换为书面文本。其准确性和效率使其成为实时转录、语音命令和其他语音转文本应用的首选解决方案。

深入 Riva 的 TTS(文本转语音)

Riva 的 TTS 技术是一项令人瞩目的成就,它可以将书面文本转换为具有卓越质量的自然音色的语音。通过利用深度学习技术的能力,这项技术生成的语音非常接近人类语音,具有准确的发音和细致的表达。开发人员甚至可以调整参数以实现所需的语音特征。Riva 的 TTS 在虚拟助手、有声读物和辅助性解决方案等多个领域都有应用。

揭示 OpenAI API

OpenAI API 为开发人员提供了将先进的自然语言处理能力无缝集成到其应用程序中的机会。这个接口提供了强大的语言模型,可以基于提示生成非常接近人类语言的文本。开发人员可以向 API 发送请求,获得生成的文本作为输出,适用于从文本生成到翻译等各种任务。

项目介绍

方案架构:

来自麦克风的语音输入通过 Riva 的自动语音识别(ASR)库转换为文本,然后传递给 OpenAI API。当 OpenAI API 返回结果时,文本会通过 Riva 的文本转语音(TTS)库转换为语音,并通过麦克风输出。

部署解决方案:

上述解决方案的部署将在Jetson Orin NX 16GB 系统上构建。这款智能边缘设备融合了强大性能和紧凑设计,可在边缘提供高达 100 TOPS 的现代 AI 性能。与 Jetson Xavier NX 和 Jetson AGX Xavier 等前身相比,Orin NX 的性能分别提升了 5 倍和 3 倍。这种提升得益于将 NVIDIA Ampere™ GPU 架构与 64 位操作能力相结合,集成了先进的多功能视频和图像处理以及 NVIDIA 深度学习加速器。

部署 Riva 服务器

步骤 1:刷 JetPack

首先,给Jetson产品刷机。

步骤 2:寻找适配的 Riva 版本

  1. 在本例中,我们在嵌入式平台上使用 Riva 2.11.0。需要JetPack 5.1或JetPack 5.1.1。
  2. 根据默认容器和模型的要求,Jetson 上有大约 15 GB 的可用磁盘空间。如果您要部署任何 Riva 模型中间表示 (RMIR) 模型,则所需的额外磁盘空间约为 14 GB 加上 RMIR 模型的大小。
  3. 您已在 Jetson 平台上启用以下电源模式。这些模式会激活所有 CPU 核心并以最大频率对 CPU/GPU 进行计时,以实现最佳性能。
代码语言:javascript
复制
sudo nvpmodel -m 0 (Jetson Orin AGX, mode MAXN)
sudo nvpmodel -m 0 (Jetson Xavier AGX, mode MAXN)
sudo nvpmodel -m 2 (Jetson Xavier NX, mode MODE_15W_6CORE)

4. 您已通过在 /etc/docker/daemon.json 文件中添加以下行,将 Jetson 平台上的默认运行时设置为 nvidia。编辑文件后使用 sudo systemctl restart docker 重新启动 Docker 服务

代码语言:javascript
复制
"default-:runtime": "nvidia"

步骤3:安装CLI tools

打开一个终端,输入

代码语言:javascript
复制
wget --content-disposition https://ngc.nvidia.com/downloads/ngccli_arm64.zip && unzip ngccli_arm64.zip && chmod u+x ngc-cli/ngc

检查二进制文件的 md5 哈希值以确保文件在下载过程中没有损坏:

代码语言:javascript
复制
find ngc-cli/ -type f -exec md5sum {} + | LC_ALL=C sort | md5sum -c ngc-cli.md5

将当前目录添加到路径:

代码语言:javascript
复制
Add your current directory to path:echo "export PATH=\"\$PATH:$(pwd)/ngc-cli\"" >> ~/.bash_profile && source ~/.bash_profile

或者创建一个符号链接:

代码语言:javascript
复制
ln -s $(pwd)/ngc-cli/ngc [destination_path]/ngc

您必须配置 NGC CLI 供您使用,以便可以运行命令。输入以下命令,并在出现提示时输入您的 API 密钥:

代码语言:javascript
复制
ngc config set

步骤 4 使用快速启动脚本进行本地部署

使用NGC CLI工具从命令行下载

代码语言:javascript
复制
ngc registry resource download-version nvidia/riva/riva_quickstart_arm64:2.11.0

初始化并启动 Riva。初始化步骤下载并准备 Docker 映像和模型。启动脚本启动服务器。

使用以下配置修改快速启动目录中的 config.sh 文件:

在下面的示例中,TTS 和 ASR 为 true,这会启用 text2speech 和 ASR 服务。NMT 和 NLP 服务为 false,从而禁用这些服务。

代码语言:javascript
复制
# Enable or Disable Riva Services
service_enabled_tts=true
service_enabled_asr=true
service_enabled_nmt=false
service_enabled_nlp=false

如果在 config.sh 中取消注释模型并启用相应的服务,则安装和配置模型。

配置完成后,输入以下命令:

代码语言:javascript
复制
cd riva_quickstart_arm64_v2.11.0

初始化并启动 Riva:

代码语言:javascript
复制
bash riva_init.sh
bash riva_start.sh

如何运行Riva的ASR?

设置输入设备和采样率(默认为16000),您可以使用以下命令检查输入设备:

代码语言:javascript
复制
python3 transcribe_mic.py --list-devices

然后运行脚本/asr/transcribe_mic.py

代码语言:javascript
复制
python3 transcribe_mic.py --input-device <device_number> --sample-rate-hz <sample_rate>

现在,当您对着麦克风讲话时,语音将转换为文本并显示在终端上。

如何运行Riva的TTS?

设置输出设备和采样率(默认为44100),您可以使用以下命令检查输入设备:

代码语言:javascript
复制
python3 talk.py --list-devices

然后运行脚本/tts/talk.py

代码语言:javascript
复制
.sh
 python3 talk.py --output-device <device_number> --sample-rate-hz <sample_rate>

现在,当您在终端上输入文本时,它将转换为语音并通过扬声器读出

如何使用OpenAI API?

首先,登录您的 OpenAI 帐户,然后访问此页面创建 API 密钥

首先,安装OpenAI API,在终端中使用以下命令:

代码语言:javascript
复制
pip3 install openai

之后,我们调用 openai.ChatCompletion.create()

此代码是使用 OpenAI API 聊天功能的示例

创建一个新的python脚本(这里我们使用vscode,您可以参考这里了解更多详细信息)并运行以下代码:

代码语言:javascript
复制
import openai

openai.api_key = "openai-api-key"#using you openai key here
model_engine = "gpt-3.5-turbo"
ans = openai.ChatCompletion.create(
    model=model_engine,
    messages=[{"role": "user", "content": "you question"},
          {"role": "assistant", "content": "The answer to the previous question "}]#use "assistant" to maintain context
)

print(ans.choices[0].message)

主要输入是 messages 参数。消息必须是消息对象的数组,其中每个对象都有一个角色(“系统”、“用户”或“助手”)和内容(消息的内容)。对话可以短至 1 条消息,也可以占很多页。

Assistant -assistant:消息帮助存储以前的回复。这是为了维持对话并为对话提供上下文。

具体信息可以参考:https://platform.openai.com/docs/api-reference/chat

关键代码概述

本节展示语音转文本、文本转语音和唤醒设置的关键代码。完整代码请参见文档末尾。

如何获取麦克风返回的信息?

将麦克风流作为迭代打开,然后迭代 asr_service.streaming_response_generator() 中的每个响应。使用is_final判断是否结束一句话

代码语言:javascript
复制
with riva.client.audio_io.MicrophoneStream(
                        args.sample_rate_hz,
                        args.file_streaming_chunk,
                        device=args.input_device,
                ) as stream:
                    for response in asr_service.streaming_response_generator(
                            audio_chunks=stream,
                            streaming_config=config,
                    ):
                        for result in response.results:
                            if result.is_final:
                                transcripts = result.alternatives[0].transcript  # print(output)
                                output = transcripts

我们如何将文本转换为语音输出?

设置参数(sample_rate_hz 和 output_device)

代码语言:javascript
复制
args1 = argparse.Namespace()
args1.language_code = 'en-US'
args1.sample_rate_hz = 48000 ##You can check the sample-rate of your own device to replace it
args1.stream = True #this shoule be true
args1.output_device = 24 #You can check the port number of your own device to replace it
service = riva.client.SpeechSynthesisService(auth)#This code is request the Riva server to synthesize the language
nchannels = 1
sampwidth = 2
sound_stream = None

我们调用 riva.client.audio_io.SoundCallBack() 函数来创建声音流,然后调用 service.synthesize_online() 来合成语音。

代码语言:javascript
复制
try:
    if args1.output_device is not None:
        #For playing audio during synthesis you will need to pass audio chunks to riv          a.client.audio_io.SoundCallBack as they arrive.
        sound_stream = riva.client.audio_io.SoundCallBack(
            args1.output_device, nchannels=nchannels, sampwidth=sampwidth,
            framerate=args1.sample_rate_hz
        )
    if args1.stream:
        #responses1 is the speech returned after synthesis,returning as an iterator
        responses1 = service.synthesize_online(
            answer, None, args1.language_code, sample_rate_hz=args1.sample_rate_hz
        )
        #Playing speech iteratively
        for resp in responses1:
            if sound_stream is not None:
                sound_stream(resp.audio)
finally:
    if sound_stream is not None:
        sound_stream.close()

如何设置唤醒词和睡眠词?

可以修改这部分代码来设置自己的唤醒词

代码语言:javascript
复制
if output == "hello ":#You can specify your wake-up word here,and remember to add a space after it
    is_wakeup = True
    anSwer('here', auth)
    output = ""
if output == "stop " and is_wakeup == True: #You can specify your pause word here,and remember to add a space after it
    is_wakeup = False
    anSwer('Bye! Have a great day!', auth)
    output = ""

运行代码

input-device和sample-rate-hz参数应该替换为你自己的

代码语言:javascript
复制
python3 <yourfilename.py> --input-device 24 --sample-rate-hz 48000

完整的代码:

代码语言:javascript
复制
import argparse
from typing import List, Iterable
import riva.client.proto.riva_asr_pb2 as rasr
import riva.client
from riva.client.argparse_utils import add_asr_config_argparse_parameters, add_connection_argparse_parameters
import openai
import riva.client.audio_io
import time

#This is the part of typing the command line
#Only the input device and the sampling rate need to be specified
def parse_args() -> argparse.Namespace:
    default_device_info = riva.client.audio_io.get_default_input_device_info()
    default_device_index = None if default_device_info is None else default_device_info['index']
    parser = argparse.ArgumentParser(
        description="Streaming transcription from microphone via Riva AI Services",
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
    )
    parser.add_argument("--input-device", type=int, default=default_device_index, help="An input audio device to use.")
    parser.add_argument("--list-devices", action="store_true", help="List input audio device indices.")
    parser = add_asr_config_argparse_parameters(parser, profanity_filter=True)
    parser = add_connection_argparse_parameters(parser)
    parser.add_argument(
        "--sample-rate-hz",
        type=int,
        help="A number of frames per second in audio streamed from a microphone.",
        default=16000,
    )
    parser.add_argument(
        "--file-streaming-chunk",
        type=int,
        default=1600,
        help="A maximum number of frames in a audio chunk sent to server.",
    )
    args = parser.parse_args()
    return args

#This function is used to make a speech using the microphone. "answer" is the content of the speech, which you can change
#These codes are modified based on riva's tutorials,you can get more details on it on github https://github.com/nvidia-riva/python-clients/tutorials
def anSwer(answer,auth):
    
    args1 = argparse.Namespace()
    args1.language_code = 'en-US'
    args1.output_divece = 24
    args1.sample_rate_hz = 48000
    args1.stream = True
    args1.output_device = 24
    service = riva.client.SpeechSynthesisService(auth)
    nchannels = 1
    sampwidth = 2
    sound_stream = None
    try:
        if args1.output_device is not None:
            #For playing audio during synthesis you will need to pass audio chunks to riva.client.audio_io.SoundCallBack as they arrive.
            sound_stream = riva.client.audio_io.SoundCallBack(
                args1.output_device, nchannels=nchannels, sampwidth=sampwidth,
                framerate=args1.sample_rate_hz
            )
        if args1.stream:
            responses1 = service.synthesize_online(
                answer, None, args1.language_code, sample_rate_hz=args1.sample_rate_hz
            )
            for resp in responses1:    
                if sound_stream is not None:
                    sound_stream(resp.audio)
    finally:
        if sound_stream is not None:
            sound_stream.close()

def main() :
    output = ""  
    answer = ""
    openai.api_key = "openai-api-key"#using you openai key here
    model_engine = "gpt-3.5-turbo"
    
    args = parse_args()
    #the args is used to specifed the speech output
    args1 = argparse.Namespace()
    args1.language_code = 'en-US'
    args1.output_divece = 24
    args1.sample_rate_hz = 48000
    args1.stream = True
    
    if args.list_devices:
        devices = riva.client.audio_io.list_input_devices()
        output += str(devices) + "\n"  
        return output
    auth = riva.client.Auth(args.ssl_cert, args.use_ssl, args.server)
    asr_service = riva.client.ASRService(auth)
    config = riva.client.StreamingRecognitionConfig(
        config=riva.client.RecognitionConfig(
            encoding=riva.client.AudioEncoding.LINEAR_PCM,
            language_code=args.language_code,
            max_alternatives=1,
            profanity_filter=args.profanity_filter,
            enable_automatic_punctuation=args.automatic_punctuation,
            verbatim_transcripts=not args.no_verbatim_transcripts,
            sample_rate_hertz=args.sample_rate_hz,
            audio_channel_count=1,
        ),
        interim_results=True,
    )
    riva.client.add_word_boosting_to_config(config, args.boosted_lm_words, args.boosted_lm_score)
    is_close = False
    is_wakeup = False
    while True:
        #Use iterators to receive mic's stream
        if not is_close:
            with riva.client.audio_io.MicrophoneStream(
                    args.sample_rate_hz,
                    args.file_streaming_chunk,
                    device=args.input_device,
            ) as stream:
                try:
                    for response in asr_service.streaming_response_generator(
                            audio_chunks=stream,
                            streaming_config=config,
                    ):
                        for result in response.results:
                            if result.is_final:
                                transcripts = result.alternatives[0].transcript  # print(output)
                                output = transcripts
                        if  output != '':  
                            if output == "hello ":#You can specify your wake-up word here,and remember to add a space after it
                                is_wakeup = True
                                anSwer('here', auth)
                                output = ""
                            if output == "stop " and is_wakeup == True: #You can specify your pause word here,and remember to add a space after it
                                is_wakeup = False
                                anSwer('Bye! Have a great day!', auth) 
                                output = ""
                            if is_wakeup == True and output != '':
                                print("ask:", output)
                                stream.close()
                                is_close = True
                                ans = openai.ChatCompletion.create(
                                    model=model_engine,
                                    messages=[{"role": "user", "content": output},
                                              {"role": "assistant", "content": answer}]#use "assistant" to maintain context
                                )
                                output = ''
                                answer = ans.choices[0].message["content"]
                                print("AI:", answer)
                                args1.output_device = 24
                                args1.sample_rate_hz = 48000

                                service = riva.client.SpeechSynthesisService(auth)
                                nchannels = 1
                                sampwidth = 2
                                sound_stream = None
                                try:
                                    if args1.output_device is not None:
                                        sound_stream = riva.client.audio_io.SoundCallBack(
                                            args1.output_device, nchannels=nchannels, sampwidth=sampwidth,
                                            framerate=args1.sample_rate_hz
                                        )
                                    start = time.time()
                                    if args1.stream:
                                        responses1 = service.synthesize_online(
                                            answer, None, args1.language_code, sample_rate_hz=args1.sample_rate_hz
                                        )
                                        first = True
                                        #print(responses)
                                        for resp in responses1:
                                            stop = time.time()
                                            if first:
                                                print(f"Time to first audio: {(stop - start):.3f}s")
                                                first = False
                                            if sound_stream is not None:
                                                #print("a:",time.time())
                                                sound_stream(resp.audio)
                                                #print("b:",time.time())
                                                
                                finally:
                                    if sound_stream is not None:
                                        sound_stream.close()
                                        #mic_closed = False
                                        is_close = True
                                break
                            
                finally:
                    is_close = False
        else:
            is_close = False





if __name__ == '__main__':
    main()
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-08-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 GPUS开发者 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
语音识别
腾讯云语音识别(Automatic Speech Recognition,ASR)是将语音转化成文字的PaaS产品,为企业提供精准而极具性价比的识别服务。被微信、王者荣耀、腾讯视频等大量业务使用,适用于录音质检、会议实时转写、语音输入法等多个场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档