Загрузка данных


# ---------------------------------------------------------------------
# Функция прямой загрузки модели с SHA256-верификацией (без ollama pull)
# Использует curl.exe вместо Invoke-WebRequest
# ---------------------------------------------------------------------
function Invoke-OllamaModelPull {
    param(
        [Parameter(Mandatory)] [string] $ModelTag,    # например "llama3.2:1b"
        [string] $ModelsDir,                          # путь к папке, где хранятся модели
        [switch] $SkipHashVerification
    )
    # Если папка не указана, используем стандартную
    if (-not $ModelsDir) { $ModelsDir = "$env:USERPROFILE\.ollama\models" }
    
    # Разбираем тег на имя и тэг
    $name, $tag = ($ModelTag -split ':')
    if (-not $tag) { $tag = 'latest' }
    $basePath = if ($name -notmatch '/') { '/library' } else { '' }
    $registryBase = "https://registry.ollama.ai/v2$basePath/$name"
    
    # Создаём структуру каталогов (blobs, manifests)
    $blobsDir = Join-Path $ModelsDir 'blobs'
    $manifestsDir = Join-Path $ModelsDir "manifests\registry.ollama.ai$basePath\$name"
    @($blobsDir, $manifestsDir) | ForEach-Object {
        if (-not (Test-Path $_)) { New-Item -ItemType Directory -Path $_ -Force | Out-Null }
    }
    
    $ManifestFile = Join-Path $manifestsDir $tag
    if (Test-Path $ManifestFile -ErrorAction SilentlyContinue) {
        Write-Host "      [!] Model already exists in $ModelsDir" -ForegroundColor Yellow
        return $true
    }
    
    Write-Host "      [=] Downloading manifest from $registryBase/manifests/$tag"
    curl.exe -L --fail -o "$ManifestFile" "$registryBase/manifests/$tag"
    if ($LASTEXITCODE -ne 0) {
        Write-Host "      [x] Failed to download manifest (curl exit code $LASTEXITCODE)" -ForegroundColor Red
        return $false
    }
    
    # Читаем манифест (предполагаем, что файл существует и содержит JSON)
    try {
        $manifestJson = Get-Content $ManifestFile -Raw | ConvertFrom-Json
    } catch {
        Write-Host "      [x] Failed to parse manifest JSON: $_" -ForegroundColor Red
        return $false
    }
    
    $blobDigests = @($manifestJson.config.digest) + ($manifestJson.layers | ForEach-Object { $_.digest })
    $total = $blobDigests.Count
    $downloaded = 0
    
    foreach ($digest in $blobDigests) {
        $blobFile = Join-Path $blobsDir ($digest -replace ':', '-')
        if (Test-Path $blobFile) {
            Write-Host "      [=] Blob $($downloaded+1)/$total already exists: $digest" -ForegroundColor DarkGray
            $downloaded++
            continue
        }
        Write-Host "      [=] Downloading blob $($downloaded+1)/$total : $digest"
        curl.exe -L --fail -o "$blobFile" "$registryBase/blobs/$digest"
        if ($LASTEXITCODE -ne 0) {
            Write-Host "      [x] Failed to download blob (curl exit code $LASTEXITCODE)" -ForegroundColor Red
            return $false
        }
        
        # Проверка SHA256 (если не пропущена)
        if (-not $SkipHashVerification) {
            $computedHash = (Get-FileHash -Path $blobFile -Algorithm SHA256).Hash.ToLower()
            $expectedHash = ($digest -replace '^sha256:', '').ToLower()
            if ($computedHash -ne $expectedHash) {
                Write-Host "      [x] Hash mismatch! Expected $expectedHash, got $computedHash" -ForegroundColor Red
                return $false
            } else {
                Write-Host "      [+] Hash verified" -ForegroundColor Green
            }
        }
        $downloaded++
    }
    
    # Регистрируем модель через API Ollama (только если сервер запущен)
    Write-Host "      [=] Registering model with Ollama API..." -ForegroundColor DarkGray
    $registerBody = @{ name = "$name`:$tag" } | ConvertTo-Json
    # Создаём временный файл для тела POST запроса, чтобы избежать проблем с кавычками в cmd.exe
    $bodyFile = [System.IO.Path]::GetTempFileName()
    Set-Content -Path $bodyFile -Value $registerBody -Encoding UTF8
    curl.exe -X POST -H "Content-Type: application/json" -d "@$bodyFile" -o NUL http://localhost:11434/api/pull
    $curlExit = $LASTEXITCODE
    Remove-Item $bodyFile -Force -ErrorAction SilentlyContinue
    if ($curlExit -eq 0) {
        Write-Host "      [+] Model registered successfully" -ForegroundColor Green
    } else {
        Write-Host "      [!] Could not auto-register (curl exit $curlExit), but model files are ready. You may need to restart Ollama." -ForegroundColor Yellow
    }
    return $true
}