Functions/GenXdev.AI/Invoke-ImageKeywordUpdate.ps1
################################################################################ <# .SYNOPSIS Updates image metadata with AI-generated descriptions and keywords. .DESCRIPTION The Invoke-ImageKeywordUpdate function analyzes images using AI to generate descriptions, keywords, and other metadata. It creates a companion JSON file for each image containing this information. The function can process new images only or update existing metadata, and supports recursive directory scanning. .PARAMETER ImageDirectory Specifies the directory containing images to process. Defaults to current directory if not specified. .PARAMETER Recurse When specified, searches for images in the specified directory and all subdirectories. .PARAMETER OnlyNew When specified, only processes images that don't already have metadata JSON files. .PARAMETER RetryFailed When specified, reprocesses images where previous metadata generation attempts failed. .EXAMPLE Invoke-ImageKeywordUpdate -ImageDirectory "C:\Photos" -Recurse -OnlyNew .EXAMPLE updateimages -Recurse -RetryFailed #> function Invoke-ImageKeywordUpdate { [CmdletBinding()] [Alias("updateimages")] param( ############################################################################### [Parameter( Mandatory = $false, Position = 0, HelpMessage = "The image directory path." )] [string] $ImageDirectory = ".\", ############################################################################### [Parameter( Mandatory = $false, Position = 1, HelpMessage = "Recurse directories." )] [switch] $Recurse, ############################################################################### [Parameter( Mandatory = $false, Position = 2, HelpMessage = "Skip if already has meta data." )] [switch] $OnlyNew, ############################################################################### [Parameter( Mandatory = $false, Position = 3, HelpMessage = "Will retry previously failed images." )] [switch] $RetryFailed ) begin { # convert relative path to absolute path $path = Expand-Path $ImageDirectory # verify directory exists before proceeding if (-not [System.IO.Directory]::Exists($path)) { Write-Host "The directory '$path' does not exist." return } } process { # get all supported image files from the specified directory Get-ChildItem -Path "$path\*.jpg", "$path\*.jpeg", "$path\*.png" ` -Recurse:$Recurse -File -ErrorAction SilentlyContinue | ForEach-Object { # handle retry logic for previously failed images if ($RetryFailed) { if ([System.IO.File]::Exists("$($PSItem):description.json")) { # delete empty metadata files to force reprocessing if ("$([System.IO.File]::ReadAllText(` "$($PSItem):description.json"))".StartsWith("{}")) { [System.IO.File]::Delete("$($PSItem):description.json") } } } $image = $PSItem.FullName # ensure image is writable by removing read-only flag if present if ($PSItem.Attributes -band [System.IO.FileAttributes]::ReadOnly) { $PSItem.Attributes = $PSItem.Attributes -bxor ` [System.IO.FileAttributes]::ReadOnly } $fileExists = [System.IO.File]::Exists("$($image):description.json") # process image if new or update requested if ((-not $OnlyNew) -or (-not $fileExists)) { # create empty metadata file if needed if (-not $fileExists) { "{}" > "$($image):description.json" } Write-Verbose "Analyzing image content: $image" # get AI-generated image description and metadata $description = Invoke-QueryImageContent ` -Query "Analyze image and return a object with properties: " + ` "'short_description' (max 80 chars), 'long_description', " + ` "'has_nudity, keywords' (array of strings), " + ` "'has_explicit_content', 'overall_mood_of_image', " + ` "'picture_type' and 'style_type'. " + ` "Output only json, no markdown or anything other then json." ` -ImagePath $image -Temperature 0.01 Write-Verbose "Received analysis: $description" try { # extract just the JSON portion of the response $description = $description.trim() $i0 = $description.IndexOf("{") $i1 = $description.LastIndexOf("}") if ($i0 -ge 0) { $description = $description.Substring($i0, $i1 - $i0 + 1) } # save formatted JSON metadata [System.IO.File]::WriteAllText( "$($image):description.json", ($description | ConvertFrom-Json | ConvertTo-Json -Compress -Depth 20 ` -WarningAction SilentlyContinue)) } catch { Write-Warning "$PSItem`r`n$description" } } } } end { } } ################################################################################ |