scalebox-sdk 0.1.25__py3-none-any.whl → 1.0.1__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.
- scalebox/__init__.py +2 -2
- scalebox/api/__init__.py +3 -1
- scalebox/api/client/api/sandboxes/post_sandboxes_sandbox_id_connect.py +193 -0
- scalebox/api/client/models/connect_sandbox.py +59 -0
- scalebox/api/client/models/error.py +2 -2
- scalebox/api/client/models/listed_sandbox.py +19 -1
- scalebox/api/client/models/new_sandbox.py +10 -0
- scalebox/api/client/models/sandbox.py +13 -0
- scalebox/api/client/models/sandbox_detail.py +24 -0
- scalebox/cli.py +125 -125
- scalebox/client/aclient.py +57 -57
- scalebox/client/client.py +102 -102
- scalebox/code_interpreter/__init__.py +12 -12
- scalebox/code_interpreter/charts.py +230 -230
- scalebox/code_interpreter/constants.py +3 -3
- scalebox/code_interpreter/exceptions.py +13 -13
- scalebox/code_interpreter/models.py +485 -485
- scalebox/connection_config.py +34 -1
- scalebox/csx_connect/__init__.py +1 -1
- scalebox/csx_connect/client.py +485 -485
- scalebox/csx_desktop/main.py +651 -651
- scalebox/exceptions.py +83 -83
- scalebox/generated/api.py +61 -61
- scalebox/generated/api_pb2.py +203 -203
- scalebox/generated/api_pb2.pyi +956 -956
- scalebox/generated/api_pb2_connect.py +1407 -1407
- scalebox/generated/rpc.py +50 -50
- scalebox/sandbox/main.py +146 -139
- scalebox/sandbox/sandbox_api.py +105 -91
- scalebox/sandbox/signature.py +40 -40
- scalebox/sandbox/utils.py +34 -34
- scalebox/sandbox_async/main.py +226 -44
- scalebox/sandbox_async/sandbox_api.py +124 -3
- scalebox/sandbox_sync/main.py +205 -130
- scalebox/sandbox_sync/sandbox_api.py +119 -3
- scalebox/test/CODE_INTERPRETER_TESTS_READY.md +323 -323
- scalebox/test/README.md +329 -329
- scalebox/test/bedrock_openai_adapter.py +67 -0
- scalebox/test/code_interpreter_test.py +34 -34
- scalebox/test/code_interpreter_test_sync.py +34 -34
- scalebox/test/run_stress_code_interpreter_sync.py +166 -0
- scalebox/test/simple_upload_example.py +123 -0
- scalebox/test/stabitiy_test.py +310 -0
- scalebox/test/test_browser_use.py +25 -0
- scalebox/test/test_browser_use_scalebox.py +61 -0
- scalebox/test/test_code_interpreter_sync_comprehensive.py +115 -65
- scalebox/test/test_connect_pause_async.py +277 -0
- scalebox/test/test_connect_pause_sync.py +267 -0
- scalebox/test/test_desktop_sandbox_sf.py +117 -0
- scalebox/test/test_download_url.py +49 -0
- scalebox/test/test_sandbox_async_comprehensive.py +1 -1
- scalebox/test/test_sandbox_object_storage_example.py +146 -0
- scalebox/test/test_sandbox_object_storage_example_async.py +156 -0
- scalebox/test/test_sf.py +137 -0
- scalebox/test/test_watch_dir_async.py +56 -0
- scalebox/test/testacreate.py +1 -1
- scalebox/test/testagetinfo.py +1 -1
- scalebox/test/testcomputeuse.py +243 -243
- scalebox/test/testsandbox_api.py +1 -3
- scalebox/test/testsandbox_sync.py +1 -1
- scalebox/test/upload_100mb_example.py +355 -0
- scalebox/utils/httpcoreclient.py +297 -297
- scalebox/utils/httpxclient.py +403 -403
- scalebox/version.py +2 -2
- {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.1.dist-info}/METADATA +1 -1
- {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.1.dist-info}/RECORD +70 -53
- {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.1.dist-info}/WHEEL +1 -1
- {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.1.dist-info}/entry_points.txt +0 -0
- {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.1.dist-info}/licenses/LICENSE +0 -0
- {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from scalebox.code_interpreter import Sandbox
|
|
2
|
+
import json
|
|
3
|
+
|
|
4
|
+
# 1. 准备要上传的文件内容
|
|
5
|
+
print("正在准备文件内容...")
|
|
6
|
+
results_data = {
|
|
7
|
+
"experiment_id": "exp_001",
|
|
8
|
+
"status": "completed",
|
|
9
|
+
"metrics": {
|
|
10
|
+
"accuracy": 0.952,
|
|
11
|
+
"precision": 0.94,
|
|
12
|
+
"recall": 0.96
|
|
13
|
+
},
|
|
14
|
+
"timestamp": "2024-01-01T12:00:00Z",
|
|
15
|
+
"details": [
|
|
16
|
+
{"epoch": 1, "loss": 0.45},
|
|
17
|
+
{"epoch": 2, "loss": 0.32},
|
|
18
|
+
{"epoch": 3, "loss": 0.18}
|
|
19
|
+
]
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
# 转换为 JSON 字符串
|
|
23
|
+
json_content = json.dumps(results_data, indent=2)
|
|
24
|
+
|
|
25
|
+
# 2. 创建沙箱并写入文件
|
|
26
|
+
print("\n正在创建沙箱并写入文件...")
|
|
27
|
+
sandbox = Sandbox.create(timeout=1800)
|
|
28
|
+
remote_path = "/home/user/results.json"
|
|
29
|
+
|
|
30
|
+
# 关键修改:使用 sandbox.write() 写入文件
|
|
31
|
+
sandbox.files.write(remote_path, json_content)
|
|
32
|
+
print(f"✅ 文件已写入沙箱: {remote_path}")
|
|
33
|
+
|
|
34
|
+
# 3. 获取预签名下载 URL
|
|
35
|
+
print("\n正在生成下载链接...")
|
|
36
|
+
download_url = sandbox.download_url(
|
|
37
|
+
path=remote_path,
|
|
38
|
+
use_signature_expiration=180 # 180秒有效期
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
print(f"\n📥 下载 URL: {download_url}")
|
|
42
|
+
print(f"⏰ 链接将在 3 分钟后过期")
|
|
43
|
+
|
|
44
|
+
upload_url = sandbox.upload_url(
|
|
45
|
+
path="/home/user",
|
|
46
|
+
use_signature_expiration=360
|
|
47
|
+
)
|
|
48
|
+
print(f"\n📥 上传 URL: {upload_url}")
|
|
49
|
+
print(f"⏰ 链接将在 6 分钟后过期")
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
示例:如何在创建同步 Sandbox 时携带 object_storage 参数。
|
|
4
|
+
|
|
5
|
+
运行前准备:
|
|
6
|
+
1. 设置环境变量 SCALEBOX_OBJECT_STORAGE_CONFIG 为 JSON 字符串或 JSON 文件路径,
|
|
7
|
+
该内容会被原样传递给后端。例如:
|
|
8
|
+
{
|
|
9
|
+
"provider": "s3",
|
|
10
|
+
"bucket": "my-sbx-bucket",
|
|
11
|
+
"region": "us-east-1",
|
|
12
|
+
"access_key_id": "AKIA...",
|
|
13
|
+
"secret_access_key": "******",
|
|
14
|
+
"endpoint": "https://s3.amazonaws.com"
|
|
15
|
+
}
|
|
16
|
+
2. (可选)设置 SCALEBOX_OBJECT_STORAGE_TEMPLATE / SCALEBOX_OBJECT_STORAGE_TIMEOUT
|
|
17
|
+
调整模板和沙箱超时时间。
|
|
18
|
+
|
|
19
|
+
注意:目前只有同步版本支持 object_storage,本示例不会自动运行,
|
|
20
|
+
需要在提供有效配置后手动执行:
|
|
21
|
+
|
|
22
|
+
PYTHONPATH=/home/ubuntu/git_home/scalebox:$PYTHONPATH \\
|
|
23
|
+
SCALEBOX_OBJECT_STORAGE_CONFIG=/path/to/config.json \\
|
|
24
|
+
python test/test_sandbox_object_storage_example.py
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
from __future__ import annotations
|
|
28
|
+
|
|
29
|
+
import json
|
|
30
|
+
import logging
|
|
31
|
+
import os
|
|
32
|
+
import sys
|
|
33
|
+
from pathlib import Path
|
|
34
|
+
from typing import Any, Dict, Optional
|
|
35
|
+
|
|
36
|
+
from scalebox.exceptions import SandboxException
|
|
37
|
+
from scalebox.sandbox_sync.main import Sandbox
|
|
38
|
+
from scalebox.sandbox.sandbox_api import SandboxQuery
|
|
39
|
+
|
|
40
|
+
logger = logging.getLogger(__name__)
|
|
41
|
+
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
|
|
42
|
+
|
|
43
|
+
# CONFIG_ENV = "SCALEBOX_OBJECT_STORAGE_CONFIG"
|
|
44
|
+
# TEMPLATE_ENV = "SCALEBOX_OBJECT_STORAGE_TEMPLATE"
|
|
45
|
+
# TIMEOUT_ENV = "SCALEBOX_OBJECT_STORAGE_TIMEOUT"
|
|
46
|
+
#
|
|
47
|
+
#
|
|
48
|
+
# def _load_object_storage_payload() -> Optional[Dict[str, Any]]:
|
|
49
|
+
# raw_value = os.environ.get(CONFIG_ENV)
|
|
50
|
+
# if not raw_value:
|
|
51
|
+
# logger.warning(
|
|
52
|
+
# "未检测到 %s 环境变量,跳过 object_storage 示例。请设置 JSON 配置后重新运行。",
|
|
53
|
+
# CONFIG_ENV,
|
|
54
|
+
# )
|
|
55
|
+
# return None
|
|
56
|
+
#
|
|
57
|
+
# config_text: Optional[str] = None
|
|
58
|
+
# potential_path = Path(raw_value)
|
|
59
|
+
# if potential_path.is_file():
|
|
60
|
+
# config_text = potential_path.read_text(encoding="utf-8")
|
|
61
|
+
# else:
|
|
62
|
+
# config_text = raw_value
|
|
63
|
+
#
|
|
64
|
+
# try:
|
|
65
|
+
# payload = json.loads(config_text)
|
|
66
|
+
# except json.JSONDecodeError as exc:
|
|
67
|
+
# logger.error("无法解析 object_storage 配置(需合法 JSON):%s", exc)
|
|
68
|
+
# raise SystemExit(1) from exc
|
|
69
|
+
#
|
|
70
|
+
# if not isinstance(payload, dict):
|
|
71
|
+
# logger.error("object_storage 配置必须是 JSON 对象,示例详见文件头部注释。")
|
|
72
|
+
# raise SystemExit(1)
|
|
73
|
+
#
|
|
74
|
+
# return payload
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
# def _mask_value(value: str) -> str:
|
|
78
|
+
# if len(value) <= 4:
|
|
79
|
+
# return "*" * len(value)
|
|
80
|
+
# return f"{value[:2]}***{value[-2:]}"
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
# def _display_object_storage_keys(config: Dict[str, Any]) -> Dict[str, Any]:
|
|
84
|
+
# masked = {}
|
|
85
|
+
# for key, value in config.items():
|
|
86
|
+
# if isinstance(value, str):
|
|
87
|
+
# masked[key] = _mask_value(value)
|
|
88
|
+
# else:
|
|
89
|
+
# masked[key] = value
|
|
90
|
+
# return masked
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def create_sandbox_with_object_storage():
|
|
94
|
+
# payload = _load_object_storage_payload()
|
|
95
|
+
# if payload is None:
|
|
96
|
+
# return
|
|
97
|
+
#
|
|
98
|
+
# template = os.environ.get(TEMPLATE_ENV, "base")
|
|
99
|
+
# timeout = int(os.environ.get(TIMEOUT_ENV, "600"))
|
|
100
|
+
|
|
101
|
+
sandbox: Optional[Sandbox] = None
|
|
102
|
+
try:
|
|
103
|
+
sandbox = Sandbox.create(
|
|
104
|
+
template="base",
|
|
105
|
+
timeout=3600,
|
|
106
|
+
metadata={"example": "object_storage"},
|
|
107
|
+
object_storage={"uri": "s3://bgd-test/test/",
|
|
108
|
+
"mount_point": "/mnt/oss",
|
|
109
|
+
# "access_key": "",
|
|
110
|
+
# "secret_key": "",
|
|
111
|
+
"region": "us-east-2",
|
|
112
|
+
"endpoint": "https://s3.us-east-2.amazonaws.com",},
|
|
113
|
+
)
|
|
114
|
+
print(sandbox.sandbox_id)
|
|
115
|
+
print(sandbox.sandbox_domain)
|
|
116
|
+
if sandbox.object_storage:
|
|
117
|
+
print(sandbox.object_storage)
|
|
118
|
+
|
|
119
|
+
info = sandbox.get_info()
|
|
120
|
+
print(info)
|
|
121
|
+
print(f"get_info.object_storage: {info.object_storage}")
|
|
122
|
+
|
|
123
|
+
listed = Sandbox.list(query=SandboxQuery(metadata={"example": "object_storage"}))
|
|
124
|
+
print(f"List 根据 metadata 命中的沙箱数量: {len(listed)}")
|
|
125
|
+
for listed_box in listed:
|
|
126
|
+
detailed = Sandbox.get_info(sandbox_id=listed_box.sandbox_id)
|
|
127
|
+
print(detailed)
|
|
128
|
+
print(
|
|
129
|
+
f"list -> sandbox {listed_box.sandbox_id} object_storage: {detailed.object_storage}"
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
# 在沙箱中运行简单命令,确认可正常访问
|
|
133
|
+
result = sandbox.commands.run("echo 'object storage sandbox is ready'")
|
|
134
|
+
print(f"命令输出: {result.stdout.strip()}")
|
|
135
|
+
except SandboxException as exc:
|
|
136
|
+
logger.error("创建或使用沙箱失败:%s", exc)
|
|
137
|
+
raise
|
|
138
|
+
finally:
|
|
139
|
+
if sandbox is not None:
|
|
140
|
+
# sandbox.kill()
|
|
141
|
+
logger.info("沙箱已销毁")
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
if __name__ == "__main__":
|
|
145
|
+
create_sandbox_with_object_storage()
|
|
146
|
+
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# pyright: reportMissingImports=false
|
|
3
|
+
"""
|
|
4
|
+
示例:如何在创建异步 Sandbox 时携带 object_storage 参数。
|
|
5
|
+
|
|
6
|
+
运行前准备:
|
|
7
|
+
1. 设置环境变量 SCALEBOX_OBJECT_STORAGE_CONFIG 为 JSON 字符串或 JSON 文件路径,
|
|
8
|
+
该内容会被原样传递给后端。例如:
|
|
9
|
+
{
|
|
10
|
+
"provider": "s3",
|
|
11
|
+
"bucket": "my-sbx-bucket",
|
|
12
|
+
"region": "us-east-1",
|
|
13
|
+
"access_key_id": "AKIA...",
|
|
14
|
+
"secret_access_key": "******",
|
|
15
|
+
"endpoint": "https://s3.amazonaws.com"
|
|
16
|
+
}
|
|
17
|
+
2. (可选)设置 SCALEBOX_OBJECT_STORAGE_TEMPLATE / SCALEBOX_OBJECT_STORAGE_TIMEOUT
|
|
18
|
+
调整模板和沙箱超时时间。
|
|
19
|
+
|
|
20
|
+
注意:object_storage 功能仍主要在同步版本可用,异步示例取决于后端实际支持状况。
|
|
21
|
+
需要在提供有效配置后手动执行:
|
|
22
|
+
|
|
23
|
+
PYTHONPATH=/home/ubuntu/git_home/scalebox:$PYTHONPATH \\
|
|
24
|
+
SCALEBOX_OBJECT_STORAGE_CONFIG=/path/to/config.json \\
|
|
25
|
+
python test/test_sandbox_object_storage_example_async.py
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
30
|
+
import asyncio
|
|
31
|
+
import json
|
|
32
|
+
import logging
|
|
33
|
+
import os
|
|
34
|
+
import sys
|
|
35
|
+
from pathlib import Path
|
|
36
|
+
from typing import Any, Dict, Optional
|
|
37
|
+
|
|
38
|
+
WORKSPACE_ROOT = Path(__file__).resolve().parents[1]
|
|
39
|
+
if str(WORKSPACE_ROOT) not in sys.path:
|
|
40
|
+
sys.path.insert(0, str(WORKSPACE_ROOT))
|
|
41
|
+
|
|
42
|
+
from scalebox.exceptions import SandboxException
|
|
43
|
+
from scalebox.sandbox_async.main import AsyncSandbox
|
|
44
|
+
from scalebox.sandbox.sandbox_api import SandboxQuery
|
|
45
|
+
|
|
46
|
+
logger = logging.getLogger(__name__)
|
|
47
|
+
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
|
|
48
|
+
|
|
49
|
+
# CONFIG_ENV = "SCALEBOX_OBJECT_STORAGE_CONFIG"
|
|
50
|
+
# TEMPLATE_ENV = "SCALEBOX_OBJECT_STORAGE_TEMPLATE"
|
|
51
|
+
# TIMEOUT_ENV = "SCALEBOX_OBJECT_STORAGE_TIMEOUT"
|
|
52
|
+
#
|
|
53
|
+
#
|
|
54
|
+
# def _load_object_storage_payload() -> Optional[Dict[str, Any]]:
|
|
55
|
+
# raw_value = os.environ.get(CONFIG_ENV)
|
|
56
|
+
# if not raw_value:
|
|
57
|
+
# logger.warning(
|
|
58
|
+
# "未检测到 %s 环境变量,跳过 object_storage 示例。请设置 JSON 配置后重新运行。",
|
|
59
|
+
# CONFIG_ENV,
|
|
60
|
+
# )
|
|
61
|
+
# return None
|
|
62
|
+
#
|
|
63
|
+
# config_text: Optional[str] = None
|
|
64
|
+
# potential_path = Path(raw_value)
|
|
65
|
+
# if potential_path.is_file():
|
|
66
|
+
# config_text = potential_path.read_text(encoding="utf-8")
|
|
67
|
+
# else:
|
|
68
|
+
# config_text = raw_value
|
|
69
|
+
#
|
|
70
|
+
# try:
|
|
71
|
+
# payload = json.loads(config_text)
|
|
72
|
+
# except json.JSONDecodeError as exc:
|
|
73
|
+
# logger.error("无法解析 object_storage 配置(需合法 JSON):%s", exc)
|
|
74
|
+
# raise SystemExit(1) from exc
|
|
75
|
+
#
|
|
76
|
+
# if not isinstance(payload, dict):
|
|
77
|
+
# logger.error("object_storage 配置必须是 JSON 对象,示例详见文件头部注释。")
|
|
78
|
+
# raise SystemExit(1)
|
|
79
|
+
#
|
|
80
|
+
# return payload
|
|
81
|
+
#
|
|
82
|
+
#
|
|
83
|
+
# def _mask_value(value: str) -> str:
|
|
84
|
+
# if len(value) <= 4:
|
|
85
|
+
# return "*" * len(value)
|
|
86
|
+
# return f"{value[:2]}***{value[-2:]}"
|
|
87
|
+
#
|
|
88
|
+
#
|
|
89
|
+
# def _display_object_storage_keys(config: Dict[str, Any]) -> Dict[str, Any]:
|
|
90
|
+
# masked = {}
|
|
91
|
+
# for key, value in config.items():
|
|
92
|
+
# if isinstance(value, str):
|
|
93
|
+
# masked[key] = _mask_value(value)
|
|
94
|
+
# else:
|
|
95
|
+
# masked[key] = value
|
|
96
|
+
# return masked
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
async def create_sandbox_with_object_storage_async():
|
|
100
|
+
# payload = _load_object_storage_payload()
|
|
101
|
+
# if payload is None:
|
|
102
|
+
# return
|
|
103
|
+
#
|
|
104
|
+
# template = os.environ.get(TEMPLATE_ENV, "base")
|
|
105
|
+
# timeout = int(os.environ.get(TIMEOUT_ENV, "600"))
|
|
106
|
+
|
|
107
|
+
sandbox: Optional[AsyncSandbox] = None
|
|
108
|
+
try:
|
|
109
|
+
sandbox = await AsyncSandbox.create(
|
|
110
|
+
template="base",
|
|
111
|
+
timeout=3600,
|
|
112
|
+
metadata={"example": "object_storage_async"},
|
|
113
|
+
object_storage={
|
|
114
|
+
"uri": "s3://bgd-test/test/",
|
|
115
|
+
"mount_point": "/mnt/oss",
|
|
116
|
+
"access_key": "",
|
|
117
|
+
"secret_key": "",
|
|
118
|
+
"region": "us-east-2",
|
|
119
|
+
"endpoint": "https://s3.us-east-2.amazonaws.com",
|
|
120
|
+
},
|
|
121
|
+
)
|
|
122
|
+
print(sandbox.sandbox_id)
|
|
123
|
+
print(sandbox.sandbox_domain)
|
|
124
|
+
if sandbox.object_storage:
|
|
125
|
+
print(sandbox.object_storage)
|
|
126
|
+
|
|
127
|
+
info = await sandbox.get_info()
|
|
128
|
+
print(info)
|
|
129
|
+
print(f"get_info.object_storage: {info.object_storage}")
|
|
130
|
+
|
|
131
|
+
listed = await AsyncSandbox.list(
|
|
132
|
+
query=SandboxQuery(metadata={"example": "object_storage_async"})
|
|
133
|
+
)
|
|
134
|
+
print(f"Async list 根据 metadata 命中的沙箱数量: {len(listed)}")
|
|
135
|
+
for listed_box in listed:
|
|
136
|
+
detailed = await AsyncSandbox.get_info(sandbox_id=listed_box.sandbox_id)
|
|
137
|
+
print(detailed)
|
|
138
|
+
print(
|
|
139
|
+
f"list -> sandbox {listed_box.sandbox_id} object_storage: {detailed.object_storage}"
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
# 在沙箱中运行简单命令,确认可正常访问
|
|
143
|
+
result = await sandbox.commands.run("echo 'async object storage sandbox is ready'")
|
|
144
|
+
print(f"命令输出: {result.stdout.strip()}")
|
|
145
|
+
except SandboxException as exc:
|
|
146
|
+
logger.error("创建或使用异步沙箱失败:%s", exc)
|
|
147
|
+
raise
|
|
148
|
+
finally:
|
|
149
|
+
if sandbox is not None:
|
|
150
|
+
# await sandbox.kill()
|
|
151
|
+
logger.info("异步沙箱已销毁")
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
if __name__ == "__main__":
|
|
155
|
+
asyncio.run(create_sandbox_with_object_storage_async())
|
|
156
|
+
|
scalebox/test/test_sf.py
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
from browser_use import Agent, BrowserProfile
|
|
2
|
+
from playwright.async_api import async_playwright
|
|
3
|
+
from dotenv import load_dotenv
|
|
4
|
+
import os, asyncio
|
|
5
|
+
from browser_use.llm import ChatOpenAI
|
|
6
|
+
import subprocess, pathlib
|
|
7
|
+
|
|
8
|
+
load_dotenv()
|
|
9
|
+
os.environ["PLAYWRIGHT_CHROMIUM_EXTRA_ARGS"] = (
|
|
10
|
+
"--no-sandbox --disable-dev-shm-usage --disable-gpu --disable-software-rasterizer"
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
# 1. 正常实例化 ChatOpenAI
|
|
14
|
+
_chat = ChatOpenAI(
|
|
15
|
+
model="Qwen/Qwen2.5-72B-Instruct",
|
|
16
|
+
api_key="sk-nbxsvrydquzfkfrrnnuutnfchpghzeuxilgawvsjqzjhumkh",
|
|
17
|
+
base_url="https://api.siliconflow.cn/v1",
|
|
18
|
+
temperature=0.1
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
llm = ChatOpenAI(
|
|
23
|
+
model="deepseek-ai/DeepSeek-R1",
|
|
24
|
+
api_key="sk-nbxsvrydquzfkfrrnnuutnfchpghzeuxilgawvsjqzjhumkh",
|
|
25
|
+
base_url="https://api.siliconflow.cn/v1",
|
|
26
|
+
temperature=0.7
|
|
27
|
+
)
|
|
28
|
+
# 2. 包一层模型,补 .provider + 转发所有必要方法
|
|
29
|
+
class SiliconFlowModel:
|
|
30
|
+
provider = "siliconflow"
|
|
31
|
+
|
|
32
|
+
def __init__(self, chat: ChatOpenAI):
|
|
33
|
+
self.chat = chat
|
|
34
|
+
# 把 browser-use 可能用到的字段全部代理
|
|
35
|
+
self.model_name = chat.model_name # ← 新增
|
|
36
|
+
self.model = chat.model_name # ← 新增(防它再换字段)
|
|
37
|
+
self.ainvoke = chat.ainvoke
|
|
38
|
+
self.invoke = chat.invoke
|
|
39
|
+
self.bind = chat.bind
|
|
40
|
+
|
|
41
|
+
# === 同步 ===
|
|
42
|
+
def invoke(self, *args, **kwargs):
|
|
43
|
+
return self.chat.invoke(*args, **kwargs)
|
|
44
|
+
|
|
45
|
+
# === 异步 ===
|
|
46
|
+
async def ainvoke(self, *args, **kwargs):
|
|
47
|
+
return await self.chat.ainvoke(*args, **kwargs)
|
|
48
|
+
|
|
49
|
+
# 如有其他缺失方法,继续代理即可
|
|
50
|
+
def bind(self, *args, **kwargs):
|
|
51
|
+
return self.chat.bind(*args, **kwargs)
|
|
52
|
+
|
|
53
|
+
# llm = SiliconFlowModel(_chat)
|
|
54
|
+
|
|
55
|
+
# 3. 创建 Agent
|
|
56
|
+
async def main():
|
|
57
|
+
# chrome_path = subprocess.check_output(
|
|
58
|
+
# ["which", "google-chrome-stable"], text=True
|
|
59
|
+
# ).strip()
|
|
60
|
+
# browser_profile = BrowserProfile(
|
|
61
|
+
# headless=True, # 先跑通再改 False
|
|
62
|
+
# # executable_path="/usr/bin/google-chrome-stable",
|
|
63
|
+
# extra_args=[
|
|
64
|
+
# "--no-sandbox",
|
|
65
|
+
# "--disable-dev-shm-usage",
|
|
66
|
+
# "--disable-gpu",
|
|
67
|
+
# "--disable-software-rasterizer",
|
|
68
|
+
# "--remote-debugging-port=9222",
|
|
69
|
+
# "--remote-debugging-address=0.0.0.0", # 允许所有地址连接
|
|
70
|
+
# "--user-data-dir=/tmp/chrome-manual-test" # 指定用户数据目录
|
|
71
|
+
# ],
|
|
72
|
+
# )
|
|
73
|
+
# "--disable-dev-shm-usage",
|
|
74
|
+
# "--disable-gpu",
|
|
75
|
+
# "--disable-software-rasterizer",
|
|
76
|
+
async with async_playwright() as pw:
|
|
77
|
+
browser = await pw.chromium.launch(
|
|
78
|
+
proxy={
|
|
79
|
+
"server": "http://net-proxy:80",
|
|
80
|
+
"username":"sbx-jz9kgqolumvmfc7ds",
|
|
81
|
+
"password": "npt-Vd4CpGtjBOQEI8wdBv3wSOd8P4Bup1NgfsM"
|
|
82
|
+
},
|
|
83
|
+
headless=False,
|
|
84
|
+
args=[
|
|
85
|
+
# '--no-sandbox',
|
|
86
|
+
|
|
87
|
+
# '--disable-dev-shm-usage',
|
|
88
|
+
# '--disable-gpu',
|
|
89
|
+
# '--disable-extensions',
|
|
90
|
+
# '--disable-background-timer-throttling',
|
|
91
|
+
# '--disable-renderer-backgrounding',
|
|
92
|
+
# '--disable-features=TranslateUI',
|
|
93
|
+
"--disable-blink-features=AutomationControlled", # 禁用自动化控制标志
|
|
94
|
+
"--start-maximized", # 最大化窗口
|
|
95
|
+
]
|
|
96
|
+
)
|
|
97
|
+
# task = """
|
|
98
|
+
# 1. 打开淘宝官网 (taobao.com)
|
|
99
|
+
# 2. 搜索"格力空调"
|
|
100
|
+
# 3. 记录下第一款商品的价格和标题
|
|
101
|
+
# 4. 打开京东官网 (jd.com)
|
|
102
|
+
# 5. 同样搜索"格力空调"
|
|
103
|
+
# 6. 记录下第一款商品的价格和标题
|
|
104
|
+
# 7. 对比在两个平台上看到的第一个商品的价格
|
|
105
|
+
# """
|
|
106
|
+
task = """
|
|
107
|
+
1. 打开google搜索
|
|
108
|
+
2、输入今日新闻
|
|
109
|
+
3、输出第一条内容
|
|
110
|
+
"""
|
|
111
|
+
# task = """
|
|
112
|
+
# 1、打开新浪网(http://sina.cn/)
|
|
113
|
+
# 2. 搜索"科技"
|
|
114
|
+
# 3. 记录前10条记录
|
|
115
|
+
# """
|
|
116
|
+
agent = Agent(
|
|
117
|
+
task=task,
|
|
118
|
+
llm=llm,
|
|
119
|
+
# browser_profile=browser_profile,
|
|
120
|
+
browser=browser,
|
|
121
|
+
use_vision=False
|
|
122
|
+
)
|
|
123
|
+
result = await agent.run()
|
|
124
|
+
print("---------- 最终结果 ----------")
|
|
125
|
+
print(result)
|
|
126
|
+
await browser.close()
|
|
127
|
+
|
|
128
|
+
# if __name__ == "__main__":
|
|
129
|
+
# asyncio.run(main())
|
|
130
|
+
loop = asyncio.get_event_loop()
|
|
131
|
+
if loop.is_closed():
|
|
132
|
+
loop = asyncio.new_event_loop()
|
|
133
|
+
asyncio.set_event_loop(loop)
|
|
134
|
+
try:
|
|
135
|
+
loop.run_until_complete(main())
|
|
136
|
+
finally:
|
|
137
|
+
loop.close()
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Minimal async test for sandbox_async.filesystem.watch_dir.
|
|
4
|
+
Creates an AsyncSandbox, watches a temp directory, writes a file to trigger
|
|
5
|
+
an event, asserts events were received, and cleans up.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import asyncio
|
|
9
|
+
import time
|
|
10
|
+
import logging
|
|
11
|
+
from typing import List
|
|
12
|
+
|
|
13
|
+
from scalebox.sandbox_async.main import AsyncSandbox
|
|
14
|
+
from scalebox.sandbox.filesystem.watch_handle import FilesystemEvent
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
|
|
18
|
+
logger = logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
async def main():
|
|
22
|
+
async with await AsyncSandbox.create(template="base", timeout=300, metadata={"test": "watch_dir_async"}) as sandbox:
|
|
23
|
+
watch_path = "/tmp/watch_async_test"
|
|
24
|
+
await sandbox.files.make_dir(watch_path)
|
|
25
|
+
|
|
26
|
+
events: List[FilesystemEvent] = []
|
|
27
|
+
|
|
28
|
+
async def on_event(ev: FilesystemEvent):
|
|
29
|
+
print(ev)
|
|
30
|
+
events.append(ev)
|
|
31
|
+
|
|
32
|
+
# Start watching directory
|
|
33
|
+
handle = await sandbox.files.watch_dir(
|
|
34
|
+
path=watch_path,
|
|
35
|
+
on_event=on_event,
|
|
36
|
+
timeout=10,
|
|
37
|
+
recursive=False,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
# Trigger a filesystem event
|
|
41
|
+
await sandbox.files.write(f"{watch_path}/new_file.txt", "content")
|
|
42
|
+
|
|
43
|
+
# Wait a bit for event propagation
|
|
44
|
+
await asyncio.sleep(2)
|
|
45
|
+
|
|
46
|
+
# Stop watching
|
|
47
|
+
await handle.stop()
|
|
48
|
+
|
|
49
|
+
logger.info(f"Received {len(events)} filesystem events")
|
|
50
|
+
assert len(events) >= 1
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
if __name__ == "__main__":
|
|
54
|
+
asyncio.run(main())
|
|
55
|
+
|
|
56
|
+
|
scalebox/test/testacreate.py
CHANGED
|
@@ -7,7 +7,7 @@ from scalebox.sandbox_async import AsyncSandbox
|
|
|
7
7
|
async def main():
|
|
8
8
|
sandbox = await AsyncSandbox.create(
|
|
9
9
|
template="base", # 或自定义模板名
|
|
10
|
-
api_key="sk-
|
|
10
|
+
api_key="sk-Wk4IgtUYOqnttx",
|
|
11
11
|
timeout=3600,
|
|
12
12
|
)
|
|
13
13
|
print("✅ 沙箱已启动,sandbox_domain:", sandbox.sandbox_domain)
|
scalebox/test/testagetinfo.py
CHANGED
|
@@ -6,7 +6,7 @@ from sandbox_async import AsyncSandbox
|
|
|
6
6
|
|
|
7
7
|
async def main():
|
|
8
8
|
sandbox = await AsyncSandbox.get_info(
|
|
9
|
-
sandbox_id="", api_key="sk-
|
|
9
|
+
sandbox_id="", api_key="sk-Wk4Ig"
|
|
10
10
|
)
|
|
11
11
|
print("✅ 沙箱已启动,sandbox_domain:", sandbox.sandbox_domain)
|
|
12
12
|
print("✅ 沙箱已启动,ID:", sandbox.sandbox_id)
|