TODO:小程序的春天你想做什么

微信小程序作为连接用户与服务的新方式,提供了便捷的获取途径及出色的用户体验。本文探讨了其特点,如导航清晰、视觉规范、易于开发等,并列举了可能的应用场景,包括旅游、资讯、便民服务等。

TODO:小程序的春天你想做什么

微信小程序是一种全新的连接用户与服务的方式,它可以在微信内被便捷地获取和传播,同时具有出色的使用体验。

初步了解小程序的特点

  1. 导航明确,来去自如
  2. 统一稳定,
  3. 视觉规范,字体、列表、表单、按钮、图标的规范
  4. 开发方便简单,微信小程序框架为开发者提供了一系列基础组件,开发者可以通过组合这些基础组件进行快速开发。
  5. 运营规范,在微信庞大的用户体系下,在切实符合用户的合理需求和利益的前提下,通过微信小程序所提供的功能和服务,为海量微信用户提供具有持续价值和高品质的服务。
  6. 在微信体系下,跨平台。

在微信的产业链里,你是否想过小程序能带给我们什么样的服务,实现什么样的价值。以下是小编整理的部分预想系统,仅供参考。

1. 旅游系统

  1. 旅游攻略
  2. 特色景点
  3. 出游事宜

2.资讯类系统

  1. 金融
  2. 娱乐
  3. 健康
  4. 教育

3.便民系统

  1. 物品条形码/二维码扫描询价/快递查询
  2. 公测导航
  3. 小区周边(吃饭、购物)
  4. 城市公交路线查询
  5. 医院导航

4. 物流系统

5. 风水系统

  1. 颜值测试
  2. 性格测试
  3. 财运测试
  4. 手机号码吉凶测试

6.气候节令

  1. 天气预报
  2. 老黄历

7.视频推荐

  1. 金融
  2. 娱乐
  3. 健康
  4. 教育

总之,小程序、小目标、小时代,我们来了,唯有加油。


wxgzh:ludong86

qrcode_for_gh_6bb1f39ae99c_258

