本文介绍了一款基于ChatGPT的英语口语练习应用SpokenAi,包括PortAudio的安装流程和核心代码,以及语音合成TextToSpeech的实现。同时提供了配置文件和部署运行示例。 --由ChatGPT总结生成
Hi,大家好,我是Baird。最近几个月大火大热的ChatGPT已经发布到ChatGPT4版本了,我也一直在关注ChatGPT的发展,一直在思考能基于ChatGPT或着说openai的能力能做出点什么应用,解决一些问题。
在仔细看过openai的API文档后,发现openai不止提供了Chat的能力,还提供了如语音转文字,图片生成等能力。虽然没有ChatGPT那么火,但经过一番试用后,发现和ChatGPT效果一样让人惊艳。索性就直接来一个openai全家桶,通过openai的能力开发一款应用试试。
开发什么呢?
ChatGPT对英语的语言能力自然不必说,而我们国人当下英语学习面临的一大问题就是哑巴英语,市面上的提供的英语对话机器人和ChatGPT比起来差得不是一星半点。只能请老师一对一真人教学? 拜托,现在都2023年了,还需要花钱请口语老师么?
来造一款Ai口语练习应用解决这个问题
ChatGPT4是由OpenAI开发的自然语言处理模型,采用了大规模无监督学习的方式进行训练,可用于生成文本、回答问题和聊天等任务。OpenAI是人工智能领域的一家公司,其API文档提供了多种功能,包括语音转文字、图片生成等。
首选先列出我们需求清单,这个是一个简单版本的英语口语练习功能,先不打算造一个大app,我们只需要解决如下问题
基于上述功能,第一期我打算先做一个终端版本的应用-SpokenAi,看看后续发展再考虑做一个Web或APP版本的程序 (实际上是缺人手缺时间 )
Tips:tensorflowtts 依赖较多,为方便完整,这里采用Docker部署
接下来,我们设计一下交互流程
简单概括总体流程有三个步骤,一是输入个人信息 二是录音转文字,三是发送消息,进行对话交互
由于是通过终端访问,主要监听键盘事件,进行不同操作
如 按W键会开始录音,录音过程中按Q停止录音,待录音翻译完成后,按Ctrl+shift+enter发送消息
编程语言: Go 1.6+
SpokenAi使用依赖于portaudio,需要提前安装好portaudio否则编译无法通过
一.PortAudio下载地址:
Mac和Linux比较好安装,Windows只能源码编译安装,具体流程如下:
除此之外,可以直接选择网上编译好的库,可以从这里https://github.com/spatialaudio/portaudio-binaries下载。
在后续编译链接过程中,还是需要安装gcc, 推荐安装MinGW-w64。
安装完成MinGW后,将下载PortAudio库文件libportaudio-x86_64-w64-mingw32.static.dll
更名成portaudio.dll,放到MinGW ld能搜索到的库路径。
将PortAudio库文件libportaudio-x86_64-w64-mingw32.static.dll
放到Window System32目录下,在运行时程序需要找到该动态库
func RecordAndSaveWithContext(ctx context.Context, filename string) error {
portaudio.Initialize()
defer portaudio.Terminate()
done := make(chan struct{})
// 初始化音频录制
recorder, err := NewAudioRecorder()
if err != nil {
return fmt.Errorf("failed to initialize audio recorder: %v", err)
}
defer recorder.Stop()
// 初始化进度条
progressBar := pb.Full.Start(maxRecordSize)
progressBar.SetRefreshRate(time.Millisecond * 200) // 设置刷新率
progressBar.Set(pb.Bytes, true) // 显示录制音频的数据量
// 记录开始时间
startTime := time.Now()
// 创建Context,用于取消录音
ctxnew, cancel := context.WithCancel(ctx)
// 开启协程进行录音
samples := make([]int32, 0)
go func() {
defer close(done)
for {
select {
case <-ctxnew.Done():
return
case data := <-recorder.dataCh:
// 将音频数据追加到samples
samples = append(samples, data...)
// 当达到最长录音时间时,取消录音
if time.Since(startTime) >= maxRecordDuration {
cancel()
break
}
// 更新录制音频的数据量
dataSize := int64(len(samples)) * int64(reflect.TypeOf(samples).Elem().Size())
progressBar.Add(int(dataSize)) // 更新进度条
progressBar.SetCurrent(dataSize)
}
}
}()
// 等待录音完成或接收到中断信号
<-done
progressBar.Finish()
// 保存音频数据到WAV文件
if err := saveToWavFile(filename, int32SliceToIntSlice(samples)); err != nil {
return fmt.Errorf("failed to save audio to file: %v", err)
}
return nil
}
主要实现功能有:
2.播放音频
// PlayWavFile 播放指定的WAV文件
func PlayWavFile(filename string) error {
// 打开WAV文件
f, err := os.Open(filename)
if err != nil {
return fmt.Errorf("failed to open WAV file: %v", err)
}
defer f.Close()
// 解码WAV文件
s, format, err := wav.Decode(f)
if err != nil {
return fmt.Errorf("failed to decode WAV file: %v", err)
}
defer s.Close()
// 初始化扬声器
err = speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/10))
if err != nil {
return fmt.Errorf("failed to initialize speaker: %v", err)
}
// 播放音频
done := make(chan struct{})
speaker.Play(beep.Seq(s, beep.Callback(func() {
close(done)
})))
// 等待音频播放完成
<-done
return nil
}
目前比较通用的TextToSpeech(TTS)方案有以下几种:
有简单调用云服务的,也有自己安装环境的。调用云服务需要注册账号,按量收费,比较费钱 。决定自己部署,采用TensorFlowTTS,通过构建Docker容器运行该服务。
Dockerfile如下,第一次构建速度会比较慢。
FROM tensorflow/tensorflow:2.6.0
# 安装必要的依赖
RUN apt-get update &&\
apt-get install -y libsndfile1
# 安装TensorFlowTTS
RUN pip install -i https://mirrors.aliyun.com/pypi/simple/ TensorFlowTTS flask
# 安装
RUN apt-get install -y git
RUN pip install git+https://github.com/repodiac/german_transliterate.git#egg=german_transliterate
RUN pip install --upgrade numpy numba
# 安装
ADD tts-server-api.py /app/tts-server-api.py
# 运行REST API服务器
CMD python /app/tts-server-api.py --host 0.0.0.0 --port 5000
如果不想自己自定义,可以直接下载我构建好的服务
docker pull ptonlix/tensorflowtts:1.0.9
docker run -itd -p 5000:5000 --name spokenai-tts ptonlix/tensorflowtts:1.0.9
tts-server-api.py 是启动Flask的API服务的脚本,对外提供/api/tts 文字转语音接口
@app.route('/api/tts', methods=['POST'])
def tts():
data = request.get_json()
text = data['text']
# fastspeech inference
input_ids = processor.text_to_sequence(text)
mel_before, mel_after, duration_outputs, _, _ = fastspeech2.inference(
input_ids=tf.expand_dims(tf.convert_to_tensor(input_ids, dtype=tf.int32), 0),
speaker_ids=tf.convert_to_tensor([0], dtype=tf.int32),
speed_ratios=tf.convert_to_tensor([1.0], dtype=tf.float32),
f0_ratios=tf.convert_to_tensor([1.0], dtype=tf.float32),
energy_ratios=tf.convert_to_tensor([1.0], dtype=tf.float32),
)
# melgan inference
audio_before = mb_melgan.inference(mel_before)[0, :, 0]
audio_after = mb_melgan.inference(mel_after)[0, :, 0]
# save to file
# Convert audio data to byte stream
buffer = io.BytesIO()
sf.write(buffer, audio_after, 22050, format='WAV', subtype='PCM_16')
audio_bytes = buffer.getvalue()
# Return audio data as a response with MIME type audio/wav
return Response(audio_bytes, mimetype='audio/wav')
解决完上述两个关键问题,剩下就是业务代码的编写
[openai]
[openai.base]
apikey = ""
apihost = "https://api.openai.com/v1"
[openai.chat]
chatmodel = "gpt-3.5-turbo"
chatmaxtoken = 2048
chattemperature = 0.7
chattopp = 1
[openai.audio]
audiomodel = "whisper-1"
[file]
[file.history]
path = "./data/history/"
[file.audio]
[file.audio.record]
path = "./data/audio/record/"
[file.audio.play]
path = "./data/audio/play/"
enable = 0
ttshost = "http://127.0.0.1:5000"
采用toml配置文件格式, 主要分为两部分
项目地址:https://github.com/ptonlix/spokenai
欢迎Star 、PR 、 Issue 、交流
安装portaudio, 参考上节PortAudio流程
# 下载源码
git clone https://github.com/ptonlix/spokenai.git
cd spokenai
# 修改配置文件
edit fat_config.toml
# 编译
go build
# 查看命令
./spokenai -h
# 运行
./spokenai
windows启动: