start.sh
Rama main · réplica de lectura del repositorio original.
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=/dev/null
. "$SCRIPT_DIR/lib/bootstrap.sh" 2>/dev/null ||
. "$SCRIPT_DIR/../lib/bootstrap.sh" 2>/dev/null ||
{ echo "Error: missing LocalAI bootstrap library: lib/bootstrap.sh" >&2; exit 1; }
AI_DIR="$(resolve_ai_dir)"
BIN_DIR="$AI_DIR/$LOCALAI_BIN_SUBDIR"
CONF_DIR="$AI_DIR/$LOCALAI_CONF_SUBDIR"
PORT_FILE="$CONF_DIR/$LOCALAI_PORT_FILE"
PID_FILE="$CONF_DIR/$LOCALAI_PID_FILE"
PID_START_FILE="$CONF_DIR/$LOCALAI_PID_FILE.start"
LOG_FILE="$AI_DIR/$LOCALAI_LOGS_SUBDIR/llama-swap.log"
CONFIG_FILE="$CONF_DIR/$LOCALAI_CONFIG_FILE"
KEYS_DIR="$CONF_DIR/$LOCALAI_KEYS_SUBDIR"
resolve_llama_swap_paths
fail_start() {
local message="$1"
if pid_file_matches_process "$PID_FILE" "$PID_START_FILE"; then
kill "$PID" 2>/dev/null || true
fi
rm -f "$PID_FILE" "$PID_START_FILE"
echo "Error: $message. See $LOG_FILE" >&2
exit 1
}
mkdir -p "$CONF_DIR" "$AI_DIR/$LOCALAI_LOGS_SUBDIR"
if [ -z "$LLAMA_SWAP_BIN" ]; then
echo "Error: llama-swap is not installed or is not in PATH." >&2
exit 1
fi
if [ ! -x "$BIN_DIR/llama-server" ]; then
echo "Error: $BIN_DIR/llama-server is missing or not executable." >&2
exit 1
fi
if [ ! -f "$PORT_FILE" ]; then
echo "$LOCALAI_DEFAULT_PORT" > "$PORT_FILE"
fi
PORT=$(<"$PORT_FILE")
if ! [[ "$PORT" =~ ^[0-9]+$ ]] || ((PORT < 1 || PORT > 65535)); then
echo "Error: invalid port in $PORT_FILE: $PORT" >&2
exit 1
fi
if [ -f "$PID_FILE" ]; then
PID=$(<"$PID_FILE")
if pid_file_matches_process "$PID_FILE" "$PID_START_FILE"; then
COMMAND=$(ps -p "$PID" -o comm= 2>/dev/null || true)
if [[ "$COMMAND" == *llama-swap* ]]; then
echo "LocalAI is already running (PID $PID) on port $PORT."
exit 0
fi
fi
rm -f "$PID_FILE" "$PID_START_FILE"
fi
# Another program on this port would answer the readiness probe below, so a
# llama-swap that failed to bind would be reported as started.
if port_is_listening "$PORT"; then
echo "Error: port $PORT is already in use by another program, so LocalAI cannot listen on it." >&2
echo "Stop that program, or choose another port: echo NEW_PORT > $PORT_FILE" >&2
exit 1
fi
"$BIN_DIR/rebuild-config.sh"
if ! localai_has_model_entries "$AI_DIR/$LOCALAI_MODELS_SUBDIR"; then
echo "No GGUF models found in $AI_DIR/$LOCALAI_MODELS_SUBDIR."
echo "LocalAI will start, but chat requests need a model file and a matching model name."
fi
nohup "$LLAMA_SWAP_BIN" \
--listen "${LOCALAI_LISTEN_HOST}:${PORT}" \
--config "$CONFIG_FILE" \
--config-dir "$KEYS_DIR" \
> "$LOG_FILE" 2>&1 &
PID=$!
echo "$PID" > "$PID_FILE"
process_start_time "$PID" > "$PID_START_FILE"
# Read once: an API key active in config.yaml also protects /running, so the
# readiness probe below must authenticate the same way external clients do.
api_auth_curl_args
for _ in {1..30}; do
if ! pid_file_matches_process "$PID_FILE" "$PID_START_FILE"; then
fail_start "llama-swap failed to start"
fi
if command -v curl >/dev/null 2>&1 &&
curl "${AUTH_CURL_ARGS[@]}" --max-time 2 -fsS "http://${LOCALAI_LISTEN_HOST}:${PORT}/running" >/dev/null 2>&1; then
break
fi
sleep 0.5
done
if ! command -v curl >/dev/null 2>&1 ||
! curl "${AUTH_CURL_ARGS[@]}" --max-time 2 -fsS "http://${LOCALAI_LISTEN_HOST}:${PORT}/running" >/dev/null 2>&1; then
fail_start "llama-swap started but API did not become ready at http://${LOCALAI_LISTEN_HOST}:${PORT}/running"
fi
# The answer must come from this llama-swap, not one that exited after a
# failed bind while something else took the port.
if ! pid_file_matches_process "$PID_FILE" "$PID_START_FILE"; then
fail_start "llama-swap exited right after starting"
fi
echo "LocalAI started at http://${LOCALAI_LISTEN_HOST}:${PORT} (PID $PID)"
echo "Use 'localai models' to see model names, and 'localai check' to verify the API."