"""
【系统控制模块】System Controller
提供音乐播放、文件操作、应用启动、定时提醒等本地系统级功能
"""
import os
import subprocess
import platform
import time
import psutil
import pygame
from datetime import datetime
import logging
import schedule
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
""" import config
from utils.logger_utils import log_time, log_step, log_var, log_call
from 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("ai_assistant")
class SystemController:
def __init__(self):
self.system = platform.system()
self.music_player = None
self._init_music_player()
@log_step("初始化音乐播放器")
@log_time
def _init_music_player(self):
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):
target_path = music_path or DEFAULT_MUSIC_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 = "🎵 未找到支持的音乐文件"
logger.info(msg)
return False, msg
try:
self.stop_music()
self.music_player.load(music_files[0])
self.music_player.play()
success_msg = f"🎶 正在播放: {os.path.basename(music_files[0])}"
logger.info(success_msg)
return True, success_msg
except Exception as e:
logger.exception("💥 播放音乐失败")
return False, f"播放失败: {str(e)}"
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)}"
def pause_music(self):
"""暂停音乐"""
try:
self.music_player.pause()
return True, "音乐已暂停"
except Exception as e:
return False, f"暂停音乐失败: {str(e)}"
def resume_music(self):
"""恢复音乐"""
try:
self.music_player.unpause()
return True, "音乐已恢复"
except Exception as e:
return False, f"恢复音乐失败: {str(e)}"
def open_application(self, app_name, **kwargs):
# 映射别名
alias_map = {
"浏览器": "browser", "browser": "browser", "chrome": "browser", "edge": "browser", "firefox": "browser",
"记事本": "text_editer", "text_editer": "text_editer",
"文件管理器": "explorer", "explorer": "explorer",
"计算器": "calc", "calc": "calc",
"终端": "terminal", "terminal": "terminal"
}
app_key = alias_map.get(app_name)
if not app_key:
return False, f"🚫 不支持的应用: {app_name}"
try:
if app_key == "browser":
url = kwargs.get("url", "https://www.baidu.com")
return self._get_browser_command(url)
else:
cmd_func = getattr(self, f"_get_{app_key}_command")
cmd = cmd_func()
subprocess.Popen(cmd, shell=True)
return True, f"🚀 正在打开 {app_name}"
except Exception as e:
logger.exception(f"💥 启动应用 {app_name} 失败")
return False, f"启动失败: {str(e)}"
def create_file(self, file_path, 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)
return True, f"文件已创建: {file_path}"
except Exception as e:
logger.exception("❌ 创建文件失败")
return False, f"创建失败: {str(e)}"
def read_file(self, file_path):
"""读取文件"""
try:
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()
return True, content
except Exception as e:
return False, f"读取文件失败: {str(e)}"
def write_file(self, file_path, content):
"""写入文件"""
try:
with open(file_path, 'w', encoding='utf-8') as f:
f.write(content)
return True, f"文件已保存: {file_path}"
except Exception as e:
return False, f"写入文件失败: {str(e)}"
def get_system_info(self):
"""获取系统信息"""
try:
info = {
"操作系统": platform.system(),
"系统版本": platform.version(),
"处理器": platform.processor(),
"内存使用率": f"{psutil.virtual_memory().percent}%",
"CPU使用率": f"{psutil.cpu_percent()}%",
"磁盘使用率": f"{psutil.disk_usage('/').percent}%"
}
return True, info
except Exception as e:
return False, f"获取系统信息失败: {str(e)}"
def set_reminder(self, message, delay_minutes):
"""设置提醒"""
try:
self.task_counter += 1
task_id = f"reminder_{self.task_counter}"
def reminder_job():
print(f"提醒: {message}")
# 这里可以添加通知功能
schedule.every(delay_minutes).minutes.do(reminder_job)
self.scheduled_tasks[task_id] = {
"message": message,
"delay": delay_minutes,
"created": datetime.now()
}
return True, f"提醒已设置: {delay_minutes}分钟后提醒 - {message}"
except Exception as e:
return False, f"设置提醒失败: {str(e)}"
def run_scheduled_tasks(self):
"""运行定时任务"""
schedule.run_pending()
def _find_music_files(self, directory):
"""查找音乐文件"""
music_extensions = ['.mp3', '.wav', '.flac', '.m4a', '.ogg']
music_files = []
try:
for root, dirs, files in os.walk(directory):
for file in files:
if any(file.lower().endswith(ext) for ext in music_extensions):
music_files.append(os.path.join(root, file))
except Exception as e:
print(f"搜索音乐文件失败: {e}")
return music_files
def _get_text_editor_command(self):
"""获取文本编辑器启动命令"""
if self.system == "Windows":
return "notepad"
elif self.system == "Darwin": # macOS
return "open -a TextEdit"
else: # Linux
return "gedit"
def _get_explorer_command(self):
"""获取文件管理器启动命令"""
if self.system == "Windows":
return "explorer"
elif self.system == "Darwin": # macOS
return "open -a Finder"
else: # Linux
return "nautilus"
def _get_calc_command(self):
"""获取计算器启动命令"""
if self.system == "Windows":
return "calc"
elif self.system == "Darwin": # macOS
return "open -a Calculator"
else: # Linux
return "gnome-calculator"
def _get_terminal_command(self):
"""获取终端启动命令"""
if self.system == "Windows":
return "cmd"
elif self.system == "Darwin": # macOS
return "open -a Terminal"
else: # Linux
return "gnome-terminal"
def _get_browser_command(self, url="https://www.baidu.com"):
try:
import webbrowser
if webbrowser.open(url):
logger.info(f"🌐 已使用默认浏览器打开: {url}")
return True, f"正在打开浏览器访问: {url}"
else:
return False, "无法打开浏览器"
except Exception as e:
logger.error(f"❌ 浏览器打开异常: {e}")
return False, str(e)
class TaskOrchestrator:
def __init__(self, system_controller, gpt_assistant=None):
self.system_controller = system_controller
self.gpt_assistant = gpt_assistant
logger.info("🔧 任务编排器已初始化")
@log_step("执行任务")
@log_time
def execute(self, ai_response):
intent = ai_response.get("intent")
action = ai_response.get("action")
params = ai_response.get("parameters", {})
# === 支持多步骤任务 ===
if intent == "task" and action == "execute":
return self._execute_task_steps(params.get("steps", []))
# 定义支持的操作映射
supported_operations = {
("music", "play"): lambda: self.system_controller.play_music(params.get("path")),
("music", "stop"): self.system_controller.stop_music,
("system", "open_application"): lambda: self.system_controller.open_application(params.get("app_name")), # 新增这一行!
("file", "create"): lambda: self.system_controller.create_file(
params.get("path"), params.get("content", "")
),
("system", "get_system_info"): lambda: self.system_controller.get_system_info()
}
func = supported_operations.get((intent, action))
if not func:
logger.warning(f"❌ 不支持的操作: {intent}.{action}")
return False
try:
success, msg = func()
logger.info(f"✅ 执行结果: {msg}")
return success
except Exception as e:
logger.exception("💥 执行任务时出错")
return False
def _execute_task_steps(self, steps):
"""逐条执行 steps 中的任务"""
if not steps:
logger.warning("⚠️ 任务列表为空")
return False
success_count = 0
total_steps = len(steps)
for i, step in enumerate(steps, start=1):
op = step.get("operation")
logger.info(f"🔄 正在执行第 {i}/{total_steps} 步: {op}")
try:
result = self._run_single_step(step)
if result:
success_count += 1
else:
logger.warning(f"🟡 第 {i} 步执行失败: {op}")
except Exception as e:
logger.exception(f"🔴 执行第 {i} 步出错: {op}")
continue
final_status = success_count == total_steps
logger.info(f"🏁 多步任务完成: {success_count}/{total_steps} 成功")
return final_status
def _run_single_step(self, step):
"""运行单个 step 操作"""
operation = step.get("operation")
mapping = {
"open_application": lambda: self.system_controller.open_application(
step.get("target"),
url=step.get("url", "https://www.baidu.com") # 可选参数
),
"create_file": lambda: self.system_controller.create_file(
file_path=step.get("path"),
content=step.get("content", "")
),
"read_file": lambda: self.system_controller.read_file(step.get("path")),
"write_file": lambda: self.system_controller.write_file(
file_path=step.get("path"),
content=step.get("content")
),
"play_music": lambda: self.system_controller.play_music(step.get("path")),
"stop_music": self.system_controller.stop_music,
"get_system_info": self.system_controller.get_system_info,
"set_reminder": lambda: self.system_controller.set_reminder(
message=step.get("message"),
delay_minutes=step.get("delay_minutes")
)
}
func = mapping.get(operation)
if not func:
logger.warning(f"🚫 不支持的操作: {operation}")
return False
try:
success, msg = func()
logger.info(f"✅ {operation} 结果: {msg}")
return success
except Exception as e:
logger.exception(f"💥 执行 {operation} 失败")
return False
为这个系统做一个测试代码
最新发布