File size: 11,562 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
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# 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