Skip to content

Commit a1ac02e

Browse files
fix: browser_install (#3231)
Co-authored-by: Wendong-Fan <w3ndong.fan@gmail.com>
1 parent 5a0ae4e commit a1ac02e

File tree

8 files changed

+265
-1055
lines changed

8 files changed

+265
-1055
lines changed

camel/storages/vectordb_storages/oceanbase.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ def __init__(
7474
ObVecClient,
7575
)
7676
from pyobvector.client.index_param import (
77-
IndexParam,
7877
IndexParams,
7978
)
8079
from pyobvector.schema import VECTOR
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
#
6+
# http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.
13+
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
14+
15+
import os
16+
import platform
17+
import shutil
18+
import subprocess
19+
from typing import Optional, Tuple
20+
21+
from camel.logger import get_logger
22+
23+
logger = get_logger(__name__)
24+
25+
26+
def find_command(
27+
cmd_base: str,
28+
windows_variants: Optional[list] = None,
29+
unix_variant: Optional[str] = None,
30+
) -> Optional[str]:
31+
"""Find command across platforms."""
32+
is_windows = platform.system() == 'Windows'
33+
34+
if is_windows and windows_variants:
35+
for variant in windows_variants:
36+
if shutil.which(variant):
37+
return variant
38+
else:
39+
variant = unix_variant or cmd_base
40+
if shutil.which(variant):
41+
return variant
42+
43+
if shutil.which(cmd_base):
44+
return cmd_base
45+
return None
46+
47+
48+
def create_command_not_found_error(
49+
command: str, error: Optional[Exception] = None
50+
) -> RuntimeError:
51+
base_msg = f"{command} is not installed or not in PATH. "
52+
if command in ['npm', 'node']:
53+
base_msg += (
54+
f"Please install Node.js{' and npm' if command == 'npm' else ''} "
55+
f"from https://nodejs.org/ to use the hybrid browser toolkit."
56+
)
57+
if not error:
58+
base_msg += (
59+
" If already installed, ensure the Node.js installation "
60+
"directory (e.g., C:\\Program Files\\nodejs on Windows) is "
61+
"in your system PATH."
62+
)
63+
if error:
64+
base_msg += f" Error details: {error!s}"
65+
return RuntimeError(base_msg)
66+
67+
68+
def create_npm_command_error(command: str, error: Exception) -> RuntimeError:
69+
return RuntimeError(
70+
f"Failed to run {command}: {error!s}. "
71+
f"Please ensure npm is properly installed and in PATH."
72+
)
73+
74+
75+
async def check_and_install_dependencies(ts_dir: str) -> Tuple[str, str]:
76+
"""Check Node.js/npm and install dependencies if needed.
77+
78+
Returns:
79+
Tuple of (npm_cmd, node_cmd) that can be used for running commands
80+
"""
81+
is_windows = platform.system() == 'Windows'
82+
use_shell = is_windows
83+
84+
npm_cmd = find_command('npm', windows_variants=['npm.cmd', 'npm.exe'])
85+
if not npm_cmd:
86+
raise create_command_not_found_error('npm')
87+
88+
try:
89+
npm_check = subprocess.run(
90+
[npm_cmd, '--version'],
91+
capture_output=True,
92+
text=True,
93+
shell=use_shell,
94+
)
95+
if npm_check.returncode != 0:
96+
raise RuntimeError(
97+
f"npm command failed with error: {npm_check.stderr}. "
98+
"Please ensure Node.js and npm are properly installed."
99+
)
100+
except (FileNotFoundError, OSError) as e:
101+
raise create_command_not_found_error('npm', e)
102+
103+
node_cmd = find_command('node', windows_variants=['node.exe'])
104+
if not node_cmd:
105+
raise create_command_not_found_error('node')
106+
107+
try:
108+
node_check = subprocess.run(
109+
[node_cmd, '--version'],
110+
capture_output=True,
111+
text=True,
112+
shell=use_shell,
113+
)
114+
if node_check.returncode != 0:
115+
raise RuntimeError(
116+
f"node command failed with error: {node_check.stderr}. "
117+
"Please ensure Node.js is properly installed."
118+
)
119+
except (FileNotFoundError, OSError) as e:
120+
raise create_command_not_found_error('node', e)
121+
122+
node_modules_path = os.path.join(ts_dir, 'node_modules')
123+
if not os.path.exists(node_modules_path):
124+
logger.warning("Node modules not found. Running npm install...")
125+
try:
126+
install_result = subprocess.run(
127+
[npm_cmd, 'install'],
128+
cwd=ts_dir,
129+
capture_output=True,
130+
text=True,
131+
shell=use_shell,
132+
)
133+
if install_result.returncode != 0:
134+
logger.error(f"npm install failed: {install_result.stderr}")
135+
raise RuntimeError(
136+
f"Failed to install npm dependencies: {install_result.stderr}\n" # noqa:E501
137+
f"Please run 'npm install' in {ts_dir} manually."
138+
)
139+
except (FileNotFoundError, OSError) as e:
140+
raise create_npm_command_error("npm install", e)
141+
logger.info("npm dependencies installed successfully")
142+
143+
dist_dir = os.path.join(ts_dir, 'dist')
144+
if not os.path.exists(dist_dir) or not os.listdir(dist_dir):
145+
logger.info("Building TypeScript...")
146+
try:
147+
build_result = subprocess.run(
148+
[npm_cmd, 'run', 'build'],
149+
cwd=ts_dir,
150+
capture_output=True,
151+
text=True,
152+
shell=use_shell,
153+
)
154+
if build_result.returncode != 0:
155+
logger.error(f"TypeScript build failed: {build_result.stderr}")
156+
raise RuntimeError(
157+
f"TypeScript build failed: {build_result.stderr}"
158+
)
159+
logger.info("TypeScript build completed successfully")
160+
except (FileNotFoundError, OSError) as e:
161+
raise create_npm_command_error("npm run build", e)
162+
else:
163+
logger.info("TypeScript already built, skipping build")
164+
165+
playwright_marker = os.path.join(ts_dir, '.playwright_installed')
166+
if not os.path.exists(playwright_marker):
167+
logger.info("Installing Playwright browsers...")
168+
npx_cmd = find_command('npx', windows_variants=['npx.cmd', 'npx.exe'])
169+
if not npx_cmd:
170+
logger.warning(
171+
"npx not found. Skipping Playwright browser installation. "
172+
"Users may need to run 'npx playwright install' manually."
173+
)
174+
else:
175+
try:
176+
playwright_install = subprocess.run(
177+
[npx_cmd, 'playwright', 'install'],
178+
cwd=ts_dir,
179+
capture_output=True,
180+
text=True,
181+
shell=use_shell,
182+
)
183+
if playwright_install.returncode == 0:
184+
logger.info("Playwright browsers installed successfully")
185+
with open(playwright_marker, 'w') as f:
186+
f.write('installed')
187+
else:
188+
logger.warning(
189+
f"Playwright browser installation failed: "
190+
f"{playwright_install.stderr}"
191+
)
192+
logger.warning(
193+
"Users may need to run 'npx playwright install' "
194+
"manually"
195+
)
196+
except (FileNotFoundError, OSError) as e:
197+
logger.warning(
198+
f"Failed to install Playwright browsers: {e!s}. "
199+
f"Users may need to run 'npx playwright install' "
200+
f"manually"
201+
)
202+
203+
return npm_cmd, node_cmd

0 commit comments

Comments
 (0)