computer-use-ootb-internal 0.0.96__py3-none-any.whl → 0.0.96.post1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -104,8 +104,8 @@ async def update_parameters(request: Request):
104
104
  shared_state.model = getattr(shared_state.args, 'model', "teach-mode-gpt-4o")
105
105
  shared_state.task = getattr(shared_state.args, 'task', "Create a claim on the SAP system, using Receipt.pdf as attachment.")
106
106
  shared_state.selected_screen = getattr(shared_state.args, 'selected_screen', 0)
107
- shared_state.user_id = getattr(shared_state.args, 'user_id', "a_test")
108
- shared_state.trace_id = getattr(shared_state.args, 'trace_id', "jess_4")
107
+ shared_state.user_id = getattr(shared_state.args, 'user_id', "hero_cases")
108
+ shared_state.trace_id = getattr(shared_state.args, 'trace_id', "build_scroll_combat")
109
109
  shared_state.api_keys = getattr(shared_state.args, 'api_keys', "sk-proj-1234567890")
110
110
  shared_state.server_url = getattr(shared_state.args, 'server_url', "http://ec2-44-234-43-86.us-west-2.compute.amazonaws.com")
111
111
 
@@ -6,7 +6,7 @@ show_click(x, y, duration_ms=800)
6
6
  """
7
7
  import sys, time
8
8
  from pathlib import Path
9
- from PySide6.QtCore import Qt, QPoint, QTimer, QEventLoop, QSize
9
+ from PySide6.QtCore import Qt, QPoint, QTimer, QEventLoop, QSize, QEasingCurve, QPropertyAnimation
10
10
  from PySide6.QtGui import QPainter, QPixmap, QMovie
11
11
  from PySide6.QtWidgets import QApplication, QWidget, QLabel
12
12
 
@@ -72,8 +72,17 @@ def _ensure_app():
72
72
  print("Using existing QApplication instance")
73
73
  _app = QApplication.instance()
74
74
 
75
- def show_click(x: int, y: int, duration_ms: int = 2000): # 增加默认播放时间
76
- """阻塞式点击动画:调用后必定肉眼可见"""
75
+ # Keep references to animations to prevent garbage collection
76
+ _active_animations = []
77
+
78
+ def show_click(x: int, y: int, duration_ms: int = 2000, existing_ms: int = 1000): # 增加默认播放时间和静止时间
79
+ """非阻塞式点击动画:立即返回,动画在后台运行
80
+
81
+ Args:
82
+ x, y : 屏幕坐标
83
+ duration_ms : 动画播放时长
84
+ existing_ms : 动画结束后静止显示的时间
85
+ """
77
86
  print(f"Attempting to show click at ({x}, {y})")
78
87
 
79
88
  if not CLICK_GIF.exists():
@@ -82,45 +91,56 @@ def show_click(x: int, y: int, duration_ms: int = 2000): # 增加默认播放
82
91
  _ensure_app()
83
92
 
84
93
  try:
85
- animation = ClickAnimation(QPoint(x, y), duration_ms)
86
-
87
- # 局部事件循环,动画结束后返回
88
- loop = QEventLoop()
89
- QTimer.singleShot(duration_ms + 150, loop.quit) # 增加等待时间
90
- loop.exec()
91
- print("Click animation completed")
94
+ # 总生存时间 = 动画时间 + 静止显示时间
95
+ total_life_ms = duration_ms + existing_ms
96
+ animation = ClickAnimation(QPoint(x, y), total_life_ms)
97
+
98
+ # Store reference to prevent garbage collection
99
+ global _active_animations
100
+ _active_animations.append(animation)
101
+
102
+ # Set up cleanup after animation completes + existing time
103
+ QTimer.singleShot(total_life_ms + 150, lambda: _clean_animation(animation))
104
+
105
+ print(f"Click animation started (non-blocking, will exist for {total_life_ms}ms)")
92
106
  except Exception as e:
93
107
  print(f"Error during show_click: {str(e)}")
94
108
 
95
109
 
96
- # --- 在原 import 区域追加 ---
97
- from PySide6.QtCore import QEasingCurve, QPropertyAnimation
98
- # --------------------------------------------------------
110
+ def _clean_animation(animation):
111
+ """Remove animation from reference list after it completes"""
112
+ global _active_animations
113
+ if animation in _active_animations:
114
+ _active_animations.remove(animation)
115
+ print("Animation cleaned up")
99
116
 
100
117
 
101
118
  # ---------- 新增函数 ----------
102
- def show_move_to(x1: int, y1: int, x2: int, y2: int, duration_ms: int = 1200):
119
+ def show_move_to(x1: int, y1: int, x2: int, y2: int, duration_ms: int = 1000, existing_ms: int = 1000):
103
120
  """
