|
# Nabil Redmann - 2025-11-04 |
|
# License: MIT |
|
# https://gist.github.com/BananaAcid/d6c4dbe51a7735905a97daf4ef0461f3 |
|
[CmdletBinding(DefaultParameterSetName="None")] |
|
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingCmdletAliases', '', Scope = 'Function', Target = '*')] |
|
|
|
param ( |
|
[string][Parameter(Mandatory=$true, ParameterSetName='None')][Alias("prompt")]$content, # == Prompt |
|
[string][Parameter(Mandatory=$false, ParameterSetName='None')]$systemPrompt, # Fallback -> .\ask.ai.prompts.ps1 |
|
|
|
[int][Parameter(Mandatory=$false, ParameterSetName='None')][ValidateRange(1, [int]::MaxValue)]$n = 1, # Pictures, default 1 |
|
[string][Parameter(Mandatory=$false, ParameterSetName='None')]$model = "AlbedoBase XL (SDXL)", # "WAI-NSFW-illustrious-SDXL" ... |
|
[string][Parameter(Mandatory=$false, ParameterSetName='None')][Alias("key")]$AIHORDE_API_KEY = $env:AIHORDE_API_KEY ? $env:AIHORDE_API_KEY : "0000000000", |
|
|
|
[switch][Parameter(Mandatory=$true, ParameterSetName='OnlyListModels')]$listModels = $false, # list available models: more then 2 servers, type of image |
|
|
|
[string][Parameter(Mandatory=$true, ParameterSetName='OnlyAwaitId')][Alias("id")]$awaitId # to continue a job |
|
) |
|
|
|
$headers = @{ |
|
"Client-Agent" = "unknown:0:unknown" # unknown:0:unknown is the default by the Aihorde API |
|
"Accept" = "application/json" |
|
} |
|
|
|
if ($listModels -eq $true) { |
|
# only models with more then 2 nodes |
|
$modelsList = Invoke-RestMethod -Uri "https://aihorde.net/api/v2/status/models" -Method Get -Headers ($headers + @{type = "image"}) |% {[PSCustomObject]$_} |? { $_.count -gt 2 } | Sort-Object -Property count |% { [PSCustomObject]@{name = $_.name; servers = $_.count; jobs = [int]$_.jobs; eta = [int]$_.eta; performance = [int]$_.performance } } |
|
return $modelsList | Format-Table |
|
} |
|
|
|
|
|
# Set the empty API key to $null for comparison |
|
if (-not $AIHORDE_API_KEY) { throw "⚠️ AIHORDE API KEY is missing! (-AIHORDE_API_KEY or `$env:AIHORDE_API_KEY)" } |
|
|
|
|
|
# import system prompt text if no argument is given |
|
if (-not $systemPrompt) { |
|
try { |
|
# import ... |
|
. .\ask.ai.prompts.ps1 |
|
if ($systemPrompt -like "") { Write-Warning "⚠️ NO SYSTEM-PROMPT found in file! (.\ask.ai.prompts.ps1 with `$systemPrompt=`"`")" } |
|
} |
|
catch { Write-Warning "⚠️ NO FILE FOUND FOR SYSTEM-PROMPT! (.\ask.ai.prompts.ps1)" } |
|
} |
|
|
|
|
|
# docs: https://aihorde.net/api/ |
|
|
|
# Base URL for image generation |
|
$url = "https://aihorde.net/api/v2/generate" |
|
|
|
|
|
# DEBUG: if $awaitId is given, $content is ignored - and generation is skipped (if this file is run as `. .\ask.ai.aihorde_image.ps1 -content "123"` (sourced!), the $awaitId will be stored in the cli session ) |
|
if (-not $awaitId) { |
|
<# |
|
POST https://aihorde.net/api/v2/generate/async |
|
200 -> AuthHeader + Body: { |
|
"id": string of image in queue, |
|
"kudos": integer of kudos available for fast generation |
|
} |
|
400, 500, ... -> { |
|
"message": "string", |
|
"rc": "ExampleHordeError" |
|
} |
|
#> |
|
$headersPostAuth = @{ |
|
"Content-Type" = "application/json" |
|
"apikey" = $AIHORDE_API_KEY |
|
} |
|
$body = @{ # params taken from https://artbot.site/create |
|
prompt = $systemPrompt + "`n`n" + $content # + " ### " + $content_negative |
|
params = @{ |
|
cfg_scale = 2 |
|
seed = "" |
|
sampler_name = "k_euler_a" |
|
height = 1024 |
|
width = 1024 |
|
post_processing = @() |
|
steps = 8 |
|
tilting = $false |
|
karras = $true |
|
hires_fix = $false |
|
clip_skip = 1 |
|
n = $n |
|
loras = @( |
|
@{ |
|
name = "246747" |
|
model = 1 |
|
clip = 1 |
|
is_version = $true |
|
} |
|
) |
|
} |
|
allow_downgrade = $true |
|
nsfw = $true |
|
censor_nsfw = $false |
|
trusted_workers = $true |
|
models = @($model) |
|
r2 = $true |
|
replacement_filter = $false |
|
shared = $false |
|
slow_workers = $true |
|
dry_run = $false |
|
} | ConvertTo-Json -Depth 10 |
|
|
|
$response = Invoke-RestMethod -Uri "$url/async" -Method Post -Headers ($headers + $headersPostAuth) -Body $body -Erroraction SilentlyContinue |
|
|
|
if ($response.rc) { throw $response } |
|
|
|
$awaitId = $response.id |
|
|
|
## info output: |
|
[PSCustomObject]$response | Format-List |
|
} |
|
else { |
|
[PSCustomObject]@{ |
|
"id (existing)" = $awaitId |
|
kudos = $response.kudos ? $response.kudos : "unchanged" |
|
} | Format-List |
|
} |
|
|
|
<# |
|
GET https://aihorde.net/api/v2/generate/check/$awaitId |
|
200 -> { |
|
"finished": 0, |
|
"processing": 0, |
|
"restarted": 0, |
|
"waiting": 0, |
|
"done": true, |
|
"faulted": false, |
|
"wait_time": 0, |
|
"queue_position": 0, |
|
"kudos": 0, |
|
"is_possible": true |
|
} |
|
400 -> { |
|
"message": "string", |
|
"rc": "ExampleHordeError" |
|
} |
|
#> |
|
$queuePositionStart = 0 |
|
#$i = 0 |
|
do { |
|
$response = Invoke-RestMethod -Uri "$url/check/$awaitId" -Method Get -Headers $headers -Erroraction SilentlyContinue |
|
|
|
if ($response.queue_position -gt $queuePositionStart) {$queuePositionStart = $response.queue_position} |
|
|
|
if ($response.queue_position) { |
|
# $i++ |
|
# if ($i -gt [System.Console]::BufferWidth - 14 - 5) { $i = 1 } # reset when overflowing the console width |
|
# Write-Host -NoNewline "`r[#$($response.queue_position), $($response.wait_time)s] $('.' * $i)" |
|
|
|
$i = [Math]::Round((( $queuePositionStart - $response.queue_position) / $queuePositionStart) * 100) |
|
Write-Progress -Activity "Queue position $($response.queue_position)" -PercentComplete $i -SecondsRemaining $response.wait_time |
|
|
|
Start-Sleep -Seconds 1 |
|
} |
|
} until ($response.done -or $response.rc) |
|
|
|
## Debug output: |
|
#$response | ConvertTo-Json -Depth 10 |
|
|
|
if ($response.rc) { throw $response } |
|
|
|
<# |
|
GET /v2/generate/status/{id} |
|
200 -> { |
|
"finished": 0, |
|
"processing": 0, |
|
"restarted": 0, |
|
"waiting": 0, |
|
"done": true, |
|
"faulted": false, |
|
"wait_time": 0, |
|
"queue_position": 0, |
|
"kudos": 0, |
|
"is_possible": true, |
|
"generations": [ |
|
{ |
|
"worker_id": "string", |
|
"worker_name": "string", |
|
"model": "string", |
|
"state": "ok", |
|
"img": "string", <-- base64 encoded image / URL (default) |
|
"seed": "string", |
|
"id": "string", |
|
"censored": true, |
|
"gen_metadata": [ |
|
{ |
|
"type": "lora", |
|
"value": "download_failed", |
|
"ref": "string" |
|
} |
|
] |
|
} |
|
], |
|
"shared": true |
|
} |
|
400 -> { |
|
"message": "string", |
|
"rc": "ExampleHordeError" |
|
} |
|
#> |
|
$response = Invoke-RestMethod -Uri "$url/status/$awaitId" -Method Get -Headers $headers |
|
|
|
## Debug output: |
|
#$response | ConvertTo-Json -Depth 10 |
|
|
|
if ($response.rc) { throw $response } |
|
|
|
$result = $response.generations |% { $_.img } |
|
|
|
return $result |