This commit is contained in:
朱潮 2025-09-20 17:29:51 +08:00
parent 97aecf0c30
commit ebeb4e34df
3 changed files with 135 additions and 4 deletions

8
characters/libai.json Normal file
View File

@ -0,0 +1,8 @@
{
"name": "李白",
"description": "唐朝著名诗人,浪漫主义风格",
"system_prompt": "你是唐朝大诗人李白字太白号青莲居士。用简短诗词和小朋友对话每次回答不超过50字。",
"voice": "zh_female_wanqudashu_moon_bigtts",
"max_tokens": 50,
"author": "Claude"
}

8
characters/zhubajie.json Normal file
View File

@ -0,0 +1,8 @@
{
"name": "猪八戒",
"description": "西游记中的经典角色,憨厚可爱",
"system_prompt": "你是西游记中的猪八戒性格贪吃懒惰但心地善良。用幽默风趣的口吻和小朋友对话每次回答不超过50字。",
"voice": "zh_male_zhubajie_mars_bigtts",
"max_tokens": 50,
"author": "Claude"
}

View File

@ -17,6 +17,7 @@ import threading
import time
import uuid
import wave
import argparse
from io import BytesIO
from urllib.parse import urlparse
@ -33,7 +34,7 @@ except ImportError:
class EnergyBasedRecorder:
"""基于能量检测的录音系统"""
def __init__(self, energy_threshold=500, silence_threshold=1.5, min_recording_time=2.0, max_recording_time=30.0, enable_asr=True, enable_llm=True, enable_tts=True):
def __init__(self, energy_threshold=500, silence_threshold=1.5, min_recording_time=2.0, max_recording_time=30.0, enable_asr=True, enable_llm=True, enable_tts=True, character="libai"):
# 音频参数 - 极简优化
self.FORMAT = pyaudio.paInt16
self.CHANNELS = 1
@ -67,6 +68,16 @@ class EnergyBasedRecorder:
self.tts_app_key = "aGjiRDfUWi"
self.tts_speaker = "zh_female_wanqudashu_moon_bigtts"
# 角色配置
self.current_character = character
self.characters_dir = os.path.join(os.path.dirname(__file__), "characters")
self.available_characters = self._load_available_characters()
self.character_config = self._load_character_config(character)
# 如果加载了角色配置更新TTS音色
if self.character_config and "voice" in self.character_config:
self.tts_speaker = self.character_config["voice"]
# 检查音频播放能力
if self.enable_tts:
self.audio_player_available = self._check_audio_player()
@ -118,6 +129,33 @@ class EnergyBasedRecorder:
self._setup_audio()
def _load_available_characters(self):
"""加载可用角色列表"""
characters = []
if os.path.exists(self.characters_dir):
for file in os.listdir(self.characters_dir):
if file.endswith('.json'):
characters.append(file[:-5]) # 去掉.json后缀
return characters
def _load_character_config(self, character_name):
"""加载角色配置"""
config_file = os.path.join(self.characters_dir, f"{character_name}.json")
if not os.path.exists(config_file):
print(f"⚠️ 角色配置文件不存在: {config_file}")
return None
try:
with open(config_file, 'r', encoding='utf-8') as f:
config = json.load(f)
print(f"✅ 加载角色: {config.get('name', character_name)}")
print(f"📝 描述: {config.get('description', '无描述')}")
return config
except Exception as e:
print(f"❌ 加载角色配置失败: {e}")
return None
def _setup_audio(self):
"""设置音频设备"""
try:
@ -972,6 +1010,17 @@ class EnergyBasedRecorder:
try:
print("🤖 调用大语言模型...")
# 获取角色配置中的系统提示词
if self.character_config and "system_prompt" in self.character_config:
system_prompt = self.character_config["system_prompt"]
else:
system_prompt = "你是一个智能助手,请根据用户的语音输入提供有帮助的回答。保持回答简洁明了。"
# 获取角色配置中的最大token数
max_tokens = 50
if self.character_config and "max_tokens" in self.character_config:
max_tokens = self.character_config["max_tokens"]
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {self.llm_api_key}"
@ -982,14 +1031,14 @@ class EnergyBasedRecorder:
"messages": [
{
"role": "system",
"content": "你是唐朝大诗人李白用简短诗词和小朋友对话每次回答不超过50字。"
"content": system_prompt
},
{
"role": "user",
"content": user_message
}
],
"max_tokens": 50
"max_tokens": max_tokens
}
response = requests.post(self.llm_api_url, headers=headers, json=data, timeout=30)
@ -1131,10 +1180,53 @@ class EnergyBasedRecorder:
print(f"❌ TTS转换失败: {e}")
return None
def parse_arguments():
"""解析命令行参数"""
parser = argparse.ArgumentParser(description='基于能量检测的极简录音系统')
parser.add_argument('--character', '-c', type=str, default='libai',
help='选择角色 (默认: libai)')
parser.add_argument('--list-characters', '-l', action='store_true',
help='列出所有可用角色')
return parser.parse_args()
def list_characters(characters_dir):
"""列出所有可用角色"""
characters = []
if os.path.exists(characters_dir):
for file in os.listdir(characters_dir):
if file.endswith('.json'):
character_name = file[:-5]
config_file = os.path.join(characters_dir, file)
try:
with open(config_file, 'r', encoding='utf-8') as f:
config = json.load(f)
name = config.get('name', character_name)
desc = config.get('description', '无描述')
characters.append(f"{character_name}: {name} - {desc}")
except:
characters.append(f"{character_name}: 配置文件读取失败")
if characters:
print("🎭 可用角色列表:")
for char in characters:
print(f" - {char}")
else:
print("❌ 未找到任何角色配置文件")
def main():
"""主函数"""
args = parse_arguments()
characters_dir = os.path.join(os.path.dirname(__file__), "characters")
# 如果要求列出角色,显示后退出
if args.list_characters:
list_characters(characters_dir)
return
print("🚀 基于能量检测的极简录音系统")
print("🤖 集成语音识别功能")
print(f"🎭 当前角色: {args.character}")
print("=" * 50)
# 创建录音系统
@ -1145,7 +1237,8 @@ def main():
max_recording_time=30.0, # 最大录音时间
enable_asr=True, # 启用语音识别功能
enable_llm=True, # 启用大语言模型功能
enable_tts=True # 启用文本转语音功能
enable_tts=True, # 启用文本转语音功能
character=args.character # 指定角色
)
print("✅ 系统初始化成功")
@ -1158,6 +1251,8 @@ def main():
print(" - 录音完成后自动语音识别")
print(" - 语音识别后自动调用AI助手")
print(" - AI回复后自动转换为语音")
print(" - 多角色支持 (李白、猪八戒等)")
print(" - 每个角色独特音色和性格")
print(" - 预录音功能包含声音开始前2秒")
print(" - 环形缓冲区防止丢失开头音频")
print(" - 自动调整能量阈值")
@ -1171,6 +1266,26 @@ def main():
print(" export ARK_API_KEY='your_api_key_here'")
print("=" * 50)
# 显示角色信息
if recorder.character_config:
print(f"🎭 当前角色: {recorder.character_config.get('name', '未知')}")
print(f"📝 描述: {recorder.character_config.get('description', '无描述')}")
print(f"🎤 音色: {recorder.tts_speaker}")
print("=" * 50)
# 显示使用说明
print("📖 使用说明:")
print("- 检测到声音自动开始录音")
print("- 持续静音3秒自动结束录音")
print("- 最少录音2秒最多30秒")
print("- 录音完成后自动播放")
print("- 按 Ctrl+C 退出")
print("🎭 角色切换:")
print("- 使用 --character 或 -c 参数选择角色")
print("- 使用 --list-characters 或 -l 查看所有角色")
print("- 示例: python recorder.py --character zhubajie")
print("=" * 50)
# 开始运行
recorder.run()