# TestAjanı başlatıcı (Windows). Baslat-Windows.bat bu betiği çağırır. # Kullanım: powershell -ExecutionPolicy Bypass -File scripts\start.ps1 [-Rebuild] [-Model qwen2.5-coder:7b] [-NoBrowser] param( [switch]$Rebuild, [string]$Model = $(if ($env:OLLAMA_MODEL) { $env:OLLAMA_MODEL } else { "qwen2.5-coder:7b" }), [switch]$NoBrowser ) $ErrorActionPreference = "Continue" # docker'ın stderr çıktıları betiği durdurmasın; çıkış kodlarına bakıyoruz [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 $Root = Split-Path -Parent $PSScriptRoot Set-Location $Root $AppUrl = "http://localhost:8000" function Step($m) { Write-Host ""; Write-Host "==> $m" -ForegroundColor Cyan } function Ok($m) { Write-Host " [OK] $m" -ForegroundColor Green } function Fail($m) { Write-Host ""; Write-Host "HATA: $m" -ForegroundColor Red; exit 1 } function HttpOk($url) { try { Invoke-WebRequest -Uri $url -UseBasicParsing -TimeoutSec 3 | Out-Null; return $true } catch { return $false } } function DockerRunning { docker info *> $null; return ($LASTEXITCODE -eq 0) } # ---------------------------------------------------------------- 1. Docker kurulu mu? Step "Docker kontrol ediliyor" $dockerBin = Join-Path $env:ProgramFiles "Docker\Docker\resources\bin" if (-not (Get-Command docker -ErrorAction SilentlyContinue) -and (Test-Path (Join-Path $dockerBin "docker.exe"))) { $env:Path = "$dockerBin;$env:Path" # yeni kurulmuş, PATH henüz yenilenmemiş } if (-not (Get-Command docker -ErrorAction SilentlyContinue)) { Write-Host " Docker Desktop kurulu degil. TestAjani kodu guvenli calistirmak icin Docker kullanir." -ForegroundColor Yellow if (Get-Command winget -ErrorAction SilentlyContinue) { $ans = Read-Host " Docker Desktop simdi winget ile kurulsun mu? [E/h]" if ($ans -notmatch '^[HhNn]') { winget install -e --id Docker.DockerDesktop --accept-source-agreements --accept-package-agreements Write-Host "" Write-Host "Kurulum bitti. Bilgisayari YENIDEN BASLATIN (WSL 2 icin gerekebilir)," -ForegroundColor Yellow Write-Host "Docker Desktop'i bir kez acip lisans ekranini onaylayin, sonra bu kisayolu tekrar calistirin." -ForegroundColor Yellow exit 0 } } Fail "Docker Desktop'i https://www.docker.com/products/docker-desktop/ adresinden kurup bu kisayolu tekrar calistirin." } Ok "docker komutu bulundu" # ---------------------------------------------------------------- 2. Docker çalışıyor mu? if (-not (DockerRunning)) { $exe = Join-Path $env:ProgramFiles "Docker\Docker\Docker Desktop.exe" if (Test-Path $exe) { Write-Host " Docker Desktop baslatiliyor (1-2 dakika surebilir)..." Start-Process $exe } else { Write-Host " Docker Desktop'i elle baslatin; bekleniyor..." } $deadline = (Get-Date).AddMinutes(4) while (-not (DockerRunning) -and (Get-Date) -lt $deadline) { Start-Sleep -Seconds 3 } if (-not (DockerRunning)) { Fail "Docker baslamadi. Docker Desktop'i acip 'Engine running' yazisini gorunce tekrar deneyin." } } docker compose version *> $null if ($LASTEXITCODE -ne 0) { Fail "'docker compose' bulunamadi. Docker Desktop'i guncelleyin." } Ok "Docker calisiyor" # ---------------------------------------------------------------- 3. Sandbox imajları Step "Kod calistirma ortamlari (sandbox imajlari)" foreach ($lang in @("python", "node", "java", "ui")) { $img = "lta-sandbox-$lang" # Dockerfile değiştiyse (ör. yeni kütüphane) imaj yeniden derlenir: özet imaj etiketinde tutulur $hash = (Get-FileHash -Algorithm SHA256 "sandbox/docker/$lang.Dockerfile").Hash.Substring(0, 16).ToLower() $have = (docker image inspect $img --format '{{ index .Config.Labels "lta.hash" }}' 2>$null) if ($Rebuild -or $LASTEXITCODE -ne 0 -or $have -ne $hash) { Write-Host " $img derleniyor (ilk seferde birkac dakika surer)..." docker build -q --label "lta.hash=$hash" -f "sandbox/docker/$lang.Dockerfile" -t $img sandbox | Out-Null if ($LASTEXITCODE -ne 0) { Fail "$img derlenemedi. Internet baglantinizi kontrol edin." } } Ok $img } # ---------------------------------------------------------------- 4. Ollama: yerel mi, konteyner mi? Step "Dil modeli sunucusu (Ollama)" $runningSvcs = (docker compose ps --services --status running 2>$null) -join " " if ((HttpOk "http://localhost:11434/api/tags") -and ($runningSvcs -notmatch '\bollama\b')) { $env:OLLAMA_URL = "http://host.docker.internal:11434" $ollamaMode = "host" $profileArgs = @() Ok "Bilgisayardaki Ollama kullanilacak" } else { $env:OLLAMA_URL = "http://ollama:11434" $ollamaMode = "docker" $profileArgs = @("--profile", "ollama") Ok "Ollama konteynerde calisacak" if (Get-Command nvidia-smi -ErrorAction SilentlyContinue) { Write-Host " [UYARI] NVIDIA ekran kartiniz var, ancak konteynerdeki Ollama GPU'yu genellikle KULLANMAZ (cok yavas)." -ForegroundColor Yellow Write-Host " Hiz icin Ollama'yi Windows'a kurun: https://ollama.com/download -> sonra bu baslaticiyi yeniden calistirin." -ForegroundColor Yellow } } $env:OLLAMA_MODEL = $Model # ---------------------------------------------------------------- 5. Uygulamayı başlat Step "Uygulama baslatiliyor" $Expected = (Get-Content (Join-Path $Root "VERSION") -ErrorAction SilentlyContinue | Select-Object -First 1) if ($Expected) { $Expected = $Expected.Trim() } # Başka bir klasörden (eski sürümden) başlatılmış ve 8000 portunu tutan uygulama konteynerini kaldır; # aksi hâlde tarayıcı eski arayüzü açmaya devam eder. $holders = docker ps -a --filter "publish=8000" --format '{{.ID}}|{{.Names}}|{{.Labels}}' 2>$null foreach ($h in @($holders)) { if (-not $h) { continue } $parts = $h -split '\|', 3 $proj = if ($parts[2] -match 'com\.docker\.compose\.project=([^,]+)') { $Matches[1] } else { "" } if ($proj -ne "llm-test-agent") { Write-Host " Eski uygulama konteyneri kaldiriliyor: $($parts[1]) (proje: $proj)" -ForegroundColor Yellow docker rm -f $parts[0] *> $null } } # Her başlatmada imaj güncellenir; değişiklik yoksa Docker önbelleği sayesinde birkaç saniye sürer $buildArgs = @("--build") $appImg = docker compose images -q app 2>$null if (-not $appImg) { Write-Host " Uygulama imaji derleniyor (ilk seferde birkac dakika surer)..." } # NVIDIA kartı varsa uygulama konteynerine GPU izleme erişimi verilir (gerçek zamanlı GPU göstergesi için) $composeFiles = @() if (Get-Command nvidia-smi -ErrorAction SilentlyContinue) { $composeFiles = @("-f", "docker-compose.yml", "-f", "docker-compose.gpu.yml") } docker compose @composeFiles @profileArgs up -d @buildArgs if ($LASTEXITCODE -ne 0 -and $composeFiles.Count) { Write-Host " [UYARI] Konteynere GPU erisimi verilemedi; GPU gostergesi yalnizca Ollama bilgisini gosterecek." -ForegroundColor Yellow docker compose @profileArgs up -d @buildArgs } if ($LASTEXITCODE -ne 0) { Fail "docker compose up basarisiz oldu. Ayrinti: docker compose logs" } Ok "Konteynerler ayakta" # ---------------------------------------------------------------- 6. Model Step "Model: $Model" for ($i = 0; $i -lt 40 -and -not (HttpOk "http://localhost:11434/api/tags"); $i++) { Start-Sleep -Seconds 2 } $have = $false try { $names = (Invoke-RestMethod -Uri "http://localhost:11434/api/tags" -TimeoutSec 5).models | ForEach-Object { $_.name } $have = ($names -contains $Model) -or ($names -contains "$Model`:latest") } catch { } if ($have) { Ok "Model zaten indirilmis" } else { Write-Host " Model indiriliyor (yalnizca ilk seferde; ~5 GB)..." if ($ollamaMode -eq "host") { ollama pull $Model } else { docker compose --profile ollama exec -T ollama ollama pull $Model } if ($LASTEXITCODE -ne 0) { Fail "Model indirilemedi: $Model" } Ok "Model hazir" } # ---------------------------------------------------------------- 7. Hazır olmasını bekle, tarayıcıyı aç Step "Arayuz hazirlaniyor" # Hafif /api/ping kullanılır (Ollama'ya dokunmaz). Eski sürümlerde ping yoksa (404) /api/health'e uzun # zaman aşımıyla bakılır. "localhost" bazı Windows kurulumlarında önce IPv6'ya gider; 127.0.0.1 de denenir. function AppVersion($base) { try { return [string](Invoke-RestMethod -Uri "$base/api/ping" -TimeoutSec 5).version } catch { if ($_.Exception.Response) { try { return [string](Invoke-RestMethod -Uri "$base/api/health" -TimeoutSec 30).version } catch { return "" } } return "" } } function WaitApp { for ($i = 0; $i -lt 60; $i++) { foreach ($u in @("http://localhost:8000", "http://127.0.0.1:8000")) { $v = AppVersion $u if ($v) { $script:AppUrl = $u; return $v } } Start-Sleep -Seconds 2 } return "" } function ShowDiag { Write-Host "" Write-Host "---- docker compose ps ----" -ForegroundColor Yellow docker compose ps -a Write-Host "---- docker compose logs app (son 60 satir) ----" -ForegroundColor Yellow docker compose logs app --tail 60 } $running = WaitApp if (-not $running) { ShowDiag; Fail "Uygulama yanit vermiyor. Yukaridaki satirlarin ekran goruntusunu paylasin." } if ($Expected -and $running -ne $Expected) { Write-Host " Calisan surum '$running', beklenen '$Expected'. Uygulama onbelleksiz yeniden derleniyor..." -ForegroundColor Yellow docker compose @composeFiles build --no-cache app if ($LASTEXITCODE -ne 0) { docker compose build --no-cache app } docker compose @composeFiles @profileArgs up -d --force-recreate app if ($LASTEXITCODE -ne 0) { docker compose @profileArgs up -d --force-recreate app } $running = WaitApp if ($running -ne $Expected) { ShowDiag Fail "Uygulama hala eski surumde ('$running'). 'docker ps' ile 8000 portunu kullanan konteyneri kontrol edin." } } # Uygulama ayakta; Ollama'ya konteynerin içinden ulaşılabiliyor mu? $h = $null try { $h = Invoke-RestMethod -Uri "$AppUrl/api/health" -TimeoutSec 30 } catch { } if ($h -and -not $h.ollama.ok) { Write-Host " [UYARI] Uygulama Ollama'ya ulasamiyor ($($h.ollama.url))." -ForegroundColor Yellow if ($h.ollama.error) { Write-Host " $($h.ollama.error)" -ForegroundColor DarkYellow } if ($ollamaMode -eq "host") { Write-Host " Cozum: 1) Gorev cubugundaki Ollama simgesinden 'Quit Ollama' deyip Ollama'yi yeniden acin." -ForegroundColor Yellow Write-Host " 2) Surerse Ollama > Settings > 'Expose Ollama to the network' secenegini acin" -ForegroundColor Yellow Write-Host " (ya da OLLAMA_HOST=0.0.0.0 ortam degiskenini ekleyip Ollama'yi yeniden baslatin)." -ForegroundColor Yellow Write-Host " 3) Windows Guvenlik Duvari Ollama icin izin isterse 'Ozel aglar'a izin verin." -ForegroundColor Yellow Write-Host " Arayuz yine de aciliyor; Ollama duzelince ust cubuktaki durum yesile doner." -ForegroundColor Yellow } } Ok "Surum: $running" Ok "Hazir: $AppUrl" if (-not $NoBrowser) { Start-Process "$AppUrl/?v=$running" } # sürüm parametresi tarayıcı önbelleğini atlatır Write-Host "" Write-Host "Durdurmak icin Durdur-Windows.bat dosyasini calistirin." exit 0