""" 【通义千问 Qwen】API集成模块 用于意图理解和任务处理 """ import json import re import logging from database import config import dashscope from dashscope import Generation # --- 导入快捷日志工具 --- from Progress.utils.logger_utils import log_time, log_step, log_var, log_call from Progress.utils.logger_config import setup_logger # 确保 logger 已配置 # --- 初始化日志器 --- logger = logging.getLogger(__name__) # 使用模块名作为 logger 名称,便于区分来源 # --- API 配置 --- DASHSCOPE_API_KEY = config.api_key DASHSCOPE_MODEL = config.model class QWENAssistant: def __init__(self): if not DASHSCOPE_API_KEY: raise ValueError("缺少 DASHSCOPE_API_KEY,请检查配置文件") dashscope.api_key = DASHSCOPE_API_KEY self.model_name = DASHSCOPE_MODEL or 'qwen-max' logger.info(f"✅ QWENAssistant 初始化完成,使用模型: {self.model_name}") self.conversation_history = [] self.system_prompt = """ 你是一个智能语音控制助手,能够理解用户的语音指令并执行相应的任务。 你的主要能力包括: 1. 播放音乐和控制媒体 2. 文件操作(创建、读取、编辑文件) 3. 文本生成(写文章、总结、翻译等) 4. 系统控制(打开应用、设置提醒等) 5. 多步骤任务编排 当用户发出指令时,你需要: 1. 理解用户的意图 2. 确定需要执行的具体操作 3. 返回结构化的响应,包含操作类型和参数 🎯 响应格式必须是严格合法的 JSON: { "intent": "操作类型", "action": "具体动作", "parameters": {"参数名": "参数值"}, "response": "给用户的回复", "needs_confirmation": true/false } 📌 支持的操作类型: - music: 音乐相关操作 - file: 文件操作 - text: 文本生成 - system: 系统控制 - task: 多步骤任务 - chat: 普通对话 ❗请始终用中文回复用户。 """ @log_time @log_step("处理语音指令") def process_voice_command(self, voice_text): """处理语音指令,返回结构化 JSON 响应""" log_var("原始输入", voice_text) if not voice_text.strip(): logger.warning("收到空语音输入") return self._create_response("chat", "empty", {}, "我没有听清楚,请重新说话。", False) log_call("添加用户消息到历史") self.conversation_history.append({"role": "user", "content": voice_text}) try: messages = [{"role": "system", "content": self.system_prompt}] messages.extend(self.conversation_history[-10:]) log_var("请求消息数", len(messages)) logger.debug("正在调用 Qwen API...") response = Generation.call( model=self.model_name, messages=messages, temperature=0.5, top_p=0.8, max_tokens=1024 ) if response.status_code != 200: error_msg = f"Qwen API 调用失败: {response.status_code}, {response.message}" logger.error(error_msg) return self._create_response("chat", "error", {}, f"服务暂时不可用: {response.message}", False) ai_response = response.output['text'].strip() log_var("模型输出", ai_response) self.conversation_history.append({"role": "assistant", "content": ai_response}) # 尝试解析 JSON try: parsed_response = json.loads(ai_response) log_call("成功解析结构化响应") return parsed_response except json.JSONDecodeError: logger.warning("输出非标准JSON,尝试提取片段") json_match = re.search(r'\{[\s\S]*\}', ai_response) if json_match: try: parsed_response = json.loads(json_match.group()) log_call("从文本中提取JSON成功") return parsed_response except json.JSONDecodeError: pass logger.info("降级为普通聊天响应") return self._create_response("chat", "reply", {}, ai_response, False) except Exception as e: logger.exception("处理语音指令时发生未预期异常") return self._create_response("chat", "error", {}, "抱歉,我遇到了一些技术问题,请稍后再试。", False) def _create_response(self, intent, action, parameters, response, needs_confirmation): resp = { "intent": intent, "action": action, "parameters": parameters, "response": response, "needs_confirmation": needs_confirmation } log_var("返回响应", resp) return resp @log_time def generate_text(self, prompt, task_type="general"): log_var("任务类型", task_type) log_var("提示词长度", len(prompt)) try: system_prompt = f""" 你是一个专业的文本生成助手。根据用户的要求生成高质量的文本内容。 任务类型:{task_type} 要求:{prompt} 请生成相应的文本内容,确保内容准确、有逻辑、语言流畅。 """ response = Generation.call( model=self.model_name, messages=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": prompt} ], temperature=0.8, max_tokens=2000 ) if response.status_code == 200: result = response.output['text'] log_var("生成结果长度", len(result)) return result else: error_msg = f"文本生成失败: {response.message}" logger.error(error_msg) return error_msg except Exception as e: logger.exception("文本生成出错") return f"抱歉,生成文本时遇到错误:{str(e)}" @log_time def summarize_text(self, text): log_var("待总结文本长度", len(text)) try: prompt = f"请总结以下文本的主要内容:\n\n{text}" response = Generation.call( model=self.model_name, messages=[{"role": "user", "content": prompt}], temperature=0.3, max_tokens=500 ) if response.status_code == 200: result = response.output['text'] log_var("总结结果长度", len(result)) return result else: error_msg = f"总结失败: {response.message}" logger.error(error_msg) return error_msg except Exception as e: logger.exception("文本总结出错") return f"抱歉,总结文本时遇到错误:{str(e)}" @log_time def translate_text(self, text, target_language="英文"): log_var("目标语言", target_language) log_var("原文长度", len(text)) try: prompt = f"请将以下文本翻译成{target_language}:\n\n{text}" response = Generation.call( model=self.model_name, messages=[{"role": "user", "content": prompt}], temperature=0.3, max_tokens=1000 ) if response.status_code == 200: result = response.output['text'] log_var("翻译结果长度", len(result)) return result else: error_msg = f"翻译失败: {response.message}" logger.error(error_msg) return error_msg except Exception as e: logger.exception("文本翻译出错") return f"抱歉,翻译文本时遇到错误:{str(e)}" def clear_history(self): old_len = len(self.conversation_history) self.conversation_history.clear() logger.info(f"🧹 对话历史已清空,共清除 {old_len} 条记录") # ============================= # 🧪 测试代码 # ============================= if __name__ == "__main__": # 初始化全局日志系统 setup_logger(name="ai_assistant", log_dir="logs") assistant = QWENAssistant() test_commands = [ "播放周杰伦的歌曲", "写一篇关于气候变化的文章", "把这段话翻译成英文:今天天气真好", "总结一下人工智能的发展历程", "你好啊", "打开浏览器" ] for cmd in test_commands: print(f"\n🔊 用户指令: {cmd}") result = assistant.process_voice_command(cmd) print("🤖 AI响应:") print(json.dumps(result, ensure_ascii=False, indent=2)) """ 【系统控制模块】System Controller 提供音乐播放、文件操作、应用启动、定时提醒等本地系统级功能 """ import os import subprocess import platform import time import psutil import pygame import schedule from datetime import datetime import logging # --- 导入配置 --- from database import config # --- 导入日志工具 --- from Progress.utils.logger_utils import log_time, log_step, log_var, log_call from Progress.utils.logger_config import setup_logger # --- 配置路径 --- RESOURCE_PATH = config.resource_path DEFAULT_MUSIC_PATH = os.path.join(RESOURCE_PATH, config.music_path) DEFAULT_DOCUMENT_PATH = os.path.join(RESOURCE_PATH, config.doc_path) # --- 初始化日志器 --- logger = logging.getLogger(__name__) class SystemController: """ 系统功能控制器:封装常见的操作系统交互操作 """ def __init__(self): self.system = platform.system() self.music_player = None self.scheduled_tasks = {} self.task_counter = 0 log_var("运行平台", self.system) self._init_music_player() @log_step("初始化音乐播放器") @log_time def _init_music_player(self): """初始化 pygame 音频引擎用于本地音乐播放""" try: pygame.mixer.init() self.music_player = pygame.mixer.music logger.info("✅ 音乐播放器初始化成功") except Exception as e: logger.exception("❌ 音乐播放器初始化失败") self.music_player = None @log_step("播放音乐") @log_time def play_music(self, music_path=None): """ 播放指定目录下的第一个音乐文件 :param music_path: 音乐文件夹路径,None 则使用默认路径 :return: (success: bool, message: str) """ if not self.music_player: error_msg = "🔇 音乐播放器未就绪" logger.error(error_msg) return False, error_msg target_path = music_path or DEFAULT_MUSIC_PATH log_var("目标音乐路径", target_path) if not os.path.exists(target_path): msg = f"📁 路径不存在: {target_path}" logger.warning(msg) return False, msg music_files = self._find_music_files(target_path) if not music_files: msg = "🎵 未在指定路径找到支持的音乐文件 (.mp3/.wav/.flac 等)" logger.info(msg) return False, msg music_file = music_files[0] log_var("即将播放", os.path.basename(music_file)) try: self.stop_music() # 停止当前播放 self.music_player.load(music_file) self.music_player.play() success_msg = f"🎶 正在播放: {os.path.basename(music_file)}" logger.info(success_msg) return True, success_msg except Exception as e: logger.exception("💥 播放音乐失败") return False, f"播放失败: {str(e)}" @log_time def stop_music(self): """停止当前播放的音乐""" try: if self.music_player and pygame.mixer.get_init(): self.music_player.stop() logger.info("⏹️ 音乐已停止") return True, "音乐已停止" except Exception as e: logger.exception("❌ 停止音乐失败") return False, f"停止失败: {str(e)}" @log_time def pause_music(self): """暂停音乐播放""" try: if self.music_player and pygame.mixer.get_init(): self.music_player.pause() logger.info("⏸️ 音乐已暂停") return True, "音乐已暂停" except Exception as e: logger.exception("❌ 暂停音乐失败") return False, f"暂停失败: {str(e)}" @log_time def resume_music(self): """恢复音乐播放""" try: if self.music_player and pygame.mixer.get_init(): self.music_player.unpause() logger.info("▶️ 音乐已恢复") return True, "音乐已恢复" except Exception as e: logger.exception("❌ 恢复音乐失败") return False, f"恢复失败: {str(e)}" @log_step("打开应用程序") @log_time def open_application(self, app_name): """ 根据名称启动常见应用程序(跨平台) :param app_name: 应用中文名,如“浏览器”、“计算器” :return: (success, message) """ app_commands = { "浏览器": self._get_browser_command(), "记事本": self._get_text_editor_command(), "文件管理器": self._get_file_manager_command(), "计算器": self._get_calculator_command(), "终端": self._get_terminal_command() } log_var("请求打开应用", app_name) if app_name not in app_commands: warn_msg = f"🚫 不支持的应用: {app_name}" logger.warning(warn_msg) return False, warn_msg command = app_commands[app_name] log_var("执行命令", command) try: subprocess.Popen(command, shell=True) success_msg = f"🚀 正在打开 {app_name}" logger.info(success_msg) return True, success_msg except Exception as e: logger.exception(f"💥 启动应用 {app_name} 失败") return False, f"启动失败: {str(e)}" @log_step("创建文件") @log_time def create_file(self, file_path, content=""): """ 创建文本文件(自动创建父目录) :param file_path: 文件完整路径 :param content: 写入内容 :return: (success, message) """ log_var("创建文件", {"path": file_path, "content_length": len(content)}) try: os.makedirs(os.path.dirname(file_path), exist_ok=True) with open(file_path, 'w', encoding='utf-8') as f: f.write(content) logger.info(f"📄 文件已创建: {file_path}") return True, f"文件已创建: {file_path}" except Exception as e: logger.exception("❌ 创建文件失败") return False, f"创建失败: {str(e)}" @log_step("读取文件") @log_time def read_file(self, file_path): """ 读取文本文件内容 :param file_path: 文件路径 :return: (success, content 或错误信息) """ log_var("读取文件", file_path) if not os.path.exists(file_path): msg = f"⚠️ 文件不存在: {file_path}" logger.warning(msg) return False, msg try: with open(file_path, 'r', encoding='utf-8') as f: content = f.read() logger.info(f"📖 成功读取文件: {file_path} ({len(content)} 字符)") return True, content except Exception as e: logger.exception("❌ 读取文件失败") return False, f"读取失败: {str(e)}" @log_step("写入文件") @log_time def write_file(self, file_path, content): """ 覆盖写入文件 :param file_path: 文件路径 :param content: 内容 :return: (success, message) """ log_var("写入文件", {"path": file_path, "length": len(content)}) try: with open(file_path, 'w', encoding='utf-8') as f: f.write(content) logger.info(f"💾 文件已保存: {file_path}") return True, f"文件已保存: {file_path}" except Exception as e: logger.exception("❌ 写入文件失败") return False, f"写入失败: {str(e)}" @log_step("获取系统信息") @log_time def get_system_info(self): """ 获取当前系统的运行状态 :return: (success, info dict) """ try: memory = psutil.virtual_memory() disk = psutil.disk_usage('/') cpu_percent = psutil.cpu_percent(interval=1) # 更准确 info = { "操作系统": platform.system(), "系统版本": platform.version(), "处理器": platform.processor() or "未知", "内存使用率": f"{memory.percent}%", "CPU使用率": f"{cpu_percent}%", "磁盘使用率": f"{disk.percent}%", "总内存": f"{memory.total // (1024 ** 3)} GB", "可用内存": f"{memory.available // (1024 ** 2)} MB" } log_var("系统信息", info) logger.info("📊 系统信息获取成功") return True, info except Exception as e: logger.exception("❌ 获取系统信息失败") return False, f"获取失败: {str(e)}" @log_step("设置提醒") @log_time def set_reminder(self, message, delay_minutes): """ 设置一个延时提醒任务 :param message: 提醒内容 :param delay_minutes: 延迟分钟数 :return: (success, message) """ log_var("设置提醒", {"delay_min": delay_minutes, "message": message}) self.task_counter += 1 task_id = f"reminder_{self.task_counter}" def reminder_job(): logger.info(f"🔔 提醒触发: {message}") # TODO: 添加桌面通知或语音播报 try: schedule.every(delay_minutes).minutes.do(reminder_job) self.scheduled_tasks[task_id] = { "message": message, "delay": delay_minutes, "created": datetime.now().isoformat() } success_msg = f"⏰ 提醒已设置: {delay_minutes} 分钟后提醒 - '{message}'" logger.info(success_msg) return True, success_msg except Exception as e: logger.exception("❌ 设置提醒失败") return False, f"设置失败: {str(e)}" @log_time def run_scheduled_tasks(self): """运行所有待处理的定时任务(通常在主循环中调用)""" schedule.run_pending() @log_time def _find_music_files(self, directory): """递归查找指定目录中的音乐文件""" music_extensions = {'.mp3', '.wav', '.flac', '.m4a', '.ogg', '.aac'} music_files = [] try: for root, dirs, files in os.walk(directory): for file in files: ext = os.path.splitext(file.lower())[1] if ext in music_extensions: full_path = os.path.join(root, file) music_files.append(full_path) log_call(f"发现音乐文件: {full_path}") except Exception as e: logger.exception(f"🔍 搜索音乐文件时出错: {directory}") log_var("搜索完成", f"共找到 {len(music_files)} 个音乐文件") return music_files # ============================= # 🛠️ 平台命令映射(私有方法) # ============================= def _get_browser_command(self): system = self.system return "start chrome" if system == "Windows" \ else "open -a Safari" if system == "Darwin" \ else "xdg-open" def _get_text_editor_command(self): system = self.system return "notepad" if system == "Windows" \ else "open -a TextEdit" if system == "Darwin" \ else "gedit" def _get_file_manager_command(self): system = self.system return "explorer" if system == "Windows" \ else "open -a Finder" if system == "Darwin" \ else "nautilus" def _get_calculator_command(self): system = self.system return "calc" if system == "Windows" \ else "open -a Calculator" if system == "Darwin" \ else "gnome-calculator" def _get_terminal_command(self): system = self.system return "cmd" if system == "Windows" \ else "open -a Terminal" if system == "Darwin" \ else "gnome-terminal" # ============================= # 🧩 任务编排器(TaskOrchestrator) # ============================= class TaskOrchestrator: """ 多步骤任务执行器,协调 SystemController 与 GPT 助手完成复杂流程 """ def __init__(self, system_controller: SystemController, gpt_assistant=None): self.system_controller = system_controller self.gpt_assistant = gpt_assistant self.task_queue = [] self.current_task = None logger.info("🔧 任务编排器已初始化") @log_step("执行任务序列") @log_time def execute_task_sequence(self, tasks): """ 按顺序执行多个任务 :param tasks: 任务列表,每个任务格式见 `_execute_single_task` :return: 结果列表 """ results = [] log_var("开始执行任务序列", {"任务数量": len(tasks)}) for i, task in enumerate(tasks): log_call(f"▶️ 执行第 {i+1} 个任务") result = self._execute_single_task(task) results.append(result) if not result["success"]: logger.warning(f"🟡 任务 {i+1} 执行失败: {result['message']}") log_var("任务序列完成", {"成功数": sum(1 for r in results if r["success"])}) return results @log_time def _execute_single_task(self, task): """执行单个结构化任务""" task_type = task.get("type") parameters = task.get("parameters", {}) log_var("执行任务", {"type": task_type, "params": parameters}) try: if task_type == "music": action = parameters.get("action", "play") handler_map = { "play": lambda: self.system_controller.play_music(parameters.get("path")), "stop": self.system_controller.stop_music, "pause": self.system_controller.pause_music, "resume": self.system_controller.resume_music } func = handler_map.get(action) if func: return {"success": True, "message": func()[1], "task": task} else: msg = f"不支持的音乐操作: {action}" logger.warning(msg) return {"success": False, "message": msg, "task": task} elif task_type == "file": action = parameters.get("action") path = parameters.get("path", "") content = parameters.get("content", "") if action == "create": res = self.system_controller.create_file(path, content) elif action == "read": res = self.system_controller.read_file(path) elif action == "write": res = self.system_controller.write_file(path, content) else: msg = f"不支持的文件操作: {action}" logger.warning(msg) return {"success": False, "message": msg, "task": task} return {"success": res[0], "message": res[1], "task": task} elif task_type == "text" and self.gpt_assistant: action = parameters.get("action") prompt = parameters.get("prompt", "") if action == "generate": content = self.gpt_assistant.generate_text(prompt) elif action == "summarize": content = self.gpt_assistant.summarize_text(prompt) elif action == "translate": target_lang = parameters.get("target_language", "英文") content = self.gpt_assistant.translate_text(prompt, target_lang) else: msg = f"不支持的文本操作: {action}" logger.warning(msg) return {"success": False, "message": msg, "task": task} return {"success": True, "message": content, "task": task} elif task_type == "system": action = parameters.get("action") if action == "info": res = self.system_controller.get_system_info() elif action == "open_app": app_name = parameters.get("app_name", "") res = self.system_controller.open_application(app_name) elif action == "reminder": msg_text = parameters.get("message", "") delay = parameters.get("delay_minutes", 5) res = self.system_controller.set_reminder(msg_text, delay) else: msg = f"不支持的系统操作: {action}" logger.warning(msg) return {"success": False, "message": msg, "task": task} return {"success": res[0], "message": res[1], "task": task} else: msg = f"不支持的任务类型: {task_type}" logger.warning(msg) return {"success": False, "message": msg, "task": task} except Exception as e: logger.exception("💥 执行单个任务时发生异常") return { "success": False, "message": f"任务执行异常: {str(e)}", "task": task } # ============================= # 🧪 测试代码 # ============================= if __name__ == "__main__": # 初始化全局日志 if not logging.getLogger().handlers: setup_logger(name="ai_assistant", log_dir="logs") logger.info("🧪 开始测试 SystemController 和 TaskOrchestrator...") controller = SystemController() # 测试音乐播放 logger.info("🎵 测试音乐播放...") success, msg = controller.play_music() logger.info(f"播放结果: {success} | {msg}") # 测试文件操作 test_file = "test/test_demo.txt" logger.info("📂 测试文件创建...") success, msg = controller.create_file(test_file, "这是由 AI 助手创建的测试文件。\n时间: " + str(datetime.now())) logger.info(f"创建结果: {success} | {msg}") logger.info("📖 测试文件读取...") success, content = controller.read_file(test_file) logger.info(f"读取结果: {success}") if success: log_var("文件内容预览", content[:100]) # 测试应用打开 logger.info("🖥️ 测试打开记事本...") success, msg = controller.open_application("记事本") logger.info(f"打开结果: {success} | {msg}") # 测试系统信息 logger.info("📊 获取系统信息...") success, info = controller.get_system_info() if success: for k, v in info.items(): log_var("系统." + k, v) # 测试提醒 logger.info("⏰ 设置一个 1 分钟后的提醒...") success, msg = controller.set_reminder("这是测试提醒!", 1) logger.info(f"提醒设置结果: {success} | {msg}") # 模拟运行一段时间的任务调度 for _ in range(3): controller.run_scheduled_tasks() time.sleep(1) logger.info("🎉 系统控制模块测试完成") """ 【语音合成模块】Text-to-Speech (TTS) 将文本转换为语音输出,支持中断、队列和多语音切换 """ import pyttsx3 import threading import queue import time import logging # --- 导入配置 --- from database import config # --- 导入日志工具 --- from Progress.utils.logger_utils import log_time, log_step, log_var, log_call from Progress.utils.logger_config import setup_logger # --- 配置参数 --- TTS_RATE = config.rate # 语速 TTS_VOLUME = config.volume # 音量 # --- 初始化日志器 --- logger = logging.getLogger(__name__) class TTSEngine: """ 基于 pyttsx3 的语音合成引擎 支持队列管理、语音控制、异步播放 """ def __init__(self): self.engine = None self.is_speaking = False self.speech_queue = queue.Queue() self.speech_thread = None self.stop_speaking = False self._initialize_engine() @log_step("初始化语音合成引擎") @log_time def _initialize_engine(self): """初始化 pyttsx3 引擎并设置语音参数""" try: self.engine = pyttsx3.init() # 设置基础属性 self.engine.setProperty('rate', TTS_RATE) self.engine.setProperty('volume', TTS_VOLUME) log_var("TTS.语速", TTS_RATE) log_var("TTS.音量", TTS_VOLUME) # 尝试选择中文语音 voices = self.engine.getProperty('voices') log_var("可用语音数量", len(voices)) selected_voice = None for voice in voices: if any(kw in voice.name.lower() for kw in ['chinese', 'mandarin', 'zh']): selected_voice = voice break if selected_voice: self.engine.setProperty('voice', selected_voice.id) log_call(f"已选择中文语音: {selected_voice.name}") elif voices: fallback_voice = voices[0] self.engine.setProperty('voice', fallback_voice.id) log_call(f"未找到中文语音,回退到: {fallback_voice.name}") else: logger.warning("系统无可用语音") logger.info("✅ 语音合成引擎初始化成功") except Exception as e: logger.exception("❌ 语音合成引擎初始化失败") self.engine = None @log_time def speak(self, text, interrupt=True): """ 主接口:语音播报文本(线程安全,支持队列) :param text: 要朗读的文本 :param interrupt: 是否打断当前正在播放的内容 :return: 是否成功提交任务 """ if not self.is_available(): logger.error("🔊 语音引擎不可用,跳过播报") return False if not text or not text.strip(): log_var("空输入被忽略", repr(text)) return False cleaned_text = text.strip() log_var("准备播报", cleaned_text) try: if interrupt: self.stop_current_speech() log_call("已中断当前语音") self.speech_queue.put(cleaned_text) if not self.speech_thread or not self.speech_thread.is_alive(): self.speech_thread = threading.Thread(target=self._speech_worker, name="TTSWorker") self.speech_thread.daemon = True self.speech_thread.start() log_call("启动语音工作线程") return True except Exception as e: logger.exception("❌ 提交语音任务时发生异常") return False def speak_async(self, text): """便捷方法:异步直接播放(不走队列)""" thread = threading.Thread(target=self._speak_sync, args=(text,), name="TTSAsync") thread.daemon = True thread.start() def _speak_sync(self, text): """同步播放单条语音(用于异步调用)""" if not self.is_available() or not text.strip(): return try: log_call(f"异步播放: {text[:30]}...") self.is_speaking = True self.engine.say(text) self.engine.runAndWait() self.is_speaking = False except Exception as e: logger.exception("❌ 同步语音播放异常") self.is_speaking = False @log_time def _speech_worker(self): """后台工作线程:从队列中取出文本并播放""" logger.debug("🎧 语音工作线程已启动") while not self.stop_speaking: try: text = self.speech_queue.get(timeout=1.0) if text is None: # 接收到停止信号 break log_var("正在播报", text) self.is_speaking = True self.engine.say(text) self.engine.runAndWait() self.is_speaking = False self.speech_queue.task_done() except queue.Empty: continue except Exception as e: logger.exception("❌ 语音工作线程运行出错") self.is_speaking = False self.speech_queue.task_done() logger.debug("🎧 语音工作线程已退出") @log_time def stop_current_speech(self): """停止当前正在播放的语音,并清空待播队列""" log_call("请求停止当前语音") try: if self.is_speaking and self.engine: self.engine.stop() self.is_speaking = False logger.info("🛑 已停止当前语音播放") # 清空队列 cleared = 0 while not self.speech_queue.empty(): try: self.speech_queue.get_nowait() self.speech_queue.task_done() cleared += 1 except queue.Empty: break if cleared > 0: log_var("清空待播队列", f"移除了 {cleared} 条消息") except Exception as e: logger.exception("❌ 停止语音播放失败") def pause_speech(self): """暂停语音(等同于 stop)""" self.stop_current_speech() @log_time def set_rate(self, rate): """设置语速""" log_var("TTS.设置语速", rate) try: if self.engine: self.engine.setProperty('rate', rate) return True except Exception as e: logger.exception("❌ 设置语速失败") return False @log_time def set_volume(self, volume): """设置音量""" log_var("TTS.设置音量", volume) try: if self.engine: self.engine.setProperty('volume', volume) return True except Exception as e: logger.exception("❌ 设置音量失败") return False @log_time def get_available_voices(self): """获取所有可用语音列表""" try: if self.engine: voices = self.engine.getProperty('voices') voice_list = [{"id": v.id, "name": v.name} for v in voices] log_var("TTS.可用语音", voice_list) return voice_list return [] except Exception as e: logger.exception("❌ 获取语音列表失败") return [] @log_time def set_voice(self, voice_id): """切换语音""" log_var("TTS.切换语音", voice_id) try: if self.engine: self.engine.setProperty('voice', voice_id) logger.info(f"🗣️ 已切换语音: {voice_id}") return True except Exception as e: logger.exception("❌ 切换语音失败") return False def is_available(self): """检查引擎是否可用""" available = self.engine is not None log_var("TTS.可用状态", available) return available @log_step("清理 TTS 资源") @log_time def cleanup(self): """释放资源:停止播放、关闭引擎""" log_call("开始清理 TTS 模块") self.stop_speaking = True self.stop_current_speech() if self.speech_thread and self.speech_thread.is_alive(): logger.debug("等待语音线程结束...") self.speech_thread.join(timeout=2) if self.speech_thread.is_alive(): logger.warning("⚠️ 语音线程未能正常退出") try: if self.engine: self.engine.stop() logger.info("🧹 TTS 引擎已停止") except Exception as e: logger.exception("❌ 清理 TTS 引擎时出错") # ============================= # 🧪 测试代码 # ============================= if __name__ == "__main__": # 初始化全局日志 if not logging.getLogger().handlers: setup_logger(name="ai_assistant", log_dir="logs") logger.info("🧪 开始测试 TTSEngine...") tts = TTSEngine() if tts.is_available(): logger.info("✅ 语音引擎可用,开始功能测试") # 测试基础语音 tts.speak("你好,我是语音助手,正在测试语音合成功能。") time.sleep(2) # 测试异步语音 tts.speak_async("这是异步语音播报,不会阻塞主线程。") time.sleep(1) # 测试语音列表 voices = tts.get_available_voices() logger.info(f"🔍 发现 {len(voices)} 个可用语音") for i, v in enumerate(voices): logger.debug(f" [{i}] {v['name']} -> {v['id'][-10:]}") # 清理资源 tts.cleanup() logger.info("🎉 测试完成,资源已清理") else: logger.error("🔴 语音引擎初始化失败,请检查系统语音支持") 还有这三个文件,把五个文件统一起来修正问题
10-22
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值