159 lines
5.5 KiB
PowerShell
159 lines
5.5 KiB
PowerShell
param(
|
|
[ValidateSet("start", "status", "stop", "worker")]
|
|
[string]$Action = "status",
|
|
|
|
[string]$Url = "https://huggingface.co/lmstudio-community/Qwen3-Coder-30B-A3B-Instruct-GGUF/resolve/main/Qwen3-Coder-30B-A3B-Instruct-Q6_K.gguf",
|
|
[string]$OutputPath = "models\gguf\1c\qwen3-coder-30b-a3b-instruct-q6_k\Qwen3-Coder-30B-A3B-Instruct-Q6_K.gguf",
|
|
[Int64]$ExpectedBytes = 25104724288,
|
|
[string]$PidFile = "reports\qwen3-coder-q6-download.pid",
|
|
[string]$StatusFile = "reports\qwen3-coder-q6-download-status.json",
|
|
[string]$LogFile = "reports\qwen3-coder-q6-download.log"
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
function Get-DownloadBytes {
|
|
if (Test-Path -LiteralPath $OutputPath) {
|
|
return (Get-Item -LiteralPath $OutputPath).Length
|
|
}
|
|
return 0
|
|
}
|
|
|
|
function Write-DownloadStatus {
|
|
param(
|
|
[string]$State,
|
|
[int]$ExitCode = 0,
|
|
[string]$Message = ""
|
|
)
|
|
|
|
$bytes = Get-DownloadBytes
|
|
$percent = if ($ExpectedBytes -gt 0) { [math]::Round(($bytes / $ExpectedBytes) * 100, 4) } else { 0 }
|
|
$payload = [ordered]@{
|
|
state = $State
|
|
bytes = $bytes
|
|
expected_bytes = $ExpectedBytes
|
|
percent = $percent
|
|
output_path = (Resolve-Path -LiteralPath (Split-Path -Parent $OutputPath) -ErrorAction SilentlyContinue).Path
|
|
file = $OutputPath
|
|
log = $LogFile
|
|
exit_code = $ExitCode
|
|
message = $Message
|
|
updated_at = (Get-Date).ToString("o")
|
|
}
|
|
$StatusFileParent = Split-Path -Parent $StatusFile
|
|
if ($StatusFileParent) {
|
|
New-Item -ItemType Directory -Force -Path $StatusFileParent | Out-Null
|
|
}
|
|
$payload | ConvertTo-Json -Depth 4 | Set-Content -LiteralPath $StatusFile -Encoding UTF8
|
|
}
|
|
|
|
function Get-WorkerProcess {
|
|
if (-not (Test-Path -LiteralPath $PidFile)) {
|
|
return $null
|
|
}
|
|
$rawPid = (Get-Content -LiteralPath $PidFile -ErrorAction SilentlyContinue | Select-Object -First 1)
|
|
if (-not $rawPid) {
|
|
return $null
|
|
}
|
|
try {
|
|
return Get-Process -Id ([int]$rawPid) -ErrorAction Stop
|
|
} catch {
|
|
return $null
|
|
}
|
|
}
|
|
|
|
function Show-Status {
|
|
$process = Get-WorkerProcess
|
|
if ($process) {
|
|
Write-DownloadStatus -State "running" -Message "worker pid $($process.Id)"
|
|
} elseif (Test-Path -LiteralPath $StatusFile) {
|
|
$status = Get-Content -LiteralPath $StatusFile -Raw
|
|
Write-Output $status
|
|
return
|
|
} else {
|
|
Write-DownloadStatus -State "not_started"
|
|
}
|
|
Get-Content -LiteralPath $StatusFile -Raw
|
|
}
|
|
|
|
function Start-Worker {
|
|
$existing = Get-WorkerProcess
|
|
if ($existing) {
|
|
Write-Output "Download already running, pid $($existing.Id)."
|
|
Show-Status
|
|
return
|
|
}
|
|
|
|
New-Item -ItemType Directory -Force -Path (Split-Path -Parent $OutputPath) | Out-Null
|
|
New-Item -ItemType Directory -Force -Path (Split-Path -Parent $LogFile) | Out-Null
|
|
Write-DownloadStatus -State "starting"
|
|
|
|
$arguments = @(
|
|
"-NoProfile",
|
|
"-ExecutionPolicy", "Bypass",
|
|
"-File", $PSCommandPath,
|
|
"-Action", "worker",
|
|
"-Url", $Url,
|
|
"-OutputPath", $OutputPath,
|
|
"-ExpectedBytes", "$ExpectedBytes",
|
|
"-PidFile", $PidFile,
|
|
"-StatusFile", $StatusFile,
|
|
"-LogFile", $LogFile
|
|
)
|
|
$process = Start-Process -FilePath "pwsh" -ArgumentList $arguments -WorkingDirectory (Get-Location) -WindowStyle Hidden -PassThru
|
|
Set-Content -LiteralPath $PidFile -Value $process.Id -Encoding ASCII
|
|
Write-Output "Started Q6 download worker, pid $($process.Id)."
|
|
Start-Sleep -Seconds 1
|
|
Show-Status
|
|
}
|
|
|
|
function Stop-Worker {
|
|
$process = Get-WorkerProcess
|
|
if ($process) {
|
|
Stop-Process -Id $process.Id -Force
|
|
Write-DownloadStatus -State "stopped" -Message "stopped pid $($process.Id)"
|
|
} else {
|
|
Write-DownloadStatus -State "stopped" -Message "no worker process"
|
|
}
|
|
if (Test-Path -LiteralPath $PidFile) {
|
|
Remove-Item -LiteralPath $PidFile -Force
|
|
}
|
|
Show-Status
|
|
}
|
|
|
|
function Invoke-Worker {
|
|
New-Item -ItemType Directory -Force -Path (Split-Path -Parent $OutputPath) | Out-Null
|
|
New-Item -ItemType Directory -Force -Path (Split-Path -Parent $LogFile) | Out-Null
|
|
Write-DownloadStatus -State "running" -Message "worker started"
|
|
|
|
while ((Get-DownloadBytes) -lt $ExpectedBytes) {
|
|
$before = Get-DownloadBytes
|
|
Add-Content -LiteralPath $LogFile -Encoding UTF8 -Value "[$((Get-Date).ToString('o'))] curl resume from $before"
|
|
& curl.exe -L --fail --retry 8 --retry-delay 5 --retry-all-errors --connect-timeout 60 --speed-time 120 --speed-limit 10240 -C - -o $OutputPath $Url 2>&1 |
|
|
Tee-Object -FilePath $LogFile -Append | Out-Null
|
|
$exitCode = $LASTEXITCODE
|
|
$after = Get-DownloadBytes
|
|
if ($after -ge $ExpectedBytes) {
|
|
Write-DownloadStatus -State "complete" -ExitCode $exitCode -Message "download complete"
|
|
if (Test-Path -LiteralPath $PidFile) {
|
|
Remove-Item -LiteralPath $PidFile -Force
|
|
}
|
|
return
|
|
}
|
|
Write-DownloadStatus -State "retrying" -ExitCode $exitCode -Message "downloaded $after of $ExpectedBytes bytes"
|
|
Start-Sleep -Seconds 10
|
|
}
|
|
|
|
Write-DownloadStatus -State "complete" -Message "download complete"
|
|
if (Test-Path -LiteralPath $PidFile) {
|
|
Remove-Item -LiteralPath $PidFile -Force
|
|
}
|
|
}
|
|
|
|
switch ($Action) {
|
|
"start" { Start-Worker }
|
|
"status" { Show-Status }
|
|
"stop" { Stop-Worker }
|
|
"worker" { Invoke-Worker }
|
|
}
|