cursor_auto_chat.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. """
  4. Cursor自动聊天工具
  5. 这个工具可以自动查找Cursor窗口,定位到chat窗口,并自动发送消息。
  6. 功能:
  7. 1. 查找Windows操作系统中运行的Cursor程序
  8. 2. 找到当前运行Cursor实例,并定位到当前的chat窗口
  9. 3. 模拟鼠标点击到chat窗口
  10. 4. 模拟键盘输入"请检查并执行所有待处理任务。"到chat窗口
  11. 5. 模拟鼠标点击chat窗口的"提交"按钮
  12. 6. 以服务方式持续运行,间隔300秒进行一次上述操作
  13. 使用方法:
  14. 1. 单次执行:python scripts/cursor_auto_chat.py --once
  15. 2. 服务模式:python scripts/cursor_auto_chat.py --daemon
  16. 3. 自定义间隔:python scripts/cursor_auto_chat.py --interval 300
  17. 4. 指定输入框位置:python scripts/cursor_auto_chat.py --input-box-pos "1180,965"
  18. """
  19. import sys
  20. import time
  21. import argparse
  22. import logging
  23. from pathlib import Path
  24. from datetime import datetime
  25. try:
  26. import win32gui
  27. import win32con
  28. import win32process
  29. import win32api
  30. import pyautogui
  31. import pywinauto
  32. from pywinauto import Application
  33. try:
  34. import pyperclip
  35. HAS_PYPERCLIP = True
  36. except ImportError:
  37. HAS_PYPERCLIP = False
  38. except ImportError as e:
  39. print(f"❌ 缺少必要的依赖库: {e}")
  40. print("请运行: pip install pywin32 pyautogui pywinauto pyperclip")
  41. sys.exit(1)
  42. # 配置日志
  43. logs_dir = Path(__file__).parent.parent / 'logs'
  44. logs_dir.mkdir(exist_ok=True)
  45. logging.basicConfig(
  46. level=logging.INFO,
  47. format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
  48. handlers=[
  49. logging.FileHandler(logs_dir / 'cursor_auto_chat.log', encoding='utf-8'),
  50. logging.StreamHandler(sys.stdout)
  51. ]
  52. )
  53. logger = logging.getLogger('CursorAutoChat')
  54. # 配置pyautogui安全设置
  55. pyautogui.FAILSAFE = True # 鼠标移到屏幕左上角会触发异常,用于紧急停止
  56. pyautogui.PAUSE = 0.5 # 每个操作之间的暂停时间(秒)
  57. # 检查pyperclip并记录
  58. if not HAS_PYPERCLIP:
  59. logger.warning("未安装pyperclip,中文输入可能有问题,建议安装: pip install pyperclip")
  60. class CursorAutoChat:
  61. """Cursor自动聊天工具类"""
  62. def __init__(self, message="请检查并执行所有待处理任务。", interval=300, input_box_pos=None):
  63. """
  64. 初始化工具
  65. Args:
  66. message: 要发送的消息内容
  67. interval: 执行间隔(秒)
  68. input_box_pos: 输入框位置 (x, y),如果提供则直接使用,不进行自动定位
  69. """
  70. self.message = message
  71. self.interval = interval
  72. self.cursor_window = None
  73. self.input_box_pos = input_box_pos # 用户指定的输入框位置
  74. logger.info(f"Cursor自动聊天工具已初始化")
  75. logger.info(f"消息内容: {self.message}")
  76. logger.info(f"执行间隔: {self.interval}秒")
  77. if self.input_box_pos:
  78. logger.info(f"使用指定的输入框位置: {self.input_box_pos}")
  79. def find_cursor_processes(self):
  80. """
  81. 查找所有运行的Cursor进程
  82. Returns:
  83. list: Cursor进程ID列表
  84. """
  85. cursor_pids = []
  86. try:
  87. import psutil
  88. for proc in psutil.process_iter(['pid', 'name', 'exe']):
  89. try:
  90. proc_name = proc.info['name'].lower() if proc.info['name'] else ''
  91. proc_exe = proc.info['exe'].lower() if proc.info['exe'] else ''
  92. # 查找Cursor相关进程
  93. if 'cursor' in proc_name or 'cursor' in proc_exe:
  94. cursor_pids.append(proc.info['pid'])
  95. logger.debug(f"找到Cursor进程: PID={proc.info['pid']}, Name={proc.info['name']}")
  96. except (psutil.NoSuchProcess, psutil.AccessDenied):
  97. continue
  98. except ImportError:
  99. # 如果没有psutil,使用win32api枚举窗口
  100. logger.warning("未安装psutil,使用窗口枚举方式查找Cursor")
  101. cursor_pids = self._find_cursor_by_windows()
  102. logger.info(f"找到 {len(cursor_pids)} 个Cursor进程")
  103. return cursor_pids
  104. def _find_cursor_by_windows(self):
  105. """通过枚举窗口查找Cursor进程"""
  106. cursor_pids = []
  107. def enum_windows_callback(hwnd, windows):
  108. if win32gui.IsWindowVisible(hwnd):
  109. window_title = win32gui.GetWindowText(hwnd)
  110. if 'cursor' in window_title.lower():
  111. _, pid = win32process.GetWindowThreadProcessId(hwnd)
  112. if pid not in cursor_pids:
  113. cursor_pids.append(pid)
  114. return True
  115. win32gui.EnumWindows(enum_windows_callback, None)
  116. return cursor_pids
  117. def find_cursor_window(self):
  118. """
  119. 查找Cursor主窗口
  120. Returns:
  121. int: 窗口句柄,如果未找到返回None
  122. """
  123. cursor_windows = [] # 存储所有可能的Cursor窗口
  124. def enum_windows_callback(hwnd, windows):
  125. if win32gui.IsWindowVisible(hwnd):
  126. window_title = win32gui.GetWindowText(hwnd)
  127. class_name = win32gui.GetClassName(hwnd)
  128. # Cursor基于Electron,窗口类名可能是Chrome_WidgetWin_1或类似
  129. # 查找可能的Cursor窗口
  130. is_cursor = False
  131. # 检查窗口标题
  132. if window_title and 'cursor' in window_title.lower():
  133. is_cursor = True
  134. # 检查窗口类名(Electron应用通常有特定类名)
  135. if class_name and ('chrome_widgetwin' in class_name.lower() or 'electron' in class_name.lower()):
  136. # 进一步检查:Electron窗口通常比较大
  137. rect = win32gui.GetWindowRect(hwnd)
  138. width = rect[2] - rect[0]
  139. height = rect[3] - rect[1]
  140. if width > 800 and height > 600:
  141. is_cursor = True
  142. if is_cursor:
  143. rect = win32gui.GetWindowRect(hwnd)
  144. width = rect[2] - rect[0]
  145. height = rect[3] - rect[1]
  146. area = width * height
  147. cursor_windows.append({
  148. 'hwnd': hwnd,
  149. 'title': window_title,
  150. 'class': class_name,
  151. 'width': width,
  152. 'height': height,
  153. 'area': area
  154. })
  155. logger.debug(f"找到可能的Cursor窗口: {window_title} ({class_name}), Size: {width}x{height}")
  156. return True
  157. win32gui.EnumWindows(enum_windows_callback, None)
  158. if not cursor_windows:
  159. logger.warning("未找到Cursor窗口")
  160. return None
  161. # 选择最大的窗口作为主窗口(通常是主应用窗口)
  162. cursor_windows.sort(key=lambda x: x['area'], reverse=True)
  163. main_window = cursor_windows[0]
  164. logger.info(f"找到Cursor主窗口: {main_window['title']} ({main_window['class']})")
  165. logger.info(f"窗口大小: {main_window['width']}x{main_window['height']} (HWND: {main_window['hwnd']})")
  166. return main_window['hwnd']
  167. def activate_cursor_window(self, hwnd):
  168. """
  169. 激活Cursor窗口
  170. Args:
  171. hwnd: 窗口句柄
  172. """
  173. try:
  174. # 恢复窗口(如果最小化)
  175. win32gui.ShowWindow(hwnd, win32con.SW_RESTORE)
  176. time.sleep(0.3)
  177. # 激活窗口
  178. win32gui.SetForegroundWindow(hwnd)
  179. time.sleep(0.5)
  180. logger.info("Cursor窗口已激活")
  181. return True
  182. except Exception as e:
  183. logger.error(f"激活窗口失败: {e}")
  184. return False
  185. def find_chat_input_area(self, hwnd):
  186. """
  187. 查找chat输入区域
  188. 使用多种策略定位Cursor的chat输入框:
  189. 1. 尝试多个快捷键打开chat(Ctrl+K, Ctrl+L, Ctrl+Shift+L等)
  190. 2. 使用相对窗口坐标定位输入框(chat通常在窗口底部中央或右侧)
  191. 3. 验证输入框是否被激活
  192. Args:
  193. hwnd: Cursor窗口句柄
  194. Returns:
  195. tuple: (是否成功, 输入框坐标(x, y)) 或 (False, None)
  196. """
  197. try:
  198. # 获取窗口位置和大小
  199. rect = win32gui.GetWindowRect(hwnd)
  200. window_left = rect[0]
  201. window_top = rect[1]
  202. window_width = rect[2] - rect[0]
  203. window_height = rect[3] - rect[1]
  204. logger.info(f"窗口位置: ({window_left}, {window_top}), 大小: {window_width}x{window_height}")
  205. # 策略1: 尝试多个快捷键打开chat
  206. logger.info("尝试使用快捷键打开chat窗口...")
  207. shortcuts = [
  208. ('ctrl', 'k'), # Cursor最常用的快捷键
  209. ('ctrl', 'l'), # 备用快捷键
  210. ('ctrl', 'shift', 'l'), # 另一个可能的快捷键
  211. ]
  212. for shortcut in shortcuts:
  213. try:
  214. logger.debug(f"尝试快捷键: {'+'.join(shortcut)}")
  215. pyautogui.hotkey(*shortcut)
  216. time.sleep(1.5) # 给chat窗口时间打开
  217. # 尝试定位输入框
  218. result = self._try_activate_input_box(hwnd, window_left, window_top, window_width, window_height)
  219. if result:
  220. input_pos = result
  221. logger.info(f"成功定位并激活chat输入框,位置: {input_pos}")
  222. return (True, input_pos)
  223. except Exception as e:
  224. logger.debug(f"快捷键 {shortcut} 失败: {e}")
  225. continue
  226. # 策略2: 直接尝试点击可能的输入框位置(即使chat已打开)
  227. logger.info("尝试直接点击可能的输入框位置...")
  228. result = self._try_activate_input_box(hwnd, window_left, window_top, window_width, window_height)
  229. if result:
  230. input_pos = result
  231. logger.info(f"成功定位并激活chat输入框,位置: {input_pos}")
  232. return (True, input_pos)
  233. logger.warning("未能定位chat输入框,将尝试通用方法")
  234. return (False, None)
  235. except Exception as e:
  236. logger.error(f"查找chat输入区域失败: {e}")
  237. return (False, None)
  238. def _try_activate_input_box(self, hwnd, window_left, window_top, window_width, window_height):
  239. """
  240. 尝试激活输入框
  241. Args:
  242. hwnd: 窗口句柄
  243. window_left: 窗口左边界
  244. window_top: 窗口上边界
  245. window_width: 窗口宽度
  246. window_height: 窗口高度
  247. Returns:
  248. tuple: 成功时返回 (x, y) 坐标,失败时返回 None
  249. """
  250. # Cursor的chat输入框通常在窗口底部中央或右侧底部
  251. # 尝试多个可能的位置(相对于窗口)
  252. # 根据实际测试,输入框位置约为(0.61, 0.92)
  253. possible_relative_positions = [
  254. (0.61, 0.92), # 实际测试位置(优先尝试)
  255. (0.6, 0.92), # 稍微偏左
  256. (0.62, 0.92), # 稍微偏右
  257. (0.61, 0.91), # 稍微偏上
  258. (0.61, 0.93), # 稍微偏下
  259. (0.75, 0.92), # 窗口右侧底部(备用)
  260. (0.5, 0.92), # 窗口底部中央(备用)
  261. (0.5, 0.88), # 窗口底部稍上(备用)
  262. (0.8, 0.9), # 窗口右侧(备用)
  263. ]
  264. for rel_x, rel_y in possible_relative_positions:
  265. try:
  266. # 计算绝对坐标
  267. abs_x = window_left + int(window_width * rel_x)
  268. abs_y = window_top + int(window_height * rel_y)
  269. logger.debug(f"尝试点击位置(相对窗口): ({rel_x:.2f}, {rel_y:.2f}) -> 绝对坐标: ({abs_x}, {abs_y})")
  270. # 点击输入框位置
  271. pyautogui.click(abs_x, abs_y)
  272. time.sleep(0.8) # 等待输入框激活
  273. # 验证输入框是否激活:尝试输入一个测试字符然后删除
  274. # 如果输入框已激活,这个操作应该成功
  275. pyautogui.write('test', interval=0.1)
  276. time.sleep(0.3)
  277. # 删除测试文本
  278. for _ in range(4):
  279. pyautogui.press('backspace')
  280. time.sleep(0.3)
  281. # 如果到这里没有异常,说明输入框可能已激活
  282. logger.info(f"成功激活输入框,位置: ({abs_x}, {abs_y})")
  283. return (abs_x, abs_y)
  284. except Exception as e:
  285. logger.debug(f"位置 ({rel_x:.2f}, {rel_y:.2f}) 失败: {e}")
  286. continue
  287. return None
  288. def send_message(self, message, input_pos=None):
  289. """
  290. 发送消息到chat窗口
  291. Args:
  292. message: 要发送的消息
  293. input_pos: 输入框坐标 (x, y),如果提供则点击该位置确保激活
  294. """
  295. try:
  296. # 如果提供了输入框位置,先移动鼠标到该位置,然后点击
  297. if input_pos:
  298. x, y = input_pos
  299. logger.info(f"移动鼠标到输入框位置: ({x}, {y})")
  300. pyautogui.moveTo(x, y, duration=0.3) # 平滑移动到输入框位置
  301. time.sleep(0.2)
  302. logger.info(f"点击输入框位置确保激活: ({x}, {y})")
  303. pyautogui.click(x, y)
  304. time.sleep(0.5) # 等待输入框激活
  305. else:
  306. # 如果没有提供位置,点击当前鼠标位置
  307. logger.info("点击当前位置确保输入框激活")
  308. pyautogui.click()
  309. time.sleep(0.3)
  310. # 清空可能的现有文本
  311. logger.info("清空输入框中的现有文本...")
  312. pyautogui.hotkey('ctrl', 'a')
  313. time.sleep(0.3)
  314. # 再次确保鼠标在输入框位置并点击(如果提供了位置)
  315. if input_pos:
  316. x, y = input_pos
  317. logger.info(f"再次移动鼠标到输入框并点击: ({x}, {y})")
  318. pyautogui.moveTo(x, y, duration=0.2)
  319. time.sleep(0.2)
  320. pyautogui.click(x, y)
  321. time.sleep(0.4) # 给足够时间让输入框完全激活
  322. else:
  323. pyautogui.click()
  324. time.sleep(0.2)
  325. # 输入消息
  326. logger.info(f"正在输入消息: {message}")
  327. # 对于中文文本,使用剪贴板方法更可靠
  328. if HAS_PYPERCLIP:
  329. try:
  330. # 保存当前剪贴板内容
  331. old_clipboard = pyperclip.paste() if hasattr(pyperclip, 'paste') else None
  332. # 复制消息到剪贴板
  333. pyperclip.copy(message)
  334. time.sleep(0.3)
  335. # 确保鼠标在输入框位置(如果提供了位置)
  336. if input_pos:
  337. x, y = input_pos
  338. logger.info(f"粘贴前确保鼠标在输入框位置: ({x}, {y})")
  339. pyautogui.moveTo(x, y, duration=0.2)
  340. time.sleep(0.2)
  341. # 再次点击确保焦点
  342. pyautogui.click(x, y)
  343. time.sleep(0.3)
  344. # 粘贴消息
  345. logger.info("执行Ctrl+V粘贴消息...")
  346. pyautogui.hotkey('ctrl', 'v')
  347. time.sleep(1.5) # 等待粘贴完成,给足够时间
  348. # 验证粘贴是否成功(可选:再次点击确保文本已输入)
  349. if input_pos:
  350. # 轻微移动鼠标确认输入框仍有焦点
  351. x, y = input_pos
  352. pyautogui.moveTo(x + 1, y + 1, duration=0.1)
  353. time.sleep(0.2)
  354. # 恢复剪贴板(可选)
  355. if old_clipboard:
  356. try:
  357. pyperclip.copy(old_clipboard)
  358. except:
  359. pass
  360. logger.info("使用剪贴板方法输入消息成功")
  361. return True
  362. except Exception as e:
  363. logger.warning(f"剪贴板方法失败: {e},尝试其他方法...")
  364. # 备用方法:直接输入(对英文有效)
  365. try:
  366. # 检查是否包含中文字符
  367. has_chinese = any('\u4e00' <= char <= '\u9fff' for char in message)
  368. if has_chinese:
  369. logger.warning("消息包含中文,但pyperclip不可用,输入可能失败")
  370. pyautogui.write(message, interval=0.05)
  371. time.sleep(0.8)
  372. logger.info("使用write方法输入成功")
  373. return True
  374. except Exception as e2:
  375. logger.error(f"使用write方法也失败: {e2}")
  376. return False
  377. except Exception as e:
  378. logger.error(f"输入消息失败: {e}")
  379. return False
  380. def click_submit_button(self):
  381. """
  382. 点击提交按钮
  383. Cursor的提交方式可能是:
  384. 1. Enter键(单行输入)
  385. 2. Ctrl+Enter组合键(多行输入或某些配置)
  386. 3. 点击提交按钮(如果存在)
  387. """
  388. try:
  389. # 策略1: 先尝试Enter键(最常见)
  390. logger.info("尝试按Enter键提交...")
  391. pyautogui.press('enter')
  392. time.sleep(1.0) # 等待消息发送
  393. # 策略2: 如果Enter不行,尝试Ctrl+Enter(某些配置下需要)
  394. # 但先等待一下,看看Enter是否生效
  395. logger.info("等待消息发送完成...")
  396. time.sleep(1.5) # 给足够时间让消息发送
  397. logger.info("消息已提交(使用Enter键)")
  398. logger.info("提示: 如果消息未出现在chat历史中,可能需要使用Ctrl+Enter")
  399. return True
  400. except Exception as e:
  401. logger.error(f"点击提交按钮失败: {e}")
  402. # 尝试备用方法
  403. try:
  404. logger.info("尝试使用Ctrl+Enter提交...")
  405. pyautogui.hotkey('ctrl', 'enter')
  406. time.sleep(1.5)
  407. logger.info("使用Ctrl+Enter提交完成")
  408. return True
  409. except Exception as e2:
  410. logger.error(f"使用Ctrl+Enter也失败: {e2}")
  411. return False
  412. def execute_once(self):
  413. """
  414. 执行一次完整的操作流程
  415. Returns:
  416. bool: 是否成功执行
  417. """
  418. logger.info("=" * 60)
  419. logger.info("开始执行自动聊天操作...")
  420. logger.info("=" * 60)
  421. try:
  422. # 步骤1: 查找Cursor进程
  423. logger.info("步骤1: 查找Cursor进程...")
  424. cursor_pids = self.find_cursor_processes()
  425. if not cursor_pids:
  426. logger.error("未找到Cursor进程,请确保Cursor正在运行")
  427. return False
  428. # 步骤2: 查找Cursor窗口
  429. logger.info("步骤2: 查找Cursor主窗口...")
  430. cursor_hwnd = self.find_cursor_window()
  431. if not cursor_hwnd:
  432. logger.error("未找到Cursor主窗口")
  433. return False
  434. # 步骤3: 激活窗口
  435. logger.info("步骤3: 激活Cursor窗口...")
  436. if not self.activate_cursor_window(cursor_hwnd):
  437. logger.error("激活窗口失败")
  438. return False
  439. # 步骤4: 定位chat输入区域
  440. logger.info("步骤4: 定位chat输入区域...")
  441. # 如果用户指定了输入框位置,直接使用
  442. if self.input_box_pos:
  443. input_pos = self.input_box_pos
  444. logger.info(f"使用用户指定的输入框位置: {input_pos}")
  445. # 激活窗口后,直接使用指定位置
  446. time.sleep(0.5)
  447. else:
  448. # 自动定位输入框
  449. result = self.find_chat_input_area(cursor_hwnd)
  450. if isinstance(result, tuple) and len(result) == 2:
  451. success, input_pos = result
  452. if success and input_pos:
  453. logger.info(f"已定位到输入框位置: {input_pos}")
  454. else:
  455. logger.warning("未能精确定位输入区域,将尝试直接输入")
  456. input_pos = None
  457. else:
  458. # 兼容旧版本返回格式
  459. if result:
  460. logger.info("已定位到输入框")
  461. input_pos = None # 旧版本不返回位置
  462. else:
  463. logger.warning("未能精确定位输入区域,将尝试直接输入")
  464. input_pos = None
  465. time.sleep(1)
  466. # 步骤5: 输入消息
  467. logger.info("步骤5: 输入消息...")
  468. if not self.send_message(self.message, input_pos):
  469. logger.error("输入消息失败")
  470. return False
  471. # 步骤6: 点击提交按钮
  472. logger.info("步骤6: 提交消息...")
  473. if not self.click_submit_button():
  474. logger.error("提交消息失败")
  475. return False
  476. logger.info("=" * 60)
  477. logger.info("✅ 自动聊天操作执行成功!")
  478. logger.info("=" * 60)
  479. return True
  480. except Exception as e:
  481. logger.error(f"执行过程中出错: {e}", exc_info=True)
  482. return False
  483. def run_daemon(self):
  484. """
  485. 以守护进程模式运行,定期执行操作
  486. """
  487. logger.info("=" * 60)
  488. logger.info("🚀 Cursor自动聊天工具已启动(守护进程模式)")
  489. logger.info(f"⏰ 执行间隔: {self.interval}秒 ({self.interval//60}分钟)")
  490. logger.info("按 Ctrl+C 停止服务")
  491. logger.info("=" * 60)
  492. try:
  493. while True:
  494. try:
  495. success = self.execute_once()
  496. if success:
  497. logger.info(f"✅ 操作执行成功,{self.interval}秒后再次执行...")
  498. else:
  499. logger.warning(f"⚠️ 操作执行失败,{self.interval}秒后重试...")
  500. time.sleep(self.interval)
  501. except KeyboardInterrupt:
  502. raise
  503. except Exception as e:
  504. logger.error(f"执行过程中出错: {e}")
  505. logger.info(f"⏳ {self.interval}秒后重试...")
  506. time.sleep(self.interval)
  507. except KeyboardInterrupt:
  508. logger.info("\n" + "=" * 60)
  509. logger.info("⛔ 用户停止了Cursor自动聊天工具")
  510. logger.info("=" * 60)
  511. def main():
  512. """主函数"""
  513. parser = argparse.ArgumentParser(
  514. description='Cursor自动聊天工具 - 自动向Cursor chat发送消息',
  515. formatter_class=argparse.RawDescriptionHelpFormatter,
  516. epilog="""
  517. 示例:
  518. # 单次执行
  519. python scripts/cursor_auto_chat.py --once
  520. # 守护进程模式(默认)
  521. python scripts/cursor_auto_chat.py --daemon
  522. # 自定义间隔(秒)
  523. python scripts/cursor_auto_chat.py --interval 300
  524. # 自定义消息
  525. python scripts/cursor_auto_chat.py --message "你的消息内容"
  526. # 指定输入框位置
  527. python scripts/cursor_auto_chat.py --input-box-pos "1180,965"
  528. """
  529. )
  530. parser.add_argument(
  531. '--once',
  532. action='store_true',
  533. help='只执行一次,不持续运行'
  534. )
  535. parser.add_argument(
  536. '--daemon',
  537. action='store_true',
  538. help='作为守护进程运行(默认模式)'
  539. )
  540. parser.add_argument(
  541. '--interval',
  542. type=int,
  543. default=300,
  544. help='执行间隔(秒),默认300秒(5分钟)'
  545. )
  546. parser.add_argument(
  547. '--message',
  548. type=str,
  549. default='请检查并执行所有待处理任务。',
  550. help='要发送的消息内容,默认: "请检查并执行所有待处理任务。"'
  551. )
  552. parser.add_argument(
  553. '--input-box-pos',
  554. type=str,
  555. default=None,
  556. help='输入框位置,格式: "x,y" (例如: "1180,965"),如果提供则直接使用该位置,不进行自动定位'
  557. )
  558. args = parser.parse_args()
  559. # 解析输入框位置(如果提供)
  560. input_box_pos = None
  561. if args.input_box_pos:
  562. try:
  563. parts = args.input_box_pos.split(',')
  564. if len(parts) == 2:
  565. input_box_pos = (int(parts[0].strip()), int(parts[1].strip()))
  566. logger.info(f"解析输入框位置: {input_box_pos}")
  567. else:
  568. logger.warning(f"输入框位置格式错误,应使用 'x,y' 格式: {args.input_box_pos}")
  569. except ValueError as e:
  570. logger.warning(f"无法解析输入框位置: {e}")
  571. # 创建工具实例
  572. tool = CursorAutoChat(message=args.message, interval=args.interval, input_box_pos=input_box_pos)
  573. # 根据参数运行
  574. if args.once:
  575. tool.execute_once()
  576. else:
  577. tool.run_daemon()
  578. if __name__ == '__main__':
  579. main()