104
- 阻塞式移动动画:在 (x1, y1) 处出现光标 GIF,
105
- 并在 duration_ms 毫秒内平滑移动到 (x2, y2)
121
+ 非阻塞式移动动画:在 (x1, y1) 处出现光标 GIF,
122
+ 并在 duration_ms 毫秒内平滑移动到 (x2, y2)
123
+ 然后在终点静止显示 existing_ms 毫秒。
124
+ 立即返回,动画在后台运行。
106
125
 
107
126
  Args:
108
127
  x1, y1 : 起点屏幕坐标
109
128
  x2, y2 : 终点屏幕坐标
110
129
  duration_ms : 移动总时长
130
+ existing_ms : 移动结束后在终点静止显示的时间
111
131
  """
112
132
  print(f"Attempting to move click from ({x1}, {y1}) → ({x2}, {y2}) "
113
- f"in {duration_ms} ms")
133
+ f"in {duration_ms} ms, then stay for {existing_ms} ms")
114
134
 
115
135
  if not CLICK_GIF.exists():
116
136
  raise FileNotFoundError(f"click.gif not found at {CLICK_GIF}")
117
137
 
118
138
  _ensure_app()
119
139
 
120
- # widget 的生命周期略长于动画,避免提前销毁
121
- life_ms = duration_ms + 200
122
- widget = ClickAnimation(QPoint(x1, y1), life_ms)
123
-
140
+ # 总生存时间 = 动画时间 + 静止显示时间
141
+ total_life_ms = duration_ms + existing_ms
142
+ widget = ClickAnimation(QPoint(x1, y1), total_life_ms)
143
+
124
144
  # 用 QPropertyAnimation 平滑移动窗口
125
145
  anim = QPropertyAnimation(widget, b"pos")
126
146
  anim.setDuration(duration_ms)
@@ -128,27 +148,67 @@ def show_move_to(x1: int, y1: int, x2: int, y2: int, duration_ms: int = 1200):
128
148
  anim.setStartValue(QPoint(x1 - 15, y1 - 15))
129
149
  anim.setEndValue(QPoint(x2 - 15, y2 - 15))
130
150
  anim.setEasingCurve(QEasingCurve.OutQuad) # 可自行更换缓动曲线
151
+
152
+ # Store references to both widget and animation to prevent garbage collection
153
+ global _active_animations
154
+ # Store them as a tuple to keep both references
155
+ animation_pair = (widget, anim)
156
+ _active_animations.append(animation_pair)
157
+
158
+ # Clean up both widget and animation after completion of total life time
159
+ def cleanup():
160
+ if animation_pair in _active_animations:
161
+ _active_animations.remove(animation_pair)
162
+ print("Move animation cleaned up")
163
+
164
+ # Connect finished signal only to print a message
165
+ anim.finished.connect(lambda: print("Movement finished, now staying still"))
166
+
167
+ # Start the animation
131
168
  anim.start()
132
-
133
- # 局部事件循环,直到动画结束
134
- loop = QEventLoop()
135
- anim.finished.connect(loop.quit)
136
- QTimer.singleShot(life_ms, loop.quit) # 双保险
137
- loop.exec()
138
-
139
- print("Moveto animation completed")
140
- # ---------------------------------
169
+
170
+ # Process events immediately to kickstart the animation
171
+ QApplication.processEvents()
172
+
173
+ # Set up final cleanup after animation + existing time
174
+ QTimer.singleShot(total_life_ms, cleanup)
175
+
176
+ print("Move-to animation started (non-blocking)")
141
177
 
142
178
 
143
179
  # ---------- 命令行测试 ----------
144
180
  if __name__ == "__main__":
181
+ # 确保应用程序实例存在
182
+ # _ensure_app()
183
+
145
184
  # 测试点击
185
+ print("Testing non-blocking click animation...")
146
186
  x, y = 500, 500
147
- print(f"Testing click at ({x}, {y})")
148
187
  show_click(x, y)
149
-
150
- # 测试移动
151
- x1, y1 = 400, 400
152
- x2, y2 = 800, 600
153
- print(f"Testing move from ({x1}, {y1}) ({x2}, {y2})")
154
- show_move_to(x1, y1, x2, y2, duration_ms=2000)
188
+
189
+ # 测试同时运行两个动画
190
+ print("\nTesting simultaneous animations...")
191
+ x1, y1 = 200, 200
192
+ x2, y2 = 600, 600
193
+ # show_click(x1, y1)
194
+ show_move_to(x1, y1, x2, y2)
195
+
196
+ # # 测试先移动,然后点击
197
+ print("\nTesting sequence with pyautogui simulation...")
198
+ x3, y3 = 800, 300
199
+ x4, y4 = 400, 500
200
+
201
+ # 启动移动动画
202
+ show_move_to(x3, y3, x4, y4)
203
+
204
+ # 模拟移动完成后的点击动画(延迟1.5秒)
205
+ QTimer.singleShot(1500, lambda: show_click(x4, y4))
206
+
207
+ # 保持主程序运行,等待所有动画完成
208
+ print("\nWaiting for all animations to complete...")
209
+ loop = QEventLoop()
210
+ # 等待足够长的时间,确保所有动画都完成(最长的动画是2000ms + 清理时间)
211
+ QTimer.singleShot(4000, loop.quit)
212
+ loop.exec()
213
+
214
+ print("All animations completed, exiting test.")
@@ -2,18 +2,12 @@ import ast
2
2
  import json
3
3
  import asyncio
4
4
  from typing import Any, Dict, cast, List, Union
5
- from collections.abc import Callable
6
5
  import uuid
7
6
  from anthropic.types.beta import (
8
- BetaContentBlock,
9
- BetaContentBlockParam,
10
7
  BetaImageBlockParam,
11
- BetaMessage,
12
- BetaMessageParam,
13
8
  BetaTextBlockParam,
14
9
  BetaToolResultBlockParam,
15
10
  )
16
- from anthropic.types import TextBlock
17
11
  from anthropic.types.beta import BetaMessage, BetaTextBlock, BetaToolUseBlock
18
12
  from computer_use_ootb_internal.computer_use_demo.tools import BashTool, ComputerTool, EditTool, ToolCollection, ToolResult
19
13
 
@@ -221,9 +215,13 @@ class TeachmodeExecutor:
221
215
 
222
216
  def _add_starrail_alt_actions(self, action_list: list[Dict[str, Any]]) -> list[Dict[str, Any]]:
223
217
  parsed_action_list = []
224
- parsed_action_list.extend([{"action": "key_down", "text": "alt", "coordinate": None}])
225
- parsed_action_list.extend(action_list)
226
- parsed_action_list.extend([{"action": "key_up", "text": "alt", "coordinate": None}])
218
+ for action in action_list:
219
+ if action["action"] in ["left_click", "mouse_move"]:
220
+ parsed_action_list.append({"action": "key_down", "text": "alt", "coordinate": None})
221
+ parsed_action_list.append(action)
222
+ parsed_action_list.append({"action": "key_up", "text": "alt", "coordinate": None})
223
+ else:
224
+ parsed_action_list.append(action)
227
225
  return parsed_action_list
228
226
 
229
227
  def _reformat_starrail_browser_actions(self, action_list: list[Dict[str, Any]]) -> list[Dict[str, Any]]:
@@ -242,9 +240,18 @@ class TeachmodeExecutor:
242
240
 
243
241
  def _add_starrail_browser_alt_actions(self, action_list: list[Dict[str, Any]]) -> list[Dict[str, Any]]:
244
242
  parsed_action_list = []
245
- parsed_action_list.extend([{"action": "key_down_windll", "text": "alt", "coordinate": None}])
246
- parsed_action_list.extend(action_list)
247
- parsed_action_list.extend([{"action": "key_up_windll", "text": "alt", "coordinate": None}])
243
+
244
+ for action in action_list:
245
+ if action["action"] in ["left_click", "mouse_move", "left_click_windll", "mouse_move_windll"]:
246
+ parsed_action_list.append({"action": "key_down_windll", "text": "alt", "coordinate": None})
247
+ parsed_action_list.append(action)
248
+ parsed_action_list.append({"action": "key_up_windll", "text": "alt", "coordinate": None})
249
+ else:
250
+ parsed_action_list.append(action)
251
+
252
+ # parsed_action_list.extend([{"action": "key_down_windll", "text": "alt", "coordinate": None}])
253
+ # parsed_action_list.extend(action_list)
254
+ # parsed_action_list.extend([{"action": "key_up_windll", "text": "alt", "coordinate": None}])
248
255
  return parsed_action_list
249
256
 
250
257
 
@@ -296,23 +296,36 @@ class ComputerTool(BaseAnthropicTool):
296
296
  raise ToolError(f"coordinate is not accepted for {action}")
297
297
 
298
298
  if action == "left_click":
299
+ x, y = pyautogui.position()
300
+ show_click(x, y)
299
301
  pyautogui.click()
300
302
  elif action == "right_click":
303
+ x, y = pyautogui.position()
304
+ show_click(x, y)
301
305
  pyautogui.rightClick()
302
306
  elif action == "middle_click":
307
+ x, y = pyautogui.position()
308
+ show_click(x, y)
303
309
  pyautogui.middleClick()
304
310
  elif action == "double_click":
311
+ x, y = pyautogui.position()
312
+ show_click(x, y)
305
313
  pyautogui.doubleClick()
306
314
  elif action == "left_press":
315
+ x, y = pyautogui.position()
316
+ show_click(x, y)
307
317
  pyautogui.mouseDown()
308
318
  time.sleep(1)
309
319
  pyautogui.mouseUp()
320
+ show_click(x, y)
310
321
  elif action == "scroll_down":
311
322
  pyautogui.scroll(-200) # Adjust scroll amount as needed
312
323
  return ToolResult(output="Scrolled down")
324
+
313
325
  elif action == "scroll_up":
314
326
  pyautogui.scroll(200) # Adjust scroll amount as needed
315
327
  return ToolResult(output="Scrolled up")
328
+
316
329
  elif action == "wait":
317
330
  time.sleep(30)
318
331
  return ToolResult(output="Waited")
@@ -355,14 +368,13 @@ class ComputerTool(BaseAnthropicTool):
355
368
  if action == "left_click_windll":
356
369
  if coordinate is None:
357
370
  x, y = pyautogui.position()
358
- # x, y = self.scale_coordinates(ScalingSource.COMPUTER, x, y)
359
371
  show_click(x, y)
360
372
  self.marbot_auto_gui.click()
361
373
  else:
362
374
  x = coordinate[0]+self.offset_x
363
375
  y = coordinate[1]+self.offset_y
364
- self.marbot_auto_gui.click(x=x, y=y)
365
376
  show_click(x, y)
377
+ self.marbot_auto_gui.click(x=x, y=y)
366
378
  elif action == "mouse_move_windll":
367
379
  if coordinate is None:
368
380
  raise ToolError(f"coordinate is required for {action}")
@@ -371,8 +383,8 @@ class ComputerTool(BaseAnthropicTool):
371
383
  x1 = coordinate[0]+self.offset_x
372
384
  y1 = coordinate[1]+self.offset_y
373
385
 
386
+ show_move_to(x0, y0, x1, y1, duration_ms=1000)
374
387
  self.marbot_auto_gui.moveTo(x=x1, y=y1)
375
- show_move_to(x0, y0, x1, y1, duration_ms=2000)
376
388
 
377
389
  # elif action == "right_click_windll":
378
390
  # self.marbot_auto_gui.rightClick(x=coordinate[0], y=coordinate[1])
@@ -41,7 +41,7 @@ def simple_teachmode_sampling_loop(
41
41
  if "star_rail" in user_id or "star_rail" in user_id:
42
42
  full_screen_game_mode = 1
43
43
 
44
- if "star_rail_dev" in trace_id or "star_rail_dev" in user_id:
44
+ if "star_rail_dev" in trace_id or "star_rail_dev" in user_id or "hero_case" in trace_id:
45
45
  full_screen_game_mode = 2
46
46
 
47
47
  print(f"Full Screen Game Mode: {full_screen_game_mode}")
@@ -102,7 +102,7 @@ def simple_teachmode_sampling_loop(
102
102
 
103
103
  try:
104
104
  step_plan = infer_server_response["generated_plan"]
105
- # step_action = json.loads(infer_server_response["generated_action"]["content"])
105
+ step_info = infer_server_response["generated_action"]["step_info"]
106
106
  step_action = infer_server_response["generated_action"]["content"]
107
107
  step_traj_idx = infer_server_response["current_traj_step"]
108
108
 
@@ -115,7 +115,8 @@ def simple_teachmode_sampling_loop(
115
115
  break
116
116
 
117
117
  # action_history.append(f"Executing Step: {step_count} - Trajectory Step: {step_traj_idx} - Plan: {step_plan} - Action: {step_action};\n")
118
- action_history.append(f"Step in Guidance Trajectory: [{step_traj_idx}], Plan: {step_plan}, Action: {step_action};\n")
118
+
119
+ action_history.append(f"Executing guidance trajectory step [{step_traj_idx}], Plan: {step_info}, Action: {step_action};\n")
119
120
 
120
121
  for message in executor({"role": "assistant", "content": step_action}):
121
122
  yield message
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: computer-use-ootb-internal
3
- Version: 0.0.96
3
+ Version: 0.0.96.post1
4
4
  Summary: Computer Use OOTB
5
5
  Author-email: Siyuan Hu <siyuan.hu.sg@gmail.com>
6
6
  Requires-Python: >=3.11
@@ -1,15 +1,12 @@
1
1
  computer_use_ootb_internal/README.md,sha256=FxpW95lyub2iX73ZDfK6ML7SdEKg060H5I6Grub7li4,31
2
- computer_use_ootb_internal/app_teachmode.py,sha256=9p4a7vRNwJOJI_gkiPVeF4ALqyLuBdcFsEEFQ-rmEbg,15629
2
+ computer_use_ootb_internal/app_teachmode.py,sha256=zmUPvFjqdhysnN1bD2QQhaAKONnAtMFd03Rb9gF1l6c,15646
3
3
  computer_use_ootb_internal/app_teachmode_gradio.py,sha256=zAw-n3s20j1Jr0S4TzXHwllKV6APJ8HEHB1KqBuzriY,7907
4
4
  computer_use_ootb_internal/dependency_check.py,sha256=y8RMEP6RXQzTgU1MS_1piBLtz4J-Hfn9RjUZg59dyvo,1333
5
- computer_use_ootb_internal/example_websocket_js.html,sha256=BLYwDExVlgiAX4vXVXW3RuP5KD8FXE4EFXIl54bwF7w,1322
6
5
  computer_use_ootb_internal/requirements-lite.txt,sha256=5DAHomz4A_P2BmTIXNkNqkHbnIF0AyZ4_1XAlb1LaYs,290
7
- computer_use_ootb_internal/run_teachmode_ootb_args.py,sha256=IN20EC5gCJZpaBQyVu5PMBk2aPBPEYIL0meTnYQrpS8,6825
8
- computer_use_ootb_internal/service_teachmode.py,sha256=e81zp3B7CA2nMjA-3qoKF4P1hlNGRI7P1tBo1j21FBk,8082
9
- computer_use_ootb_internal/service_teachmode_test.py,sha256=zpfBFFKD9WGLX4m77ajOBfmczpYsCa3_qTBweeSNRV8,1112
10
- computer_use_ootb_internal/computer_use_demo/animation/click_animation.py,sha256=ZKmlZnMVW4zdxkUVWCTQF2rqq2h70qq5bAuLYVa4qxc,5312
6
+ computer_use_ootb_internal/run_teachmode_ootb_args.py,sha256=djr4E7_G_qG9H6qmRz1mrM9Yrcxf1tnlSPH5ZqykF5Y,6845
7
+ computer_use_ootb_internal/computer_use_demo/animation/click_animation.py,sha256=BsHW1yFLHE5DqLUofnR-D3jnglLcYCaVN34jquWvh94,7725
11
8
  computer_use_ootb_internal/computer_use_demo/animation/icons8-select-cursor-transparent-96.gif,sha256=4LfwsfFQnREXrNRs32aJU2jO65JXianJoL_8q7-8elg,30966
12
- computer_use_ootb_internal/computer_use_demo/executor/teachmode_executor.py,sha256=x6XwhrmSnD0_euotx0X0fFyak2o9khttV4XwaGpzV3E,16121
9
+ computer_use_ootb_internal/computer_use_demo/executor/teachmode_executor.py,sha256=y7lg_PjMif2WwCKWWC7g8Ys2zPRMh08Vtt42fStujY4,16623
13
10
  computer_use_ootb_internal/computer_use_demo/gui_agent/gui_parser/simple_parser/__init__.py,sha256=h2CNeuACklxVpJC65QR8_6AvSybEZLmeO45hY_-lLBs,61
14
11
  computer_use_ootb_internal/computer_use_demo/gui_agent/gui_parser/simple_parser/gui_capture.py,sha256=CxFJbsSb68ERKH7-C4RaaZy7FIhhzrzGx5qQJ4C37cA,13907
15
12
  computer_use_ootb_internal/computer_use_demo/gui_agent/gui_parser/simple_parser/gui_parser.py,sha256=KSTJ0cMwh3ahUMzHRaDgA2sVNUL4MNlF7qEBGN3G0SI,28993
@@ -33,12 +30,12 @@ computer_use_ootb_internal/computer_use_demo/tools/base.py,sha256=QDqpuuKlhUKJT2
33
30
  computer_use_ootb_internal/computer_use_demo/tools/bash.py,sha256=rHetQ80_v-TTi-1oxIA7ncFEwJxFTh8FJCErIoZbGeY,4236
34
31
  computer_use_ootb_internal/computer_use_demo/tools/collection.py,sha256=8RzHLobL44_Jjt8ltXS6I8XJlEAQOfc75dmnDUaHE-8,922
35
32
  computer_use_ootb_internal/computer_use_demo/tools/colorful_text.py,sha256=cvlmnhAImDTwoRRwhT5au7mNFhfAD7ZfeoDEVdVzDKw,892
36
- computer_use_ootb_internal/computer_use_demo/tools/computer.py,sha256=eXH6-h9YEo-1sSkQNG6Ld43aDm0Ip-ioYNyF1Q60Jd0,25164
33
+ computer_use_ootb_internal/computer_use_demo/tools/computer.py,sha256=bKOkCtE4iYmPpRxldslAAa5yQOs6NkhITJYCfZllWXI,25526
37
34
  computer_use_ootb_internal/computer_use_demo/tools/computer_marbot.py,sha256=zZuWz9ArfP3Zss-afnscrPkgCtB5UWbCy7HwAOvO2bo,5970
38
35
  computer_use_ootb_internal/computer_use_demo/tools/edit.py,sha256=b0PwUitxckHCQqFP3ZwlthWdqNkn7WETeTHeB6-o98c,11486
39
36
  computer_use_ootb_internal/computer_use_demo/tools/run.py,sha256=xhXdnBK1di9muaO44CEirL9hpGy3NmKbjfMpyeVmn8Y,1595
40
37
  computer_use_ootb_internal/computer_use_demo/tools/screen_capture.py,sha256=L8qfvtUkPPQGt92N-2Zfw5ZTDBzLsDps39uMnX3_uSA,6857
41
- computer_use_ootb_internal-0.0.96.dist-info/METADATA,sha256=MY4ASXzlq1JoyiE_JWcQHytdoNWxSv0eXUSx8ap3haY,909
42
- computer_use_ootb_internal-0.0.96.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
43
- computer_use_ootb_internal-0.0.96.dist-info/entry_points.txt,sha256=-AbmawU7IRQuDZihgVMVDrFoY4E6rnXYOUB-5vSeBKs,93
44
- computer_use_ootb_internal-0.0.96.dist-info/RECORD,,
38
+ computer_use_ootb_internal-0.0.96.post1.dist-info/METADATA,sha256=45BKygjaYFw3snR8rr1qk9pH9cVJYmjZP9T5O5PSjAo,915
39
+ computer_use_ootb_internal-0.0.96.post1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
40
+ computer_use_ootb_internal-0.0.96.post1.dist-info/entry_points.txt,sha256=-AbmawU7IRQuDZihgVMVDrFoY4E6rnXYOUB-5vSeBKs,93
41
+ computer_use_ootb_internal-0.0.96.post1.dist-info/RECORD,,
@@ -1,41 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <title>Teachmode Client</title>
5
- <!-- include socket.io client -->
6
- <script src="https://cdn.socket.io/4.5.4/socket.io.min.js"></script>
7
- </head>
8
- <body>
9
- <h1>Teachmode WebSocket Test</h1>
10
- <div id="messages"></div>
11
-
12
- <script>
13
- const socket = io("http://localhost:5000"); // Your server’s URL/port
14
-
15
- // Listen for partial responses
16
- socket.on("partial_response", (data) => {
17
- console.log("Got partial:", data);
18
- const div = document.createElement("div");
19
- div.innerText = "Assistant: " + data.content;
20
- document.getElementById("messages").appendChild(div);
21
- });
22
-
23
- // Listen for done event
24
- socket.on("done", (data) => {
25
- console.log("Task completed:", data);
26
- const div = document.createElement("div");
27
- div.innerText = "TASK DONE!";
28
- document.getElementById("messages").appendChild(div);
29
- });
30
-
31
- // When connected, emit run_teachmode
32
- socket.on("connect", () => {
33
- console.log("Connected to server. Emitting run_teachmode event...");
34
- socket.emit("run_teachmode", {
35
- user_input: "Hello, I'd like to do X, Y, Z."
36
- // you can include model, task, user_id, trace_id, etc. if desired
37
- });
38
- });
39
- </script>
40
- </body>
41
- </html>
@@ -1,194 +0,0 @@
1
- import argparse
2
- import time
3
- import json
4
- import threading
5
-
6
- from flask import Flask, request, jsonify
7
- from flask_socketio import SocketIO, emit
8
-
9
- from screeninfo import get_monitors
10
- from computer_use_ootb_internal.computer_use_demo.tools.computer import get_screen_details
11
- from computer_use_ootb_internal.run_teachmode_ootb_args import simple_teachmode_sampling_loop
12
-
13
- ###############################################################################
14
- # Shared State
15
- ###############################################################################
16
- class SharedState:
17
- def __init__(self):
18
- self.args = None # Will hold argparse-like namespace
19
- self.messages = [] # If you want to store a global chat or last session
20
-
21
- shared_state = SharedState()
22
-
23
- ###############################################################################
24
- # Flask + SocketIO Application Setup
25
- ###############################################################################
26
- app = Flask(__name__)
27
- app.config["SECRET_KEY"] = "some-secret-key" # In production, change this
28
- socketio = SocketIO(app, cors_allowed_origins="*")
29
-
30
- ###############################################################################
31
- # Utility Functions
32
- ###############################################################################
33
- def setup_default_args():
34
- """
35
- Creates argparse-like defaults.
36
- You can also parse real CLI args if you wish.
37
- """
38
- parser = argparse.ArgumentParser(description="Teachmode SocketIO Server.")
39
- parser.add_argument("--model", default="teach-mode-gpt-4o")
40
- parser.add_argument("--task", default="Help me complete data extraction on YouTube video.")
41
- parser.add_argument("--selected_screen", type=int, default=0)
42
- parser.add_argument("--user_id", default="liziqi")
43
- parser.add_argument("--trace_id", default="default_trace")
44
- parser.add_argument("--api_key_file", default="api_key.json")
45
- parser.add_argument("--api_keys", default="")
46
- parser.add_argument(
47
- "--server_url",
48
- default="http://ec2-44-234-43-86.us-west-2.compute.amazonaws.com/generate_action",
49
- help="Server URL for the session (local='http://localhost:5000/generate_action', \
50
- aws='http://ec2-44-234-43-86.us-west-2.compute.amazonaws.com/generate_action').",
51
- )
52
-
53
- # If you really want to parse sys.argv, do parser.parse_args().
54
- # But you can also return the defaults for this example:
55
- return parser.parse_args([])
56
-
57
- def apply_args_to_state(args):
58
- """
59
- Helper that prints or logs relevant arguments and stores them in shared_state.
60
- """
61
- print("[apply_args_to_state] Applying arguments:", args)
62
- shared_state.args = args
63
-
64
- def run_teachmode_task(user_input):
65
- """
66
- Calls simple_teachmode_sampling_loop and emits partial responses over SocketIO.
67
- """
68
- # 1) Log or store user input
69
- print(f"[run_teachmode_task] Received user_input: {user_input}")
70
- # Optionally store or reset message history for this session
71
- shared_state.messages = [{"role": "user", "content": user_input}]
72
-
73
- # 2) Grab arguments from shared_state
74
- args = shared_state.args
75
- if not args:
76
- print("[run_teachmode_task] No arguments in shared_state, applying defaults.")
77
- args = setup_default_args()
78
- apply_args_to_state(args)
79
-
80
- # 3) Run the sampling loop
81
- print(f"[run_teachmode_task] Starting the sampling loop with task: {args.task}")
82
- sampling_loop = simple_teachmode_sampling_loop(
83
- model=args.model,
84
- task=args.task,
85
- selected_screen=args.selected_screen,
86
- user_id=args.user_id,
87
- trace_id=args.trace_id,
88
- api_keys=args.api_keys,
89
- server_url=args.server_url
90
- )
91
-
92
- # 4) Send partial responses
93
- for loop_msg in sampling_loop:
94
- print(f"[run_teachmode_task] Emitting partial response: {loop_msg}")
95
- # You can store it in shared_state messages
96
- shared_state.messages.append({"role": "assistant", "content": loop_msg})
97
- # Emit immediately so the client sees partial responses
98
- emit("partial_response", {"role": "assistant", "content": loop_msg})
99
- time.sleep(1) # Optional delay to simulate real-time streaming
100
-
101
- # 5) Done event
102
- print("[run_teachmode_task] Completed all messages.")
103
- emit("done", {"messages": shared_state.messages, "status": "completed"})
104
-
105
- ###############################################################################
106
- # HTTP Endpoint: update_params
107
- ###############################################################################
108
- @app.route("/update_params", methods=["POST"])
109
- def update_parameters():
110
- """
111
- HTTP endpoint that allows updating the parameters (like Gradio's /update_params).
112
- Expects JSON body with fields matching the argparse Namespace (model, task, etc.)
113
- """
114
- data = request.json
115
- if not data:
116
- return jsonify({"status": "error", "message": "No JSON provided."}), 400
117
-
118
- # Build an argparse.Namespace from the JSON keys
119
- # Fallback to the existing arguments if some keys are missing
120
- old_args = shared_state.args or setup_default_args()
121
- new_args_dict = {**vars(old_args), **data} # Merge old with new
122
- new_args = argparse.Namespace(**new_args_dict)
123
- apply_args_to_state(new_args)
124
-
125
- return jsonify({
126
- "status": "success",
127
- "message": "Parameters updated",
128
- "new_args": vars(new_args)
129
- })
130
-
131
- ###############################################################################
132
- # HTTP Endpoint: get_messages
133
- ###############################################################################
134
- @app.route("/get_messages", methods=["GET"])
135
- def get_messages():
136
- """
137
- Example new function: returns the current chat messages in shared_state.
138
- """
139
- return jsonify(shared_state.messages)
140
-
141
- ###############################################################################
142
- # HTTP Endpoint: clear_messages
143
- ###############################################################################
144
- @app.route("/clear_messages", methods=["POST"])
145
- def clear_messages():
146
- """
147
- Example new function: clears the stored chat messages in shared_state.
148
- """
149
- shared_state.messages = []
150
- return jsonify({"status": "success", "message": "Chat history cleared."})
151
-
152
- ###############################################################################
153
- # SocketIO Event: run_teachmode
154
- ###############################################################################
155
- @socketio.on("run_teachmode")
156
- def handle_run_teachmode(data):
157
- """
158
- Websocket event that starts the teachmode sampling loop.
159
- `data` can include e.g. {"user_input": "..."}.
160
- """
161
- user_input = data.get("user_input", "Hello, let's start!")
162
- run_teachmode_task(user_input)
163
-
164
- ###############################################################################
165
- # SocketIO Event: connect
166
- ###############################################################################
167
- @socketio.on("connect")
168
- def on_connect():
169
- print("[SocketIO] Client connected.")
170
-
171
- @socketio.on("disconnect")
172
- def on_disconnect():
173
- print("[SocketIO] Client disconnected.")
174
-
175
- ###############################################################################
176
- # Main
177
- ###############################################################################
178
- def main():
179
- # Pre-populate shared_state with default arguments
180
- args = setup_default_args()
181
- apply_args_to_state(args)
182
-
183
- # Optional: Preload screen info if needed
184
- screens = get_monitors()
185
- print("Detected screens:", screens)
186
- screen_names, primary_index = get_screen_details()
187
- print("Screen names:", screen_names, "Default selected index:", primary_index)
188
-
189
- # Run the Flask-SocketIO app
190
- # eventlet is the default async_mode if installed, but we specify it explicitly.
191
- socketio.run(app, host="0.0.0.0", port=5001, debug=True)
192
-
193
- if __name__ == "__main__":
194
- main()
@@ -1,41 +0,0 @@
1
- import socketio
2
-
3
- # Create a Socket.IO client instance
4
- sio = socketio.Client()
5
-
6
- @sio.on('connect')
7
- def on_connect():
8
- print("Connected to the server.")
9
- # Once connected, send the event to start the teachmode process:
10
- data = {
11
- "user_input": "Hello, I'd like to open the Chrome browser."
12
- # You can add more parameters here if needed, e.g.:
13
- # "model": "teach-mode-gpt-4o",
14
- # "task": "Some task",
15
- # "user_id": "my_user",
16
- # etc.
17
- }
18
- print("Emitting 'run_teachmode' event with data:", data)
19
- sio.emit("run_teachmode", data)
20
-
21
- @sio.on('partial_response')
22
- def on_partial_response(data):
23
- print("[partial_response] =>", data)
24
-
25
- @sio.on('done')
26
- def on_done(data):
27
- print("[done] =>", data)
28
- # Since the process is completed, you can disconnect:
29
- sio.disconnect()
30
-
31
- @sio.on('disconnect')
32
- def on_disconnect():
33
- print("Disconnected from server.")
34
-
35
-
36
- if __name__ == "__main__":
37
- # Connect to the Socket.IO server (adapt host/port as needed):
38
- sio.connect("http://localhost:5001")
39
-
40
- # Keep the client alive to receive events
41
- sio.wait()