-
Notifications
You must be signed in to change notification settings - Fork 18
Expand file tree
/
Copy pathinstall.sh
More file actions
executable file
·350 lines (313 loc) · 13.2 KB
/
Copy pathinstall.sh
File metadata and controls
executable file
·350 lines (313 loc) · 13.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
#!/usr/bin/env bash
#
# HugAgentOS one-command installer for the personal, no-Docker profile.
#
# Usage:
# curl -fsSL https://raw.githubusercontent.com/ZJU-REAL/HugAgentOS/main/install.sh | bash
#
# Optional locations:
# HUGAGENT_HOME=$HOME/.hugagent
# HUGAGENT_SOURCE_DIR=$HOME/.hugagent/source
set -euo pipefail
REPOSITORY_URL="https://github.com/ZJU-REAL/HugAgentOS.git"
REPOSITORY_BRANCH="main"
HUGAGENT_DATA_DIR="${HUGAGENT_HOME:-${HOME}/.hugagent}"
SOURCE_DIR="${HUGAGENT_SOURCE_DIR:-${HUGAGENT_DATA_DIR}/source}"
VENV_DIR="${HUGAGENT_DATA_DIR}/venv"
CJK_FONT_DIR="${HUGAGENT_DATA_DIR}/fonts"
if [[ -t 1 ]]; then
GREEN=$'\033[32m'
YELLOW=$'\033[33m'
RED=$'\033[31m'
RESET=$'\033[0m'
else
GREEN=""
YELLOW=""
RED=""
RESET=""
fi
info() {
printf '%s> %s%s\n' "${GREEN}" "$*" "${RESET}"
}
warn() {
printf '%s! %s%s\n' "${YELLOW}" "$*" "${RESET}"
}
die() {
printf '%sx %s%s\n' "${RED}" "$*" "${RESET}" >&2
exit 1
}
command -v git >/dev/null 2>&1 || die "Git is required. Install Git and run this command again."
command -v curl >/dev/null 2>&1 || die "curl is required. Install curl and run this command again."
PYTHON_BIN="${PYTHON:-python3}"
command -v "${PYTHON_BIN}" >/dev/null 2>&1 || die "Python 3.11 or later is required."
"${PYTHON_BIN}" - <<'PYTHON_CHECK' || die "Python 3.11 or later is required."
import sys
raise SystemExit(0 if sys.version_info >= (3, 11) else 1)
PYTHON_CHECK
# AgentScope pulls the Python ripgrep package. On Linux, PyPI only provides a
# prebuilt wheel for x86_64 + glibc 2.39 or newer; other Linux targets build it
# from source and therefore need a Rust toolchain.
NEEDS_RUST="$("${PYTHON_BIN}" - <<'PYTHON_RUST_CHECK'
import platform
import re
import sys
needs_rust = False
if sys.platform.startswith("linux"):
machine = platform.machine().lower()
libc_name, libc_version = platform.libc_ver()
parts = tuple(int(x) for x in re.findall(r"\d+", libc_version)[:2])
has_compatible_wheel = (
machine in {"x86_64", "amd64"}
and libc_name.lower() == "glibc"
and parts >= (2, 39)
)
needs_rust = not has_compatible_wheel
print("yes" if needs_rust else "no")
PYTHON_RUST_CHECK
)"
if [[ "${NEEDS_RUST}" == "yes" ]] && ! command -v cargo >/dev/null 2>&1; then
die "Rust/Cargo is required on this Linux platform to build the ripgrep dependency. Install the current stable Rust toolchain and run this command again."
fi
command -v node >/dev/null 2>&1 || die "Node.js 20 or later is required to build the web application."
command -v npm >/dev/null 2>&1 || die "npm is required to build the web application."
NODE_MAJOR="$(node -p 'Number(process.versions.node.split(".")[0])')"
[[ "${NODE_MAJOR}" =~ ^[0-9]+$ ]] || die "Unable to determine the Node.js version."
(( NODE_MAJOR >= 20 )) || die "Node.js 20 or later is required. Found $(node --version)."
info "Python: $("${PYTHON_BIN}" --version 2>&1)"
info "Node.js: $(node --version)"
mkdir -p "${HUGAGENT_DATA_DIR}" "${CJK_FONT_DIR}"
has_libreoffice() {
command -v libreoffice >/dev/null 2>&1 ||
command -v soffice >/dev/null 2>&1 ||
[[ -x /Applications/LibreOffice.app/Contents/MacOS/soffice ]]
}
run_as_root() {
if (( EUID == 0 )); then
"$@"
return
fi
command -v sudo >/dev/null 2>&1 || return 1
if sudo -n true >/dev/null 2>&1; then
sudo "$@"
elif [[ -r /dev/tty && -w /dev/tty ]]; then
sudo "$@" </dev/tty
else
return 1
fi
}
install_libreoffice() {
if command -v apt-get >/dev/null 2>&1; then
run_as_root apt-get update &&
run_as_root env DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
libreoffice-impress libreoffice-writer libreoffice-calc
elif command -v dnf >/dev/null 2>&1; then
run_as_root dnf install -y libreoffice-impress libreoffice-writer libreoffice-calc
elif command -v yum >/dev/null 2>&1; then
run_as_root yum install -y libreoffice-impress libreoffice-writer libreoffice-calc
elif command -v apk >/dev/null 2>&1; then
run_as_root apk add --no-cache libreoffice
elif command -v pacman >/dev/null 2>&1; then
run_as_root pacman -S --needed --noconfirm libreoffice-fresh
elif command -v brew >/dev/null 2>&1; then
brew install --cask libreoffice
else
return 1
fi
}
libreoffice_install_hint() {
if command -v apt-get >/dev/null 2>&1; then
echo "sudo apt-get update && sudo apt-get install -y libreoffice-impress libreoffice-writer libreoffice-calc"
elif command -v dnf >/dev/null 2>&1; then
echo "sudo dnf install -y libreoffice-impress libreoffice-writer libreoffice-calc"
elif command -v yum >/dev/null 2>&1; then
echo "sudo yum install -y libreoffice-impress libreoffice-writer libreoffice-calc"
elif command -v apk >/dev/null 2>&1; then
echo "sudo apk add libreoffice"
elif command -v pacman >/dev/null 2>&1; then
echo "sudo pacman -S --needed libreoffice-fresh"
elif command -v brew >/dev/null 2>&1; then
echo "brew install --cask libreoffice"
else
echo "Install LibreOffice with your system package manager"
fi
}
wants_libreoffice_install() {
case "${HUGAGENT_INSTALL_LIBREOFFICE:-ask}" in
1|true|TRUE|yes|YES) return 0 ;;
0|false|FALSE|no|NO) return 1 ;;
ask|"") ;;
*) warn "Ignoring invalid HUGAGENT_INSTALL_LIBREOFFICE value; expected 1 or 0." ;;
esac
# `curl ... | bash` consumes stdin, so read the answer from the controlling
# terminal. Non-interactive installs skip this optional dependency unless
# HUGAGENT_INSTALL_LIBREOFFICE=1 is set explicitly.
if [[ -t 1 && -r /dev/tty ]]; then
local answer
printf '%sLibreOffice is optional. Install it now for PPT/Word previews and Office-to-PDF conversion? [Y/n] %s' "${YELLOW}" "${RESET}" >/dev/tty
IFS= read -r answer </dev/tty || return 1
case "${answer}" in
""|y|Y|yes|YES) return 0 ;;
*) return 1 ;;
esac
fi
return 1
}
# LibreOffice remains optional, but surface the affected features during
# installation instead of waiting for the first Office preview to fail.
if ! has_libreoffice; then
warn "LibreOffice wasn't found. PPT/Word online preview and Office-to-PDF conversion will be unavailable; document generation and download still work."
if wants_libreoffice_install; then
info "Installing LibreOffice for PPT and Word previews"
install_libreoffice || warn "LibreOffice couldn't be installed automatically."
else
warn "Skipping optional LibreOffice installation."
fi
fi
if has_libreoffice; then
info "LibreOffice is ready for PPT and Word previews"
else
warn "Continuing without LibreOffice. Install it later and restart HugAgentOS to enable the affected features."
warn "Manual install: $(libreoffice_install_hint)"
fi
has_local_cjk_font() {
local candidate
for candidate in \
"${CJK_FONT_DIR}"/*.[tT][tT][fFcC] \
"${CJK_FONT_DIR}"/*.[oO][tT][fF]; do
[[ -f "${candidate}" ]] && return 0
done
return 1
}
# PDF Agent Skills need a Unicode font to render Chinese instead of square
# placeholders. Prefer an existing system font; otherwise download and unpack
# WenQuanYi into the user's HugAgentOS data directory without requiring root.
if [[ ! -f /usr/share/fonts/truetype/wqy/wqy-zenhei.ttc ]] && ! has_local_cjk_font; then
if command -v apt-get >/dev/null 2>&1 && command -v dpkg-deb >/dev/null 2>&1; then
info "Installing a local CJK font for PDF Agent Skills"
FONT_PACKAGE_DIR="$(mktemp -d)"
if (
cd "${FONT_PACKAGE_DIR}"
apt-get download fonts-wqy-zenhei >/dev/null 2>&1
FONT_PACKAGE="$(find . -maxdepth 1 -type f -name 'fonts-wqy-zenhei_*.deb' -print -quit)"
[[ -n "${FONT_PACKAGE}" ]]
dpkg-deb -x "${FONT_PACKAGE}" extracted
FONT_FILE="$(find extracted -type f -iname 'wqy-zenhei.ttc' -print -quit)"
[[ -n "${FONT_FILE}" ]]
cp "${FONT_FILE}" "${CJK_FONT_DIR}/wqy-zenhei.ttc"
); then
info "Local CJK font is ready"
else
warn "Unable to download a CJK font. PDFs can still be created, but Chinese text may render as square placeholders."
fi
rm -rf -- "${FONT_PACKAGE_DIR}"
else
warn "No supported CJK font was found. PDFs can still be created, but Chinese text may render as square placeholders."
fi
fi
if [[ -e "${SOURCE_DIR}" && ! -d "${SOURCE_DIR}/.git" ]]; then
die "${SOURCE_DIR} exists but is not a Git checkout. Set HUGAGENT_SOURCE_DIR to another path."
fi
if [[ -d "${SOURCE_DIR}/.git" ]]; then
ORIGIN_URL="$(git -C "${SOURCE_DIR}" remote get-url origin 2>/dev/null || true)"
case "${ORIGIN_URL}" in
"${REPOSITORY_URL}"|"https://github.com/ZJU-REAL/HugAgentOS"|"git@github.com:ZJU-REAL/HugAgentOS.git") ;;
*) die "${SOURCE_DIR} points to a different Git repository: ${ORIGIN_URL}" ;;
esac
if [[ -n "$(git -C "${SOURCE_DIR}" status --porcelain)" ]]; then
die "${SOURCE_DIR} contains local changes. Commit or move them before updating HugAgentOS."
fi
info "Updating HugAgentOS in ${SOURCE_DIR}"
git -C "${SOURCE_DIR}" checkout "${REPOSITORY_BRANCH}" >/dev/null
git -C "${SOURCE_DIR}" pull --ff-only origin "${REPOSITORY_BRANCH}"
else
info "Downloading HugAgentOS to ${SOURCE_DIR}"
git clone --depth 1 --branch "${REPOSITORY_BRANCH}" "${REPOSITORY_URL}" "${SOURCE_DIR}"
fi
venv_is_usable() {
[[ -x "${VENV_DIR}/bin/python" ]] || return 1
"${VENV_DIR}/bin/python" -c 'import sys; raise SystemExit(0 if sys.version_info >= (3, 11) else 1)' \
>/dev/null 2>&1 || return 1
if command -v uv >/dev/null 2>&1; then
uv pip list --python "${VENV_DIR}/bin/python" >/dev/null 2>&1
else
"${VENV_DIR}/bin/python" -m pip --version >/dev/null 2>&1
fi
}
if ! venv_is_usable; then
if [[ -d "${VENV_DIR}" ]]; then
warn "The existing virtual environment is incomplete or uses an unsupported Python version; rebuilding it."
fi
if command -v uv >/dev/null 2>&1; then
info "Creating the Python environment with uv"
uv venv --clear "${VENV_DIR}" --python "${PYTHON_BIN}" >/dev/null
else
info "Creating the Python environment with venv"
"${PYTHON_BIN}" -m venv --clear "${VENV_DIR}" || \
die "Unable to create a virtual environment. On Debian/Ubuntu, install python3.11-venv (or python3-venv) and run this command again."
fi
fi
VENV_PYTHON="${VENV_DIR}/bin/python"
if command -v uv >/dev/null 2>&1; then
pip_install() {
uv pip install --python "${VENV_PYTHON}" "$@"
}
else
"${VENV_PYTHON}" -m pip install --quiet --upgrade pip
pip_install() {
"${VENV_PYTHON}" -m pip install --quiet "$@"
}
fi
cd "${SOURCE_DIR}"
info "Installing Python dependencies. This can take several minutes."
pip_install -r requirements.txt
info "Installing memory dependencies"
pip_install -r requirements-mem0.txt
# Install the embedded client/server as a tested pair, and actively reconcile an
# existing venv. PyMilvus 3 calls AllocTimestamp, which the current embedded
# Lite adapter does not implement. Keep Lite 3.1 so existing local data stays in
# the same storage format; protobuf<7 is required by current mem0.
pip_install --upgrade \
"protobuf<7" \
"pymilvus==2.5.18" \
"milvus-lite==3.1.0"
info "Installing Agent Skills Python dependencies"
pip_install -r docker/requirements-script-runner.txt
pip_install --no-deps -e .
SKILL_NODE_DIR="${HUGAGENT_DATA_DIR}/node"
PLAYWRIGHT_BROWSER_DIR="${SKILL_NODE_DIR}/browsers"
info "Installing Agent Skills Node.js dependencies"
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm install --silent --no-audit --no-fund \
--no-package-lock --prefix "${SKILL_NODE_DIR}" pptxgenjs playwright
if PLAYWRIGHT_BROWSERS_PATH="${PLAYWRIGHT_BROWSER_DIR}" \
"${SKILL_NODE_DIR}/node_modules/.bin/playwright" install chromium; then
info "Chromium for PDF rendering is ready"
else
warn "Chromium download failed. Word, Excel, and PPT generation still work; advanced PDF cover rendering will use its fallback."
fi
info "Building the web application"
(
cd src/frontend
npm install --silent --no-audit --no-fund --no-package-lock
BUILD_NODE_OPTIONS="${NODE_OPTIONS:-}"
if [[ "${BUILD_NODE_OPTIONS}" != *"--max-old-space-size="* ]]; then
BUILD_NODE_OPTIONS="${BUILD_NODE_OPTIONS} --max-old-space-size=6144"
fi
VITE_EDITION=ce VITE_DEFAULT_LANGUAGE=en NODE_OPTIONS="${BUILD_NODE_OPTIONS# }" npm run build
)
HUGAGENT_BIN="${VENV_DIR}/bin/hugagent"
[[ -x "${HUGAGENT_BIN}" ]] || die "The HugAgentOS command was not installed correctly."
printf '\n'
info "HugAgentOS is installed."
printf ' Source: %s\n' "${SOURCE_DIR}"
printf ' Data: %s\n' "${HUGAGENT_DATA_DIR}"
printf ' Start: %s\n' "${HUGAGENT_BIN}"
printf '\n'
info "Starting HugAgentOS"
# The CE server seeds admin/admin on a fresh data directory and requires a
# password change immediately after sign-in. Model providers are configured in
# Settings, so the one-command path does not require an interactive wizard.
export HUGAGENT_BOOTSTRAP_DEFAULT_PLUGINS=1
if [[ -t 1 && -r /dev/tty ]]; then
exec "${HUGAGENT_BIN}" serve </dev/tty
fi
exec "${HUGAGENT_BIN}" serve