使用 PyAudio、语音识别、pyttsx3 和 SerpApi 构建简单的基于 CLI 的语音助手

news2024/11/20 6:31:35
德米特里·祖布☀️

一、介绍

        正如您从标题中看到的,这是一个演示项目,显示了一个非常基本的语音助手脚本,可以根据 Google 搜索结果在终端中回答您的问题。

        您可以在 GitHub 存储库中找到完整代码:dimitryzub/serpapi-demo-projects/speech-recognition/cli-based/

        后续博客文章将涉及:

  • 使用Flask、一些 HTML、CSS 和 Javascript 的基于 Web 的解决方案。
  • 使用Flutter和Dart的基于 Android 和 Windows 的解决方案。

二、我们将在这篇博文中构建什么

2.1 环境准备

        首先,让我们确保我们处于不同的环境中,并正确安装项目所需的库。最难(可能)是 安装 .pyaudio,关于此种困难可以参看下文克服:

   [解决]修复 win 32/64 位操作系统上的 PyAudio pip 安装错误 

2.2 虚拟环境和库安装

        在开始安装库之前,我们需要为此项目创建并激活一个新环境:

# if you're on Linux based systems
$ python -m venv env && source env/bin/activate
$ (env) <path>

# if you're on Windows and using Bash terminal
$ python -m venv env && source env/Scripts/activate
$ (env) <path>

# if you're on Windows and using CMD
python -m venv env && .\env\Scripts\activate
$ (env) <path>

        解释python -m venv env告诉 Python 运行 module( -m)venv并创建一个名为 的文件夹env&&代表“与”。source <venv_name>/bin/activate将激活您的环境,并且您将只能在该环境中安装库。

        现在安装所有需要的库:

pip install rich pyttsx3 SpeechRecognition google-search-results

        现在到pyaudio. 请记住,pyaudio安装时可能会引发错误。您可能需要进行额外的研究。

        如果您使用的是 Linux,我们需要安装一些开发依赖项才能使用pyaudio

$ sudo apt-get install -y libasound-dev portaudio19-dev
$ pip install pyaudio

如果您使用的是 Windows,则更简单(使用 CMD 和 Git Bash 进行测试):

pip install pyaudio

三、完整代码

import os
import speech_recognition
import pyttsx3
from serpapi import GoogleSearch
from rich.console import Console
from dotenv import load_dotenv

load_dotenv('.env')
console = Console()

def main():
    console.rule('[bold yellow]SerpApi Voice Assistant Demo Project')
    recognizer = speech_recognition.Recognizer()

    while True:
        with console.status(status='Listening you...', spinner='point') as progress_bar:
            try:
                with speech_recognition.Microphone() as mic:
                    recognizer.adjust_for_ambient_noise(mic, duration=0.1)
                    audio = recognizer.listen(mic)
                    text = recognizer.recognize_google(audio_data=audio).lower()
                    console.print(f'[bold]Recognized text[/bold]: {text}')

                    progress_bar.update(status='Looking for answers...', spinner='line')
                    params = {
                        'api_key': os.getenv('API_KEY'),
                        'device': 'desktop',
                        'engine': 'google',
                        'q': text,
                        'google_domain': 'google.com',
                        'gl': 'us',
                        'hl': 'en'
                    }
                    search = GoogleSearch(params)
                    results = search.get_dict()

                    try:
                        if 'answer_box' in results:
                            try:
                                primary_answer = results['answer_box']['answer']
                            except:
                                primary_answer = results['answer_box']['result']
                            console.print(f'[bold]The answer is[/bold]: {primary_answer}')
                        elif 'knowledge_graph' in results:
                            secondary_answer = results['knowledge_graph']['description']
                            console.print(f'[bold]The answer is[/bold]: {secondary_answer}')
                        else:
                            tertiary_answer = results['answer_box']['list']
                            console.print(f'[bold]The answer is[/bold]: {tertiary_answer}')

                        progress_bar.stop() # if answered is success -> stop progress bar.
                        user_promnt_to_contiune_if_answer_is_success = input('Would you like to to search for something again? (y/n) ')

                        if user_promnt_to_contiune_if_answer_is_success == 'y':
                            recognizer = speech_recognition.Recognizer()
                            continue # run speech recognizion again until `user_promt` == 'n'
                        else:
                            console.rule('[bold yellow]Thank you for cheking SerpApi Voice Assistant Demo Project')
                            break
                    except KeyError:
                        progress_bar.stop()
                        error_user_promt = input("Sorry, didn't found the answer. Would you like to rephrase it? (y/n) ")

                        if error_user_promt == 'y':
                            recognizer = speech_recognition.Recognizer()
                            continue # run speech recognizion again until `user_promt` == 'n'
                        else:
                            console.rule('[bold yellow]Thank you for cheking SerpApi Voice Assistant Demo Project')
                            break
            except speech_recognition.UnknownValueError:
                progress_bar.stop()
                user_promt_to_continue = input('Sorry, not quite understood you. Could say it again? (y/n) ')

                if user_promt_to_continue == 'y':
                    recognizer = speech_recognition.Recognizer()
                    continue # run speech recognizion again until `user_promt` == 'n'
                else:
                    progress_bar.stop()
                    console.rule('[bold yellow]Thank you for cheking SerpApi Voice Assistant Demo Project')
                    break

