- 共享引擎(app/src/main):GestureEngine 6 手势识别、AudioEngine 三层音频 (ExoPlayer BGM 交叉淡入 / 对白 ducking / SoundPool 低延迟)、Game/GameEngine 状态机接口、MainActivity 全屏封面 + TalkBack - 《声命线》storyline:末世互动广播剧,3 幕 8 抉择点 4 结局 - 《声东击西》reflex:听声辨位反应,12 波战斗 + BGM 三档 BPM 变速 - 《暗室》escape:3x3 网格密室逃脱,钥匙→铁柜→保险丝→电箱→大门谜题链 - 文档:setup(从零搭建)/ architecture(架构)/ engine-api(引擎 API)/ asset-pipeline(资产流水线)/ games/*(三款游戏设计文档) - 资产管线:Qwen3-TTS 对白 + 程序合成音效/BGM + Mureka BGM 的 gen 脚本与台账, 全部 ogg 资产入库可复现 - env.d 环境脚本:android/tts 入库;sfx/mureka 含密钥不入库,仅提交 .example.sh 模板
136 lines
6.4 KiB
Bash
Executable File
136 lines
6.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# SA3 MLX installer — uv-based.
|
|
#
|
|
# Creates a project-local .venv/ with the right Python and runtime deps,
|
|
# then hands off to install.py for the interactive weight-download prompt.
|
|
#
|
|
# Usage:
|
|
# ./install.sh # auto-detect uv, prompt to install if missing
|
|
# ./install.sh -y # assume yes to "install uv?" prompt
|
|
# ./install.sh --python VER # pin a specific Python (default: 3.11)
|
|
#
|
|
# After install:
|
|
# source .venv/bin/activate
|
|
# python sa3_mlx.py --prompt "lofi house" --dit medium --decoder same-l
|
|
# # or, without activating:
|
|
# .venv/bin/python sa3_mlx.py --prompt "lofi house" --dit medium --decoder same-l
|
|
#
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
VENV_DIR="$SCRIPT_DIR/.venv"
|
|
PY_VERSION_DEFAULT="3.11"
|
|
|
|
# ── colours ─────────────────────────────────────────────────────────────────
|
|
if [[ -t 1 ]]; then
|
|
BOLD=$'\033[1m'; CYAN=$'\033[1;36m'; RED=$'\033[1;31m'
|
|
YELLOW=$'\033[1;33m'; GREEN=$'\033[1;32m'; DIM=$'\033[2m'; RESET=$'\033[0m'
|
|
else
|
|
BOLD=""; CYAN=""; RED=""; YELLOW=""; GREEN=""; DIM=""; RESET=""
|
|
fi
|
|
step() { printf '\n%s→ %s%s\n' "$CYAN" "$1" "$RESET"; }
|
|
fail() { printf '%serror%s: %s\n' "$RED" "$RESET" "$1" >&2; }
|
|
warn() { printf '%swarning%s: %s\n' "$YELLOW" "$RESET" "$1" >&2; }
|
|
ok() { printf ' %s✓%s %s\n' "$GREEN" "$RESET" "$1"; }
|
|
|
|
# ── arg parsing ─────────────────────────────────────────────────────────────
|
|
ASSUME_YES=0
|
|
PY_VERSION="$PY_VERSION_DEFAULT"
|
|
EXTRA_ARGS=()
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
-y|--yes) ASSUME_YES=1; shift ;;
|
|
--python) PY_VERSION="$2"; shift 2 ;;
|
|
--python=*) PY_VERSION="${1#--python=}"; shift ;;
|
|
-h|--help)
|
|
sed -n '2,/^set -euo/p' "$0" | sed -e '$d' -e 's/^# \{0,1\}//'
|
|
exit 0 ;;
|
|
*) EXTRA_ARGS+=("$1"); shift ;;
|
|
esac
|
|
done
|
|
|
|
# ── platform sanity ─────────────────────────────────────────────────────────
|
|
OS="$(uname -s)"; ARCH="$(uname -m)"
|
|
if [[ "$OS" != "Darwin" || "$ARCH" != "arm64" ]]; then
|
|
warn "this stack is Apple-Silicon-only (MLX is Metal-backed). Detected $OS/$ARCH — installs will probably fail."
|
|
fi
|
|
|
|
# ── ensure uv is installed ──────────────────────────────────────────────────
|
|
ensure_uv() {
|
|
if command -v uv >/dev/null 2>&1; then
|
|
ok "uv $(uv --version 2>/dev/null | awk '{print $2}') already installed at $(command -v uv)"
|
|
return 0
|
|
fi
|
|
|
|
step "uv not found — uv is required (much faster than pip, also manages Python versions)"
|
|
if [[ "$ASSUME_YES" -ne 1 ]]; then
|
|
printf ' Install uv now via the official installer? (curl + sh) %s[Y/n]%s ' "$DIM" "$RESET"
|
|
read -r REPLY < /dev/tty
|
|
case "$REPLY" in
|
|
""|y|Y|yes|YES) ;;
|
|
*)
|
|
fail "install aborted — install uv manually then re-run:"
|
|
printf ' curl -LsSf https://astral.sh/uv/install.sh | sh\n' >&2
|
|
printf ' or: brew install uv\n' >&2
|
|
exit 1 ;;
|
|
esac
|
|
fi
|
|
|
|
step "Installing uv (curl -LsSf https://astral.sh/uv/install.sh | sh)"
|
|
if ! curl -LsSf https://astral.sh/uv/install.sh | sh; then
|
|
fail "uv installer failed. Try a manual install:"
|
|
printf ' brew install uv\n' >&2
|
|
exit 1
|
|
fi
|
|
# The installer drops uv at ~/.local/bin/uv (or $XDG_BIN_HOME)
|
|
export PATH="$HOME/.local/bin:${XDG_BIN_HOME:-}:$PATH"
|
|
if ! command -v uv >/dev/null 2>&1; then
|
|
fail "uv was installed but isn't on PATH. Add ~/.local/bin to PATH, restart your shell, and re-run install.sh."
|
|
exit 1
|
|
fi
|
|
ok "uv $(uv --version | awk '{print $2}') installed"
|
|
}
|
|
|
|
ensure_uv
|
|
|
|
# ── create venv (uv auto-installs the requested Python if missing) ──────────
|
|
step "Creating virtual environment at .venv/ with Python $PY_VERSION"
|
|
if [[ -d "$VENV_DIR" ]]; then
|
|
EXISTING_PY=$("$VENV_DIR/bin/python" -c 'import sys; print(".".join(map(str, sys.version_info[:2])))' 2>/dev/null || echo "unknown")
|
|
if [[ "$EXISTING_PY" == "$PY_VERSION"* ]]; then
|
|
ok "reusing existing .venv (Python $EXISTING_PY)"
|
|
else
|
|
warn "existing .venv uses Python $EXISTING_PY (wanted $PY_VERSION) — recreating"
|
|
rm -rf "$VENV_DIR"
|
|
uv venv --seed --python "$PY_VERSION" "$VENV_DIR"
|
|
fi
|
|
else
|
|
uv venv --seed --python "$PY_VERSION" "$VENV_DIR"
|
|
fi
|
|
|
|
# ── install runtime deps ────────────────────────────────────────────────────
|
|
step "Installing dependencies (uv pip install -r requirements.txt)"
|
|
VIRTUAL_ENV="$VENV_DIR" uv pip install -r "$SCRIPT_DIR/requirements.txt"
|
|
|
|
# ── ffmpeg (optional) ────────────────────────────────────────────────────────
|
|
# Soft dependency: dataset decode already works via libsndfile (bundled with the
|
|
# soundfile wheel just installed), and training demos fall back to WAV without
|
|
# ffmpeg. It's only needed for compact MP3 demos + sa3_mlx.py's exotic-WAV
|
|
# fallback path — so a missing ffmpeg is a warning, never a failure.
|
|
step "Checking for ffmpeg (optional)"
|
|
if command -v ffmpeg >/dev/null 2>&1; then
|
|
ok "ffmpeg found at $(command -v ffmpeg)"
|
|
else
|
|
warn "ffmpeg not found — demos will save as WAV (larger); exotic-format audio"
|
|
warn " loading is disabled. Install it (fast, prebuilt bottle on Apple Silicon):"
|
|
printf ' %sbrew install ffmpeg%s\n' "$BOLD" "$RESET" >&2
|
|
fi
|
|
|
|
# ── hand off to install.py ──────────────────────────────────────────────────
|
|
# Any unrecognized args we collected (e.g. --download medium,sm-music) get
|
|
# forwarded to install.py via EXTRA_ARGS.
|
|
step "Bundle picker"
|
|
INSTALL_SKIP_PIP=1 exec "$VENV_DIR/bin/python" "$SCRIPT_DIR/scripts/install.py" \
|
|
"${EXTRA_ARGS[@]+"${EXTRA_ARGS[@]}"}"
|