#!/usr/bin/env bash # ============================================================================= # DEVELOP — Installer dell'intelligenza (Brain) su Linux / Raspberry Pi # Uso: curl -fsSL https://developcontroller.com/install.sh | bash # 100% locale: scarica il Brain, il motore AI e i modelli, imposta l'avvio # automatico (systemd --user) e verifica. Nessun dato esce dal dispositivo. # ============================================================================= set -u PKG_URL="${DEVELOP_PKG_URL:-https://developcontroller.com/develop-brain.tar.gz}" INSTALL_DIR="${DEVELOP_HOME:-$HOME/DEVELOP_BRAIN}" PY="$(command -v python3 || true)" PORT="${BRAIN_PORT:-8088}" TMP="$(mktemp -d)"; trap 'rm -rf "$TMP"' EXIT c_gold="\033[1;33m"; c_ok="\033[1;32m"; c_err="\033[1;31m"; c_off="\033[0m" say(){ printf "${c_gold}• %s${c_off}\n" "$1"; } ok(){ printf "${c_ok}✓ %s${c_off}\n" "$1"; } err(){ printf "${c_err}✗ %s${c_off}\n" "$1" >&2; } SUDO=""; [ "$(id -u)" != "0" ] && command -v sudo >/dev/null 2>&1 && SUDO="sudo" echo "=================================================" echo " DEVELOP — Installa l'intelligenza (Linux/RPi)" echo "=================================================" # 1) Requisiti ----------------------------------------------------------------- [ "$(uname -s)" = "Linux" ] || { err "Questo installer è per Linux/Raspberry. Su Mac usa install.command, su Windows install.ps1."; exit 1; } [ -n "$PY" ] || { err "python3 non trovato. Installalo (es. sudo apt install -y python3 python3-pip)."; exit 1; } command -v curl >/dev/null 2>&1 || { err "curl non trovato."; exit 1; } ARCH="$(uname -m)" ok "Linux $ARCH · python3 OK" # Modello in base alla RAM: 14B solo se >=24GB, altrimenti 8B RAM_GB=$(awk '/MemTotal/{print int($2/1048576)}' /proc/meminfo 2>/dev/null || echo 0) if [ "${RAM_GB:-0}" -ge 24 ]; then MODEL="qwen3:14b"; MODEL_LABEL="Genius 2.0"; else MODEL="qwen3:8b"; MODEL_LABEL="Brain 1.0"; fi ai_label(){ case "$1" in qwen3:14b) echo "Genius 2.0";; qwen3:8b|qwen3:4b) echo "Brain 1.0";; gemma3:4b) echo "modulo visione";; qwen3-vl:4b-instruct) echo "modulo trova oggetti";; nomic-embed-text) echo "modulo memoria";; qwen2.5-coder:7b) echo "modulo sviluppo";; *) echo "componente AI";; esac; } say "RAM ${RAM_GB} GB -> intelligenza $MODEL_LABEL" case "$ARCH" in aarch64|arm64) say "Raspberry/ARM: consigliato Pi 5 con 16 GB; i modelli grandi sono lenti su Pi.";; esac # 2) Pacchetto Brain: dalla CHIAVETTA se presente, altrimenti download -------- say "Preparo l'intelligenza…" mkdir -p "$INSTALL_DIR" SELF_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" 2>/dev/null && pwd || echo .)" BUNDLE="${DEVELOP_BUNDLE_DIR:-}" [ -z "$BUNDLE" ] && { [ -d "$SELF_DIR/motore_ai" ] || [ -d "$SELF_DIR/modelli_ai" ] || [ -f "$SELF_DIR/app/develop-brain.tar.gz" ]; } && BUNDLE="$SELF_DIR" [ -z "$BUNDLE" ] && [ -d "$SELF_DIR/../motore_ai" ] && BUNDLE="$(cd "$SELF_DIR/.." && pwd)" if [ -n "$BUNDLE" ] && [ -f "$BUNDLE/app/develop-brain.tar.gz" ]; then cp "$BUNDLE/app/develop-brain.tar.gz" "$TMP/brain.tar.gz" && ok "Uso il pacchetto dalla chiavetta" elif [ -f "$SELF_DIR/develop-brain.tar.gz" ]; then cp "$SELF_DIR/develop-brain.tar.gz" "$TMP/brain.tar.gz" && ok "Uso il pacchetto dalla chiavetta" elif ! curl -fsSL "$PKG_URL" -o "$TMP/brain.tar.gz"; then err "Pacchetto non trovato (né sulla chiavetta né da $PKG_URL)"; exit 1 fi tar -xzf "$TMP/brain.tar.gz" -C "$INSTALL_DIR" || { err "Estrazione fallita"; exit 1; } [ -f "$INSTALL_DIR/brain_server.py" ] || { err "Pacchetto incompleto."; exit 1; } ok "Intelligenza installata in $INSTALL_DIR" # 3) Dipendenze Python --------------------------------------------------------- say "Preparo le dipendenze…" "$PY" -m pip install --user --quiet pillow 2>/dev/null \ || "$PY" -m pip install --user --quiet --break-system-packages pillow 2>/dev/null \ || $SUDO apt-get install -y python3-pil >/dev/null 2>&1 \ || say "Pillow non installato: analisi immagini ridotta." ok "Dipendenze pronte" # 4) Voce (TTS) ---------------------------------------------------------------- if ! command -v espeak-ng >/dev/null 2>&1; then say "Installo la voce (espeak-ng)…" ( $SUDO apt-get install -y espeak-ng >/dev/null 2>&1 \ || $SUDO dnf install -y espeak-ng >/dev/null 2>&1 \ || $SUDO pacman -S --noconfirm espeak-ng >/dev/null 2>&1 ) \ && ok "Voce pronta" || say "espeak-ng non installato: la voce (TTS) sarà disattiva finché non lo installi." fi # 5) Motore AI locale + modelli ------------------------------------------------ if ! command -v ollama >/dev/null 2>&1; then say "Installo il motore AI locale…" if [ -n "$BUNDLE" ] && [ -f "$BUNDLE/motore_ai/ollama-install.sh" ]; then sh "$BUNDLE/motore_ai/ollama-install.sh" >/dev/null 2>&1 && ok "Motore AI installato (dalla chiavetta)" \ || say "Installazione motore AI dalla chiavetta non riuscita." else curl -fsSL https://ollama.com/install.sh | sh >/dev/null 2>&1 && ok "Motore AI installato" \ || say "Installa il motore AI da ollama.com se voce/visione locale non parte." fi fi ( ollama serve >/dev/null 2>&1 & ) 2>/dev/null sleep 3 if [ -n "$BUNDLE" ] && [ -d "$BUNDLE/modelli_ai/models" ]; then say "Copio i modelli dalla chiavetta (niente download)…" mkdir -p "$HOME/.ollama/models" cp -R "$BUNDLE/modelli_ai/models/." "$HOME/.ollama/models/" 2>/dev/null && ok "Modelli copiati dalla chiavetta" fi say "Preparo i modelli (se non gia' presenti, li scarico — solo la prima volta)…" for m in "$MODEL" gemma3:4b nomic-embed-text qwen2.5-coder:7b qwen3-vl:4b-instruct; do ollama pull "$m" >/dev/null 2>&1 && ok "$(ai_label "$m") pronto" || say "$(ai_label "$m") non scaricato (riprova più tardi)." done # 6) Configurazione locale (nessun segreto) ------------------------------------ if [ ! -f "$INSTALL_DIR/.env" ]; then cat > "$INSTALL_DIR/.env" </dev/null 2>&1; then sha256sum "$1" | cut -d' ' -f1; else shasum -a 256 "$1" | cut -d' ' -f1; fi; } VOICE_DIR="$INSTALL_DIR/models"; VOICE_MODEL="$VOICE_DIR/ggml-base.bin" VOICE_SHA="60ed5bc3dd14eea856493d334349b405782ddcaf0028d4b5df4088345fba2efe" mkdir -p "$VOICE_DIR" if [ "$(sha256_di "$VOICE_MODEL" 2>/dev/null)" != "$VOICE_SHA" ]; then say "Scarico il modello della voce (141 MB, solo la prima volta)…" if curl -fL --retry 2 -s -o "$TMP/ggml-base.bin" "https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.bin" \ && [ "$(sha256_di "$TMP/ggml-base.bin")" = "$VOICE_SHA" ]; then mv "$TMP/ggml-base.bin" "$VOICE_MODEL" && ok "Modello della voce pronto" else say "Modello della voce non scaricato o non verificato: la scrittura a voce resta disattiva." fi fi WH_DIR="$INSTALL_DIR/bin/whisper" case "$ARCH" in x86_64|amd64) WH_ASSET="whisper-bin-ubuntu-x64.tar.gz"; WH_SHA="a72becf15d7917f990f6313867a52638b82b7f9ef237fb0c980dac56a135781c"; WH_TOP="whisper-bin-ubuntu-x64";; aarch64|arm64) WH_ASSET="whisper-bin-ubuntu-arm64.tar.gz"; WH_SHA="6b95ebfc60447df48e70ef00a73bdc3f41679ed2d01ef465827206a2ff325149"; WH_TOP="whisper-bin-ubuntu-arm64";; *) WH_ASSET="";; esac if [ -n "$WH_ASSET" ] && [ ! -x "$WH_DIR/whisper-cli" ]; then say "Scarico il programma di trascrizione vocale (whisper.cpp, licenza MIT)…" if curl -fL --retry 2 -s -o "$TMP/$WH_ASSET" "https://github.com/ggml-org/whisper.cpp/releases/download/b5454/$WH_ASSET" && [ "$(sha256_di "$TMP/$WH_ASSET")" = "$WH_SHA" ]; then mkdir -p "$WH_DIR" && tar -xzf "$TMP/$WH_ASSET" -C "$WH_DIR" --strip-components=1 \ && cat > "$WH_DIR/LICENSE-whisper.cpp.txt" <<'EOFLIC' MIT License Copyright (c) 2023-2026 The ggml authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Fonte: https://github.com/ggml-org/whisper.cpp (release b5454) EOFLIC else say "Programma di trascrizione non scaricato o non verificato: la scrittura a voce resta disattiva." fi fi if [ -x "$WH_DIR/whisper-cli" ]; then if "$WH_DIR/whisper-cli" --help >/dev/null 2>&1; then grep -q '^WHISPER_BIN=' "$INSTALL_DIR/.env" 2>/dev/null || echo "WHISPER_BIN=$WH_DIR/whisper-cli" >> "$INSTALL_DIR/.env" ok "Trascrizione vocale pronta" else say "Il programma di trascrizione non parte su questo sistema: la scrittura a voce resta disattiva." fi fi # 7) Avvio automatico (systemd --user) ----------------------------------------- say "Imposto l'avvio automatico…" mkdir -p "$HOME/.config/systemd/user" cat > "$HOME/.config/systemd/user/develop-brain.service" </dev/null 2>&1 || $SUDO loginctl enable-linger "$USER" >/dev/null 2>&1 || true systemctl --user daemon-reload >/dev/null 2>&1 systemctl --user enable --now develop-brain.service >/dev/null 2>&1 && ok "Avvio automatico attivo" \ || { say "systemd --user non disponibile: avvio in background."; ( cd "$INSTALL_DIR" && nohup "$PY" brain_server.py >brain.out 2>&1 & ); } # 8) Verifica ------------------------------------------------------------------ say "Avvio e verifica…" UP="" for i in $(seq 1 30); do curl -fsS "http://127.0.0.1:$PORT/health" >/dev/null 2>&1 && { UP=1; break; }; sleep 2; done echo if [ -n "$UP" ]; then ok "Intelligenza ATTIVA su http://127.0.0.1:$PORT" if [ -d "$HOME/Desktop" ]; then cat > "$HOME/Desktop/DEVELOP.desktop" </dev/null && ok "Icona 'DEVELOP' creata sul Desktop" fi echo " → Setup e app: http://127.0.0.1:$PORT/setup-check" command -v xdg-open >/dev/null 2>&1 && xdg-open "http://127.0.0.1:$PORT/setup-check" >/dev/null 2>&1 || true else err "Avvio non confermato. Controlla: systemctl --user status develop-brain oppure $INSTALL_DIR/brain.out" fi echo "================================================="