402 lines
17 KiB
Bash
Executable file
402 lines
17 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# ==============================================================================
|
|
# LLM Runner: Unified Inference Server Orchestrator for llama-server
|
|
# Target Hardware: AMD ROCm / Radeon AI PRO R9700 (~28-30GB VRAM)
|
|
# ==============================================================================
|
|
|
|
set -euo pipefail
|
|
|
|
# Sanitize environment:
|
|
# TEMP/TMP are standard POSIX variables for temporary file directories.
|
|
# If set to a sampling temperature (float/number), ROCm/libstdc++ crashes during initialization!
|
|
if [ -n "${TEMP:-}" ] && [ ! -d "${TEMP}" ]; then
|
|
TEMPERATURE="${TEMPERATURE:-${TEMP}}"
|
|
unset TEMP
|
|
fi
|
|
if [ -n "${TMP:-}" ] && [ ! -d "${TMP}" ]; then
|
|
unset TMP
|
|
fi
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
LOG_DIR="${LLM_LOG_DIR:-${LOG_DIR:-${SCRIPT_DIR}/logs}}"
|
|
mkdir -p "${LOG_DIR}"
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Helpers & Color Output
|
|
# ------------------------------------------------------------------------------
|
|
BOLD="\033[1m"
|
|
GREEN="\033[32m"
|
|
BLUE="\033[34m"
|
|
YELLOW="\033[33m"
|
|
RED="\033[31m"
|
|
CYAN="\033[36m"
|
|
RESET="\033[0m"
|
|
|
|
log_info() { echo -e "${BLUE}[INFO]${RESET} $*"; }
|
|
log_success() { echo -e "${GREEN}[✓]${RESET} $*"; }
|
|
log_warn() { echo -e "${YELLOW}[!]${RESET} $*"; }
|
|
log_error() { echo -e "${RED}[✗]${RESET} $*" >&2; }
|
|
|
|
# Find llama-server binary
|
|
find_llama_server() {
|
|
if command -v llama-server >/dev/null 2>&1; then
|
|
command -v llama-server
|
|
elif [ -x "/run/current-system/sw/bin/llama-server" ]; then
|
|
echo "/run/current-system/sw/bin/llama-server"
|
|
else
|
|
log_error "llama-server executable not found in PATH or system profile!"
|
|
exit 1
|
|
fi
|
|
}
|
|
LLAMA_SERVER="$(find_llama_server)"
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Status & Inspection
|
|
# ------------------------------------------------------------------------------
|
|
check_health() {
|
|
local port="${1:-11434}"
|
|
local host="${2:-127.0.0.1}"
|
|
if curl -s "http://${host}:${port}/health" 2>/dev/null | grep -q '"status":\s*"ok"\|"ok"'; then
|
|
return 0
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
cmd_status() {
|
|
echo -e "${BOLD}=== Local LLM Server Status ===${RESET}"
|
|
local ports=(11434 11435 11436)
|
|
local any_running=0
|
|
|
|
for port in "${ports[@]}"; do
|
|
local pid
|
|
pid=$(lsof -ti :"$port" 2>/dev/null || fuser "$port/tcp" 2>/dev/null || true)
|
|
if [ -n "$pid" ]; then
|
|
any_running=1
|
|
local model_info
|
|
model_info=$(curl -s "http://127.0.0.1:${port}/v1/models" 2>/dev/null | jq -r '.data[0].id // "unknown"' 2>/dev/null || echo "initializing...")
|
|
echo -e " Port ${CYAN}${port}${RESET}: ${GREEN}RUNNING${RESET} (PID: ${pid}) - Model: ${BOLD}${model_info}${RESET}"
|
|
else
|
|
echo -e " Port ${CYAN}${port}${RESET}: ${YELLOW}STOPPED${RESET}"
|
|
fi
|
|
done
|
|
|
|
echo ""
|
|
return 0
|
|
}
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Stop Servers
|
|
# ------------------------------------------------------------------------------
|
|
cmd_stop() {
|
|
local target="${1:-all}"
|
|
log_info "Stopping server(s): ${target}..."
|
|
|
|
if [ "$target" = "all" ]; then
|
|
pkill -f "llama-server" 2>/dev/null || true
|
|
log_success "All llama-server processes terminated."
|
|
else
|
|
fuser -k -9 "$target/tcp" 2>/dev/null || true
|
|
log_success "Killed server on port ${target}."
|
|
fi
|
|
}
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Launch Single Server Instance
|
|
# ------------------------------------------------------------------------------
|
|
launch_instance() {
|
|
local name="$1"
|
|
local model="$2"
|
|
local port="$3"
|
|
local ctx="$4"
|
|
local mmproj="${5:-}"
|
|
local template="${6:-}"
|
|
local temp="${7:-0.6}"
|
|
local top_p="${8:-0.95}"
|
|
local top_k="${9:-40}"
|
|
local min_p="${10:-0.05}"
|
|
local ngl="${11:-99}"
|
|
local load_mode="${12:-none}"
|
|
local flash_attn="${13:-on}"
|
|
local ctk="${14:-q8_0}"
|
|
local ctv="${15:-q8_0}"
|
|
local reasoning="${16:-false}"
|
|
local log_file="${LOG_DIR}/${name}.log"
|
|
|
|
if [ ! -f "$model" ]; then
|
|
log_error "Model file not found: ${model}"
|
|
exit 1
|
|
fi
|
|
|
|
# Ensure target port is free
|
|
if fuser "$port/tcp" >/dev/null 2>&1; then
|
|
log_warn "Port ${port} is in use. Stopping existing process on port ${port}..."
|
|
fuser -k -9 "$port/tcp" 2>/dev/null || true
|
|
sleep 1
|
|
fi
|
|
|
|
local flags=(
|
|
-m "${model}"
|
|
--host "${LLM_HOST:-${HOST:-0.0.0.0}}"
|
|
--port "${port}"
|
|
--ctx-size "${ctx}"
|
|
-np "${LLM_PARALLEL:-${PARALLEL:-1}}"
|
|
--n-gpu-layers "${ngl}"
|
|
--load-mode "${load_mode}"
|
|
--temp "${temp}"
|
|
--top-p "${top_p}"
|
|
--top-k "${top_k}"
|
|
--min-p "${min_p}"
|
|
-ctk "${ctk}"
|
|
-ctv "${ctv}"
|
|
-fa "${flash_attn}"
|
|
-b "${LLM_BATCH_SIZE:-${BATCH_SIZE:-2048}}"
|
|
-ub "${LLM_UBATCH_SIZE:-${UBATCH_SIZE:-512}}"
|
|
)
|
|
|
|
if [ -n "${mmproj}" ] && [ -f "${mmproj}" ]; then
|
|
flags+=(--mmproj "${mmproj}" --image-min-tokens "${LLM_IMAGE_MIN_TOKENS:-${IMAGE_MIN_TOKENS:-1024}}")
|
|
fi
|
|
|
|
if [ -n "${template}" ] && [ -f "${template}" ]; then
|
|
flags+=(--chat-template-file "${template}" --jinja)
|
|
fi
|
|
|
|
if [ "${reasoning}" = "true" ]; then
|
|
flags+=(--reasoning-preserve)
|
|
fi
|
|
|
|
log_info "Starting ${BOLD}${name}${RESET} on port ${CYAN}${port}${RESET} (CTX: ${ctx})..."
|
|
"${LLAMA_SERVER}" "${flags[@]}" > "${log_file}" 2>&1 &
|
|
local s_pid=$!
|
|
|
|
# Wait for initialization
|
|
log_info "Waiting for ${name} to initialize (PID: ${s_pid})..."
|
|
while true; do
|
|
if ! kill -0 "${s_pid}" 2>/dev/null; then
|
|
log_error "${name} failed to start! Last 20 log lines from ${log_file}:"
|
|
tail -n 20 "${log_file}" >&2
|
|
exit 1
|
|
fi
|
|
if check_health "${port}"; then
|
|
break
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
log_success "${name} is READY at http://localhost:${port} (PID: ${s_pid})"
|
|
echo "${s_pid}"
|
|
}
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Presets
|
|
# ------------------------------------------------------------------------------
|
|
cmd_cluster() {
|
|
log_info "Starting Multi-Agent Cluster (SuperQwen 27B + 2x Qwen 4B)..."
|
|
pkill -f "llama-server" 2>/dev/null || true
|
|
sleep 1
|
|
|
|
# Trap to gracefully stop all background instances on Ctrl+C
|
|
cleanup_cluster() {
|
|
log_warn "Stopping cluster instances..."
|
|
pkill -P $$ 2>/dev/null || true
|
|
pkill -f "llama-server" 2>/dev/null || true
|
|
exit 0
|
|
}
|
|
trap cleanup_cluster SIGINT SIGTERM EXIT
|
|
|
|
# SuperQwen 3.8 27B (Planner)
|
|
local planner_model="${LLM_PLANNER_MODEL:-${PLANNER_MODEL:-${LLM_MODEL:-${MODEL:-${SCRIPT_DIR}/models/Qwen3.8/Qwen3.8-27B-UD-Q4_K_XL.gguf}}}}"
|
|
if [ ! -f "${planner_model}" ] && [ -f "${SCRIPT_DIR}/models/Qwen3.8/SuperQwen3.8-27b-abliterated-Q4_K_M.gguf" ]; then
|
|
planner_model="${SCRIPT_DIR}/models/Qwen3.8/SuperQwen3.8-27b-abliterated-Q4_K_M.gguf"
|
|
fi
|
|
local planner_mmproj="${LLM_PLANNER_MMPROJ:-${PLANNER_MMPROJ:-${SCRIPT_DIR}/models/Qwen3.8/mmproj-SuperQwen3.8-27b-abliterated-Q8_0.gguf}}"
|
|
if [ "${planner_mmproj}" = "none" ]; then planner_mmproj=""; fi
|
|
local planner_tmpl="${LLM_PLANNER_TEMPLATE:-${PLANNER_TEMPLATE:-${SCRIPT_DIR}/templates/Qwen3.8/chat_template.jinja}}"
|
|
|
|
# Qwen 3.5 4B (Workers)
|
|
local worker_model="${LLM_WORKER_MODEL:-${WORKER_MODEL:-${SCRIPT_DIR}/models/Qwen3.5/Qwen3.5-4B-Q5_K_M.gguf}}"
|
|
local worker_mmproj="${LLM_WORKER_MMPROJ:-${WORKER_MMPROJ:-${SCRIPT_DIR}/models/Qwen3.5/mmproj-BF16.gguf}}"
|
|
if [ "${worker_mmproj}" = "none" ]; then worker_mmproj=""; fi
|
|
local worker_tmpl="${LLM_WORKER_TEMPLATE:-${WORKER_TEMPLATE:-${SCRIPT_DIR}/templates/Qwen3.5/chat_template.jinja}}"
|
|
|
|
# 1. Planner on 11434
|
|
launch_instance "planner_27b" "$planner_model" "${LLM_PLANNER_PORT:-${PLANNER_PORT:-11434}}" "${LLM_PLANNER_CTX:-${PLANNER_CTX:-65536}}" \
|
|
"$planner_mmproj" "$planner_tmpl" "${LLM_PLANNER_TEMP:-${PLANNER_TEMP:-0.6}}" "${LLM_PLANNER_TOP_P:-${PLANNER_TOP_P:-0.95}}" "${LLM_PLANNER_TOP_K:-${PLANNER_TOP_K:-40}}" \
|
|
"${LLM_PLANNER_MIN_P:-${PLANNER_MIN_P:-0.05}}" "${LLM_PLANNER_NGL:-${PLANNER_NGL:-99}}" "${LLM_PLANNER_LOAD_MODE:-${PLANNER_LOAD_MODE:-none}}" "${LLM_FLASH_ATTN:-${FLASH_ATTN:-on}}" \
|
|
"${LLM_PLANNER_CTK:-${PLANNER_CTK:-q8_0}}" "${LLM_PLANNER_CTV:-${PLANNER_CTV:-q8_0}}" "false"
|
|
|
|
# 2. Worker 1 on 11435
|
|
launch_instance "worker_4b_1" "$worker_model" "${LLM_WORKER1_PORT:-${WORKER1_PORT:-11435}}" "${LLM_WORKER1_CTX:-${WORKER1_CTX:-16384}}" \
|
|
"$worker_mmproj" "$worker_tmpl" "${LLM_WORKER1_TEMP:-${WORKER1_TEMP:-0.7}}" "${LLM_WORKER1_TOP_P:-${WORKER1_TOP_P:-0.8}}" "${LLM_WORKER1_TOP_K:-${WORKER1_TOP_K:-20}}" \
|
|
"${LLM_WORKER1_MIN_P:-${WORKER1_MIN_P:-0.05}}" "${LLM_WORKER1_NGL:-${WORKER1_NGL:-99}}" "${LLM_LOAD_MODE:-${LOAD_MODE:-mmap}}" "${LLM_FLASH_ATTN:-${FLASH_ATTN:-on}}" \
|
|
"${LLM_WORKER1_CTK:-${WORKER1_CTK:-q8_0}}" "${LLM_WORKER1_CTV:-${WORKER1_CTV:-q8_0}}" "false"
|
|
|
|
# 3. Worker 2 on 11436
|
|
launch_instance "worker_4b_2" "$worker_model" "${LLM_WORKER2_PORT:-${WORKER2_PORT:-11436}}" "${LLM_WORKER2_CTX:-${WORKER2_CTX:-16384}}" \
|
|
"$worker_mmproj" "$worker_tmpl" "${LLM_WORKER2_TEMP:-${WORKER2_TEMP:-0.7}}" "${LLM_WORKER2_TOP_P:-${WORKER2_TOP_P:-0.8}}" "${LLM_WORKER2_TOP_K:-${WORKER2_TOP_K:-20}}" \
|
|
"${LLM_WORKER2_MIN_P:-${WORKER2_MIN_P:-0.05}}" "${LLM_WORKER2_NGL:-${WORKER2_NGL:-99}}" "${LLM_LOAD_MODE:-${LOAD_MODE:-mmap}}" "${LLM_FLASH_ATTN:-${FLASH_ATTN:-on}}" \
|
|
"${LLM_WORKER2_CTK:-${WORKER2_CTK:-q8_0}}" "${LLM_WORKER2_CTV:-${WORKER2_CTV:-q8_0}}" "false"
|
|
|
|
echo ""
|
|
log_success "All 3 cluster servers are operational:"
|
|
echo " [Planner] SuperQwen 3.8 27B -> http://localhost:${LLM_PLANNER_PORT:-${PLANNER_PORT:-11434}}"
|
|
echo " [Implementer] Qwen 3.5 4B #1 -> http://localhost:${LLM_WORKER1_PORT:-${WORKER1_PORT:-11435}}"
|
|
echo " [Implementer] Qwen 3.5 4B #2 -> http://localhost:${LLM_WORKER2_PORT:-${WORKER2_PORT:-11436}}"
|
|
echo ""
|
|
echo "Logs directory: ${LOG_DIR}/"
|
|
echo "Press Ctrl+C to stop all instances gracefully."
|
|
wait
|
|
}
|
|
|
|
cmd_muse() {
|
|
log_info "Starting Muse-Glimmer 30B Solo Server (Max Context: 128K)..."
|
|
pkill -f "llama-server" 2>/dev/null || true
|
|
sleep 1
|
|
local model="${LLM_MODEL:-${MODEL:-${SCRIPT_DIR}/models/muse-glimmer/Muse-Glimmer-30B-UD-Q4_K_XL.gguf}}"
|
|
local mmproj="${LLM_MMPROJ:-${MMPROJ:-${SCRIPT_DIR}/models/muse-glimmer/mmproj-Muse-Glimmer-30B-Q8_0.gguf}}"
|
|
if [ "${mmproj}" = "none" ]; then mmproj=""; fi
|
|
local tmpl="${LLM_TEMPLATE:-${TEMPLATE:-${SCRIPT_DIR}/templates/muse-glimmer/chat_template.jinja}}"
|
|
|
|
launch_instance "muse_solo" "$model" "${LLM_PORT:-${PORT:-11434}}" "${LLM_CTX:-${CTX:-131072}}" \
|
|
"$mmproj" "$tmpl" "${LLM_TEMPERATURE:-${TEMPERATURE:-${SAMPLING_TEMP:-0.6}}}" \
|
|
"${LLM_TOP_P:-${TOP_P:-0.95}}" "${LLM_TOP_K:-${TOP_K:-40}}" \
|
|
"${LLM_MIN_P:-${MIN_P:-0.05}}" "${LLM_NGL:-${NGL:-99}}" \
|
|
"${LLM_LOAD_MODE:-${LOAD_MODE:-none}}" "${LLM_FLASH_ATTN:-${FLASH_ATTN:-on}}" \
|
|
"${LLM_CTK:-${CTK:-q8_0}}" "${LLM_CTV:-${CTV:-q8_0}}" \
|
|
"${LLM_REASONING_PRESERVE:-${REASONING_PRESERVE:-true}}"
|
|
|
|
echo ""
|
|
echo "Streaming logs: tail -f ${LOG_DIR}/muse_solo.log"
|
|
echo "Press Ctrl+C to stop."
|
|
wait
|
|
}
|
|
|
|
cmd_superqwen() {
|
|
log_info "Starting SuperQwen 3.8 27B Solo Server (Max Context: 256K)..."
|
|
pkill -f "llama-server" 2>/dev/null || true
|
|
sleep 1
|
|
local model="${LLM_MODEL:-${MODEL:-${SCRIPT_DIR}/models/Qwen3.8/SuperQwen3.8-27b-abliterated-Q4_K_M.gguf}}"
|
|
if [ ! -f "${model}" ] && [ -f "${SCRIPT_DIR}/models/Qwen3.8/Qwen3.8-27B-UD-Q4_K_XL.gguf" ]; then
|
|
model="${SCRIPT_DIR}/models/Qwen3.8/Qwen3.8-27B-UD-Q4_K_XL.gguf"
|
|
fi
|
|
local mmproj="${LLM_MMPROJ:-${MMPROJ:-${SCRIPT_DIR}/models/Qwen3.8/mmproj-SuperQwen3.8-27b-abliterated-Q8_0.gguf}}"
|
|
if [ "${mmproj}" = "none" ]; then mmproj=""; fi
|
|
local tmpl="${LLM_TEMPLATE:-${TEMPLATE:-${SCRIPT_DIR}/templates/Qwen3.8/chat_template.jinja}}"
|
|
|
|
launch_instance "superqwen_solo" "$model" "${LLM_PORT:-${PORT:-11434}}" "${LLM_CTX:-${CTX:-262144}}" \
|
|
"$mmproj" "$tmpl" "${LLM_TEMPERATURE:-${TEMPERATURE:-${SAMPLING_TEMP:-0.6}}}" \
|
|
"${LLM_TOP_P:-${TOP_P:-0.95}}" "${LLM_TOP_K:-${TOP_K:-40}}" \
|
|
"${LLM_MIN_P:-${MIN_P:-0.05}}" "${LLM_NGL:-${NGL:-99}}" \
|
|
"${LLM_LOAD_MODE:-${LOAD_MODE:-none}}" "${LLM_FLASH_ATTN:-${FLASH_ATTN:-on}}" \
|
|
"${LLM_CTK:-${CTK:-q8_0}}" "${LLM_CTV:-${CTV:-q8_0}}" \
|
|
"${LLM_REASONING_PRESERVE:-${REASONING_PRESERVE:-true}}"
|
|
|
|
echo ""
|
|
echo "Streaming logs: tail -f ${LOG_DIR}/superqwen_solo.log"
|
|
echo "Press Ctrl+C to stop."
|
|
wait
|
|
}
|
|
|
|
cmd_qwen4b() {
|
|
log_info "Starting Qwen 3.5 4B Solo Server..."
|
|
pkill -f "llama-server" 2>/dev/null || true
|
|
sleep 1
|
|
local model="${LLM_MODEL:-${MODEL:-${SCRIPT_DIR}/models/Qwen3.5/Qwen3.5-4B-Q5_K_M.gguf}}"
|
|
local mmproj="${LLM_MMPROJ:-${MMPROJ:-${SCRIPT_DIR}/models/Qwen3.5/mmproj-BF16.gguf}}"
|
|
if [ "${mmproj}" = "none" ]; then mmproj=""; fi
|
|
local tmpl="${LLM_TEMPLATE:-${TEMPLATE:-${SCRIPT_DIR}/templates/Qwen3.5/chat_template.jinja}}"
|
|
|
|
launch_instance "qwen4b_solo" "$model" "${LLM_PORT:-${PORT:-11434}}" "${LLM_CTX:-${CTX:-32768}}" \
|
|
"$mmproj" "$tmpl" "${LLM_TEMPERATURE:-${TEMPERATURE:-${SAMPLING_TEMP:-0.7}}}" \
|
|
"${LLM_TOP_P:-${TOP_P:-0.8}}" "${LLM_TOP_K:-${TOP_K:-20}}" \
|
|
"${LLM_MIN_P:-${MIN_P:-0.05}}" "${LLM_NGL:-${NGL:-99}}" \
|
|
"${LLM_LOAD_MODE:-${LOAD_MODE:-mmap}}" "${LLM_FLASH_ATTN:-${FLASH_ATTN:-on}}" \
|
|
"${LLM_CTK:-${CTK:-q8_0}}" "${LLM_CTV:-${CTV:-q8_0}}" "false"
|
|
|
|
echo ""
|
|
echo "Streaming logs: tail -f ${LOG_DIR}/qwen4b_solo.log"
|
|
echo "Press Ctrl+C to stop."
|
|
wait
|
|
}
|
|
|
|
cmd_custom() {
|
|
log_info "Starting Custom Server Instance..."
|
|
pkill -f "llama-server" 2>/dev/null || true
|
|
sleep 1
|
|
local model="${LLM_MODEL:-${MODEL:-}}"
|
|
if [ -z "${model}" ] || [ ! -f "${model}" ]; then
|
|
log_error "No valid MODEL specified! Pass LLM_MODEL=/path/to/model.gguf"
|
|
exit 1
|
|
fi
|
|
local mmproj="${LLM_MMPROJ:-${MMPROJ:-}}"
|
|
if [ "${mmproj}" = "none" ]; then mmproj=""; fi
|
|
local tmpl="${LLM_TEMPLATE:-${TEMPLATE:-}}"
|
|
local name="custom_solo"
|
|
|
|
launch_instance "${name}" "$model" "${LLM_PORT:-${PORT:-11434}}" "${LLM_CTX:-${CTX:-65536}}" \
|
|
"$mmproj" "$tmpl" "${LLM_TEMPERATURE:-${TEMPERATURE:-${SAMPLING_TEMP:-0.6}}}" \
|
|
"${LLM_TOP_P:-${TOP_P:-0.95}}" "${LLM_TOP_K:-${TOP_K:-40}}" \
|
|
"${LLM_MIN_P:-${MIN_P:-0.05}}" "${LLM_NGL:-${NGL:-99}}" \
|
|
"${LLM_LOAD_MODE:-${LOAD_MODE:-none}}" "${LLM_FLASH_ATTN:-${FLASH_ATTN:-on}}" \
|
|
"${LLM_CTK:-${CTK:-q8_0}}" "${LLM_CTV:-${CTV:-q8_0}}" \
|
|
"${LLM_REASONING_PRESERVE:-${REASONING_PRESERVE:-false}}"
|
|
|
|
echo ""
|
|
echo "Streaming logs: tail -f ${LOG_DIR}/${name}.log"
|
|
echo "Press Ctrl+C to stop."
|
|
wait
|
|
}
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Help / Usage
|
|
# ------------------------------------------------------------------------------
|
|
cmd_help() {
|
|
cat <<EOF
|
|
Usage: $(basename "$0") <command> [options]
|
|
|
|
Commands:
|
|
cluster Launch multi-agent cluster (SuperQwen 27B on 11434, 2x Qwen 4B on 11435/11436)
|
|
muse Launch Muse-Glimmer 30B Solo (128K context, port 11434)
|
|
superqwen Launch SuperQwen 3.8 27B Solo (256K context, port 11434)
|
|
qwen4b Launch Qwen 3.5 4B Solo (port 11434)
|
|
custom Launch custom model instance (requires LLM_MODEL=/path/to/model.gguf)
|
|
status Show current server health and active ports
|
|
stop [target] Stop servers (target: "all" or port number like 11434)
|
|
help Display this help message
|
|
|
|
Environment Variables:
|
|
LLM_MODEL Path to GGUF model file (fallback: MODEL)
|
|
LLM_MMPROJ Path to mmproj file, or "none" (fallback: MMPROJ)
|
|
LLM_TEMPLATE Path to chat template file (fallback: TEMPLATE)
|
|
LLM_HOST Bind address (default: 0.0.0.0)
|
|
LLM_PORT Main port override (default: 11434)
|
|
LLM_CTX Context size override (default: preset-specific)
|
|
LLM_TEMPERATURE Sampling temperature (default: preset-specific)
|
|
LLM_PARALLEL Parallel slot count (default: 1)
|
|
LLM_FLASH_ATTN Enable Flash Attention: "on" or "off" (default: on)
|
|
LLM_LOG_DIR Path to write logs (default: ./logs)
|
|
|
|
EOF
|
|
}
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Dispatch
|
|
# ------------------------------------------------------------------------------
|
|
ACTION="${1:-help}"
|
|
shift || true
|
|
|
|
case "${ACTION}" in
|
|
cluster) cmd_cluster "$@" ;;
|
|
muse) cmd_muse "$@" ;;
|
|
superqwen) cmd_superqwen "$@" ;;
|
|
qwen4b) cmd_qwen4b "$@" ;;
|
|
custom) cmd_custom "$@" ;;
|
|
status) cmd_status "$@" ;;
|
|
stop) cmd_stop "$@" ;;
|
|
help|--help|-h) cmd_help ;;
|
|
*)
|
|
log_error "Unknown command: ${ACTION}"
|
|
cmd_help
|
|
exit 1
|
|
;;
|
|
esac
|