Signed-off-by: sairate <sairate@sina.cn>

This commit is contained in:
sairate 2024-09-27 20:28:27 +08:00
commit a20d8bfbb5
15 changed files with 333 additions and 0 deletions

8
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

10
.idea/AIchat.iml Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/venv" />
</content>
<orderEntry type="jdk" jdkName="Python 3.12 (AIchat)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GitToolBoxBlameSettings">
<option name="version" value="2" />
</component>
</project>

View File

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

7
.idea/misc.xml Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.12 (AIchat)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.12 (AIchat)" project-jdk-type="Python SDK" />
</project>

8
.idea/modules.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/AIchat.iml" filepath="$PROJECT_DIR$/.idea/AIchat.iml" />
</modules>
</component>
</project>

4
README.md Normal file
View File

@ -0,0 +1,4 @@
``` python
pip install python-dotenv
```

24
app.py Normal file
View File

@ -0,0 +1,24 @@
from flask import Flask, render_template
import sqlite3
app = Flask(__name__)
@app.route('/')
def index():
# 连接数据库
conn = sqlite3.connect('conversation.db')
c = conn.cursor()
# 从数据库中获取数据
c.execute("SELECT * FROM conversation")
conversations = c.fetchall()
# 关闭数据库连接
conn.close()
return render_template("./index.html", conversations=conversations)
if __name__ == '__main__':
app.run(debug=True)

Binary file not shown.

BIN
conversation.db Normal file

Binary file not shown.

26
index.html Normal file
View File

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Conversation Table</title>
</head>
<body>
<h1>Conversation Table</h1>
<table border="1">
<tr>
<th>ID</th>
<th>Message</th>
<!-- 添加其他列标题 -->
</tr>
{% for conversation in conversations %}
<tr>
<td>{{ conversation[0] }}</td>
<td>{{ conversation[1] }}</td>
<!-- 添加其他列数据 -->
</tr>
{% endfor %}
</table>
</body>
</html>

223
main.py Normal file
View File

