File size: 9,348 Bytes
4346e8f 9438a57 4346e8f 9438a57 4346e8f 9438a57 4346e8f 9438a57 4346e8f 9438a57 4346e8f 9438a57 4346e8f 9438a57 4346e8f | 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 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | #!/usr/bin/env bash
# TestAjanı başlatıcı (macOS + Linux).
# Kullanım: ./scripts/start.sh [--rebuild] [--model MODEL] [--no-browser]
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT"
MODEL="${OLLAMA_MODEL:-qwen2.5-coder:7b}"
REBUILD=0
OPEN_BROWSER=1
APP_URL="http://localhost:8000"
while [ $# -gt 0 ]; do
case "$1" in
--rebuild) REBUILD=1 ;;
--model) MODEL="$2"; shift ;;
--no-browser) OPEN_BROWSER=0 ;;
-h|--help) sed -n '2,3p' "$0"; exit 0 ;;
*) echo "Bilinmeyen seçenek: $1"; exit 2 ;;
esac
shift
done
OS="$(uname -s)"
step() { printf '\n\033[1;34m==>\033[0m %s\n' "$1"; }
ok() { printf ' \033[32m✓\033[0m %s\n' "$1"; }
fail() { printf '\n\033[31mHATA:\033[0m %s\n' "$1"; exit 1; }
http_ok() { curl -fsS -m 3 -o /dev/null "$1" 2>/dev/null; }
# ---------------------------------------------------------------- 1. Docker kurulu mu?
step "Docker kontrol ediliyor"
if ! command -v docker >/dev/null 2>&1; then
if [ "$OS" = "Darwin" ]; then
echo " Docker Desktop kurulu değil."
if command -v brew >/dev/null 2>&1; then
read -r -p " Homebrew ile şimdi kurulsun mu? [E/h] " ans
if [[ ! "$ans" =~ ^[Hh] ]]; then
brew install --cask docker
else
fail "Docker Desktop'ı https://www.docker.com/products/docker-desktop/ adresinden kurup tekrar deneyin."
fi
else
fail "Docker Desktop'ı https://www.docker.com/products/docker-desktop/ adresinden kurup tekrar deneyin."
fi
else
fail "Docker kurulu değil. Kurulum: https://docs.docker.com/engine/install/ (hızlı yol: curl -fsSL https://get.docker.com | sh)"
fi
fi
ok "docker komutu bulundu"
# ---------------------------------------------------------------- 2. Docker çalışıyor mu?
if ! docker info >/dev/null 2>&1; then
if [ "$OS" = "Darwin" ]; then
echo " Docker Desktop başlatılıyor…"
open -a Docker || fail "Docker Desktop açılamadı. Uygulamalar klasöründen elle açın."
elif docker info 2>&1 | grep -qi "permission denied"; then
fail "Docker'a erişim izni yok. Şunu çalıştırıp oturumu kapatıp açın: sudo usermod -aG docker \$USER"
else
echo " Docker servisi başlatılıyor (sudo parolası istenebilir)…"
sudo systemctl start docker 2>/dev/null || true
fi
for _ in $(seq 1 60); do
docker info >/dev/null 2>&1 && break
sleep 3
done
docker info >/dev/null 2>&1 || fail "Docker 3 dakikada başlamadı. Docker'ı elle açıp tekrar deneyin."
fi
docker compose version >/dev/null 2>&1 || fail "'docker compose' bulunamadı. Docker'ı güncelleyin (Compose v2 gerekli)."
ok "Docker çalışıyor"
# ---------------------------------------------------------------- 3. Sandbox imajları
step "Kod çalıştırma ortamları (sandbox imajları)"
for lang in python node java ui; do
img="lta-sandbox-$lang"
# Dockerfile değiştiyse (ör. yeni kütüphane) imaj yeniden derlenir: özet imaj etiketinde tutulur
hash="$( (sha256sum "sandbox/docker/$lang.Dockerfile" 2>/dev/null || shasum -a 256 "sandbox/docker/$lang.Dockerfile") | cut -c1-16)"
have="$(docker image inspect "$img" --format '{{ index .Config.Labels "lta.hash" }}' 2>/dev/null || true)"
if [ "$REBUILD" = 1 ] || [ "$have" != "$hash" ]; then
echo " $img derleniyor (ilk seferde birkaç dakika sürer)…"
docker build -q --label "lta.hash=$hash" -f "sandbox/docker/$lang.Dockerfile" -t "$img" sandbox >/dev/null
fi
ok "$img"
done
# ---------------------------------------------------------------- 4. Ollama: yerel mi, konteyner mi?
step "Dil modeli sunucusu (Ollama)"
PROFILE_ARGS=()
if http_ok "http://localhost:11434/api/tags" && ! docker compose ps --services --status running 2>/dev/null | grep -qx ollama; then
export OLLAMA_URL="http://host.docker.internal:11434"
OLLAMA_MODE=host
ok "Bilgisayardaki Ollama kullanılacak"
else
export OLLAMA_URL="http://ollama:11434"
OLLAMA_MODE=docker
PROFILE_ARGS=(--profile ollama)
ok "Ollama konteynerde çalışacak"
if command -v nvidia-smi >/dev/null || [ "$(uname)" = "Darwin" ]; then
echo " [UYARI] Konteynerdeki Ollama ekran kartını (Mac'te Metal) genellikle kullanmaz; çok yavaş olur."
echo " Hız için Ollama'yı bilgisayara kurun: https://ollama.com/download — sonra yeniden başlatın."
fi
fi
export OLLAMA_MODEL="$MODEL"
# ---------------------------------------------------------------- 5. Uygulamayı başlat
step "Uygulama başlatılıyor"
EXPECTED="$(head -n1 VERSION 2>/dev/null | tr -d '[:space:]')"
# Başka bir klasörden (eski sürümden) başlatılmış ve 8000 portunu tutan uygulama konteynerini kaldır
docker ps -a --filter "publish=8000" --format '{{.ID}}|{{.Names}}|{{.Labels}}' 2>/dev/null | while IFS='|' read -r cid cname clabels; do
proj="$(printf '%s' "$clabels" | tr ',' '\n' | sed -n 's/^com\.docker\.compose\.project=//p')"
if [ -n "$cid" ] && [ "$proj" != "llm-test-agent" ]; then
echo " Eski uygulama konteyneri kaldırılıyor: $cname (proje: ${proj:-yok})"
docker rm -f "$cid" >/dev/null 2>&1 || true
fi
done
# Her başlatmada imaj güncellenir; değişiklik yoksa Docker önbelleği sayesinde birkaç saniye sürer
BUILD_ARGS=(--build)
if [ -z "$(docker compose images -q app 2>/dev/null)" ]; then
echo " Uygulama imajı derleniyor (ilk seferde birkaç dakika sürer)…"
fi
# Not: macOS'taki bash 3.2 boş dizileri "set -u" altında sorun sayar; bu yüzden ${a[@]+...} kalıbı
# NVIDIA kartı varsa uygulama konteynerine GPU izleme erişimi verilir (gerçek zamanlı GPU göstergesi için)
GPU_FILES=()
command -v nvidia-smi >/dev/null && GPU_FILES=(-f docker-compose.yml -f docker-compose.gpu.yml)
if ! docker compose ${GPU_FILES[@]+"${GPU_FILES[@]}"} ${PROFILE_ARGS[@]+"${PROFILE_ARGS[@]}"} up -d ${BUILD_ARGS[@]+"${BUILD_ARGS[@]}"}; then
[ ${#GPU_FILES[@]} -gt 0 ] || fail "docker compose up başarısız oldu. Ayrıntı: docker compose logs"
echo " [UYARI] Konteynere GPU erişimi verilemedi; GPU göstergesi yalnızca Ollama bilgisini gösterecek."
docker compose ${PROFILE_ARGS[@]+"${PROFILE_ARGS[@]}"} up -d ${BUILD_ARGS[@]+"${BUILD_ARGS[@]}"} || fail "docker compose up başarısız oldu."
fi
ok "Konteynerler ayakta"
# ---------------------------------------------------------------- 6. Model
step "Model: $MODEL"
for _ in $(seq 1 40); do http_ok "http://localhost:11434/api/tags" && break; sleep 2; done
if curl -fsS -m 5 "http://localhost:11434/api/tags" 2>/dev/null | grep -q "\"name\":\"$MODEL"; then
ok "Model zaten indirilmiş"
else
echo " Model indiriliyor (yalnızca ilk seferde; ~5 GB)…"
if [ "$OLLAMA_MODE" = host ]; then
ollama pull "$MODEL"
else
docker compose --profile ollama exec -T ollama ollama pull "$MODEL"
fi
ok "Model hazır"
fi
# ---------------------------------------------------------------- 7. Hazır olmasını bekle, tarayıcıyı aç
step "Arayüz hazırlanıyor"
# Hafif /api/ping kullanılır (Ollama'ya dokunmaz); eski sürümde ping yoksa /api/health'e uzun zaman aşımıyla bakılır.
app_version() {
local v
v="$(curl -fsS -m 5 "$1/api/ping" 2>/dev/null | sed -n 's/.*"version":"\([^"]*\)".*/\1/p')"
[ -n "$v" ] || v="$(curl -fsS -m 30 "$1/api/health" 2>/dev/null | sed -n 's/.*"version":"\([^"]*\)".*/\1/p')"
printf '%s' "$v"
}
wait_app() {
local v u
for _ in $(seq 1 60); do
for u in "http://localhost:8000" "http://127.0.0.1:8000"; do
v="$(app_version "$u")"
if [ -n "$v" ]; then APP_URL="$u"; RUNNING="$v"; return 0; fi
done
sleep 2
done
RUNNING=""; return 1
}
show_diag() {
printf '\n\033[33m---- docker compose ps ----\033[0m\n'; docker compose ps -a || true
printf '\033[33m---- docker compose logs app (son 60 satır) ----\033[0m\n'; docker compose logs app --tail 60 || true
}
wait_app || { show_diag; fail "Uygulama yanıt vermiyor. Yukarıdaki satırların ekran görüntüsünü paylaşın."; }
if [ -n "$EXPECTED" ] && [ "$RUNNING" != "$EXPECTED" ]; then
echo " Çalışan sürüm '${RUNNING}', beklenen '${EXPECTED}'. Uygulama önbelleksiz yeniden derleniyor…"
docker compose ${GPU_FILES[@]+"${GPU_FILES[@]}"} build --no-cache app || docker compose build --no-cache app
docker compose ${GPU_FILES[@]+"${GPU_FILES[@]}"} ${PROFILE_ARGS[@]+"${PROFILE_ARGS[@]}"} up -d --force-recreate app \
|| docker compose ${PROFILE_ARGS[@]+"${PROFILE_ARGS[@]}"} up -d --force-recreate app
wait_app || true
[ "$RUNNING" = "$EXPECTED" ] || { show_diag; fail "Uygulama hâlâ eski sürümde ('${RUNNING}'). 'docker ps' ile 8000 portunu kullanan konteyneri kontrol edin."; }
fi
if ! curl -fsS -m 30 "$APP_URL/api/health" 2>/dev/null | grep -q '"ollama":{"ok":true'; then
printf ' \033[33m!\033[0m Uygulama Ollama’ya ulaşamıyor (%s).\n' "$OLLAMA_URL"
echo " Ollama'yı yeniden başlatın; sürerse OLLAMA_HOST=0.0.0.0 ile başlatın (Linux: systemctl edit ollama)."
echo " Arayüz yine de açılıyor; Ollama düzelince üst çubuktaki durum yeşile döner."
fi
ok "Sürüm: $RUNNING"
ok "Hazır: $APP_URL"
if [ "$OPEN_BROWSER" = 1 ]; then
if [ "$OS" = "Darwin" ]; then open "$APP_URL/?v=$RUNNING"
elif command -v xdg-open >/dev/null 2>&1; then xdg-open "$APP_URL/?v=$RUNNING" >/dev/null 2>&1 &
fi
fi
echo
echo "Durdurmak için: ./scripts/stop.sh (veya Durdur kısayolu)"
|