mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-06-15 17:25:26 -04:00
feat(platform): Add support for APFEL as part of the dependencies and models for the Cookbook. (#2657)
* feat(platform): add support for Apple Silicon detection in platform compatibility test(tests): enhance shell_routes tests for Apple Silicon compatibility * fix issues with missing import * fix: correct package name in package-lock.json and enhance package installation commands in shell_routes.py and cookbook.js * feat: add Apfel startup and health checks on macOS - bootstrap Apfel via Homebrew on arm64 macOS - start `apfel --serve --port 11435` detached for Odysseus - verify readiness via `/health` - clean up the Apfel process on exit or Ctrl+C * fix: duplicate variable declaration post-merge conflict - Should fix `node` CI issues. * fix: issues with the update status of the APFEL dependency. - fixed by changing the main conditional that determines the update. * Fix: Remove unnecessary whitespaces and formatting for the model_routes.py file. * Fix: whitespace issues with the model_routes file * Fix: Remove unnecessary whitespaces and formatting for the model_routes.py file. Final * Fix: Fixed updates using PIP for APFEL instead of custom cmd
This commit is contained in:
committed by
GitHub
parent
8f2c8d2dc8
commit
8d9d4ec9c6
+89
-68
@@ -20,14 +20,14 @@ cd "$REPO_DIR"
|
||||
# the command line every run — consistent with how app.py reads them via
|
||||
# python-dotenv. Variables already set in the shell take priority over .env.
|
||||
if [ -f .env ]; then
|
||||
while IFS='=' read -r key value; do
|
||||
[[ "$key" =~ ^[[:space:]]*# ]] && continue
|
||||
[[ -z "${key// }" ]] && continue
|
||||
value="${value%%#*}"
|
||||
value="${value#"${value%%[![:space:]]*}"}"
|
||||
value="${value%"${value##*[![:space:]]}"}"
|
||||
[ -n "$key" ] && [ -z "${!key+x}" ] && export "$key=$value"
|
||||
done < .env
|
||||
while IFS='=' read -r key value; do
|
||||
[[ "$key" =~ ^[[:space:]]*# ]] && continue
|
||||
[[ -z "${key// }" ]] && continue
|
||||
value="${value%%#*}"
|
||||
value="${value#"${value%%[![:space:]]*}"}"
|
||||
value="${value%"${value##*[![:space:]]}"}"
|
||||
[ -n "$key" ] && [ -z "${!key+x}" ] && export "$key=$value"
|
||||
done < .env
|
||||
fi
|
||||
|
||||
# Shell overrides (ODYSSEUS_PORT / ODYSSEUS_HOST) take top priority, then .env
|
||||
@@ -36,7 +36,7 @@ PORT="${ODYSSEUS_PORT:-${APP_PORT:-7860}}" # 7860, not 7000 — macOS AirPlay
|
||||
HOST="${ODYSSEUS_HOST:-${APP_BIND:-127.0.0.1}}" # Set APP_BIND=0.0.0.0 in .env for LAN/Tailscale access.
|
||||
PROBE_HOST="$HOST"
|
||||
if [ "$PROBE_HOST" = "0.0.0.0" ] || [ "$PROBE_HOST" = "::" ]; then
|
||||
PROBE_HOST="127.0.0.1"
|
||||
PROBE_HOST="127.0.0.1"
|
||||
fi
|
||||
|
||||
# Friendly message on any failure — re-running is safe (every step is idempotent).
|
||||
@@ -46,20 +46,20 @@ echo "▶ Odysseus quick start for macOS"
|
||||
|
||||
# Fail fast if the port is already taken (e.g. a previous run still running).
|
||||
if (exec 3<>"/dev/tcp/$PROBE_HOST/$PORT") 2>/dev/null; then
|
||||
echo "✗ Port $PORT is already in use on $PROBE_HOST. Stop what's using it, or pick another port:"
|
||||
echo " ODYSSEUS_PORT=7900 ./start-macos.sh"
|
||||
exit 1
|
||||
echo "✗ Port $PORT is already in use on $PROBE_HOST. Stop what's using it, or pick another port:"
|
||||
echo " ODYSSEUS_PORT=7900 ./start-macos.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 1. Homebrew — the macOS package manager. We can't safely auto-install it
|
||||
# (it wants its own interactive confirmation), so point the user at it.
|
||||
if ! command -v brew >/dev/null 2>&1; then
|
||||
echo
|
||||
echo "Homebrew is required but not installed. Install it (one command), then re-run this script:"
|
||||
echo ' /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"'
|
||||
echo
|
||||
echo "More info: https://brew.sh"
|
||||
exit 1
|
||||
echo
|
||||
echo "Homebrew is required but not installed. Install it (one command), then re-run this script:"
|
||||
echo ' /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"'
|
||||
echo
|
||||
echo "More info: https://brew.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 2. Find a Python 3.11+ to build the environment with.
|
||||
@@ -72,15 +72,15 @@ fi
|
||||
# (or non-mac) we just use whatever Python 3.11+ is on PATH.
|
||||
PY=""
|
||||
if [ "$(uname -m)" = "arm64" ]; then
|
||||
cands="/opt/homebrew/bin/python3.13 /opt/homebrew/bin/python3.12 /opt/homebrew/bin/python3.11"
|
||||
cands="/opt/homebrew/bin/python3.13 /opt/homebrew/bin/python3.12 /opt/homebrew/bin/python3.11"
|
||||
else
|
||||
cands="python3 python3.13 python3.12 python3.11"
|
||||
cands="python3 python3.13 python3.12 python3.11"
|
||||
fi
|
||||
for cand in $cands; do
|
||||
p="$(command -v "$cand" 2>/dev/null)" || continue
|
||||
if "$p" -c 'import sys; raise SystemExit(0 if sys.version_info[:2] >= (3, 11) else 1)' 2>/dev/null; then
|
||||
PY="$p"; break
|
||||
fi
|
||||
p="$(command -v "$cand" 2>/dev/null)" || continue
|
||||
if "$p" -c 'import sys; raise SystemExit(0 if sys.version_info[:2] >= (3, 11) else 1)' 2>/dev/null; then
|
||||
PY="$p"; break
|
||||
fi
|
||||
done
|
||||
|
||||
# System dependencies (each installed only if missing, so re-runs stay fast and
|
||||
@@ -98,40 +98,41 @@ done
|
||||
# Install a Homebrew formula only if its command isn't already present. A failed
|
||||
# install warns but does not abort — Cookbook can be set up later.
|
||||
brew_ensure() {
|
||||
if command -v "$1" >/dev/null 2>&1; then
|
||||
echo " ✓ $2 already installed"
|
||||
return 0
|
||||
fi
|
||||
echo " installing $2…"
|
||||
if ! brew install "$2"; then
|
||||
echo " ⚠ Couldn't install $2 right now — Cookbook (local model serving) may be limited."
|
||||
echo " You can install it later with: brew install $2"
|
||||
fi
|
||||
if command -v "$1" >/dev/null 2>&1; then
|
||||
echo " ✓ $2 already installed"
|
||||
return 0
|
||||
fi
|
||||
echo " installing $2…"
|
||||
if ! brew install "$2"; then
|
||||
echo " ⚠ Couldn't install $2 right now — Cookbook (local model serving) may be limited."
|
||||
echo " You can install it later with: brew install $2"
|
||||
fi
|
||||
}
|
||||
|
||||
echo "▶ Checking dependencies (Homebrew)…"
|
||||
if [ -n "$PY" ]; then
|
||||
echo " (using $("$PY" --version 2>&1) at $PY)"
|
||||
echo " (using $("$PY" --version 2>&1) at $PY)"
|
||||
else
|
||||
echo " installing python@3.11…"
|
||||
brew install python@3.11 || true
|
||||
PY="$(command -v /opt/homebrew/bin/python3.11 || command -v python3.11 || true)"
|
||||
echo " installing python@3.11…"
|
||||
brew install python@3.11 || true
|
||||
PY="$(command -v /opt/homebrew/bin/python3.11 || command -v python3.11 || true)"
|
||||
fi
|
||||
brew_ensure tmux tmux
|
||||
brew_ensure llama-server llama.cpp
|
||||
brew_ensure apfel apfel
|
||||
|
||||
if [ -z "$PY" ] || [ ! -x "$PY" ]; then
|
||||
echo "✗ Couldn't find a Python 3.11+ to build the environment with."
|
||||
echo " Check: ls /opt/homebrew/bin/python3* (or install one: brew install python@3.11)"
|
||||
exit 1
|
||||
echo "✗ Couldn't find a Python 3.11+ to build the environment with."
|
||||
echo " Check: ls /opt/homebrew/bin/python3* (or install one: brew install python@3.11)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 3. Python environment + dependencies (kept inside the repo, in venv/).
|
||||
# Named `venv` to match the manual steps and build-macos-app.sh, so the
|
||||
# clickable .app reuses this same environment.
|
||||
if [ ! -d venv ]; then
|
||||
echo "▶ Creating Python environment…"
|
||||
"$PY" -m venv venv
|
||||
echo "▶ Creating Python environment…"
|
||||
"$PY" -m venv venv
|
||||
fi
|
||||
VENV_PY="./venv/bin/python3"
|
||||
REQ_HASH="$(md5 -q requirements.txt 2>/dev/null || md5sum requirements.txt | cut -d' ' -f1)"
|
||||
@@ -150,9 +151,9 @@ fi
|
||||
# it got installed (e.g., from an older requirements-optional.txt), remove
|
||||
# it to prevent ChromaDB from silently failing in HTTP-only mode.
|
||||
if "$VENV_PY" -m pip show chromadb-client >/dev/null 2>&1; then
|
||||
echo "▶ Cleaning up conflicting chromadb-client package…"
|
||||
"$VENV_PY" -m pip uninstall -y chromadb-client
|
||||
"$VENV_PY" -m pip install --force-reinstall chromadb
|
||||
echo "▶ Cleaning up conflicting chromadb-client package…"
|
||||
"$VENV_PY" -m pip uninstall -y chromadb-client
|
||||
"$VENV_PY" -m pip install --force-reinstall chromadb
|
||||
fi
|
||||
|
||||
# 4. First-run setup: creates data dirs and prints an initial admin password
|
||||
@@ -161,19 +162,39 @@ fi
|
||||
echo "▶ Preparing Odysseus…"
|
||||
ODYSSEUS_SKIP_RUN_HINT=1 ./venv/bin/python setup.py
|
||||
|
||||
# Local provider bootstrap.
|
||||
# On Apple Silicon macOS, Apfel is treated as a sibling local model server
|
||||
# to Ollama: if Homebrew has it installed, we start its OpenAI-compatible
|
||||
# server on the port next to Ollama, since the default port is 11434 and that's busy (because of ollama).
|
||||
MACHINE_ARCH="$(uname -m)"
|
||||
APFEL_PID=""
|
||||
if [ "$MACHINE_ARCH" = "arm64" ]; then
|
||||
if command -v apfel >/dev/null 2>&1; then
|
||||
APFEL_LOG="${TMPDIR:-/tmp}/odysseus-apfel.log"
|
||||
echo "▶ Starting Apfel server in the background on port 11435…"
|
||||
echo " logging to $APFEL_LOG"
|
||||
nohup apfel --serve --port 11435 >"$APFEL_LOG" 2>&1 &
|
||||
APFEL_PID=$!
|
||||
else
|
||||
echo "▶ Apfel is not installed (brew formula missing); skipping Apfel server bootstrap."
|
||||
fi
|
||||
else
|
||||
echo "▶ Non-ARM macOS detected; skipping Apfel server bootstrap."
|
||||
fi
|
||||
|
||||
# 5. Launch. Bind to loopback by default; opt into LAN/Tailscale with
|
||||
# ODYSSEUS_HOST=0.0.0.0.
|
||||
URL_HOST="$HOST"
|
||||
if [ "$URL_HOST" = "0.0.0.0" ] || [ "$URL_HOST" = "::" ]; then
|
||||
URL_HOST="127.0.0.1"
|
||||
URL_HOST="127.0.0.1"
|
||||
fi
|
||||
URL="http://$URL_HOST:$PORT"
|
||||
TAILSCALE_URL=""
|
||||
if [ "$HOST" = "0.0.0.0" ] && command -v tailscale >/dev/null 2>&1; then
|
||||
TS_IP="$(tailscale ip -4 2>/dev/null | head -n 1 || true)"
|
||||
if [ -n "$TS_IP" ]; then
|
||||
TAILSCALE_URL="http://$TS_IP:$PORT"
|
||||
fi
|
||||
TS_IP="$(tailscale ip -4 2>/dev/null | head -n 1 || true)"
|
||||
if [ -n "$TS_IP" ]; then
|
||||
TAILSCALE_URL="http://$TS_IP:$PORT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Open the browser automatically once the server is accepting connections — so
|
||||
@@ -182,33 +203,33 @@ fi
|
||||
# ODYSSEUS_NO_OPEN=1 (e.g. over SSH / headless).
|
||||
POLLER_PID=""
|
||||
if [ -z "$ODYSSEUS_NO_OPEN" ] && command -v open >/dev/null 2>&1; then
|
||||
(
|
||||
for _ in $(seq 1 90); do
|
||||
if (exec 3<>"/dev/tcp/$PROBE_HOST/$PORT") 2>/dev/null; then
|
||||
printf '\n'
|
||||
printf ' ┌────────────────────────────────────────────┐\n'
|
||||
printf ' │ ✓ Odysseus is ready — opening your browser │\n'
|
||||
printf ' │ %-40s │\n' "$URL"
|
||||
printf ' │ (Press Ctrl+C in this window to stop) │\n'
|
||||
printf ' └────────────────────────────────────────────┘\n\n'
|
||||
open "$URL"
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
) &
|
||||
POLLER_PID=$!
|
||||
(
|
||||
for _ in $(seq 1 90); do
|
||||
if (exec 3<>"/dev/tcp/$PROBE_HOST/$PORT") 2>/dev/null; then
|
||||
printf '\n'
|
||||
printf ' ┌────────────────────────────────────────────┐\n'
|
||||
printf ' │ ✓ Odysseus is ready — opening your browser │\n'
|
||||
printf ' │ %-40s │\n' "$URL"
|
||||
printf ' │ (Press Ctrl+C in this window to stop) │\n'
|
||||
printf ' └────────────────────────────────────────────┘\n\n'
|
||||
open "$URL"
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
) &
|
||||
POLLER_PID=$!
|
||||
fi
|
||||
|
||||
# Setup is done — drop the setup-failure handler, and clean up the background
|
||||
# opener when the server exits or the user presses Ctrl+C.
|
||||
trap - ERR
|
||||
trap '[ -n "$POLLER_PID" ] && kill "$POLLER_PID" 2>/dev/null' EXIT INT TERM
|
||||
trap '[ -n "$POLLER_PID" ] && kill "$POLLER_PID" 2>/dev/null; [ -n "$APFEL_PID" ] && kill "$APFEL_PID" 2>/dev/null' EXIT INT TERM
|
||||
|
||||
echo
|
||||
echo "▶ Starting Odysseus — it will open in your browser at $URL"
|
||||
if [ -n "$TAILSCALE_URL" ]; then
|
||||
echo " Tailscale/LAN URL: $TAILSCALE_URL"
|
||||
echo " Tailscale/LAN URL: $TAILSCALE_URL"
|
||||
fi
|
||||
echo " (this takes a few seconds; press Ctrl+C here to stop)"
|
||||
echo
|
||||
|
||||
Reference in New Issue
Block a user