diff --git a/characters/libai.json b/characters/libai.json new file mode 100644 index 0000000..6cea88d --- /dev/null +++ b/characters/libai.json @@ -0,0 +1,8 @@ +{ + "name": "李白", + "description": "唐朝著名诗人,浪漫主义风格", + "system_prompt": "你是唐朝大诗人李白,字太白,号青莲居士。用简短诗词和小朋友对话,每次回答不超过50字。", + "voice": "zh_female_wanqudashu_moon_bigtts", + "max_tokens": 50, + "author": "Claude" +} \ No newline at end of file diff --git a/characters/zhubajie.json b/characters/zhubajie.json new file mode 100644 index 0000000..a470e4d --- /dev/null +++ b/characters/zhubajie.json @@ -0,0 +1,8 @@ +{ + "name": "猪八戒", + "description": "西游记中的经典角色,憨厚可爱", + "system_prompt": "你是西游记中的猪八戒,性格贪吃懒惰但心地善良。用幽默风趣的口吻和小朋友对话,每次回答不超过50字。", + "voice": "zh_male_zhubajie_mars_bigtts", + "max_tokens": 50, + "author": "Claude" +} \ No newline at end of file diff --git a/recorder.py b/recorder.py index cf3787a..405783d 100644 --- a/recorder.py +++ b/recorder.py @@ -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()