@ -0,0 +1,223 @@
import pyaudio
import wave
import requests
import json
import base64
import os
import edge_tts
import asyncio
import pygame
import openai
import uuid # 用于生成唯一的文件名
import sqlite3
def create_connection(db_file='conversation.db'):
# 连接到数据库(如果不存在,则会被创建)
conn = sqlite3.connect('conversation.db')
# 创建一个游标对象用于执行SQL语句
c = conn.cursor()
# 创建一个名为conversation的表
c.execute('''CREATE TABLE IF NOT EXISTS conversation
(id INTEGER PRIMARY KEY AUTOINCREMENT,
question TEXT,
answer TEXT,
audio_path TEXT)''')
def insert_data(question, answer, audio_path):
conn = sqlite3.connect('conversation.db')
cursor = conn.cursor()
cursor.execute("INSERT INTO conversation (question, answer, audio_path) VALUES (?, ?, ?)",
(question, answer, audio_path))
conn.commit()
conn.close()
# 1.录音
# 用Pyaudio录制音频(生成wav文件)
def audio_record(rec_time, filename):
"""
:param rec_time : 音频录制时间
:param filename : 输出音频文件
:返回值在当前目录输出一个音频文件
"""
CHUNK = 1024 # 定义数据流块
FORMAT = pyaudio.paInt16 # 16bit编码格式
CHANNELS = 1 # 单声道
RATE = 16000 # 16000采样频率
# 创建一个音频对象
p = pyaudio.PyAudio()
# 创建音频数据流
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK)
print('Start recording...')
frames = list() # 空列表用于保存录制的音频流
# 录制音频数据
for i in range(0, int(RATE / CHUNK * rec_time)):
data = stream.read(CHUNK)
frames.append(data)
# 录制完成
# print(frames)
# 停止数据流
stream.stop_stream()
stream.close()
# 关闭pyaudio
p.terminate()
print('recording done...')
# 保存音频文件
with wave.open(filename, 'wb') as f:
f.setnchannels(CHANNELS) # 设置音频声道数
f.setsampwidth(p.get_sample_size(FORMAT)) # 以字节为样本返回样本宽度
f.setframerate(RATE) # 设置采样频率
f.writeframes(b''.join(frames))
f.close()
# 2 获取token
API_KEY = "7myE5M0cY5gjyKbxcFQqWmZE" # 这里请替换为你的API_KEY
SECRET_KEY = "A2AtUqbqVLdo0kgfiwITWUlB0fxwCA3w" # 这里请替换为你的SECRET_KEY
def get_access_token():
"""
使用 AKSK 生成鉴权签名Access Token
:return: access_token或是None(如果错误)
"""
url = "https://aip.baidubce.com/oauth/2.0/token"
params = {"grant_type": "client_credentials", "client_id": API_KEY, "client_secret": SECRET_KEY}
return str(requests.post(url, params=params).json().get("access_token"))
# 3.上传录音文件
def BaiduYuYin(file_url, token):
"""
:param file_url: 录音文件路径
:param token: 获取的access token
:return: 录音识别出来的文本
"""
try:
RATE = '16000'
FORMAT = 'wav'
CUID = 'rvs7K414cquxm4f62jtasIRi6iNRNXR6'
DEV_PID = '1536' # 普通话,支持简单的英文识别
file_url = file_url
token = token
# 以字节格式读取文件之后进行编码
with open(file_url, 'rb') as f:
speech = base64.b64encode(f.read()).decode('utf-8')
size = os.path.getsize(file_url) # 语音文件的字节数
headers = {'Content-Type': 'application/json',
'Accept': 'application/json'} # json格式post上传本地文件
url = 'https://vop.baidu.com/server_api'
data = {
"format": FORMAT, # 格式
"rate": RATE, # 取样频率,固定值16000
"dev_pid": DEV_PID, # 语音识别类型
"speech": speech, # 本地语音文件的二进制数据,需要进行base64编码
"cuid": CUID, # 用户唯一标识,用来区分用户 建议填写能区分用户的机器MAC地址或IMEI码,长度为60字符以内。
"len": size, # 语音文件的字节数
"channel": 1, # 声道数,仅支持单声道,固定值为1
"token": token,
}
req = requests.request("POST", url, data=json.dumps(data),
headers=headers) # request.post 改为requests.request("POST"……)
data_dict = json.loads(req.text)
# print(data_dict['result'][0])
return data_dict['result'][0] # 返回文本
except:
return '识别不清楚'
from ollama import Client
def get_completion(prompt, model="solar"):
client = Client(host='http://8.130.118.164:11434/')
response = client.chat(model, messages=[
{
'role': 'user',
'content': prompt,
},
])
return response['message']['content']
# 5.文本转语音TTSedge-tts
async def generate_audio_from_text(text, file_url):
"""
:param text:需要进行转换的文本
:file_url:转换后输出的音频文件地址
:return:
"""
voice = 'zh-CN-YunxiNeural'
output = file_url
rate = '-4%'
volume = '+0%'
tts = edge_tts.Communicate(text=text, voice=voice, rate=rate, volume=volume)
await tts.save(output)
# 6.播放音频文件pygame
def play_mp3(mp3_file):
"""
:param mp3_file:需要播放的录音文件地址
:return:
"""
pygame.init() # 初始化pygame
pygame.mixer.init() # 初始化音频混合器
pygame.mixer.music.load(mp3_file) # 加载指定MP3文件
pygame.mixer.music.play() # 播放
clock = pygame.time.Clock()
while pygame.mixer.music.get_busy(): # 使用一个循环来等待音频播放完毕,保证程序不会在播放结束前退出
clock.tick(3)
def main():
create_connection()
while True:
# 1. 提示用户发言
print('请发言,谢谢!')
# 2. 录制音频
audio_record(5, 'user_audio.wav')
print('结束发言')
# 3. 获取百度语音识别的access token
baidu_token = get_access_token()
print('Baidu access token obtained.')
# 4. 上传录音文件并进行语音识别
baidu_result = BaiduYuYin('./user_audio.wav', baidu_token)
print('Baidu speech recognition result:', baidu_result)
# 5. 调用大语言模型进行文本生成
model_response = get_completion(baidu_result)
print('Model response:', model_response)
# 6. 将文本转换为语音,保存到唯一的文件名
unique_audio_filename = "./audio/"+str(uuid.uuid4()) + '.mp3' # 保存为不同的文件名以避免访问冲突
asyncio.run(generate_audio_from_text(model_response, unique_audio_filename))
insert_data(baidu_result, model_response,unique_audio_filename)# 插入数据库
# 7. 播放生成的语音
play_mp3(unique_audio_filename)
# 8. 提示用户继续对话或退出
user_input = input('继续对话或输入"退出"退出: ')
if user_input == '退出':
break
if __name__ == "__main__":
main()

BIN
requirements.txt Normal file

Binary file not shown.

11
test.py Normal file
View File

@ -0,0 +1,11 @@
from ollama import Client
def get_completion(prompt, model="solar"):
client = Client(host='http://8.130.118.164:11434/')
response = client.chat(model, messages=[
{
'role': 'user',
'content': prompt,
},
])
return response['message']['content']
print(get_completion("你好,我是小明。"))

BIN
user_audio.wav Normal file

Binary file not shown.