Consolidated local ollama model logic
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
Kannst du mir ein Skript bauen, dass wenn ich den Namen der Tabelle in sql server habe,
|
||||
du mir das T-SQL ausgibst was ich brauche, um select sourcedb.Tabelle col1, col2,... etc. INTO Tabelle col1, col2,... etc. zu erzeugen?
|
||||
|
||||
Executable
+45
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_OVERRIDE="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
export ROOT_OVERRIDE
|
||||
# shellcheck disable=SC1091
|
||||
source "${ROOT_OVERRIDE}/scripts/common.sh"
|
||||
|
||||
init_log bootstrap-native
|
||||
print_header "bootstrap-native: START"
|
||||
|
||||
need_cmd curl
|
||||
need_cmd python
|
||||
need_cmd ollama
|
||||
load_env
|
||||
check_for_legacy_docker_ollama
|
||||
|
||||
log "bootstrap-native: waiting for Ollama API at ${OLLAMA_URL}"
|
||||
wait_for_ollama_api "$OLLAMA_URL" 120 || fail "Ollama API not reachable at ${OLLAMA_URL}" 40
|
||||
ok "bootstrap-native: Ollama API reachable"
|
||||
|
||||
log "bootstrap-native: pulling base model ${BASE_MODEL}"
|
||||
ollama pull "${BASE_MODEL}"
|
||||
|
||||
if [[ -n "${EXTRA_MODELS}" ]]; then
|
||||
for m in ${EXTRA_MODELS}; do
|
||||
log "bootstrap-native: pulling extra model ${m}"
|
||||
ollama pull "$m"
|
||||
done
|
||||
fi
|
||||
|
||||
tmp="$(mktemp)"
|
||||
trap 'rm -f "$tmp"' EXIT
|
||||
render_modelfile "$tmp"
|
||||
|
||||
log "bootstrap-native: building expert model ${EXPERT_MODEL}"
|
||||
ollama create "${EXPERT_MODEL}" -f "$tmp"
|
||||
|
||||
tags="$(fetch_tags)"
|
||||
printf '%s' "$tags" | is_json || fail "/api/tags did not return valid JSON" 41
|
||||
model_in_tags "$EXPERT_MODEL" "$tags" || fail "expert model missing after bootstrap: ${EXPERT_MODEL}" 42
|
||||
ok "bootstrap-native: expert model available: ${EXPERT_MODEL}"
|
||||
|
||||
warmup_sqlai
|
||||
print_footer "bootstrap-native: END status=OK log=${LOG_FILE}"
|
||||
@@ -1,68 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cp -n "${ROOT}/.env.example" "${ROOT}/.env" || true
|
||||
source "${ROOT}/.env"
|
||||
|
||||
ts(){ date -Is; }
|
||||
|
||||
log_dir="${ROOT}/logs"
|
||||
mkdir -p "$log_dir"
|
||||
log_file="${log_dir}/bootstrap-$(date -Iseconds).log"
|
||||
exec > >(tee -a "$log_file") 2>&1
|
||||
|
||||
echo "[$(ts)] bootstrap: starting (ROOT=$ROOT)"
|
||||
|
||||
echo "[$(ts)] bootstrap: docker compose up -d"
|
||||
docker compose -f "${ROOT}/docker-compose.yml" up -d
|
||||
|
||||
echo "[$(ts)] bootstrap: waiting for Ollama API at ${OLLAMA_URL} ..."
|
||||
for i in {1..120}; do
|
||||
if curl -sS "${OLLAMA_URL}/api/tags" >/dev/null 2>&1; then
|
||||
echo "[$(ts)] bootstrap: Ollama API is up."
|
||||
break
|
||||
fi
|
||||
if [[ $i -eq 120 ]]; then
|
||||
echo "[$(ts)] bootstrap: ERROR: API did not come up in time."
|
||||
exit 1
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
echo "[$(ts)] bootstrap: pulling base model: ${BASE_MODEL}"
|
||||
docker exec -it ollama ollama pull "${BASE_MODEL}"
|
||||
|
||||
if [[ -n "${EXTRA_MODELS:-}" ]]; then
|
||||
for m in ${EXTRA_MODELS}; do
|
||||
echo "[$(ts)] bootstrap: pulling extra model: $m"
|
||||
docker exec -it ollama ollama pull "$m"
|
||||
done
|
||||
fi
|
||||
|
||||
echo "[$(ts)] bootstrap: building expert model: ${EXPERT_MODEL}"
|
||||
|
||||
tmp="$(mktemp)"
|
||||
sed "s/\${BASE_MODEL}/${BASE_MODEL}/g" "${ROOT}/Modelfile" > "$tmp"
|
||||
|
||||
docker cp "$tmp" ollama:/tmp/Modelfile.jr-sql-expert
|
||||
docker exec -it ollama ollama create "${EXPERT_MODEL}" -f /tmp/Modelfile.jr-sql-expert
|
||||
|
||||
rm -f "$tmp"
|
||||
|
||||
echo "[$(ts)] bootstrap: verifying model exists..."
|
||||
docker exec -it ollama ollama list | grep -F "${EXPERT_MODEL}" >/dev/null && \
|
||||
echo "[$(ts)] bootstrap: OK: ${EXPERT_MODEL} is available."
|
||||
|
||||
# Warmup
|
||||
if [[ -x "${ROOT}/bin/sqlai" ]]; then
|
||||
echo "[$(ts)] bootstrap: warmup: sending a short request (no-metrics)..."
|
||||
"${ROOT}/bin/sqlai" ask --text "Warmup: reply with exactly 'OK'." --no-metrics || {
|
||||
echo "[$(ts)] bootstrap: WARN: warmup failed (continuing)."
|
||||
}
|
||||
echo "[$(ts)] bootstrap: warmup: done"
|
||||
else
|
||||
echo "[$(ts)] bootstrap: WARN: ${ROOT}/bin/sqlai not executable; skipping warmup."
|
||||
fi
|
||||
|
||||
echo "[$(ts)] bootstrap: done"
|
||||
Executable
+51
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
LOG_DIR="${ROOT}/logs"
|
||||
mkdir -p "$LOG_DIR"
|
||||
LOG_FILE="${LOG_DIR}/cleanup-docker-ollama-$(date -Iseconds).log"
|
||||
exec > >(tee -a "$LOG_FILE") 2>&1
|
||||
|
||||
ts(){ date -Is; }
|
||||
log(){ echo "[$(ts)] $*"; }
|
||||
|
||||
log "cleanup-docker-ollama: START ROOT=${ROOT}"
|
||||
|
||||
if ! command -v docker >/dev/null 2>&1; then
|
||||
log "cleanup-docker-ollama: docker not installed; nothing to do"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ -f "${ROOT}/docker-compose.yml" ]] && docker compose version >/dev/null 2>&1; then
|
||||
log "cleanup-docker-ollama: docker compose down --remove-orphans"
|
||||
docker compose -f "${ROOT}/docker-compose.yml" down --remove-orphans || true
|
||||
fi
|
||||
|
||||
if docker ps -a --format '{{.Names}}' | grep -qx 'ollama'; then
|
||||
log "cleanup-docker-ollama: removing container ollama"
|
||||
docker rm -f ollama || true
|
||||
else
|
||||
log "cleanup-docker-ollama: container ollama not present"
|
||||
fi
|
||||
|
||||
if docker images --format '{{.Repository}}:{{.Tag}}' | grep -qx 'ollama/ollama:latest'; then
|
||||
log "cleanup-docker-ollama: removing image ollama/ollama:latest"
|
||||
docker image rm -f ollama/ollama:latest || true
|
||||
else
|
||||
log "cleanup-docker-ollama: image ollama/ollama:latest not present"
|
||||
fi
|
||||
|
||||
if [[ "${PURGE_OLLAMA_DOCKER_VOLUMES:-0}" == "1" ]]; then
|
||||
mapfile -t volumes < <(docker volume ls --format '{{.Name}}' | grep -E 'ollama' || true)
|
||||
if (( ${#volumes[@]} > 0 )); then
|
||||
log "cleanup-docker-ollama: removing volumes: ${volumes[*]}"
|
||||
docker volume rm "${volumes[@]}" || true
|
||||
else
|
||||
log "cleanup-docker-ollama: no ollama volumes found"
|
||||
fi
|
||||
else
|
||||
log "cleanup-docker-ollama: keeping volumes (set PURGE_OLLAMA_DOCKER_VOLUMES=1 to remove them)"
|
||||
fi
|
||||
|
||||
log "cleanup-docker-ollama: END log=${LOG_FILE}"
|
||||
Executable
+149
@@ -0,0 +1,149 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="${ROOT_OVERRIDE:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
|
||||
ENV_FILE="${ENV_FILE:-${ROOT}/.env}"
|
||||
MODFILE="${MODFILE:-${ROOT}/Modelfile}"
|
||||
SQLAI_BIN="${SQLAI_BIN:-${ROOT}/bin/sqlai}"
|
||||
LOG_FILE=""
|
||||
|
||||
_ts_prefix(){ date -Is; }
|
||||
ts(){ _ts_prefix; }
|
||||
|
||||
log(){ echo "[$(ts)] $*"; }
|
||||
ok(){ log "OK $*"; }
|
||||
warn(){ log "WARN $*"; }
|
||||
fail(){
|
||||
local msg="$1"
|
||||
local code="${2:-1}"
|
||||
log "FAIL $msg"
|
||||
exit "$code"
|
||||
}
|
||||
|
||||
need_cmd(){
|
||||
command -v "$1" >/dev/null 2>&1 || fail "missing command: $1" 10
|
||||
}
|
||||
|
||||
init_log(){
|
||||
local name="$1"
|
||||
local log_dir="${ROOT}/logs"
|
||||
mkdir -p "$log_dir"
|
||||
LOG_FILE="${log_dir}/${name}-$(date -Iseconds).log"
|
||||
export LOG_FILE
|
||||
exec > >(tee -a "$LOG_FILE") 2>&1
|
||||
}
|
||||
|
||||
load_env(){
|
||||
if [[ ! -f "$ENV_FILE" && -f "${ROOT}/.env.example" ]]; then
|
||||
cp -n "${ROOT}/.env.example" "$ENV_FILE" || true
|
||||
fi
|
||||
|
||||
if [[ -f "$ENV_FILE" ]]; then
|
||||
set -a
|
||||
# shellcheck disable=SC1090
|
||||
source "$ENV_FILE"
|
||||
set +a
|
||||
fi
|
||||
|
||||
: "${OLLAMA_URL:=http://127.0.0.1:11434}"
|
||||
: "${EXPERT_MODEL:=jr-sql-expert}"
|
||||
: "${BASE_MODEL:=}"
|
||||
: "${EXTRA_MODELS:=}"
|
||||
export OLLAMA_URL EXPERT_MODEL BASE_MODEL EXTRA_MODELS
|
||||
|
||||
# The Ollama CLI honors OLLAMA_HOST.
|
||||
export OLLAMA_HOST="$OLLAMA_URL"
|
||||
}
|
||||
|
||||
is_json(){
|
||||
python -c 'import json,sys; json.load(sys.stdin)' >/dev/null 2>&1
|
||||
}
|
||||
|
||||
wait_for_ollama_api(){
|
||||
local url="$1"
|
||||
local max_wait="${2:-120}"
|
||||
local i
|
||||
|
||||
for ((i=1; i<=max_wait; i++)); do
|
||||
if curl -fsS "${url}/api/tags" >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
fetch_tags(){
|
||||
curl -fsS "${OLLAMA_URL}/api/tags"
|
||||
}
|
||||
|
||||
model_in_tags(){
|
||||
local model="$1"
|
||||
local tags="$2"
|
||||
TAGS_JSON="$tags" python - "$model" <<'PY'
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
m = sys.argv[1]
|
||||
obj = json.loads(os.environ['TAGS_JSON'])
|
||||
names = {it.get('name') for it in obj.get('models', []) if it.get('name')}
|
||||
ok = (
|
||||
m in names or
|
||||
f"{m}:latest" in names or
|
||||
(m.endswith(':latest') and m[:-7] in names)
|
||||
)
|
||||
sys.exit(0 if ok else 1)
|
||||
PY
|
||||
}
|
||||
|
||||
render_modelfile(){
|
||||
local out_file="$1"
|
||||
[[ -f "$MODFILE" ]] || fail "Modelfile not found at $MODFILE" 20
|
||||
[[ -n "$BASE_MODEL" ]] || fail "BASE_MODEL is empty" 21
|
||||
|
||||
python - "$MODFILE" "$out_file" "$BASE_MODEL" <<'PY'
|
||||
from pathlib import Path
|
||||
import sys
|
||||
src = Path(sys.argv[1]).read_text(encoding='utf-8')
|
||||
out = src.replace('${BASE_MODEL}', sys.argv[3])
|
||||
Path(sys.argv[2]).write_text(out, encoding='utf-8')
|
||||
PY
|
||||
}
|
||||
|
||||
check_for_legacy_docker_ollama(){
|
||||
if ! command -v docker >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if docker ps --format '{{.Names}}' | grep -qx 'ollama'; then
|
||||
fail "legacy docker container 'ollama' is still running; run cleanup-docker-ollama.sh first" 30
|
||||
fi
|
||||
|
||||
if docker ps -a --format '{{.Names}}' | grep -qx 'ollama'; then
|
||||
warn "legacy docker container 'ollama' still exists in stopped state; cleanup recommended"
|
||||
fi
|
||||
|
||||
if docker images --format '{{.Repository}}:{{.Tag}}' | grep -qx 'ollama/ollama:latest'; then
|
||||
warn "legacy docker image ollama/ollama:latest still exists; cleanup recommended"
|
||||
fi
|
||||
}
|
||||
|
||||
warmup_sqlai(){
|
||||
if [[ -x "$SQLAI_BIN" ]]; then
|
||||
log "warmup via ${SQLAI_BIN}"
|
||||
"$SQLAI_BIN" ask --text "Warmup: reply with exactly 'OK'." --no-metrics || warn "warmup failed"
|
||||
else
|
||||
warn "${SQLAI_BIN} not executable; skipping warmup"
|
||||
fi
|
||||
}
|
||||
|
||||
print_header(){
|
||||
echo "================================================================================"
|
||||
log "$1 ROOT=$ROOT"
|
||||
}
|
||||
|
||||
print_footer(){
|
||||
log "$1"
|
||||
echo "================================================================================"
|
||||
}
|
||||
Executable
+60
@@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_OVERRIDE="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
export ROOT_OVERRIDE
|
||||
# shellcheck disable=SC1091
|
||||
source "${ROOT_OVERRIDE}/scripts/common.sh"
|
||||
|
||||
init_log selftest-native
|
||||
print_header "selftest-native: START"
|
||||
|
||||
need_cmd curl
|
||||
need_cmd python
|
||||
need_cmd ollama
|
||||
need_cmd grep
|
||||
load_env
|
||||
check_for_legacy_docker_ollama
|
||||
|
||||
[[ -x "$SQLAI_BIN" ]] || fail "bin/sqlai missing or not executable at ${SQLAI_BIN}" 60
|
||||
|
||||
log "selftest-native: waiting for Ollama API at ${OLLAMA_URL}"
|
||||
wait_for_ollama_api "$OLLAMA_URL" 120 || fail "Ollama API not reachable at ${OLLAMA_URL}" 61
|
||||
ok "selftest-native: Ollama API reachable"
|
||||
|
||||
tags="$(fetch_tags)"
|
||||
[[ -n "$tags" ]] || fail "/api/tags returned empty body" 62
|
||||
printf '%s' "$tags" | is_json || fail "/api/tags did not return valid JSON" 63
|
||||
ok "selftest-native: /api/tags returned valid JSON"
|
||||
|
||||
if model_in_tags "$EXPERT_MODEL" "$tags"; then
|
||||
ok "selftest-native: expert model present: ${EXPERT_MODEL}"
|
||||
else
|
||||
fail "expert model missing: ${EXPERT_MODEL}" 64
|
||||
fi
|
||||
|
||||
if [[ -n "${BASE_MODEL}" ]]; then
|
||||
if model_in_tags "$BASE_MODEL" "$tags"; then
|
||||
ok "selftest-native: base model present: ${BASE_MODEL}"
|
||||
else
|
||||
fail "base model missing: ${BASE_MODEL}" 65
|
||||
fi
|
||||
fi
|
||||
|
||||
log "selftest-native: warmup request via sqlai"
|
||||
set +e
|
||||
"$SQLAI_BIN" ask --text "Warmup: reply with exactly 'OK'." --no-metrics
|
||||
rc=$?
|
||||
set -e
|
||||
[[ "$rc" -eq 0 ]] || warn "warmup failed rc=${rc}"
|
||||
|
||||
log "selftest-native: real query via sqlai"
|
||||
set +e
|
||||
out="$("$SQLAI_BIN" ask --text "Give a concise checklist to troubleshoot parameter sniffing in SQL Server 2022. Keep it technical." --no-metrics 2>&1)"
|
||||
rc=$?
|
||||
set -e
|
||||
[[ "$rc" -eq 0 ]] || fail "real query failed rc=${rc}" 66
|
||||
[[ -n "${out//[[:space:]]/}" ]] || fail "real query returned empty output" 67
|
||||
ok "selftest-native: real query returned non-empty output"
|
||||
|
||||
print_footer "selftest-native: END status=OK log=${LOG_FILE}"
|
||||
@@ -1,212 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
ENV_FILE="${ROOT}/.env"
|
||||
|
||||
ts(){ date -Is; }
|
||||
|
||||
log_dir="${ROOT}/logs"
|
||||
mkdir -p "$log_dir"
|
||||
log_file="${log_dir}/selftest-$(date -Iseconds).log"
|
||||
exec > >(tee -a "$log_file") 2>&1
|
||||
|
||||
echo "================================================================================"
|
||||
echo "[$(ts)] selftest: START ROOT=$ROOT"
|
||||
|
||||
# -------- helpers --------
|
||||
fail() {
|
||||
local msg="$1"
|
||||
local code="${2:-1}"
|
||||
echo "[$(ts)] selftest: FAIL code=$code msg=$msg"
|
||||
echo "[$(ts)] selftest: END status=FAIL"
|
||||
echo "================================================================================"
|
||||
exit "$code"
|
||||
}
|
||||
|
||||
warn() {
|
||||
echo "[$(ts)] selftest: WARN $*"
|
||||
}
|
||||
|
||||
ok() {
|
||||
echo "[$(ts)] selftest: OK $*"
|
||||
}
|
||||
|
||||
need_cmd() {
|
||||
command -v "$1" >/dev/null 2>&1 || fail "missing command: $1" 10
|
||||
}
|
||||
|
||||
# robust JSON check
|
||||
is_json() {
|
||||
# reads stdin
|
||||
python -c 'import json,sys; json.load(sys.stdin)' >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# Extract model names from /api/tags JSON and check membership
|
||||
model_in_tags() {
|
||||
# args: modelname, tags_json_string
|
||||
local model="$1"
|
||||
local tags="$2"
|
||||
printf '%s' "$tags" | python -c '
|
||||
import json,sys
|
||||
m=sys.argv[1]
|
||||
obj=json.load(sys.stdin)
|
||||
names=set()
|
||||
for it in obj.get("models", []):
|
||||
n=it.get("name")
|
||||
if n: names.add(n)
|
||||
ok = (m in names) or (m + ":latest" in names) or (m.endswith(":latest") and m[:-7] in names)
|
||||
sys.exit(0 if ok else 1)
|
||||
' "$model" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# -------- preflight --------
|
||||
need_cmd docker
|
||||
need_cmd curl
|
||||
need_cmd python
|
||||
need_cmd grep
|
||||
need_cmd sed
|
||||
|
||||
if [[ ! -f "$ENV_FILE" ]]; then
|
||||
warn ".env not found, creating from .env.example"
|
||||
cp -n "${ROOT}/.env.example" "${ROOT}/.env" || true
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC1090
|
||||
source "${ROOT}/.env"
|
||||
|
||||
: "${OLLAMA_URL:=http://127.0.0.1:11434}"
|
||||
: "${EXPERT_MODEL:=jr-sql-expert}"
|
||||
: "${BASE_MODEL:=}"
|
||||
|
||||
ok "loaded env: OLLAMA_URL=$OLLAMA_URL EXPERT_MODEL=$EXPERT_MODEL BASE_MODEL=${BASE_MODEL:-<empty>}"
|
||||
|
||||
if [[ ! -x "${ROOT}/bin/sqlai" ]]; then
|
||||
fail "bin/sqlai missing or not executable at ${ROOT}/bin/sqlai" 11
|
||||
fi
|
||||
|
||||
# docker compose availability (plugin or legacy)
|
||||
if docker compose version >/dev/null 2>&1; then
|
||||
ok "docker compose available"
|
||||
else
|
||||
fail "docker compose not available (install docker compose plugin)" 12
|
||||
fi
|
||||
|
||||
# container state
|
||||
if docker ps --format '{{.Names}}' | grep -qx 'ollama'; then
|
||||
ok "container 'ollama' is running"
|
||||
else
|
||||
warn "container 'ollama' not running; attempting 'docker compose up -d'"
|
||||
docker compose -f "${ROOT}/docker-compose.yml" up -d || fail "docker compose up failed" 13
|
||||
if ! docker ps --format '{{.Names}}' | grep -qx 'ollama'; then
|
||||
fail "container 'ollama' still not running after compose up" 14
|
||||
fi
|
||||
ok "container 'ollama' is running after compose up"
|
||||
fi
|
||||
|
||||
# API wait loop
|
||||
ok "waiting for Ollama API at $OLLAMA_URL ..."
|
||||
api_ok="0"
|
||||
for i in {1..120}; do
|
||||
if curl -sS "${OLLAMA_URL}/api/tags" >/dev/null 2>&1; then
|
||||
api_ok="1"
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
[[ "$api_ok" == "1" ]] || fail "Ollama API not reachable at $OLLAMA_URL after waiting" 20
|
||||
ok "Ollama API reachable"
|
||||
|
||||
# Fetch /api/tags and validate JSON
|
||||
tags="$(curl -sS "${OLLAMA_URL}/api/tags" || true)"
|
||||
[[ -n "$tags" ]] || fail "/api/tags returned empty body" 21
|
||||
|
||||
if ! printf '%s' "$tags" | is_json; then
|
||||
echo "[$(ts)] selftest: /api/tags RAW_BEGIN"
|
||||
printf '%s\n' "$tags" | head -n 200
|
||||
echo "[$(ts)] selftest: /api/tags RAW_END"
|
||||
fail "/api/tags did not return JSON" 22
|
||||
fi
|
||||
ok "/api/tags returned valid JSON"
|
||||
|
||||
# Model availability checks
|
||||
expert_present="0"
|
||||
base_present="0"
|
||||
|
||||
if model_in_tags "$EXPERT_MODEL" "$tags"; then
|
||||
expert_present="1"
|
||||
ok "EXPERT_MODEL present: $EXPERT_MODEL"
|
||||
else
|
||||
warn "EXPERT_MODEL not present in tags: $EXPERT_MODEL"
|
||||
fi
|
||||
|
||||
if [[ -n "${BASE_MODEL:-}" ]] && model_in_tags "$BASE_MODEL" "$tags"; then
|
||||
base_present="1"
|
||||
ok "BASE_MODEL present: $BASE_MODEL"
|
||||
else
|
||||
if [[ -n "${BASE_MODEL:-}" ]]; then
|
||||
warn "BASE_MODEL not present in tags: $BASE_MODEL"
|
||||
else
|
||||
warn "BASE_MODEL empty in .env"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$expert_present" != "1" && "$base_present" != "1" ]]; then
|
||||
warn "No expert/base model found. Attempting to pull BASE_MODEL if set..."
|
||||
if [[ -n "${BASE_MODEL:-}" ]]; then
|
||||
docker exec -it ollama ollama pull "${BASE_MODEL}" || warn "ollama pull BASE_MODEL failed"
|
||||
tags2="$(curl -sS "${OLLAMA_URL}/api/tags" || true)"
|
||||
if printf '%s' "$tags2" | is_json && model_in_tags "$BASE_MODEL" "$tags2"; then
|
||||
ok "BASE_MODEL now present after pull: $BASE_MODEL"
|
||||
base_present="1"
|
||||
else
|
||||
fail "Neither EXPERT_MODEL nor BASE_MODEL available after attempted pull" 23
|
||||
fi
|
||||
else
|
||||
fail "Neither EXPERT_MODEL nor BASE_MODEL available and BASE_MODEL is empty" 24
|
||||
fi
|
||||
fi
|
||||
|
||||
# Warmup request
|
||||
ok "warmup request via sqlai (no-metrics)"
|
||||
set +e
|
||||
"${ROOT}/bin/sqlai" ask --text "Warmup: reply with exactly 'OK'." --no-metrics
|
||||
rc=$?
|
||||
set -e
|
||||
if [[ "$rc" -ne 0 ]]; then
|
||||
warn "warmup failed rc=$rc (continuing to real query)"
|
||||
else
|
||||
ok "warmup succeeded"
|
||||
fi
|
||||
|
||||
# Real query (slightly longer)
|
||||
ok "real query via sqlai (ask)"
|
||||
set +e
|
||||
out="$("${ROOT}/bin/sqlai" ask --text "Give a concise checklist to troubleshoot parameter sniffing in SQL Server 2022. Keep it technical." --no-metrics 2>&1)"
|
||||
rc=$?
|
||||
set -e
|
||||
if [[ "$rc" -ne 0 ]]; then
|
||||
echo "[$(ts)] selftest: sqlai output BEGIN"
|
||||
printf '%s\n' "$out" | tail -n 200
|
||||
echo "[$(ts)] selftest: sqlai output END"
|
||||
fail "real query failed rc=$rc" 30
|
||||
fi
|
||||
|
||||
# Basic sanity: must contain at least some non-empty text
|
||||
if [[ -z "${out//[[:space:]]/}" ]]; then
|
||||
fail "real query returned empty output" 31
|
||||
fi
|
||||
|
||||
ok "real query returned non-empty output"
|
||||
|
||||
# Summary
|
||||
echo "--------------------------------------------------------------------------------"
|
||||
echo "[$(ts)] selftest: SUMMARY"
|
||||
echo "[$(ts)] selftest: API=OK"
|
||||
echo "[$(ts)] selftest: EXPERT_MODEL_PRESENT=$expert_present"
|
||||
echo "[$(ts)] selftest: BASE_MODEL_PRESENT=$base_present"
|
||||
echo "[$(ts)] selftest: LOG_FILE=$log_file"
|
||||
echo "--------------------------------------------------------------------------------"
|
||||
|
||||
echo "[$(ts)] selftest: END status=OK"
|
||||
echo "================================================================================"
|
||||
Executable
+46
@@ -0,0 +1,46 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_OVERRIDE="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
export ROOT_OVERRIDE
|
||||
# shellcheck disable=SC1091
|
||||
source "${ROOT_OVERRIDE}/scripts/common.sh"
|
||||
|
||||
init_log update-native
|
||||
print_header "update-native: START"
|
||||
|
||||
need_cmd curl
|
||||
need_cmd python
|
||||
need_cmd ollama
|
||||
load_env
|
||||
check_for_legacy_docker_ollama
|
||||
|
||||
log "update-native: waiting for Ollama API at ${OLLAMA_URL}"
|
||||
wait_for_ollama_api "$OLLAMA_URL" 120 || fail "Ollama API not reachable at ${OLLAMA_URL}" 50
|
||||
ok "update-native: Ollama API reachable"
|
||||
|
||||
log "update-native: pulling base model ${BASE_MODEL}"
|
||||
ollama pull "${BASE_MODEL}"
|
||||
|
||||
if [[ -n "${EXTRA_MODELS}" ]]; then
|
||||
for m in ${EXTRA_MODELS}; do
|
||||
log "update-native: pulling extra model ${m}"
|
||||
ollama pull "$m"
|
||||
done
|
||||
fi
|
||||
|
||||
tmp="$(mktemp)"
|
||||
trap 'rm -f "$tmp"' EXIT
|
||||
render_modelfile "$tmp"
|
||||
|
||||
log "update-native: rebuilding expert model ${EXPERT_MODEL}"
|
||||
ollama create "${EXPERT_MODEL}" -f "$tmp"
|
||||
|
||||
tags="$(fetch_tags)"
|
||||
printf '%s' "$tags" | is_json || fail "/api/tags did not return valid JSON" 51
|
||||
model_in_tags "$BASE_MODEL" "$tags" || fail "base model missing after update: ${BASE_MODEL}" 52
|
||||
model_in_tags "$EXPERT_MODEL" "$tags" || fail "expert model missing after update: ${EXPERT_MODEL}" 53
|
||||
ok "update-native: base and expert models are available"
|
||||
|
||||
warmup_sqlai
|
||||
print_footer "update-native: END status=OK log=${LOG_FILE}"
|
||||
@@ -1,70 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
source "${ROOT}/.env"
|
||||
|
||||
ts(){ date -Is; }
|
||||
|
||||
log_dir="${ROOT}/logs"
|
||||
mkdir -p "$log_dir"
|
||||
log_file="${log_dir}/update-$(date -Iseconds).log"
|
||||
exec > >(tee -a "$log_file") 2>&1
|
||||
|
||||
echo "[$(ts)] update: starting (ROOT=$ROOT)"
|
||||
|
||||
echo "[$(ts)] update: pulling docker image(s)"
|
||||
docker compose -f "${ROOT}/docker-compose.yml" pull
|
||||
|
||||
echo "[$(ts)] update: restarting services"
|
||||
docker compose -f "${ROOT}/docker-compose.yml" up -d
|
||||
|
||||
echo "[$(ts)] update: waiting for Ollama API at ${OLLAMA_URL} ..."
|
||||
for i in {1..120}; do
|
||||
if curl -sS "${OLLAMA_URL}/api/tags" >/dev/null 2>&1; then
|
||||
echo "[$(ts)] update: Ollama API is up."
|
||||
break
|
||||
fi
|
||||
if [[ $i -eq 120 ]]; then
|
||||
echo "[$(ts)] update: ERROR: API did not come up in time."
|
||||
exit 1
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
echo "[$(ts)] update: pulling base model: ${BASE_MODEL}"
|
||||
docker exec -it ollama ollama pull "${BASE_MODEL}"
|
||||
|
||||
if [[ -n "${EXTRA_MODELS:-}" ]]; then
|
||||
for m in ${EXTRA_MODELS}; do
|
||||
echo "[$(ts)] update: pulling extra model: $m"
|
||||
docker exec -it ollama ollama pull "$m"
|
||||
done
|
||||
fi
|
||||
|
||||
echo "[$(ts)] update: rebuilding expert model: ${EXPERT_MODEL}"
|
||||
|
||||
tmp="$(mktemp)"
|
||||
sed "s/\${BASE_MODEL}/${BASE_MODEL}/g" "${ROOT}/Modelfile" > "$tmp"
|
||||
|
||||
docker cp "$tmp" ollama:/tmp/Modelfile.jr-sql-expert
|
||||
docker exec -it ollama ollama create "${EXPERT_MODEL}" -f /tmp/Modelfile.jr-sql-expert
|
||||
|
||||
rm -f "$tmp"
|
||||
|
||||
echo "[$(ts)] update: verifying model exists..."
|
||||
docker exec -it ollama ollama list | grep -F "${EXPERT_MODEL}" >/dev/null && \
|
||||
echo "[$(ts)] update: OK: ${EXPERT_MODEL} is available."
|
||||
|
||||
# Warmup (loads model + GPU kernels, reduces first real query latency)
|
||||
if [[ -x "${ROOT}/bin/sqlai" ]]; then
|
||||
echo "[$(ts)] update: warmup: sending a short request (no-metrics)..."
|
||||
"${ROOT}/bin/sqlai" ask --text "Warmup: reply with exactly 'OK'." --no-metrics || {
|
||||
echo "[$(ts)] update: WARN: warmup failed (continuing)."
|
||||
}
|
||||
echo "[$(ts)] update: warmup: done"
|
||||
else
|
||||
echo "[$(ts)] update: WARN: ${ROOT}/bin/sqlai not executable; skipping warmup."
|
||||
fi
|
||||
|
||||
echo "[$(ts)] update: complete"
|
||||
Reference in New Issue
Block a user