Installer llama.cpp

curl -LsSf https://llama.app/install.sh | sh

Ou clone repo : 

git clone https://github.com/ggml-org/llama.cpp

Installer redis : 

pacman -S redis

Script llama.cpp.sh qui fait le café à placé dans ~/Scripts/ :

#!/bin/bash
set -euo pipefail
# Configuration par défaut
LLAMA_SERVER="/home/perru/Git/models/llama.cpp/build/bin/llama-server"
HOST="0.0.0.0"
PORT="8080"
# Contexte centralisé
#CTX_SIZE="32768"  # 32K tokens
#CTX_SIZE="65536"  # 64K tokens
CTX_SIZE="131072" # 128K tokens
#CTX_SIZE="262144"  # 256K tokens
#CTX_SIZE="524288"  # 512K tokens
THREADS="16"
# Fichiers de configuration persistants
PIDFILE="/tmp/llama-manager.pid"
MODELFILE="/tmp/llama-manager.model"
LOGFILE="/tmp/llama-server.log"
PERSISTENT_STATE="$HOME/.llama_manager_state"
# Configuration Redis
REDIS_HOST="localhost"
REDIS_PORT="6379"
REDIS_PREFIX="llama_conv_"
# Timeout pour le démarrage
START_TIMEOUT=180
# Déclaration des tableaux associatifs
declare -A MODELS
declare -A HF_REPOS
declare -A HF_FILES
declare -A MODEL_DIRS
# ------------------------------------------------------------
# Modèles
# ------------------------------------------------------------
# Qwen
MODELS[qwen]="$HOME/models/qwen3-coder-30b/Qwen3-Coder-30B-A3B-Instruct-Q4_K_M.gguf"
HF_REPOS[qwen]="unsloth/Qwen3-Coder-30B-A3B-Instruct-GGUF"
HF_FILES[qwen]="Qwen3-Coder-30B-A3B-Instruct-Q4_K_M.gguf"
MODEL_DIRS[qwen]="$HOME/models/qwen3-coder-30b"
# Mistral
MODELS[mistral]="$HOME/models/mistral-small-3.2-24b/Mistral-Small-3.2-24B-Instruct-2506-UD-Q4_K_XL.gguf"
HF_REPOS[mistral]="unsloth/Mistral-Small-3.2-24B-Instruct-2506-GGUF"
HF_FILES[mistral]="Mistral-Small-3.2-24B-Instruct-2506-UD-Q4_K_XL.gguf"
MODEL_DIRS[mistral]="$HOME/models/mistral-small-3.2-24b"
# Gemma
MODELS[gemma]="$HOME/models/gemma-4-26b-a4b/gemma-4-26B-A4B-it-UD-IQ4_XS.gguf"
HF_REPOS[gemma]="unsloth/gemma-4-26B-A4B-it-GGUF"
HF_FILES[gemma]="gemma-4-26B-A4B-it-UD-IQ4_XS.gguf"
MODEL_DIRS[gemma]="$HOME/models/gemma-4-26b-a4b"
# ============================================================
# Fonctions utilitaires
# ============================================================
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"
}
# ============================================================
# Fonctions d'affichage du contexte
# ============================================================
show_context_info() {
    log "Context Size: $CTX_SIZE tokens"
    log "Context Size: $((CTX_SIZE / 1024))K tokens"
    # Estimation de la mémoire utilisée par le contexte
    local estimated_mem_mb=$((CTX_SIZE * 4 / 1024))  # Approximation 4 bytes par token
    log "Estimated VRAM usage: ~${estimated_mem_mb} MB"
    # Vérification si le contexte est trop grand
    if [ "$CTX_SIZE" -gt "131072" ]; then
        log "WARNING: Context size > 128K tokens - may cause memory issues"
    elif [ "$CTX_SIZE" -gt "65536" ]; then
        log "INFO: Context size > 64K tokens - running with caution"
    else
        log "INFO: Context size within normal range"
    fi
}
# ============================================================
# Mise à jour de llama.cpp
# ============================================================
update_llama_cpp() {
    local llama_cpp_dir="/home/perru/Git/models/llama.cpp"
    log "Updating llama.cpp..."
    # Vérifier si le répertoire existe
    if [[ ! -d "$llama_cpp_dir" ]]; then
        log "ERROR: llama.cpp directory not found at $llama_cpp_dir"
        log "Please clone the repository first:"
        log "  git clone https://github.com/ggerganov/llama.cpp.git $llama_cpp_dir"
        exit 1
    fi
    # Aller dans le répertoire
    cd "$llama_cpp_dir" || exit 1
    # Récupérer les dernières modifications
    git fetch origin
    # Vérifier si une mise à jour est disponible
    local current_commit=$(git rev-parse HEAD)
    local upstream_commit=$(git rev-parse origin/main)
    if [[ "$current_commit" != "$upstream_commit" ]]; then
        log "New updates available for llama.cpp"
        log "Current commit: $current_commit"
        log "Upstream commit: $upstream_commit"
        # Faire le pull
        if ! git pull origin main; then
            log "ERROR: Failed to pull updates from origin"
            exit 1
        fi
        log "llama.cpp updated successfully"
    else
        log "llama.cpp is already up to date"
    fi
    # Build avec les mêmes paramètres que ton setup
    log "Building llama.cpp with Vulkan support..."
    # Nettoyer le build précédent
    rm -rf build
    # Créer le build avec les mêmes options que ton setup
    cmake -B build \
      -DGGML_VULKAN=ON \
      -DCMAKE_BUILD_TYPE=Release
    # Compiler
    cmake --build build -j$(nproc)
    # Vérifier que le binaire a été créé
    if [[ ! -f "build/bin/llama-server" ]]; then
        log "ERROR: Failed to build llama-server"
        exit 1
    fi
    log "llama.cpp built successfully with Vulkan support"
    # Revenir au répertoire original
    cd - > /dev/null || exit 1
    log "llama.cpp update completed"
}
# ============================================================
# PID
# ============================================================
get_pid() {
    if [[ -f "$PIDFILE" ]]; then
        cat "$PIDFILE"
    fi
}
server_running() {
    local pid
    pid="$(get_pid || true)"
    [[ -n "$pid" ]] &&
        kill -0 "$pid" 2>/dev/null
}
# ============================================================
# Redis - Gestion des conversations
# ============================================================
# Sauvegarder une conversation
save_conversation() {
    local session_id="$1"
    local conversation_data="$2"
    if command -v redis-cli >/dev/null 2>&1; then
        redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" SET "${REDIS_PREFIX}${session_id}" "$conversation_data" 2>/dev/null || true
    fi
}
# Charger une conversation
load_conversation() {
    local session_id="$1"
    if command -v redis-cli >/dev/null 2>&1; then
        redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" GET "${REDIS_PREFIX}${session_id}" 2>/dev/null || true
    fi
}
# Supprimer une conversation
delete_conversation() {
    local session_id="$1"
    if command -v redis-cli >/dev/null 2>&1; then
        redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" DEL "${REDIS_PREFIX}${session_id}" 2>/dev/null || true
    fi
}
# Liste toutes les conversations actives
list_conversations() {
    if command -v redis-cli >/dev/null 2>&1; then
        redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" KEYS "${REDIS_PREFIX}*" 2>/dev/null | sed "s/${REDIS_PREFIX}//" || true
    fi
}
# Générer un ID de session
generate_session_id() {
    echo "session_$(date +%s)_$(openssl rand -hex 4)"
}
# ============================================================
# Persistance - Nouvelles fonctions
# ============================================================
save_state() {
    local model_name="$1"
    local pid="$2"
    # Sauvegarder l'état dans un fichier persistant
    cat > "$PERSISTENT_STATE" << EOF
MODEL=$model_name
PID=$pid
HOST=$HOST
PORT=$PORT
CTX_SIZE=$CTX_SIZE
THREADS=$THREADS
EOF
}
load_state() {
    if [[ -f "$PERSISTENT_STATE" ]]; then
        # Charger les variables depuis le fichier
        source "$PERSISTENT_STATE" 2>/dev/null || true
        # Vérifier si le modèle est toujours configuré
        if [[ -n "${MODELS[$MODEL]+x}" ]]; then
            log "Loading persistent state: $MODEL"
            return 0
        fi
    fi
    return 1
}
# ============================================================
# Stop - CORRECTION
# ============================================================
stop_server() {
    local pid
    pid="$(get_pid || true)"
    if [[ -n "$pid" ]] && kill -0 "$pid" 2>/dev/null; then
        log "Stopping llama-server (PID $pid)..."
        # Tuer le processus et ses enfants
        pkill -P "$pid" 2>/dev/null || true  # Tuer les enfants
        kill -TERM "$pid" 2>/dev/null || true  # Tuer le processus principal
        # Attendre un peu que le processus se termine
        sleep 2
        # Vérifier si le processus est toujours actif
        if kill -0 "$pid" 2>/dev/null; then
            log "Force killing llama-server (PID $pid)..."
            kill -9 "$pid" 2>/dev/null || true
        fi
    fi
    # Nettoyer le fichier PID
    rm -f "$PIDFILE"
    # Nettoyer les fichiers temporaires
    rm -f "/tmp/llama-server-*.log" 2>/dev/null || true
    # Vérifier qu'aucun processus ne reste en arrière-plan
    pkill -f "llama-server" 2>/dev/null || true
    # Effacer l'état persistant
    rm -f "$PERSISTENT_STATE" 2>/dev/null || true
}
# ============================================================
# Force stop - pour s'assurer que tout est arrêté
# ============================================================
force_stop() {
    log "Force stopping all llama-server processes..."
    # Tuer tous les processus llama-server
    pkill -f "llama-server" 2>/dev/null || true
    # Nettoyer les fichiers
    rm -f "$PIDFILE" "/tmp/llama-server-*.log" 2>/dev/null || true
    # Effacer l'état persistant
    rm -f "$PERSISTENT_STATE" 2>/dev/null || true
    # Vérifier l'état
    if pgrep -f "llama-server" > /dev/null; then
        log "WARNING: Some llama-server processes still running"
        pgrep -f "llama-server"
    else
        log "All llama-server processes stopped"
    fi
}
# ============================================================
# GPU Information
# ============================================================
show_gpu_info() {
    if ! command -v vulkaninfo >/dev/null 2>&1; then
        echo "  vulkaninfo: unavailable"
        return
    fi
    vulkaninfo --summary 2>/dev/null |
        grep -E 'deviceName|driverName|driverInfo|deviceType' |
        head -10 ||
        true
}
show_gpu_memory() {
    if [[ -r /sys/class/drm/card1/device/mem_info_vram_total ]]; then
        local total used free
        total="$(cat /sys/class/drm/card1/device/mem_info_vram_total)"
        used="$(cat /sys/class/drm/card1/device/mem_info_vram_used)"
        total=$((total / 1024 / 1024))
        used=$((used / 1024 / 1024))
        free=$((total - used))
        echo "  VRAM total : ${total} MiB"
        echo "  VRAM used  : ${used} MiB"
        echo "  VRAM free  : ${free} MiB"
    else
        echo "  VRAM information unavailable"
    fi
}
# ============================================================
# Hugging Face update
# ============================================================
update_model() {
    local name="$1"
    local repo="${HF_REPOS[$name]}"
    local file="${HF_FILES[$name]}"
    local dir="${MODEL_DIRS[$name]}"
    log "Checking Hugging Face model..."
    log "  Repository: $repo"
    log "  File:       $file"
    log
    mkdir -p "$dir"
    if ! command -v hf >/dev/null 2>&1; then
        log "ERROR: Hugging Face CLI 'hf' not found."
        log
        log "Install it with:"
        log "  curl -LsSf https://hf.co/cli/install.sh | bash"
        exit 1
    fi
    if ! hf download "$repo" "$file" --local-dir "$dir"; then
        log "ERROR: failed to download model from Hugging Face."
        exit 1
    fi
    log
    log "✓ Model checked/updated"
}
# ============================================================
# Model validation
# ============================================================
check_model() {
    local name="$1"
    local model="${MODELS[$name]}"
    if [[ ! -f "$model" ]]; then
        log
        log "ERROR: model not found:"
        log "  $model"
        log
        exit 1
    fi
    if [[ ! -r "$model" ]]; then
        log
        log "ERROR: model is not readable: $model"
        log
        exit 1
    fi
    local size
    size="$(du -h "$model" | awk '{print $1}')"
    log "Model:"
    log "  Name: $name"
    log "  File: $model"
    log "  Size: $size"
}
# ============================================================
# Status
# ============================================================
status() {
    local pid
    pid="$(get_pid || true)"
    if [[ -n "$pid" ]] && kill -0 "$pid" 2>/dev/null; then
        log "llama-server: RUNNING"
        log "PID:          $pid"
        log "URL:          http://$HOST:$PORT"
        if [[ -f "$MODELFILE" ]]; then
            log "Model:        $(cat "$MODELFILE")"
        fi
        log
        if curl -sf \
            --max-time 3 \
            "http://$HOST:$PORT/health" \
            >/dev/null 2>&1; then
            log "Health:       OK"
        else
            log "Health:       NOT READY"
        fi
        # Afficher les informations du contexte
        log
        log "Context Info:"
        show_context_info
    else
        log "llama-server: STOPPED"
        # Essayer de charger l'état persistant
        if load_state; then
            log "Last model was: $MODEL"
            log "Last PID was: $PID"
        fi
    fi
    log
    log "GPU:"
    show_gpu_info
    log
    log "Memory:"
    show_gpu_memory
}
# ============================================================
# Afficher le status dans une fenêtre
# ============================================================
show_status_window() {
    local status_output
    status_output=$(status 2>&1)
    # Essayer avec zenity d'abord
    if command -v zenity >/dev/null 2>&1; then
        echo "$status_output" | zenity --text-info --title="LLaMA Server Status" --width=600 --height=400 2>/dev/null
    # Ensuite avec xterm
    elif command -v xterm >/dev/null 2>&1; then
        echo "$status_output" | xterm -e less 2>/dev/null
    # Enfin avec une simple sortie dans le terminal
    else
        echo "$status_output"
    fi
}
# ============================================================
# List models
# ============================================================
list_models() {
    log "Available models:"
    log "=================="
    # Récupérer la liste des clés du tableau MODELS
    for model in "${!MODELS[@]}"; do
        local model_path="${MODELS[$model]}"
        local size=""
        if [[ -f "$model_path" ]]; then
            size="$(du -h "$model_path" | awk '{print $1}')"
        else
            size="NOT FOUND"
        fi
        log "  $model ($size)"
        log "    Path: $model_path"
        log "    HF Repo: ${HF_REPOS[$model]}"
        log "    HF File: ${HF_FILES[$model]}"
        log
    done
}
# ============================================================
# Start model - AMÉLIORATION DU CONTEXT
# ============================================================
start_model() {
    local name="$1"
    if [[ -z "${MODELS[$name]+x}" ]]; then
        log "Unknown model: $name"
        log
        list_models
        usage
    fi
    local model="${MODELS[$name]}"
    log
    log "========================================"
    log " llama.cpp model manager"
    log "========================================"
    log
    log "Selected model: $name"
    log
    # --------------------------------------------------------
    # Update model
    # --------------------------------------------------------
    update_model "$name"
    log
    # --------------------------------------------------------
    # Validate
    # --------------------------------------------------------
    check_model "$name"
    log
    # --------------------------------------------------------
    # GPU information
    # --------------------------------------------------------
    log "GPU:"
    show_gpu_info
    log
    log "VRAM before loading:"
    show_gpu_memory
    log
    # --------------------------------------------------------
    # Stop previous server
    # --------------------------------------------------------
    stop_server
    sleep 1
    # --------------------------------------------------------
    # Remember selected model
    # --------------------------------------------------------
    echo "$name" > "$MODELFILE"
    # --------------------------------------------------------
    # Start - Utilisation du contexte centralisé
    # --------------------------------------------------------
    log "Starting llama-server with context size: $CTX_SIZE"
    log
    # Générer un nouveau fichier de log avec timestamp
    LOGFILE="/tmp/llama-server-$(date +%Y%m%d-%H%M%S).log"
    "$LLAMA_SERVER" \
        -m "$model" \
        --ctx-size "$CTX_SIZE" \
        --parallel 1 \
        --jinja \
        --threads "$THREADS" \
        --device Vulkan0 \
        --host "$HOST" \
        --port "$PORT" \
        >"$LOGFILE" 2>&1 &
    local pid=$!
    echo "$pid" > "$PIDFILE"
    # Sauvegarder l'état persistant
    save_state "$name" "$pid"
    log "PID: $pid"
    log "Waiting for server..."
    # --------------------------------------------------------
    # Wait for health
    # --------------------------------------------------------
    for ((i=1; i<=START_TIMEOUT; i++)); do
        if curl -sf \
            --max-time 2 \
            "http://$HOST:$PORT/health" \
            >/dev/null 2>&1; then
            log
            log "✓ $name is ready"
            log
            log "URL: http://$HOST:$PORT"
            log "PID: $pid"
            log "Log: $LOGFILE"
            log
            log "VRAM after loading:"
            show_gpu_memory
            return
        fi
        sleep 1
    done
    log "ERROR: Server failed to start within $START_TIMEOUT seconds"
    exit 1
}
# ============================================================
# Afficher l'aide
# ============================================================
usage() {
    cat << EOF
Usage: $0 [command] [options]
Commands:
  start            Start a model
  stop                    Stop the server
  force-stop              Force stop all servers
  status                  Show server status
  list-models             List all available models
  list-conversations      List all conversations
  save-conversation   Save conversation
  load-conversation  Load conversation
  delete-conversation  Delete conversation
  update-llama            Update llama.cpp to latest version
Examples:
  $0 start qwen
  $0 status
  $0 list-models
  $0 list-conversations
  $0 update-llama
  $0 save-conversation session_123 "User: Hello\nAI: Hi there!"
  $0 load-conversation session_123
EOF
    exit 1
}
# ============================================================
# Point d'entrée principal
# ============================================================
main() {
    if [[ $# -eq 0 ]]; then
        usage
    fi
    case "$1" in
        start)
            if [[ $# -lt 2 ]]; then
                log "ERROR: Missing model name"
                usage
            fi
            start_model "$2"
            ;;
        stop)
            stop_server
            ;;
        force-stop)
            force_stop
            ;;
        status)
            # Si le script est appelé directement avec status, afficher dans la fenêtre
            if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
                show_status_window
            else
                status
            fi
            ;;
        list-models)
            list_models
            ;;
        list-conversations)
            log "Active conversations:"
            list_conversations
            ;;
        save-conversation)
            if [[ $# -lt 3 ]]; then
                log "ERROR: Missing session ID or data"
                usage
            fi
            save_conversation "$2" "$3"
            log "Conversation saved with ID: $2"
            ;;
        load-conversation)
            if [[ $# -lt 2 ]]; then
                log "ERROR: Missing session ID"
                usage
            fi
            local data=$(load_conversation "$2")
            if [[ -n "$data" ]]; then
                log "Conversation data for $2:"
                echo "$data"
            else
                log "No conversation found for ID: $2"
            fi
            ;;
        delete-conversation)
            if [[ $# -lt 2 ]]; then
                log "ERROR: Missing session ID"
                usage
            fi
            delete_conversation "$2"
            log "Conversation deleted: $2"
            ;;
        update-llama)
            update_llama_cpp
            ;;
        *)
            log "Unknown command: $1"
            usage
            ;;
    esac
}
# Exécuter le script
main "$@"

Et le menu.xml de labwc si jamais : 

<?xml version="1.0" encoding="utf-8"?>
<openbox_menu xmlns="http://openbox.org/"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://openbox.org/ file:///usr/share/openbox/menu.xsd">

<menu id="root-menu" label="Menu">

<!-- Applications principales --> <item label="Terminal"> <action name="Execute"><command>foot</command></action> </item>

<item label="Navigateur"> <action name="Execute"><command>librewolf</command></action> </item>

<item label="Fichiers"> <action name="Execute"><command>thunar</command></action> </item>

<item label="Éditeur"> <action name="Execute"><command>subl</command></action> </item>

<item label="Lutris (Proton)"> <action name="Execute"> <command>sh -c 'LUTRIS_ENABLE_PROTON=1 lutris'</command> </action> </item>

<item label="Slippi Online"> <action name="Execute"><command>slippi-launcher</command></action> </item>

<item label="Steam (minimal)"> <action name="Execute"> <command>sh -c 'steam-native -cef-disable-gpu-compositing -cef-disable-gpu'</command> </action> </item>

<separator/>

<!-- Menu IA --> <menu id="ia-menu" label="IA"> <item label="Start Qwen"> <action name="Execute"> <command>/home/perru/Scripts/llama.cpp.sh start qwen</command> </action> </item> <item label="Start Mistral"> <action name="Execute"> <command>/home/perru/Scripts/llama.cpp.sh start mistral</command> </action> </item> <item label="Start Gemma"> <action name="Execute"> <command>/home/perru/Scripts/llama.cpp.sh start gemma</command> </action> </item> <separator/> <item label="Status"> <action name="Execute"> <command>/home/perru/Scripts/llama.cpp.sh status</command> </action> </item> <item label="Stop Server"> <action name="Execute"> <command>/home/perru/Scripts/llama.cpp.sh stop</command> </action> </item> <item label="Force Stop"> <action name="Execute"> <command>/home/perru/Scripts/llama.cpp.sh force-stop</command> </action> </item> </menu>

<separator/>

<!-- Applications auto --> <menu id="applications" label="Applications" execute="labwc-menu-generator -p -I" />

<separator/>

<!-- Outils --> <item label="Capture écran"> <action name="Execute"> <command>sh -c 'grim -g "$(slurp)"'</command> </action> </item>

<separator/>

<!-- Système --> <item label="Recharger labwc"> <action name="Reconfigure"/> </item>

<item label="Relancer Waybar"> <action name="Execute"> <command>killall -SIGUSR2 waybar</command> </action> </item>

<separator/>

<!-- Session --> <menu id="session" label="Session">

<item label="Quitter"> <action name="Exit"/> </item>

<item label="Redémarrer"> <action name="Execute"> <command>systemctl -i reboot</command> </action> </item>

<item label="Éteindre"> <action name="Execute"> <command>systemctl -i poweroff</command> </action> </item>

</menu>

</menu>

</openbox_menu>

Y a plus qu'à tester : http://localhost:8080/