-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinstall.sh
More file actions
executable file
·283 lines (249 loc) · 10.5 KB
/
install.sh
File metadata and controls
executable file
·283 lines (249 loc) · 10.5 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
#!/bin/bash
set -e
# ============================================================================
# Output formatting
# ============================================================================
BOLD='\033[1m'
RESET='\033[0m'
log() { echo -e "${BOLD}$1${RESET}"; }
info() { log "✨ $1"; }
tip() { log "💡 $1"; }
warn() { log "⚠️ $1"; }
error() { log "❌ $1" >&2; }
success() { echo -e "✔️ $1\n"; }
# ============================================================================
# Platform detection
# ============================================================================
case "$(uname -s)" in
Darwin) PLATFORM=darwin ;;
Linux) PLATFORM=linux ;;
*) error "Unsupported platform: $(uname -s)"; exit 1 ;;
esac
# ============================================================================
# Configuration
# ============================================================================
PYTHON_VERSION="${PYTHON_VERSION:-3.11}"
GITHUB_REPO="${GITHUB_REPO:-https://github.com/codesmax/chocopi.git}"
if [[ "$PLATFORM" == "darwin" ]]; then
INSTALL_DIR="${CHOCOPI_DIR:-$HOME/chocopi}"
else
CHOCOPI_USER="${CHOCOPI_USER:-chocopi}"
CHOCOPI_HOME="/home/${CHOCOPI_USER}"
INSTALL_DIR="${CHOCOPI_INSTALL_DIR:-/opt/chocopi}"
if [[ ! -f /etc/debian_version ]]; then
error "This installer requires a Debian-based Linux distribution"
exit 1
fi
if [[ -f /proc/cpuinfo ]] && grep -q "Raspberry Pi" /proc/cpuinfo; then
if [[ "$(uname -m)" != "aarch64" ]]; then
warn "Running on Raspberry Pi with '$(uname -m)' architecture. For best performance, use a 64-bit Raspberry Pi OS (aarch64)."
fi
fi
fi
# ============================================================================
# Installation summary
# ============================================================================
info "Installing ChocoPi Language Tutor..."
echo
if [[ "$PLATFORM" == "darwin" ]]; then
echo "This script will:"
echo " • Install Homebrew (if needed)"
echo " • Install portaudio and uv via Homebrew"
echo " • Clone/update ChocoPi to ${INSTALL_DIR}"
echo " • Set up Python ${PYTHON_VERSION} virtual environment and dependencies"
echo " • Optionally configure API key"
else
echo "This script will:"
echo " • Install system dependencies (pipewire, python3, etc.)"
echo " • Create '${CHOCOPI_USER}' user with limited privileges"
echo " • Clone/update ChocoPi to ${INSTALL_DIR}"
echo " • Set up Python ${PYTHON_VERSION} virtual environment and dependencies"
echo " • Configure PipeWire/WirePlumber for Bluetooth audio"
echo " • Install and enable systemd service"
fi
echo
read -p "Continue with installation? [Y/n] " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]] && [[ -n $REPLY ]]; then
info "Installation cancelled"
exit 0
fi
# ============================================================================
# System dependencies
# ============================================================================
if [[ "$PLATFORM" == "darwin" ]]; then
if ! command -v brew &>/dev/null; then
info "Installing Homebrew..."
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
eval "$(/opt/homebrew/bin/brew shellenv)" 2>/dev/null || \
eval "$(/usr/local/bin/brew shellenv)" 2>/dev/null || true
fi
success "Homebrew ready"
info "Installing portaudio..."
brew install portaudio
success "portaudio installed"
if ! command -v uv &>/dev/null; then
info "Installing uv..."
brew install uv
fi
success "uv ready"
else
info "Installing system dependencies..."
sudo apt update
sudo apt install -y git pipx libportaudio2 libasound2-dev libegl1 libegl-dev pipewire pipewire-audio pulseaudio-utils
success "System dependencies installed"
if ! id "${CHOCOPI_USER}" &>/dev/null; then
info "Creating ${CHOCOPI_USER} user..."
sudo useradd -m -s /bin/bash -G audio,video,render,bluetooth "${CHOCOPI_USER}"
success "User ${CHOCOPI_USER} created"
info "Enabling systemd linger for ${CHOCOPI_USER}..."
sudo loginctl enable-linger "${CHOCOPI_USER}"
success "Systemd linger enabled"
fi
if [[ ! -d "${INSTALL_DIR}" ]]; then
info "Setting up application directory..."
sudo mkdir -p "${INSTALL_DIR}"
sudo chown "${CHOCOPI_USER}:${CHOCOPI_USER}" "${INSTALL_DIR}"
success "Application directory created at ${INSTALL_DIR}"
fi
info "Installing uv for ${CHOCOPI_USER}..."
sudo -u "${CHOCOPI_USER}" pipx install uv
sudo -u "${CHOCOPI_USER}" pipx ensurepath
success "uv installed"
fi
# ============================================================================
# Clone or update repository
# ============================================================================
if [[ ! -d "${INSTALL_DIR}/.git" ]]; then
info "Cloning ChocoPi to ${INSTALL_DIR}..."
if [[ "$PLATFORM" == "darwin" ]]; then
git clone "${GITHUB_REPO}" "${INSTALL_DIR}"
else
sudo -u "${CHOCOPI_USER}" git clone "${GITHUB_REPO}" "${INSTALL_DIR}"
fi
success "Repository cloned"
else
info "Repository already exists, updating..."
if [[ "$PLATFORM" == "darwin" ]]; then
git -C "${INSTALL_DIR}" pull
else
sudo -u "${CHOCOPI_USER}" git -C "${INSTALL_DIR}" pull
fi
success "Repository updated"
fi
# ============================================================================
# Python environment
# ============================================================================
info "Setting up Python ${PYTHON_VERSION} environment..."
if [[ "$PLATFORM" == "darwin" ]]; then
uv venv "${INSTALL_DIR}/.venv" --python "${PYTHON_VERSION}"
uv pip install -e "${INSTALL_DIR}" --python "${INSTALL_DIR}/.venv/bin/python"
chmod +x "${INSTALL_DIR}/chocopi"
else
UV="${CHOCOPI_HOME}/.local/bin/uv"
sudo -u "${CHOCOPI_USER}" "$UV" venv "${INSTALL_DIR}/.venv" --clear --python "${PYTHON_VERSION}"
sudo -u "${CHOCOPI_USER}" "$UV" pip install -e "${INSTALL_DIR}" --python "${INSTALL_DIR}/.venv/bin/python"
sudo chmod +x "${INSTALL_DIR}/chocopi"
fi
success "Python environment configured"
# ============================================================================
# Linux: audio and service setup
# ============================================================================
if [[ "$PLATFORM" == "linux" ]]; then
info "Configuring PipeWire/WirePlumber for Bluetooth audio..."
WP_VERSION=$(dpkg-query -W -f='${Version}' wireplumber 2>/dev/null | grep -oP '^\d+\.\d+' || echo "0.5")
WP_MAJOR=$(echo "$WP_VERSION" | cut -d. -f1)
WP_MINOR=$(echo "$WP_VERSION" | cut -d. -f2)
if [[ "$WP_MAJOR" -eq 0 ]] && [[ "$WP_MINOR" -lt 5 ]]; then
log "🔎 Detected WirePlumber ${WP_VERSION} (Lua config)"
WP_CONFIG_DIR="${CHOCOPI_HOME}/.config/wireplumber/bluetooth.lua.d"
WP_CONFIG_FILE="51-bluetooth-audio.lua"
else
log "🔎 Detected WirePlumber ${WP_VERSION} (conf format)"
WP_CONFIG_DIR="${CHOCOPI_HOME}/.config/wireplumber/wireplumber.conf.d"
WP_CONFIG_FILE="51-bluetooth-audio.conf"
fi
if [[ -f "${INSTALL_DIR}/install/wireplumber/${WP_CONFIG_FILE}" ]]; then
sudo -u "${CHOCOPI_USER}" mkdir -p "${WP_CONFIG_DIR}"
sudo -u "${CHOCOPI_USER}" cp "${INSTALL_DIR}/install/wireplumber/${WP_CONFIG_FILE}" "${WP_CONFIG_DIR}/"
success "WirePlumber Bluetooth config installed"
fi
PW_EC_SRC="${INSTALL_DIR}/install/pipewire/99-echo-cancel.conf"
if [[ -f "${PW_EC_SRC}" ]]; then
PW_CONFIG_DIR="${CHOCOPI_HOME}/.config/pipewire/pipewire.conf.d"
sudo -u "${CHOCOPI_USER}" mkdir -p "${PW_CONFIG_DIR}"
sudo -u "${CHOCOPI_USER}" cp "${PW_EC_SRC}" "${PW_CONFIG_DIR}/"
success "PipeWire echo cancellation config installed"
fi
info "Restarting WirePlumber..."
sudo -u "${CHOCOPI_USER}" XDG_RUNTIME_DIR=/run/user/$(id -u "${CHOCOPI_USER}") systemctl --user restart wireplumber
success "PipeWire and Bluetooth services configured"
info "Installing systemd service..."
sudo cp "${INSTALL_DIR}/install/systemd/chocopi.service" /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable chocopi
success "Systemd service installed and enabled"
fi
# ============================================================================
# API key
# ============================================================================
info "Configuring API key..."
read -p "Enter your OpenAI API key (or press Enter to configure later): " API_KEY
if [[ -n "$API_KEY" ]]; then
if [[ "$PLATFORM" == "darwin" ]]; then
echo "OPENAI_API_KEY=${API_KEY}" > "${INSTALL_DIR}/.env"
chmod 600 "${INSTALL_DIR}/.env"
else
echo "OPENAI_API_KEY=${API_KEY}" | sudo tee "${INSTALL_DIR}/.env" > /dev/null
sudo chown "${CHOCOPI_USER}:${CHOCOPI_USER}" "${INSTALL_DIR}/.env"
sudo chmod 600 "${INSTALL_DIR}/.env"
fi
success ".env file created"
else
tip "To configure later:"
if [[ "$PLATFORM" == "darwin" ]]; then
echo " echo 'OPENAI_API_KEY=your_key_here' > ${INSTALL_DIR}/.env"
echo " chmod 600 ${INSTALL_DIR}/.env"
else
echo " echo 'OPENAI_API_KEY=your_key_here' | sudo tee ${INSTALL_DIR}/.env"
echo " sudo chown ${CHOCOPI_USER}:${CHOCOPI_USER} ${INSTALL_DIR}/.env"
echo " sudo chmod 600 ${INSTALL_DIR}/.env"
fi
echo
fi
# ============================================================================
# Done
# ============================================================================
echo
log "🎉 Installation complete!"
echo
if [[ "$PLATFORM" == "linux" ]]; then
if [[ -n "$API_KEY" ]]; then
info "Starting ChocoPi service..."
sudo systemctl start chocopi
echo
info "Service status:"
sudo systemctl status chocopi --no-pager -l
echo
else
tip "Then start the service:"
echo " sudo systemctl start chocopi"
echo
fi
tip "Helpful commands:"
echo " sudo systemctl status chocopi # Check status"
echo " sudo journalctl -u chocopi -f # View logs"
echo
tip "To pair a Bluetooth audio device:"
echo " sudo -u ${CHOCOPI_USER} bluetoothctl"
echo " scan on; pair <MAC>; trust <MAC>; connect <MAC>; exit"
echo
else
tip "To run ChocoPi:"
echo " cd ${INSTALL_DIR} && ./chocopi"
echo
tip "Audio troubleshooting:"
echo " python -m sounddevice # list audio devices"
echo
fi
tip "See README.md for configuration and usage."