-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathllm-server-gui
More file actions
executable file
·157 lines (135 loc) · 4.73 KB
/
llm-server-gui
File metadata and controls
executable file
·157 lines (135 loc) · 4.73 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
#!/bin/bash
#
# llm-server-gui — Terminal model selector for llm-server
# Lists available GGUF models and launches llm-server with the selected one.
#
# Usage:
# llm-server-gui # Select from configured model dir
# llm-server-gui --model-dir /path # Custom model directory
# llm-server-gui --model /path/to/model.gguf # Launch specific model
# llm-server-gui -h|--help # Show this help message
#
# Examples:
# llm-server-gui --model-dir ~/models
# llm-server-gui --model ~/models/Qwen3.5.gguf --benchmark
#
# Environment:
# LLM_MODEL_DIR Default search path (default: ~/ai_models)
#
set -euo pipefail
CONFIG_DIR="$HOME/.config/llm-server"
CONFIG_FILE="$CONFIG_DIR/config.sh"
mkdir -p "$CONFIG_DIR"
# Load persistent config
[[ -f "$CONFIG_FILE" ]] && source "$CONFIG_FILE"
MODEL_DIR="${LLM_MODEL_DIR:-$HOME/ai_models}"
SPECIFIC_MODEL=""
# Auto-detect platform and use correct launcher
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
if [[ "$(uname -s)" == "Darwin" ]]; then
LAUNCHER="$SCRIPT_DIR/llm-server-mac"
# Fallback to llm-server if mac version doesn't exist (e.g. symlinked)
[[ ! -x "$LAUNCHER" ]] && LAUNCHER="$SCRIPT_DIR/llm-server"
else
LAUNCHER="$SCRIPT_DIR/llm-server"
fi
# Help flag
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
sed -n '4,/^$/s/^# \?//p' "$0"
exit 0
fi
# Parse args (pass through to llm-server)
PASSTHROUGH_ARGS=()
while [[ $# -gt 0 ]]; do
case "$1" in
--model-dir) MODEL_DIR="$2"; shift 2 ;;
--model) SPECIFIC_MODEL="$2"; shift 2 ;;
*) PASSTHROUGH_ARGS+=("$1"); shift ;;
esac
done
# First-run setup: If default dir is empty/missing, ask user
if [[ ! -d "$MODEL_DIR" || -z "$(ls -A "$MODEL_DIR" 2>/dev/null)" ]]; then
echo "═══ llm-server First Run Setup ═══"
echo "No models found in: $MODEL_DIR"
echo ""
read -p "Enter the full path to your model directory: " USER_PATH
# Expand tilde if present
USER_PATH="${USER_PATH/#\~/$HOME}"
if [[ -d "$USER_PATH" ]]; then
echo "LLM_MODEL_DIR=\"$USER_PATH\"" > "$CONFIG_FILE"
MODEL_DIR="$USER_PATH"
echo "✓ Path saved to $CONFIG_FILE"
else
echo "Error: Directory not found: $USER_PATH"
exit 1
fi
fi
# If a specific model is provided, launch directly without TUI
if [[ -n "$SPECIFIC_MODEL" ]]; then
if [[ ! -f "$SPECIFIC_MODEL" ]]; then
echo "Error: Model not found: $SPECIFIC_MODEL"
exit 1
fi
exec "$LAUNCHER" "${PASSTHROUGH_ARGS[@]}" "$SPECIFIC_MODEL"
fi
if [[ ! -d "$MODEL_DIR" ]]; then
echo "Error: Model directory not found: $MODEL_DIR"
exit 1
fi
if [[ ! -x "$LAUNCHER" ]]; then
echo "Error: llm-server not found at $LAUNCHER"
exit 1
fi
# Find GGUF models (show first file of split GGUFs, skip duplicates)
declare -a MODEL_PATHS MODEL_DISPLAY
idx=0
while IFS= read -r file; do
basename=$(basename "$file")
# Skip split GGUF parts that aren't the first file
if [[ "$basename" =~ -[0-9]+-of-[0-9]+\.gguf$ ]]; then
[[ ! "$basename" =~ -00001-of-[0-9]+\.gguf$ ]] && continue
fi
# Get total size (including all split parts)
dir=$(dirname "$file")
pattern=$(echo "$basename" | sed 's/-[0-9]*-of-[0-9]*\.gguf/.gguf/')
# Calculate total bytes (cross-platform: macOS stat -f%z, Linux stat --printf)
total_bytes=0
while IFS= read -r part; do
sz=$(stat -f%z "$part" 2>/dev/null || stat --printf="%s" "$part" 2>/dev/null || echo 0)
total_bytes=$(( total_bytes + sz ))
done < <(find "$dir" -name "${pattern%.gguf}*" -type f 2>/dev/null)
(( total_bytes == 0 )) && total_bytes=$(stat -f%z "$file" 2>/dev/null || stat --printf="%s" "$file" 2>/dev/null || echo 0)
size_gb=$(awk "BEGIN {printf \"%.1f\", $total_bytes/1073741824}")
# Detect MoE from filename patterns (A3B, A10B, etc.)
arch="dense"
[[ "$basename" =~ A[0-9]+B ]] && arch="MoE"
MODEL_PATHS+=("$file")
MODEL_DISPLAY+=("$basename (${size_gb}GB, $arch)")
idx=$(( idx + 1 ))
done < <(find "$MODEL_DIR" -name "*.gguf" -type f 2>/dev/null | sort)
if (( idx == 0 )); then
echo "No GGUF models found in $MODEL_DIR"
exit 1
fi
# Display menu
echo ""
echo "═══ Available Models ═══"
echo ""
for i in $(seq 0 $(( idx - 1 ))); do
printf " %2d. %s\n" "$((i+1))" "${MODEL_DISPLAY[$i]}"
done
echo ""
# Read selection
while true; do
read -rp "Select model (1-$idx, q to quit): " choice
[[ "$choice" == "q" || "$choice" == "Q" ]] && exit 0
if [[ "$choice" =~ ^[0-9]+$ ]] && (( choice >= 1 && choice <= idx )); then
break
fi
echo "Invalid choice."
done
SELECTED="${MODEL_PATHS[$((choice-1))]}"
echo ""
echo "Launching: $(basename "$SELECTED")"
echo ""
exec "$LAUNCHER" "${PASSTHROUGH_ARGS[@]}" "$SELECTED"