python + api2d 实现语音版chatgpt

1、前言:

        最近在翻自己电脑的时候,发现之前还做过这个。为了防止换电脑时丢失,这里写个博客记录下。

2、功能模块:

        整个项目分为五个文件,如下表:

文件名 作用
main.py主函数
ChatgptApi.py实现与api2d交互的接口
RecordModule.py实现录音功能
TextToSpeechModule.py实现文本转语音功能
SpeechToTextModule.py实现语音转文本功能

        项目整体思路:通过RecordModule模块录音,生成音频文件。再通过SpeechToTextModule模块将音频文件转换为文本。之后,通过ChatgptApi模块将文本发送给chatgpt,返回回答后调用TextToSpeechModule模块将文本转为音频文件并播放。

2.1、main.py

import RecordModule
import ChatgptApi
import TextToSpeechModule
import SpeechToTextModule
import keyboard
from playsound import playsound

# 利用api2d接口实现的chatgpt语音对话,其中文本转语音是使用whisper库离线转的,而回复以及语音转文本则是使用了api2d的接口
if __name__ == '__main__':
    press = 'alt'
    confirmPress = 'enter'
    mode = 'debug mode'
    # 本地语音只支持中英文
    # 使用本地语音节省经费,但效果不如OPENAI
    isUseLocalSpeaker = "true"
    text = ''
    background = '输入给你的文字是通过其他语音转文本模型识别的,可能会出错,需要你自行纠正并理解,你输出的文字会转换为语音。要求输出口语化,并加入一些语气词'
    ChatgptApi.SetBackGround(background)
    ChatgptApi.SetMemory(flag=False)
    if mode == 'debug mode':
        print('press ' + press + ' to recording')
        while True:
            if keyboard.is_pressed(press):
                RecordModule.setPressKey(press)
                RecordModule.Record('question.mp3')
                text = SpeechToTextModule.STT('question.mp3')
                print('question:')
                print(text)
                if mode == 'debug mode':
                    text = input("修正内容:") or text
                    print(text)
                text = ChatgptApi.rquestChatGpt(text)
                print('response:')
                print(text)
                if isUseLocalSpeaker == "true":
                    # 本地文本转语音
                   TextToSpeechModule.TTSLcoal(text=text,language=0,rate=200,volume=0.9,filename="respones.mp3",sayit=1)
                else:
                    TextToSpeechModule.TTS(text, 'mp3')
                    playsound('response.mp3')
                print('press ' + press + ' to recording')
            elif keyboard.is_pressed('esc'):
                break
    elif mode == 'text mode':
        while True:
            text = input("内容:") or text
            print(text)
            if text == 'esc':
                break
            text = ChatgptApi.rquestChatGpt(text)
            print('response:')
            print(text)

2.2、ChatgptApi.py

import requests
import json
import whisper

url = "https://oa.api2d.net/v1/chat/completions"
msg = []
jsonBody = {}
question = '你好'
background = '输入可能会出错,需要你自行纠正并理解。要求输出口语化,并加入一些语气词。你的回复尽量简短'
isMem = True

def rquestChatGpt(text):
    question = text
    msg.append({'role': 'system', 'content': background})
    msg.append({'role': 'user', 'content': question})
    jsonBody["model"] = "gpt-3.5-turbo-0613"
    jsonBody['messages'] = msg
    jsonBody['safe_mode'] = False
    # jsonBody['max_tokens'] = 100
    payload = json.dumps(jsonBody)
    headers = {
        'Authorization': 'Bearer <在api2d官网上申请的Forward Key>',
        'User-Agent': 'Apifox/1.0.0 (https://openai.api2d.net)',
        'Content-Type': 'application/json'
    }
    response = requests.request("POST", url, headers=headers, data=payload)
    response = json.loads(response.text)
    response = response['choices'][0]['message']['content']
    if isMem == True:
        msg.append({'role': 'assistant', 'content': response})
    else:
        msg.clear()
        msg.append({'role': 'system', 'content': background})
    return response

def ClearMemory():
    msg.clear()
    msg.append({'role': 'system', 'content': background})

def SetMemory(flag = True):
    global  isMem
    isMem = flag