if __name__ == '__main__':
    main()

四、代码说明

导入库:

import os
import speech_recognition
import pyttsx3
from serpapi import GoogleSearch
from rich.console import Console
from dotenv import load_dotenv
  • rich用于在终端中进行漂亮格式化的 Python 库。
  • pyttsx3Python 的文本到语音转换器可离线工作。
  • SpeechRecognition用于将语音转换为文本的 Python 库。
  • google-search-resultsSerpApi 的 Python API 包装器,可解析来自 15 个以上搜索引擎的数据。
  • os读取秘密环境变量。在本例中,它是 SerpApi API 密钥。
  • dotenv从文件加载环境变量(SerpApi API 密钥).env.env文件可以重命名为任何文件:(.napoleon .点)代表环境变量文件。

定义rich Console(). 它将用于美化终端输出(动画等):

console = Console()

定义main所有发生的函数:

def main():
    console.rule('[bold yellow]SerpApi Voice Assistant Demo Project')
    recognizer = speech_recognition.Recognizer()

在函数的开头,我们定义speech_recognition.Recognizer()并将console.rule创建以下输出:

───────────────────────────────────── SerpApi Voice Assistant Demo Project ─────────────────────────────────────

下一步是创建一个 while 循环,该循环将不断监听麦克风输入以识别语音:

while True:
    with console.status(status='Listening you...', spinner='point') as progress_bar:
        try:
            with speech_recognition.Microphone() as mic:
                recognizer.adjust_for_ambient_noise(mic, duration=0.1)
                audio = recognizer.listen(mic)

                text = recognizer.recognize_google(audio_data=audio).lower()
                console.print(f'[bold]Recognized text[/bold]: {text}')
  • console.status-rich进度条,仅用于装饰目的。
  • speech_recognition.Microphone()开始从麦克风拾取输入。
  • recognizer.adjust_for_ambient_noise旨在根据环境能量水平校准能量阈值。
  • recognizer.listen监听实际的用户文本。
  • recognizer.recognize_google使用 Google Speech Recongition API 执行语音识别。lower()是降低识别文本。
  • console.print允许使用文本修改的语句rich print,例如添加粗体斜体等。

spinner='point'将产生以下输出(使用python -m rich.spinner查看列表spinners):

之后,我们需要初始化 SerpApi 搜索参数以进行搜索:

