computer-use-ootb-internal 0.0.102.post1__py3-none-any.whl → 0.0.103__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.
- computer_use_ootb_internal/app_teachmode.py +0 -101
- computer_use_ootb_internal/computer_use_demo/animation/click_animation.py +57 -190
- computer_use_ootb_internal/computer_use_demo/animation/test_animation.py +40 -0
- computer_use_ootb_internal/computer_use_demo/executor/teachmode_executor.py +0 -3
- computer_use_ootb_internal/computer_use_demo/gui_agent/gui_parser/simple_parser/test_capture.py +7 -7
- computer_use_ootb_internal/computer_use_demo/tools/computer.py +0 -1
- computer_use_ootb_internal/requirements-lite.txt +2 -1
- computer_use_ootb_internal/run_teachmode_ootb_args.py +2 -6
- {computer_use_ootb_internal-0.0.102.post1.dist-info → computer_use_ootb_internal-0.0.103.dist-info}/METADATA +4 -3
- {computer_use_ootb_internal-0.0.102.post1.dist-info → computer_use_ootb_internal-0.0.103.dist-info}/RECORD +12 -14
- computer_use_ootb_internal/example_websocket_js.html +0 -41
- computer_use_ootb_internal/service_teachmode.py +0 -194
- computer_use_ootb_internal/service_teachmode_test.py +0 -41
- {computer_use_ootb_internal-0.0.102.post1.dist-info → computer_use_ootb_internal-0.0.103.dist-info}/WHEEL +0 -0
- {computer_use_ootb_internal-0.0.102.post1.dist-info → computer_use_ootb_internal-0.0.103.dist-info}/entry_points.txt +0 -0
@@ -4,11 +4,6 @@ import json
|
|
4
4
|
from datetime import datetime
|
5
5
|
import threading
|
6
6
|
import requests
|
7
|
-
import platform # Add platform import
|
8
|
-
import subprocess # Add subprocess import
|
9
|
-
import pyautogui # Add pyautogui import
|
10
|
-
import webbrowser # Add webbrowser import
|
11
|
-
import os # Import os for path joining
|
12
7
|
from fastapi import FastAPI, Request
|
13
8
|
from fastapi.responses import JSONResponse
|
14
9
|
from fastapi.middleware.cors import CORSMiddleware
|
@@ -92,99 +87,6 @@ class SharedState:
|
|
92
87
|
shared_state = None
|
93
88
|
rate_limiter = RateLimiter(interval_seconds=2)
|
94
89
|
|
95
|
-
# Add the new prepare_environment function here
|
96
|
-
def prepare_environment(state):
|
97
|
-
"""Prepares the environment before starting the main processing loop, e.g., opening specific apps."""
|
98
|
-
if platform.system() == "Windows":
|
99
|
-
# Assuming Star Rail mode is indicated by user_id containing "star_rail"
|
100
|
-
# You might need to adjust this condition based on the actual logic in run_teachmode_args
|
101
|
-
is_star_rail = "star_rail" in state.user_id.lower() or \
|
102
|
-
"star_rail" in state.trace_id.lower() or \
|
103
|
-
"hero_case" in state.trace_id.lower()
|
104
|
-
|
105
|
-
if is_star_rail:
|
106
|
-
print("Star Rail mode detected on Windows. Opening Edge browser...")
|
107
|
-
url = "https://sr.mihoyo.com/cloud/#/"
|
108
|
-
browser_opened = False
|
109
|
-
try:
|
110
|
-
print(f"Attempting to open {url} using specific Edge paths...")
|
111
|
-
# Common paths for msedge.exe
|
112
|
-
edge_paths = [
|
113
|
-
os.path.join(os.environ.get("ProgramFiles(x86)", "C:\Program Files (x86)"), "Microsoft\Edge\Application\msedge.exe"),
|
114
|
-
os.path.join(os.environ.get("ProgramFiles", "C:\Program Files"), "Microsoft\Edge\Application\msedge.exe")
|
115
|
-
]
|
116
|
-
|
117
|
-
opened_with_subprocess = False
|
118
|
-
for edge_path in edge_paths:
|
119
|
-
if os.path.exists(edge_path):
|
120
|
-
try:
|
121
|
-
print(f"Trying path: {edge_path}")
|
122
|
-
subprocess.Popen([edge_path, url])
|
123
|
-
print(f"Successfully launched Edge with Popen using path: {edge_path}")
|
124
|
-
opened_with_subprocess = True
|
125
|
-
browser_opened = True
|
126
|
-
break # Exit loop once successfully opened
|
127
|
-
except Exception as sub_e:
|
128
|
-
print(f"Failed to launch Edge with Popen using {edge_path}: {sub_e}")
|
129
|
-
else:
|
130
|
-
print(f"Edge path not found: {edge_path}")
|
131
|
-
|
132
|
-
# Fallback to webbrowser.open if subprocess failed
|
133
|
-
if not opened_with_subprocess:
|
134
|
-
print("Subprocess launch failed, falling back to webbrowser.open()...")
|
135
|
-
try:
|
136
|
-
if webbrowser.open(url):
|
137
|
-
print("Successfully opened browser using webbrowser.open() as fallback.")
|
138
|
-
browser_opened = True
|
139
|
-
else:
|
140
|
-
print("webbrowser.open() also failed to indicate success.")
|
141
|
-
except Exception as web_e:
|
142
|
-
print(f"webbrowser.open() fallback failed: {web_e}")
|
143
|
-
|
144
|
-
if not browser_opened:
|
145
|
-
print("ERROR: Failed to open browser using both subprocess and webbrowser.")
|
146
|
-
# Decide if you want to proceed without the browser or raise an error
|
147
|
-
# For now, we'll proceed to the click attempt but it might fail
|
148
|
-
|
149
|
-
# Add pyautogui click after attempting to open the browser
|
150
|
-
print("Proceeding with pyautogui actions...")
|
151
|
-
time.sleep(5) # Wait time for the browser to load
|
152
|
-
|
153
|
-
# Print detected screen size
|
154
|
-
screen_width, screen_height = pyautogui.size()
|
155
|
-
print(f"Detected screen size: {screen_width}x{screen_height}")
|
156
|
-
|
157
|
-
click_x = int(screen_width * (1036 / 1280))
|
158
|
-
click_y = int(screen_height * (500 / 720))
|
159
|
-
print(f"Calculated click coordinates: ({click_x}, {click_y})")
|
160
|
-
|
161
|
-
# Disable failsafe before clicking
|
162
|
-
pyautogui.FAILSAFE = False
|
163
|
-
print("PyAutoGUI failsafe temporarily disabled.")
|
164
|
-
|
165
|
-
print(f"Clicking at coordinates: ({click_x}, {click_y})")
|
166
|
-
pyautogui.click(click_x, click_y)
|
167
|
-
time.sleep(2)
|
168
|
-
pyautogui.click(click_x, click_y)
|
169
|
-
|
170
|
-
# Re-enable failsafe (optional, as script might end anyway)
|
171
|
-
# pyautogui.FAILSAFE = True
|
172
|
-
# print("PyAutoGUI failsafe re-enabled.")
|
173
|
-
|
174
|
-
except FileNotFoundError:
|
175
|
-
# This specific error might occur if edge_path exists but execution fails
|
176
|
-
print("Error: Could not execute the browser command (FileNotFound). Check permissions or path.")
|
177
|
-
except Exception as e:
|
178
|
-
print(f"Error during environment preparation (browser/click): {e}")
|
179
|
-
finally:
|
180
|
-
# Ensure failsafe is re-enabled if an error occurs after disabling it
|
181
|
-
pyautogui.FAILSAFE = True
|
182
|
-
print("PyAutoGUI failsafe re-enabled.")
|
183
|
-
else:
|
184
|
-
# Placeholder for potential preparations on other OS or non-Star Rail modes
|
185
|
-
print("Environment preparation: No specific actions required for this OS/mode.")
|
186
|
-
|
187
|
-
|
188
90
|
@app.post("/update_params")
|
189
91
|
async def update_parameters(request: Request):
|
190
92
|
data = await request.json()
|
@@ -209,9 +111,6 @@ async def update_parameters(request: Request):
|
|
209
111
|
|
210
112
|
log_ootb_request(shared_state.server_url, "update_params", data)
|
211
113
|
|
212
|
-
# Call the preparation function here, after parameters are updated
|
213
|
-
prepare_environment(shared_state)
|
214
|
-
|
215
114
|
return JSONResponse(
|
216
115
|
content={"status": "success", "message": "Parameters updated", "new_args": vars(shared_state.args)},
|
217
116
|
status_code=200
|
@@ -1,214 +1,81 @@
|
|
1
|
-
""
|
2
|
-
|
3
|
-
→ 在屏幕 (x,y) 显示点击动画,停留 duration_ms 毫秒
|
4
|
-
依赖: pyside6
|
5
|
-
确保同目录有 click.gif
|
6
|
-
"""
|
7
|
-
import sys, time
|
1
|
+
# click_anim_async.py ← put this in its own file (important for Windows "spawn")
|
2
|
+
import sys, multiprocessing as mp
|
8
3
|
from pathlib import Path
|
9
|
-
from PySide6.QtCore
|
10
|
-
from PySide6.QtGui
|
4
|
+
from PySide6.QtCore import Qt, QPoint, QTimer, QEasingCurve, QPropertyAnimation, QSize
|
5
|
+
from PySide6.QtGui import QMovie
|
11
6
|
from PySide6.QtWidgets import QApplication, QWidget, QLabel
|
12
7
|
|
13
8
|
CLICK_GIF = Path(__file__).with_name("icons8-select-cursor-transparent-96.gif")
|
14
9
|
|
10
|
+
# ---------------------------- tiny in‑process GUI helpers ----------------------------
|
15
11
|
class ClickAnimation(QWidget):
|
16
|
-
def __init__(self, pos: QPoint, life_ms: int):
|
12
|
+
def __init__(self, pos: QPoint, life_ms: int, size_px: int = 50):
|
17
13
|
super().__init__(None,
|
18
14
|
Qt.FramelessWindowHint | Qt.Tool | Qt.WindowStaysOnTopHint
|
19
15
|
| Qt.WindowTransparentForInput)
|
20
16
|
self.setAttribute(Qt.WA_TranslucentBackground)
|
21
|
-
|
22
|
-
if not CLICK_GIF.exists():
|
23
|
-
print(f"Error: click.gif not found at {CLICK_GIF}")
|
24
|
-
return
|
25
|
-
|
26
|
-
try:
|
27
|
-
# 创建标签显示GIF
|
28
|
-
self.label = QLabel(self)
|
29
|
-
self.movie = QMovie(str(CLICK_GIF))
|
30
|
-
|
31
|
-
# 获取原始尺寸并打印(仅供参考)
|
32
|
-
self.movie.jumpToFrame(0)
|
33
|
-
original_size = self.movie.currentPixmap().size()
|
34
|
-
print(f"GIF original size: {original_size.width()}x{original_size.height()}")
|
35
|
-
|
36
|
-
# 将GIF缩放到30x30像素
|
37
|
-
target_size = QSize(50, 50)
|
38
|
-
self.movie.setScaledSize(target_size)
|
39
|
-
|
40
|
-
# 设置标签尺寸和GIF
|
41
|
-
self.label.setMovie(self.movie)
|
42
|
-
self.label.setFixedSize(target_size)
|
43
|
-
|
44
|
-
# 设置窗口大小和位置
|
45
|
-
self.resize(target_size)
|
46
|
-
self.move(pos.x() - 15, pos.y() - 15) # 居中显示
|
47
|
-
|
48
|
-
# 提高播放性能
|
49
|
-
self.movie.setCacheMode(QMovie.CacheAll)
|
50
|
-
|
51
|
-
# 开始播放动画
|
52
|
-
self.movie.start()
|
53
|
-
|
54
|
-
# 设置定时器关闭窗口
|
55
|
-
QTimer.singleShot(life_ms, self.close)
|
56
|
-
|
57
|
-
self.show()
|
58
|
-
self.raise_()
|
59
|
-
print(f"Click animation created at ({pos.x()}, {pos.y()}), size: 30x30, duration: {life_ms}ms")
|
60
|
-
except Exception as e:
|
61
|
-
print(f"Error creating click animation: {str(e)}")
|
62
17
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
if QApplication.instance() is None:
|
69
|
-
print("Creating new QApplication instance")
|
70
|
-
_app = QApplication(sys.argv)
|
71
|
-
else:
|
72
|
-
print("Using existing QApplication instance")
|
73
|
-
_app = QApplication.instance()
|
18
|
+
self.label = QLabel(self)
|
19
|
+
movie = QMovie(str(CLICK_GIF))
|
20
|
+
movie.setScaledSize(QSize(size_px, size_px))
|
21
|
+
self.label.setMovie(movie)
|
22
|
+
self.label.setFixedSize(size_px, size_px)
|
74
23
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
def show_click(x: int, y: int, duration_ms: int = 2000, existing_ms: int = 2000): # 增加默认播放时间和静止时间
|
79
|
-
"""非阻塞式点击动画:立即返回,动画在后台运行
|
80
|
-
|
81
|
-
Args:
|
82
|
-
x, y : 屏幕坐标
|
83
|
-
duration_ms : 动画播放时长
|
84
|
-
existing_ms : 动画结束后静止显示的时间
|
85
|
-
"""
|
86
|
-
print(f"Attempting to show click at ({x}, {y})")
|
87
|
-
|
88
|
-
if not CLICK_GIF.exists():
|
89
|
-
raise FileNotFoundError(f"click.gif not found at {CLICK_GIF}")
|
90
|
-
|
91
|
-
_ensure_app()
|
92
|
-
|
93
|
-
try:
|
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)")
|
106
|
-
except Exception as e:
|
107
|
-
print(f"Error during show_click: {str(e)}")
|
24
|
+
self.resize(size_px, size_px)
|
25
|
+
self.move(pos.x() - size_px//2, pos.y() - size_px//2)
|
108
26
|
|
27
|
+
movie.setCacheMode(QMovie.CacheAll)
|
28
|
+
movie.start()
|
29
|
+
QTimer.singleShot(life_ms, self.close)
|
30
|
+
self.show()
|
31
|
+
self.raise_()
|
109
32
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
33
|
+
# ------------------------- worker functions that live in a **child** -----------------
|
34
|
+
def _worker_click(x, y, duration_ms, existing_ms):
|
35
|
+
app = QApplication(sys.argv)
|
36
|
+
total = duration_ms + existing_ms
|
37
|
+
widget = ClickAnimation(QPoint(x, y), total) # Store in variable to prevent garbage collection
|
38
|
+
QTimer.singleShot(total + 200, app.quit) # close event‑loop afterwards
|
39
|
+
app.exec()
|
116
40
|
|
41
|
+
def _worker_move(x1, y1, x2, y2, duration_ms, existing_ms):
|
42
|
+
app = QApplication(sys.argv)
|
43
|
+
total = duration_ms + existing_ms
|
44
|
+
widget = ClickAnimation(QPoint(x1, y1), total)
|
117
45
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
立即返回,动画在后台运行。
|
46
|
+
anim = QPropertyAnimation(widget, b"pos")
|
47
|
+
anim.setDuration(duration_ms)
|
48
|
+
anim.setStartValue(widget.pos())
|
49
|
+
anim.setEndValue(QPoint(x2 - widget.width()//2, y2 - widget.height()//2))
|
50
|
+
anim.setEasingCurve(QEasingCurve.OutQuad)
|
51
|
+
anim.start()
|
125
52
|
|
126
|
-
|
127
|
-
|
128
|
-
x2, y2 : 终点屏幕坐标
|
129
|
-
duration_ms : 移动总时长
|
130
|
-
existing_ms : 移动结束后在终点静止显示的时间
|
131
|
-
"""
|
132
|
-
print(f"Attempting to move click from ({x1}, {y1}) → ({x2}, {y2}) "
|
133
|
-
f"in {duration_ms} ms, then stay for {existing_ms} ms")
|
53
|
+
QTimer.singleShot(total + 200, app.quit)
|
54
|
+
app.exec()
|
134
55
|
|
56
|
+
# ------------------------------- public API (non‑blocking) ---------------------------
|
57
|
+
def show_click(x: int, y: int, duration_ms: int = 800, existing_ms: int = 800):
|
135
58
|
if not CLICK_GIF.exists():
|
136
|
-
raise FileNotFoundError(f"
|
59
|
+
raise FileNotFoundError(f"GIF not found at {CLICK_GIF}")
|
60
|
+
mp.get_context("spawn").Process(
|
61
|
+
target=_worker_click,
|
62
|
+
args=(x, y, duration_ms, existing_ms),
|
63
|
+
daemon=False # keep running even if parent exits
|
64
|
+
).start()
|
137
65
|
|
138
|
-
|
66
|
+
def show_move_to(x1: int, y1: int, x2: int, y2: int,
|
67
|
+
duration_ms: int = 1000, existing_ms: int = 800):
|
68
|
+
if not CLICK_GIF.exists():
|
69
|
+
raise FileNotFoundError(f"GIF not found at {CLICK_GIF}")
|
70
|
+
mp.get_context("spawn").Process(
|
71
|
+
target=_worker_move,
|
72
|
+
args=(x1, y1, x2, y2, duration_ms, existing_ms),
|
73
|
+
daemon=False
|
74
|
+
).start()
|
139
75
|
|
140
|
-
# 总生存时间 = 动画时间 + 静止显示时间
|
141
|
-
total_life_ms = duration_ms + existing_ms
|
142
|
-
widget = ClickAnimation(QPoint(x1, y1), total_life_ms)
|
143
|
-
|
144
|
-
# 用 QPropertyAnimation 平滑移动窗口
|
145
|
-
anim = QPropertyAnimation(widget, b"pos")
|
146
|
-
anim.setDuration(duration_ms)
|
147
|
-
# ClickAnimation 内部已经向左上偏移了 15px,这里沿用同样的偏移
|
148
|
-
anim.setStartValue(QPoint(x1 - 15, y1 - 15))
|
149
|
-
anim.setEndValue(QPoint(x2 - 15, y2 - 15))
|
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
|
168
|
-
anim.start()
|
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)")
|
177
76
|
|
178
77
|
|
179
|
-
# ---------- 命令行测试 ----------
|
180
78
|
if __name__ == "__main__":
|
181
|
-
#
|
182
|
-
|
183
|
-
|
184
|
-
# 测试点击
|
185
|
-
print("Testing non-blocking click animation...")
|
186
|
-
x, y = 500, 500
|
187
|
-
show_click(x, y)
|
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, duration_ms=2000)
|
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, duration_ms=1500)
|
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.")
|
79
|
+
# from click_anim_async import show_click
|
80
|
+
show_click(500, 500)
|
81
|
+
show_move_to(300, 300, 600, 600)
|
@@ -0,0 +1,40 @@
|
|
1
|
+
"""
|
2
|
+
Test script to verify cursor animation is working
|
3
|
+
"""
|
4
|
+
import asyncio
|
5
|
+
import sys
|
6
|
+
import time
|
7
|
+
from pathlib import Path
|
8
|
+
from computer_use_ootb_internal.computer_use_demo.tools.computer import ComputerTool
|
9
|
+
|
10
|
+
async def test_animations():
|
11
|
+
|
12
|
+
# Initialize the computer tool
|
13
|
+
computer = ComputerTool()
|
14
|
+
|
15
|
+
# Test mouse move animation
|
16
|
+
print("Testing mouse move animation...")
|
17
|
+
await computer(action="mouse_move_windll", coordinate=(500, 500))
|
18
|
+
print("Waiting 2 seconds...")
|
19
|
+
await asyncio.sleep(2)
|
20
|
+
|
21
|
+
# Test click animation
|
22
|
+
print("Testing click animation...")
|
23
|
+
await computer(action="left_click_windll", coordinate=(700, 300))
|
24
|
+
print("Waiting 2 seconds...")
|
25
|
+
await asyncio.sleep(2)
|
26
|
+
|
27
|
+
# Test another move
|
28
|
+
print("Testing move and click sequence...")
|
29
|
+
await computer(action="mouse_move_windll", coordinate=(300, 300))
|
30
|
+
await asyncio.sleep(1)
|
31
|
+
await computer(action="left_click_windll", coordinate=(300, 300))
|
32
|
+
|
33
|
+
# Wait for animations to complete
|
34
|
+
print("Waiting for animations to complete...")
|
35
|
+
await asyncio.sleep(3)
|
36
|
+
|
37
|
+
print("Test completed")
|
38
|
+
|
39
|
+
if __name__ == "__main__":
|
40
|
+
asyncio.run(test_animations())
|
@@ -249,9 +249,6 @@ class TeachmodeExecutor:
|
|
249
249
|
else:
|
250
250
|
parsed_action_list.append(action)
|
251
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}])
|
255
252
|
return parsed_action_list
|
256
253
|
|
257
254
|
|
computer_use_ootb_internal/computer_use_demo/gui_agent/gui_parser/simple_parser/test_capture.py
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
from PIL import ImageGrab
|
2
|
-
|
3
|
-
bbox=(2560, 366, 2560+1920, 366+1080)
|
4
|
-
|
5
|
-
screenshot = ImageGrab.grab(bbox=bbox, all_screens=True)
|
6
|
-
|
7
|
-
screenshot = screenshot.convert('RGB')
|
1
|
+
from PIL import ImageGrab
|
2
|
+
|
3
|
+
bbox=(2560, 366, 2560+1920, 366+1080)
|
4
|
+
|
5
|
+
screenshot = ImageGrab.grab(bbox=bbox, all_screens=True)
|
6
|
+
|
7
|
+
screenshot = screenshot.convert('RGB')
|
8
8
|
screenshot.save("screenshot.png")
|
@@ -317,7 +317,6 @@ class ComputerTool(BaseAnthropicTool):
|
|
317
317
|
pyautogui.mouseDown()
|
318
318
|
time.sleep(1)
|
319
319
|
pyautogui.mouseUp()
|
320
|
-
show_click(x, y)
|
321
320
|
elif action == "scroll_down":
|
322
321
|
pyautogui.scroll(-200) # Adjust scroll amount as needed
|
323
322
|
return ToolResult(output="Scrolled down")
|
@@ -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 or "hero_case" in
|
44
|
+
if "star_rail_dev" in trace_id or "star_rail_dev" in user_id or "hero_case" in user_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_info = infer_server_response["
|
105
|
+
step_info = infer_server_response["generated_plan"]["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
|
|
@@ -125,8 +125,6 @@ def simple_teachmode_sampling_loop(
|
|
125
125
|
|
126
126
|
|
127
127
|
|
128
|
-
|
129
|
-
|
130
128
|
if __name__ == "__main__":
|
131
129
|
parser = argparse.ArgumentParser(
|
132
130
|
description="Run a synchronous sampling loop for assistant/tool interactions in teach-mode."
|
@@ -138,8 +136,6 @@ if __name__ == "__main__":
|
|
138
136
|
)
|
139
137
|
parser.add_argument(
|
140
138
|
"--task",
|
141
|
-
# default="Help me to complete the extraction of the viewer data of Downald Trump's first video on youtube,\
|
142
|
-
# fill in the excel sheet.",
|
143
139
|
default="Click on the Google Chorme icon",
|
144
140
|
help="The task to be completed by the assistant (e.g., 'Complete some data extraction.').",
|
145
141
|
)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: computer-use-ootb-internal
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.103
|
4
4
|
Summary: Computer Use OOTB
|
5
5
|
Author-email: Siyuan Hu <siyuan.hu.sg@gmail.com>
|
6
6
|
Requires-Python: >=3.11
|
@@ -14,14 +14,15 @@ Requires-Dist: matplotlib
|
|
14
14
|
Requires-Dist: opencv-python
|
15
15
|
Requires-Dist: pre-commit==3.8.0
|
16
16
|
Requires-Dist: pyautogui==0.9.54
|
17
|
+
Requires-Dist: pyside6
|
17
18
|
Requires-Dist: pytest-asyncio==0.23.6
|
18
19
|
Requires-Dist: pytest==8.3.3
|
19
|
-
Requires-Dist: pywinauto
|
20
|
+
Requires-Dist: pywinauto
|
20
21
|
Requires-Dist: ruff==0.6.7
|
21
22
|
Requires-Dist: screeninfo
|
22
23
|
Requires-Dist: streamlit>=1.38.0
|
23
24
|
Requires-Dist: textdistance
|
24
|
-
Requires-Dist: uiautomation
|
25
|
+
Requires-Dist: uiautomation
|
25
26
|
Provides-Extra: dev
|
26
27
|
Requires-Dist: pytest-asyncio>=0.23.6; extra == 'dev'
|
27
28
|
Requires-Dist: pytest>=8.3.3; extra == 'dev'
|
@@ -1,19 +1,17 @@
|
|
1
1
|
computer_use_ootb_internal/README.md,sha256=FxpW95lyub2iX73ZDfK6ML7SdEKg060H5I6Grub7li4,31
|
2
|
-
computer_use_ootb_internal/app_teachmode.py,sha256=
|
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/
|
6
|
-
computer_use_ootb_internal/
|
7
|
-
computer_use_ootb_internal/
|
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=j3v-CrFp61mZiJ4-eT06txkOoguZipbakrQFj2d_mbk,7759
|
5
|
+
computer_use_ootb_internal/requirements-lite.txt,sha256=5DAHomz4A_P2BmTIXNkNqkHbnIF0AyZ4_1XAlb1LaYs,290
|
6
|
+
computer_use_ootb_internal/run_teachmode_ootb_args.py,sha256=UEiwLSdERzBqbCH2Em20b4UNzAb__S8cJSnkceVcBsY,6686
|
7
|
+
computer_use_ootb_internal/computer_use_demo/animation/click_animation.py,sha256=QR_DEDk7bVON5EQ_xsJGrxNa3NoxqubYyXPFRB12pmQ,3183
|
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/
|
9
|
+
computer_use_ootb_internal/computer_use_demo/animation/test_animation.py,sha256=SOJz2yffXTkjuAHqk0IZLcMriR0KQYTo7W1b8wGyRGY,1222
|
10
|
+
computer_use_ootb_internal/computer_use_demo/executor/teachmode_executor.py,sha256=Rr_I0Uk8hsqTmq3Fr3KOtjkXTqSb4pkNxmutENbv8dc,16368
|
13
11
|
computer_use_ootb_internal/computer_use_demo/gui_agent/gui_parser/simple_parser/__init__.py,sha256=h2CNeuACklxVpJC65QR8_6AvSybEZLmeO45hY_-lLBs,61
|
14
12
|
computer_use_ootb_internal/computer_use_demo/gui_agent/gui_parser/simple_parser/gui_capture.py,sha256=CxFJbsSb68ERKH7-C4RaaZy7FIhhzrzGx5qQJ4C37cA,13907
|
15
13
|
computer_use_ootb_internal/computer_use_demo/gui_agent/gui_parser/simple_parser/gui_parser.py,sha256=KSTJ0cMwh3ahUMzHRaDgA2sVNUL4MNlF7qEBGN3G0SI,28993
|
16
|
-
computer_use_ootb_internal/computer_use_demo/gui_agent/gui_parser/simple_parser/test_capture.py,sha256=
|
14
|
+
computer_use_ootb_internal/computer_use_demo/gui_agent/gui_parser/simple_parser/test_capture.py,sha256=26uxu70di9Me-jseym5ejF7RNIbP35uPEiipN5qamIc,211
|
17
15
|
computer_use_ootb_internal/computer_use_demo/gui_agent/gui_parser/simple_parser/uia_parser.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
18
16
|
computer_use_ootb_internal/computer_use_demo/gui_agent/gui_parser/simple_parser/utils.py,sha256=GEA1ES7vOpHBg_Suxpl99reh34kRG4RQpp072JQBK5c,9787
|
19
17
|
computer_use_ootb_internal/computer_use_demo/gui_agent/gui_parser/simple_parser/icon_detection/icon_detection.py,sha256=ysTgvtjE1XM7QSrLLy1HD0i6_7iOb9GME5FWJljrJg0,9752
|
@@ -33,12 +31,12 @@ computer_use_ootb_internal/computer_use_demo/tools/base.py,sha256=QDqpuuKlhUKJT2
|
|
33
31
|
computer_use_ootb_internal/computer_use_demo/tools/bash.py,sha256=rHetQ80_v-TTi-1oxIA7ncFEwJxFTh8FJCErIoZbGeY,4236
|
34
32
|
computer_use_ootb_internal/computer_use_demo/tools/collection.py,sha256=8RzHLobL44_Jjt8ltXS6I8XJlEAQOfc75dmnDUaHE-8,922
|
35
33
|
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=
|
34
|
+
computer_use_ootb_internal/computer_use_demo/tools/computer.py,sha256=kpcp3orAdSwzBJMvL8zt_OgF6kT9UdZaJuqkjja7bic,25493
|
37
35
|
computer_use_ootb_internal/computer_use_demo/tools/computer_marbot.py,sha256=zZuWz9ArfP3Zss-afnscrPkgCtB5UWbCy7HwAOvO2bo,5970
|
38
36
|
computer_use_ootb_internal/computer_use_demo/tools/edit.py,sha256=b0PwUitxckHCQqFP3ZwlthWdqNkn7WETeTHeB6-o98c,11486
|
39
37
|
computer_use_ootb_internal/computer_use_demo/tools/run.py,sha256=xhXdnBK1di9muaO44CEirL9hpGy3NmKbjfMpyeVmn8Y,1595
|
40
38
|
computer_use_ootb_internal/computer_use_demo/tools/screen_capture.py,sha256=L8qfvtUkPPQGt92N-2Zfw5ZTDBzLsDps39uMnX3_uSA,6857
|
41
|
-
computer_use_ootb_internal-0.0.
|
42
|
-
computer_use_ootb_internal-0.0.
|
43
|
-
computer_use_ootb_internal-0.0.
|
44
|
-
computer_use_ootb_internal-0.0.
|
39
|
+
computer_use_ootb_internal-0.0.103.dist-info/METADATA,sha256=un-dDRkh_CxGGAaFc-BSNKzMVpRvl0YabB3qZEJRbq4,910
|
40
|
+
computer_use_ootb_internal-0.0.103.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
41
|
+
computer_use_ootb_internal-0.0.103.dist-info/entry_points.txt,sha256=-AbmawU7IRQuDZihgVMVDrFoY4E6rnXYOUB-5vSeBKs,93
|
42
|
+
computer_use_ootb_internal-0.0.103.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()
|
File without changes
|
File without changes
|