def SetBackGround(str):
    global background
    background = str

        国内无法直接访问openAI的网络api,可以通过api2d中转,就是费用会贵一点点。

        api2d官网:API2D

2.3、RecordModule.py

import pyaudio
import wave
import keyboard

CHUNK = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 2
RATE = 16000
FILE = 'question.mp3'
press = 'space'
def setPressKey(key):
    global press
    press = key

def Record(file):
    FILE = file
    p = pyaudio.PyAudio()  # 初始化
    print('Recording ON, press ' + press + ' to stop Recording')

    stream = p.open(format=FORMAT,
                    channels=CHANNELS,
                    rate=RATE,
                    input=True,
                    frames_per_buffer=CHUNK)  # 创建录音文件
    frames = []
    while True:
        if keyboard.is_pressed(press):
            break
        data = stream.read(CHUNK)
        frames.append(data)  # 开始录音

    print("Recording OFF")
    stream.stop_stream()
    stream.close()
    p.terminate()

    wf = wave.open(FILE, 'wb')  # 保存
    wf.setnchannels(CHANNELS)
    wf.setsampwidth(p.get_sample_size(FORMAT))
    wf.setframerate(RATE)
    wf.writeframes(b''.join(frames))
    wf.close()

2.4、TextToSpeechModule.py

import requests
import json
import pyttsx3
from zhconv import convert

def TTS(input, type):
   url = "https://oa.api2d.net/v1/audio/speech"
   msg = []
   jsonBody = {}
   jsonBody["model"] = "tts-1"
   jsonBody['input'] = input
   jsonBody['voice'] = 'alloy'
   jsonBody['response_format'] = type
   payload = json.dumps(jsonBody)
   headers = {
      'Authorization': 'Bearer <在api2d官网上申请的Forward Key>',
      'User-Agent': 'Apifox/1.0.0 (https://apifox.com)',
      'Content-Type': 'application/json'
   }
   response = requests.request("POST", url, headers=headers, data=payload)
   file = open('response.' + type,'wb')
   file.write(response.content)
   file.close()
   #print(response.text)
   return response.content

def TTSLcoal(text, language, rate, volume, filename, sayit=0):
   # 参数说明: 六个重要参数,阅读的文字,语言(0-英文/1-中文),语速,音量(0-1),保存的文件名(以.mp3收尾),是否发言(0否1是)
   text = convert(text, 'zh-hans')  # 转换字符串为简中
   engine = pyttsx3.init()  # 初始化语音引擎
   engine.setProperty('rate', rate)  # 设置语速
   # 速度调试结果:50戏剧化的慢,200正常,350用心听小说,500敷衍了事
   engine.setProperty('volume', volume)  # 设置音量
   voices = engine.getProperty('voices')  # 获取当前语音的详细信息
   if int(language) == 0:
      engine.setProperty('voice', voices[0].id)  # 设置第一个语音合成器 #改变索引,改变声音。0中文,1英文(只有这两个选择)
   elif int(language) == 1:
      engine.setProperty('voice', voices[1].id)
   if int(sayit) == 1:
      engine.say(text)  # pyttsx3->将结果念出来
   elif int(sayit) == 0:
      print("那我就不念了哈")
   engine.save_to_file(text, filename)  # 保存音频文件
   print(filename, "保存成功")
   engine.runAndWait()  # pyttsx3结束语句(必须加)
   engine.stop()  # pyttsx3结束语句(必须加)

        这里有两个接口,其中TTS接口是调用了OpenAI文本转语音的网络api,效果很好,但是需要花钱。而TTSLcoal接口则是使用了第三方库pyttsx3来实现,免费但比较僵硬。

2.5、SpeechToTextModule.py

import whisper

def STT(file = 'question.mp3'):
	model = whisper.load_model("base")
	audio = whisper.load_audio(file)
	audio = whisper.pad_or_trim(audio)
	mel = whisper.log_mel_spectrogram(audio).to(model.device)
	_, probs = model.detect_language(mel)
	print(f"Detected language: {max(probs, key=probs.get)}")
	options = whisper.DecodingOptions(fp16=False)  # cpu一定要設置false
	result = whisper.decode(model, mel, options)
	return result.text
  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值