progress_bar.update(status='Looking for answers...', spinner='line') 
params = {
    'api_key': os.getenv('API_KEY'),  # serpapi api key   
    'device': 'desktop',              # device used for 
    'engine': 'google',               # serpapi parsing engine: https://serpapi.com/status
    'q': text,                        # search query 
    'google_domain': 'google.com',    # google domain:          https://serpapi.com/google-domains
    'gl': 'us',                       # country of the search:  https://serpapi.com/google-countries
    'hl': 'en'                        # language of the search: https://serpapi.com/google-languages
    # other parameters such as locations: https://serpapi.com/locations-api
}
search = GoogleSearch(params)         # where data extraction happens on the SerpApi backend
results = search.get_dict()           # JSON -> Python dict

progress_bar.update将会progress_bar用新的status(控制台中打印的文本)进行更新,spinner='line'并将产生以下动画:

之后,使用 SerpApi 的Google 搜索引擎 API从 Google 搜索中提取数据。

代码的以下部分将执行以下操作:

try:
    if 'answer_box' in results:
        try:
            primary_answer = results['answer_box']['answer']
        except:
            primary_answer = results['answer_box']['result']
        console.print(f'[bold]The answer is[/bold]: {primary_answer}')

     elif 'knowledge_graph' in results:
            secondary_answer = results['knowledge_graph']['description']
            console.print(f'[bold]The answer is[/bold]: {secondary_answer}')
        else:
            tertiary_answer = results['answer_box']['list']
            console.print(f'[bold]The answer is[/bold]: {tertiary_answer}')
        progress_bar.stop()  # if answered is success -> stop progress bar

        user_promnt_to_contiune_if_answer_is_success = input('Would you like to to search for something again? (y/n) ')

        if user_promnt_to_contiune_if_answer_is_success == 'y':
            recognizer = speech_recognition.Recognizer()
            continue         # run speech recognizion again until `user_promt` == 'n'
        else:
            console.rule('[bold yellow]Thank you for cheking SerpApi Voice Assistant Demo Project')
            break

    except KeyError:
        progress_bar.stop()  # if didn't found the answer -> stop progress bar
        error_user_promt = input("Sorry, didn't found the answer. Would you like to rephrase it? (y/n) ")

        if error_user_promt == 'y':
            recognizer = speech_recognition.Recognizer()
            continue         # run speech recognizion again until `user_promt` == 'n'
        else:
            console.rule('[bold yellow]Thank you for cheking SerpApi Voice Assistant Demo Project')
            break

最后一步是处理麦克风没有拾取声音时的错误:

# while True:
#     with console.status(status='Listening you...', spinner='point') as progress_bar:
#         try:
            # speech recognition code
            # data extraction code
        except speech_recognition.UnknownValueError:
                progress_bar.stop()         # if didn't heard the speech -> stop progress bar
                user_promt_to_continue = input('Sorry, not quite understood you. Could say it again? (y/n) ')

          if user_promt_to_continue == 'y':
              recognizer = speech_recognition.Recognizer()
              continue               # run speech recognizion again until `user_promt` == 'n'
          else:
              progress_bar.stop()    # if want to quit -> stop progress bar
              console.rule('[bold yellow]Thank you for cheking SerpApi Voice Assistant Demo Project')
              break

console.rule()将提供以下输出:

───────────────────── Thank you for cheking SerpApi Voice Assistant Demo Project ──────────────────────

添加if __name__ == '__main__'惯用语,以防止用户在无意时意外调用某些脚本,并调用main将运行整个脚本的函数:

if __name__ == '__main__':
    main()

五、链接

  • rich
  • pyttsx3
  • SpeechRecognition
  • google-search-results
  • os
  • dotenv

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

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

相关文章

fork() 详解,返回2次什么意思?

在 Unix-like 系统中&#xff0c;fork() 函数是用于创建新进程的系统调用。当调用 fork() 时&#xff0c;会创建一个新的子进程&#xff0c;该子进程是原始进程的副本。fork() 函数在父进程和子进程中返回不同的值&#xff0c;具体如下&#xff1a; 对于父进程&#xff1a;for…

