# SeibertGPT – Einrichtung für pi (Windows). Quelle: https://gpt.seibert.ai/clients # Der Key wird nur lokal abgefragt und landet in deinem Benutzerprofil, nie in einer Datei; gesendet wird er nur an das Gateway. & { $ErrorActionPreference = 'Stop' Write-Host 'SeibertGPT: Einrichtung für pi' if (-not ([bool](Get-Command pi -ErrorAction SilentlyContinue))) { Write-Host 'pi scheint nicht installiert zu sein. Download: https://nodejs.org/' $ans = Read-Host 'Trotzdem fortfahren? (j/N)' if ($ans -notmatch '^[jJyY]$') { return } } $targetDir = [Environment]::ExpandEnvironmentVariables('%USERPROFILE%\.pi\agent') New-Item -ItemType Directory -Force -Path $targetDir | Out-Null do { $secure = Read-Host -AsSecureString 'SeibertGPT-API-Key (beginnt mit sgpt_)' $bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($secure) try { $key = [Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr).Trim() } finally { [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr) } if (-not $key.StartsWith('sgpt_')) { Write-Host 'Das ist kein SeibertGPT-Key. Keys findest du unter https://gpt.seibert.ai/konto/keys' } } until ($key.StartsWith('sgpt_')) [Environment]::SetEnvironmentVariable("SEIBERTGPT_API_KEY", $key, "User") $env:SEIBERTGPT_API_KEY = $key Write-Host 'Key als Benutzer-Umgebungsvariable SEIBERTGPT_API_KEY gespeichert (in deinem Windows-Benutzerprofil).' $target = Join-Path $targetDir 'models.json' $ours = @' { "providers": { "seibertgpt": { "baseUrl": "https://api.gpt.seibert.ai/v1", "api": "openai-completions", "apiKey": "$SEIBERTGPT_API_KEY", "compat": { "supportsStore": false, "supportsDeveloperRole": false, "maxTokensField": "max_tokens" }, "models": [ { "id": "deepseek-v41-flash", "name": "Standard mit Denkmodus (SeibertGPT)", "contextWindow": 1000000, "input": [ "text", "image" ] }, { "id": "deepseek-v41-flash-fast", "name": "ohne Denkmodus – schnell (SeibertGPT)", "contextWindow": 1000000, "input": [ "text", "image" ] }, { "id": "deepseek-v41-flash-low", "name": "Denkaufwand niedrig (SeibertGPT)", "contextWindow": 1000000, "input": [ "text", "image" ] }, { "id": "deepseek-v41-flash-high", "name": "Denkaufwand hoch (SeibertGPT)", "contextWindow": 1000000, "input": [ "text", "image" ] }, { "id": "deepseek-v41-flash-max", "name": "Denkaufwand maximal (SeibertGPT)", "contextWindow": 1000000, "input": [ "text", "image" ] } ] } } } '@ $mergePaths = @() $mergePaths += ,@('providers','seibertgpt') $absentPaths = @() function Get-JsonPath($obj, $path) { foreach ($p in $path) { if ($null -eq $obj -or -not ($obj.PSObject.Properties.Name -contains $p)) { return $null }; $obj = $obj.$p }; return ,$obj } function Set-JsonPath($obj, $path, $value) { for ($i = 0; $i -lt $path.Count - 1; $i++) { $p = $path[$i] if (-not ($obj.$p -is [System.Management.Automation.PSCustomObject])) { $obj | Add-Member -NotePropertyName $p -NotePropertyValue ([pscustomobject]@{}) -Force } $obj = $obj.$p } $obj | Add-Member -NotePropertyName $path[-1] -NotePropertyValue $value -Force } $utf8 = New-Object System.Text.UTF8Encoding($false) $raw = $null if (Test-Path -LiteralPath $target) { $raw = Get-Content -Raw -Encoding UTF8 -LiteralPath $target } if ([string]::IsNullOrWhiteSpace($raw)) { [IO.File]::WriteAllText($target, $ours + "`r`n", $utf8) Write-Host "Config angelegt: $target" } else { $existing = $null # PowerShell 7 liest JSON mit Kommentaren, beim Zurückschreiben gingen sie verloren: vorher erkennen (Strings ausgeblendet). if (($raw -replace '"(?:[^"\\]|\\.)*"', '""') -notmatch '//|/\*') { try { $existing = $raw | ConvertFrom-Json } catch { $existing = $null } } if ($existing -isnot [System.Management.Automation.PSCustomObject]) { $side = [IO.Path]::ChangeExtension($target, $null).TrimEnd('.') + '.seibertgpt.json' [IO.File]::WriteAllText($side, $ours + "`r`n", $utf8) Write-Host "Deine Config enthält Kommentare und wurde nicht verändert. Unsere liegt daneben: $side – übernimm den Block 'seibertgpt' von Hand." } else { Copy-Item -LiteralPath $target -Destination ("$target.bak-" + (Get-Date -Format 'yyyyMMdd-HHmmss')) $oursObj = $ours | ConvertFrom-Json foreach ($p in $mergePaths) { $v = Get-JsonPath $oursObj $p; if ($null -ne $v) { Set-JsonPath $existing $p $v } } foreach ($p in $absentPaths) { $v = Get-JsonPath $oursObj $p; if ($null -ne $v -and $null -eq (Get-JsonPath $existing $p)) { Set-JsonPath $existing $p $v } } [IO.File]::WriteAllText($target, ($existing | ConvertTo-Json -Depth 50) + "`r`n", $utf8) Write-Host "Config ergänzt: $target (Sicherung daneben: *.bak-...)" } } [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 try { Invoke-WebRequest -UseBasicParsing -TimeoutSec 15 -Uri 'https://api.gpt.seibert.ai/v1/models' -Headers @{ Authorization = "Bearer $key" } | Out-Null Write-Host 'Verbindung ok.' } catch { $code = 'keine Antwort' if ($_.Exception.Response) { $code = [int]$_.Exception.Response.StatusCode } if ($code -eq 401) { Write-Host 'Der Key wurde abgelehnt – ist er gesperrt? Siehe https://gpt.seibert.ai/konto/keys' } elseif ($code -eq 403) { Write-Host 'Zugriff verweigert – IP-Bindung oder kein aktiver Plan. Siehe https://gpt.seibert.ai/konto/keys' } else { Write-Host "Gateway nicht erreichbar ($code). Einrichtung ist trotzdem fertig." } } Write-Host 'Neues PowerShell-Fenster öffnen und starten mit: pi --model seibertgpt/' Write-Host 'Fertig.' }