mirror of
https://github.com/zhayujie/chatgpt-on-wechat.git
synced 2026-06-02 00:57:41 +08:00
1.新增wechaty方案的语音识别、语音回复功能;2.更新README;
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,5 +1,6 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
.idea
|
.idea
|
||||||
|
.wechaty/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
venv*
|
venv*
|
||||||
*.pyc
|
*.pyc
|
||||||
|
|||||||
48
README.md
48
README.md
@@ -62,15 +62,14 @@
|
|||||||
支持 Linux、MacOS、Windows 系统(可在Linux服务器上长期运行),同时需安装 `Python`。
|
支持 Linux、MacOS、Windows 系统(可在Linux服务器上长期运行),同时需安装 `Python`。
|
||||||
> 建议Python版本在 3.7.1~3.9.X 之间,3.10及以上版本在 MacOS 可用,其他系统上不确定能否正常运行。
|
> 建议Python版本在 3.7.1~3.9.X 之间,3.10及以上版本在 MacOS 可用,其他系统上不确定能否正常运行。
|
||||||
|
|
||||||
|
**1.克隆项目代码:**
|
||||||
1.克隆项目代码:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/zhayujie/chatgpt-on-wechat
|
git clone https://github.com/zhayujie/chatgpt-on-wechat
|
||||||
cd chatgpt-on-wechat/
|
cd chatgpt-on-wechat/
|
||||||
```
|
```
|
||||||
|
|
||||||
2.安装所需核心依赖:
|
**2.安装所需核心依赖:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip3 install itchat-uos==1.5.0.dev0
|
pip3 install itchat-uos==1.5.0.dev0
|
||||||
@@ -78,13 +77,45 @@ pip3 install --upgrade openai
|
|||||||
```
|
```
|
||||||
注:`itchat-uos`使用指定版本1.5.0.dev0,`openai`使用最新版本,需高于0.27.0。
|
注:`itchat-uos`使用指定版本1.5.0.dev0,`openai`使用最新版本,需高于0.27.0。
|
||||||
|
|
||||||
|
**3.安装所需拓展依赖(接收语音,回复语音):**
|
||||||
|
### wechaty 处理语音所需
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip3 install pysilk
|
||||||
|
pip3 install pysilk-mod
|
||||||
|
pip3 install pydub
|
||||||
|
```
|
||||||
|
|
||||||
|
### 百度
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip3 install baidu-aip chardet
|
||||||
|
```
|
||||||
|
### Google
|
||||||
|
|
||||||
|
(1) 安装 SpeechRecognition
|
||||||
|
```bash
|
||||||
|
pip3 install SpeechRecognition
|
||||||
|
```
|
||||||
|
(2) 安装 ffmpeg 和 espeak
|
||||||
|
|
||||||
|
MacOS:
|
||||||
|
```bash
|
||||||
|
brew install ffmpeg espeak
|
||||||
|
```
|
||||||
|
Windows:下载ffmpeg.exe
|
||||||
|
|
||||||
|
Linux:
|
||||||
|
```bash
|
||||||
|
apt-get install ffmpeg espeak
|
||||||
|
```
|
||||||
|
|
||||||
## 配置
|
## 配置
|
||||||
|
|
||||||
配置文件的模板在根目录的`config-template.json`中,需复制该模板创建最终生效的 `config.json` 文件:
|
配置文件的模板在根目录的`config-template.json`中,需复制该模板创建最终生效的 `config.json` 文件:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cp config-template.json config.json
|
cp config-template.json config.json
|
||||||
```
|
```
|
||||||
|
|
||||||
然后在`config.json`中填入配置,以下是对默认配置的说明,可根据需要进行自定义修改:
|
然后在`config.json`中填入配置,以下是对默认配置的说明,可根据需要进行自定义修改:
|
||||||
@@ -93,14 +124,21 @@ cp config-template.json config.json
|
|||||||
# config.json文件内容示例
|
# config.json文件内容示例
|
||||||
{
|
{
|
||||||
"open_ai_api_key": "YOUR API KEY", # 填入上面创建的 OpenAI API KEY
|
"open_ai_api_key": "YOUR API KEY", # 填入上面创建的 OpenAI API KEY
|
||||||
|
"open_ai_api_base": "https://api.openai.com/v1", # 自定义 OpenAI API 地址
|
||||||
"proxy": "127.0.0.1:7890", # 代理客户端的ip和端口
|
"proxy": "127.0.0.1:7890", # 代理客户端的ip和端口
|
||||||
|
"baidu_app_id": "", # 百度AI的App Id
|
||||||
|
"baidu_api_key": "", # 百度AI的API KEY
|
||||||
|
"baidu_secret_key": "", # 百度AI的Secret KEY
|
||||||
|
"wechaty_puppet_service_token":"", # wechaty服务token
|
||||||
"single_chat_prefix": ["bot", "@bot"], # 私聊时文本需要包含该前缀才能触发机器人回复
|
"single_chat_prefix": ["bot", "@bot"], # 私聊时文本需要包含该前缀才能触发机器人回复
|
||||||
"single_chat_reply_prefix": "[bot] ", # 私聊时自动回复的前缀,用于区分真人
|
"single_chat_reply_prefix": "[bot] ", # 私聊时自动回复的前缀,用于区分真人
|
||||||
"group_chat_prefix": ["@bot"], # 群聊时包含该前缀则会触发机器人回复
|
"group_chat_prefix": ["@bot"], # 群聊时包含该前缀则会触发机器人回复
|
||||||
"group_name_white_list": ["ChatGPT测试群", "ChatGPT测试群2"], # 开启自动回复的群名称列表
|
"group_name_white_list": ["ChatGPT测试群", "ChatGPT测试群2"], # 开启自动回复的群名称列表
|
||||||
"image_create_prefix": ["画", "看", "找"], # 开启图片回复的前缀
|
"image_create_prefix": ["画", "看", "找"], # 开启图片回复的前缀
|
||||||
"conversation_max_tokens": 1000, # 支持上下文记忆的最多字符数
|
"conversation_max_tokens": 1000, # 支持上下文记忆的最多字符数
|
||||||
"character_desc": "你是ChatGPT, 一个由OpenAI训练的大型语言模型, 你旨在回答并解决人们的任何问题,并且可以使用多种语言与人交流。" # 人格描述
|
"speech_recognition": false, # 是否开启语音识别
|
||||||
|
"voice_reply_voice": false, # 是否开启语音回复
|
||||||
|
"character_desc": "你是ChatGPT, 一个由OpenAI训练的大型语言模型, 你旨在回答并解决人们的任何问题,并且可以使用多种语言与人交流。", # 人格描述
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
**配置说明:**
|
**配置说明:**
|
||||||
|
|||||||
@@ -10,12 +10,16 @@ import json
|
|||||||
import time
|
import time
|
||||||
import asyncio
|
import asyncio
|
||||||
import requests
|
import requests
|
||||||
|
import pysilk
|
||||||
|
import wave
|
||||||
|
from pydub import AudioSegment
|
||||||
from typing import Optional, Union
|
from typing import Optional, Union
|
||||||
from wechaty_puppet import MessageType, FileBox, ScanStatus # type: ignore
|
from wechaty_puppet import MessageType, FileBox, ScanStatus # type: ignore
|
||||||
from wechaty import Wechaty, Contact
|
from wechaty import Wechaty, Contact
|
||||||
from wechaty.user import Message, Room, MiniProgram, UrlLink
|
from wechaty.user import Message, Room, MiniProgram, UrlLink
|
||||||
from channel.channel import Channel
|
from channel.channel import Channel
|
||||||
from common.log import logger
|
from common.log import logger
|
||||||
|
from common.tmp_dir import TmpDir
|
||||||
from config import conf
|
from config import conf
|
||||||
|
|
||||||
|
|
||||||
@@ -89,6 +93,48 @@ class WechatyChannel(Channel):
|
|||||||
await self._do_send_img(content, to_user_id)
|
await self._do_send_img(content, to_user_id)
|
||||||
else:
|
else:
|
||||||
await self._do_send(content, to_user_id)
|
await self._do_send(content, to_user_id)
|
||||||
|
elif room is None and msg.type() == MessageType.MESSAGE_TYPE_AUDIO:
|
||||||
|
if not msg.is_self(): # 接收语音消息
|
||||||
|
# 下载语音文件
|
||||||
|
voice_file = await msg.to_file_box()
|
||||||
|
silk_file = TmpDir().path() + voice_file.name
|
||||||
|
await voice_file.to_file(silk_file)
|
||||||
|
logger.info("[WX]receive voice file: " + silk_file)
|
||||||
|
# 将文件转成wav格式音频
|
||||||
|
wav_file = silk_file.replace(".slk", ".wav")
|
||||||
|
with open(silk_file, 'rb') as f:
|
||||||
|
silk_data = f.read()
|
||||||
|
pcm_data = pysilk.decode(silk_data)
|
||||||
|
|
||||||
|
with wave.open(wav_file, 'wb') as wav_data:
|
||||||
|
wav_data.setnchannels(1)
|
||||||
|
wav_data.setsampwidth(2)
|
||||||
|
wav_data.setframerate(24000)
|
||||||
|
wav_data.writeframes(pcm_data)
|
||||||
|
if os.path.exists(wav_file):
|
||||||
|
converter_state = "true" # 转换wav成功
|
||||||
|
else:
|
||||||
|
converter_state = "false" # 转换wav失败
|
||||||
|
logger.info("[WX]receive voice converter: " + converter_state)
|
||||||
|
# 语音识别为文本
|
||||||
|
query = super().build_voice_to_text(wav_file)
|
||||||
|
# 交验关键字
|
||||||
|
match_prefix = self.check_prefix(query, conf().get('single_chat_prefix'))
|
||||||
|
if match_prefix is not None:
|
||||||
|
if match_prefix != '':
|
||||||
|
str_list = query.split(match_prefix, 1)
|
||||||
|
if len(str_list) == 2:
|
||||||
|
query = str_list[1].strip()
|
||||||
|
# 返回消息
|
||||||
|
if conf().get('voice_reply_voice'):
|
||||||
|
await self._do_send_voice(query, from_user_id)
|
||||||
|
else:
|
||||||
|
await self._do_send(query, from_user_id)
|
||||||
|
else:
|
||||||
|
logger.info("[WX]receive voice check prefix: " + 'False')
|
||||||
|
# 清除缓存文件
|
||||||
|
os.remove(wav_file)
|
||||||
|
os.remove(silk_file)
|
||||||
elif room and msg.type() == MessageType.MESSAGE_TYPE_TEXT:
|
elif room and msg.type() == MessageType.MESSAGE_TYPE_TEXT:
|
||||||
# 群组&文本消息
|
# 群组&文本消息
|
||||||
room_id = room.room_id
|
room_id = room.room_id
|
||||||
@@ -135,6 +181,39 @@ class WechatyChannel(Channel):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.exception(e)
|
logger.exception(e)
|
||||||
|
|
||||||
|
|
||||||
|
async def _do_send_voice(self, query, reply_user_id):
|
||||||
|
try:
|
||||||
|
if not query:
|
||||||
|
return
|
||||||
|
context = dict()
|
||||||
|
context['session_id'] = reply_user_id
|
||||||
|
reply_text = super().build_reply_content(query, context)
|
||||||
|
if reply_text:
|
||||||
|
# 转换 mp3 文件为 silk 格式
|
||||||
|
mp3_file = super().build_text_to_voice(reply_text)
|
||||||
|
silk_file = mp3_file.replace(".mp3", ".silk")
|
||||||
|
# Load the MP3 file
|
||||||
|
audio = AudioSegment.from_file(mp3_file, format="mp3")
|
||||||
|
# Convert to WAV format
|
||||||
|
audio = audio.set_frame_rate(24000).set_channels(1)
|
||||||
|
wav_data = audio.raw_data
|
||||||
|
sample_width = audio.sample_width
|
||||||
|
# Encode to SILK format
|
||||||
|
silk_data = pysilk.encode(wav_data, 24000)
|
||||||
|
# Save the silk file
|
||||||
|
with open(silk_file, "wb") as f:
|
||||||
|
f.write(silk_data)
|
||||||
|
# 发送语音
|
||||||
|
t = int(time.time())
|
||||||
|
file_box = FileBox.from_file(silk_file, name=str(t) + '.silk')
|
||||||
|
await self.send(file_box, reply_user_id)
|
||||||
|
# 清除缓存文件
|
||||||
|
os.remove(mp3_file)
|
||||||
|
os.remove(silk_file)
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception(e)
|
||||||
|
|
||||||
async def _do_send_img(self, query, reply_user_id):
|
async def _do_send_img(self, query, reply_user_id):
|
||||||
try:
|
try:
|
||||||
if not query:
|
if not query:
|
||||||
|
|||||||
@@ -1,13 +1,18 @@
|
|||||||
{
|
{
|
||||||
"open_ai_api_key": "YOUR API KEY",
|
"open_ai_api_key": "YOUR API KEY",
|
||||||
"proxy": "",
|
"proxy": "",
|
||||||
|
"wechaty_puppet_service_token":"",
|
||||||
|
"baidu_app_id": "",
|
||||||
|
"baidu_api_key": "",
|
||||||
|
"baidu_secret_key": "",
|
||||||
"single_chat_prefix": ["bot", "@bot"],
|
"single_chat_prefix": ["bot", "@bot"],
|
||||||
"single_chat_reply_prefix": "[bot] ",
|
"single_chat_reply_prefix": "[bot] ",
|
||||||
"group_chat_prefix": ["@bot"],
|
"group_chat_prefix": ["@bot"],
|
||||||
"group_name_white_list": ["ChatGPT测试群", "ChatGPT测试群2"],
|
"group_name_white_list": ["ChatGPT测试群", "ChatGPT测试群2"],
|
||||||
"image_create_prefix": ["画", "看", "找"],
|
"image_create_prefix": ["画", "看", "找"],
|
||||||
"conversation_max_tokens": 1000,
|
|
||||||
"speech_recognition": false,
|
"speech_recognition": false,
|
||||||
"character_desc": "你是ChatGPT, 一个由OpenAI训练的大型语言模型, 你旨在回答并解决人们的任何问题,并且可以使用多种语言与人交流。",
|
"voice_reply_voice": false,
|
||||||
"expires_in_seconds": 3600
|
"conversation_max_tokens": 1000,
|
||||||
|
"expires_in_seconds": 3600,
|
||||||
|
"character_desc": "你是ChatGPT, 一个由OpenAI训练的大型语言模型, 你旨在回答并解决人们的任何问题,并且可以使用多种语言与人交流。"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user