万界星空科技云MES系统产品追溯功能介绍

制造业工厂产品质量贯穿于产品的整个生命周期&#xff0c;也是企业参与市场竞争求生存求发展的基础&#xff0c;而制造过程中出现的产品质量问题则是产品最终质量的基石。 MES系统是一种信息化管理系统&#xff0c;它可以实现产品的全生命周期的监控和管理&#xff0c;同时&am…

openGauss Meetup(天津站)精彩回顾 | openGauss天津用户组正式成立

由openGauss社区、天开发展集团、天津市软件行业协会、天大智图&#xff08;天津&#xff09;科技有限公司联合主办的“openGauss Meetup • 天津站”已于10月13日落下帷幕&#xff0c;此次活动邀请到众多业内技术专家&#xff0c;从技术创新、学术创新、发展创新、以及生态共建…

【面试系列】Vue

引言&#xff1a;下面是一些常见的 Vue 面试题和对应的答案 目录 1. Vue 是什么&#xff1f;它有哪些特点&#xff1f;2. Vue 的生命周期有哪些&#xff1f;请简要描述每个生命周期的作用。3. Vue 组件间通信的有哪些方式&#xff1f;4. Vue 的 computed 和 watch 的区别是什么…

【LeetCode:2530. 执行 K 次操作后的最大分数 | 堆】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

javaEE - 1(9000字详解多线程)

一&#xff1a;认识线程 1.1 线程的概念 线程是操作系统中执行的最小单位&#xff0c;它是进程中的一个实体。一个进程可以包含多个线程&#xff0c;并且这些线程共享进程的资源&#xff0c;如内存、文件句柄等&#xff0c;但每个线程有自己的独立执行流程和栈空间。 线程在…

关于vant 的tabbar功能

1、想要实现tabbar页面A&#xff0c;其他的页面B&#xff08;非tabbar页面&#xff09;。 从A页面进入B页面&#xff0c;底部的active选中效果应该被取消掉&#xff0c;但是还是选中A。 按照官网的说法有两个方法 一、根据path路径 二、自定义的model 但是&#xff01;但是…

孩子近视了用什么台灯好呢?对视力友好的护眼台灯推荐

对于很多家里有孩子写作业、或者夜晚需要面对电脑或手机屏幕加班写文案、搞剪辑等工作的朋友&#xff0c;一款“好”的台灯不仅可以保护眼睛、缓解视疲劳&#xff0c;而且还能够更贴心与智能&#xff0c;提升工作效率。最近总结了一期非常好用的护眼台灯&#xff0c;希望可以给…

如何恢复红米手机删除的照片/文件?(亲测有效的6 种方式)

如何恢复红米手机删除的照片/文件&#xff1f;&#xff08;亲测有效的6 种方式&#xff09; 凭借出色的相机和实惠的价格&#xff0c;小米红米系列已成为全球知名品牌。但是&#xff0c;最近有人抱怨说他们的红米手机丢失了很多珍贵的照片或视频&#xff0c;希望知道如何从小米…

Scrum敏捷开发方法

什么是Scrum敏捷开发方法&#xff1f; Scrum是一种广泛使用的敏捷开发方法&#xff0c;旨在提高软件开发和项目管理的效率。Scrum强调迭代、协作、自组织和透明度&#xff0c;使团队能够更好地应对不断变化的需求和复杂性。Scrum方法的核心思想是通过一系列短期周期来交付功能…

创建线程的四种方法(Java)

目录 一、继承 Thread类 二、实现Runnable接口 三、实现Callable接口 四、使用线程池 一、继承 Thread类 创建一个类 Thread 类&#xff0c;并重写run()方法&#xff0c;通过start()启动线程。以继承的方式创建的线程可以使用当前类来获取线程的名称、状态、优先级等相关信…

PXIE板卡,4口QSFP+,PCIE GEN3 X8,XILINX FPGA XCVU3P设计

PXIE板卡&#xff0c;4口QSFP&#xff0c;PCIE GEN3 X8&#xff0c;基于XILINX FPGA XCVU3P设计。 1&#xff1a;电路拓扑 ● 支持利用 EEPROM 存储数据&#xff1b; ● 电源时序控制和总功耗监控&#xff1b; 2&#xff1a;电路调试 3&#xff1a;测试 PCIE gen3 x8&#…

通讯协议学习之路:SPI协议理论

通讯协议之路主要分为两部分&#xff0c;第一部分从理论上面讲解各类协议的通讯原理以及通讯格式&#xff0c;第二部分从具体运用上讲解各类通讯协议的具体应用方法。 后续文章会同时发表在个人博客(jason1016.club)、CSDN&#xff1b;视频会发布在bilibili(UID:399951374) 序、…

同一网段内两台电脑ping不通,诡异问题记录

今天发现了个诡异的问题&#xff0c;和锐捷技术倒腾了半天&#xff0c;记录一下。 症状&#xff1a; 如图&#xff08;简单画了下&#xff09;&#xff0c;pc1 到 网络打印机 10.64.253.184 &#xff0c;就是ping不通... 但是在交换机上&#xff0c;在路由器上&#xff0c;在…

企业数据安全组织建设

PS:内容均为个人学习及实践积累所得&#xff01; 前言&&背景 企业数据安全组织团队的建设非常重要。 首先,数据是企业最重要的资产和核心竞争力。如果数据泄露或遭到破坏,将直接威胁企业的生存。因此,数据安全事关企业的生存和发展。建立专业的数据安全团队,可以系统…

多云系列|10个关键的多云战略:云计算成本的完整可视性

了解和控制你的云计算支出是每个企业都会遇到的一个难题。根据IDC最近的一项研究&#xff0c;IT决策者面临的首要挑战之一是控制云计算成本。对于大多数企业来说&#xff0c;问题在于他们所有的云资源没有完全的可视性。这可能是由于其他部门绕过IT部门为其开发项目进行支出&am…

论坛介绍|COSCon'23 区块链(B)

众多开源爱好者翘首期盼的开源盛会&#xff1a;第八届中国开源年会&#xff08;COSCon23&#xff09;将于10月28-29日在四川成都市高新区菁蓉汇举办。本次大会的主题是&#xff1a;“开源&#xff1a;川流不息、山海相映”&#xff01;各位新老朋友们&#xff0c;欢迎到成都&am…

【论文复现】基于多模态深度学习方法的单细胞多组学数据聚类(【生物信息学】实验二:多组学数据融合:scMDC)

目录 一、实验介绍 1. 论文&#xff1a;基于多模态深度学习方法的单细胞多组学数据聚类 Abstract 2. Github链接 二、实验环境 0. 作者要求 1. 环境复现 实验一 实验二&#xff08;本实验&#xff09; 2. 库版本介绍 实验一 实验二 3. IDE 三、实验内容 1. 用法…

Linux高性能服务器编程——ch4笔记

第4章 TCP/IP 通信案例&#xff1a;访问 Internet 上的Web 服务器 4.1 实例总图 4.2 部署代理服务器 客户端和目标服务器之间可能存在多个代理服务器。 正向代理&#xff1a;要求客户端自己设置代理服务器的地址。 反向代理&#xff1a;设置在服务器端。 透明代理&#xff1…

JavaScript从入门到精通系列第二十一篇:JavaScript中的原型对象详解

文章目录 前言 一&#xff1a;原型对象 1&#xff1a;什么是原型对象 2&#xff1a;原型对象的作用 3&#xff1a;通过原型对象实现工厂方法 二&#xff1a;原型对象咋说 1&#xff1a;in和原型对象 2&#xff1a;hasOwnProperty()函数 3&#xff1a;hasOwnProperty()来…