Skip to content

Instantly share code, notes, and snippets.

@SMSAgentSoftware
Created December 13, 2024 21:46
Show Gist options
  • Select an option

  • Save SMSAgentSoftware/a26556be51e4e94b0af9b6003ff6b87e to your computer and use it in GitHub Desktop.

Select an option

Save SMSAgentSoftware/a26556be51e4e94b0af9b6003ff6b87e to your computer and use it in GitHub Desktop.

Revisions

  1. SMSAgentSoftware created this gist Dec 13, 2024.
    312 changes: 312 additions & 0 deletions Invoke-GoogleAIChat.ps1
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,312 @@
    function Invoke-GoogleAIChat {
    <#
    .SYNOPSIS
    PowerShell function for Google Chat API interaction via REST.
    .DESCRIPTION
    Provides a robust interface to Google Chat API with features including:
    - Conversation history management
    - Token usage tracking
    - Markdown rendering support
    - Temperature control for response creativity
    - Verbosity levels for response detail
    - Browser-based markdown viewing option
    .PARAMETER Prompt
    The message to send to the Google Chat API.
    Mandatory: Yes
    Pipeline: Accepts input
    Position: 0
    .PARAMETER Endpoint
    The Google API endpoint URL.
    Mandatory: No
    Default: Standard endpoint URL
    Validation: Must be HTTPS URL
    .PARAMETER Model
    The deployment name of the AI model.
    Mandatory: No
    Default: o1-mini
    Valid values: You define the values that the parameter can accept.
    .PARAMETER KeyVaultName
    The name of your Azure Key Vault.
    Mandatory: No
    .PARAMETER SecretName
    The name of the secret in your Azure Key Vault containing the Google API key.
    Mandatory: No
    .PARAMETER MaxTokens
    The maximum number of tokens to generate in the response.
    Mandatory: No
    Default: 16384
    Range: 1 - 16384
    .PARAMETER IncludeTokenUsage
    Switch to include token usage statistics in response.
    Mandatory: No
    .PARAMETER Temperature
    Controls response creativity and randomness.
    Mandatory: No
    Default: 0.2
    Range: 0.0 - 2.0
    .PARAMETER StartNewChat
    Switch to start a new chat session / clear chat history.
    Mandatory: No
    .PARAMETER ModelContext
    System context/prompt for AI behavior.
    Mandatory: No
    Default: PowerShell expert assistant context
    .PARAMETER NoMarkdown
    Switch to disable markdown rendering.
    Mandatory: No
    .PARAMETER UseBrowser
    Switch to view markdown in browser.
    Mandatory: No
    .PARAMETER Verbosity
    Controls response detail level.
    Mandatory: No
    Default: medium
    Valid values: none, low, medium, high
    .EXAMPLE
    PS> Invoke-GoogleAIChat "Write a function to get system info"
    Returns AI-generated PowerShell code with explanations
    .EXAMPLE
    PS> "How to use arrays?" | Invoke-GoogleAIChat -Temperature 0.8 -Verbosity high
    Returns detailed array explanation with high creativity
    .NOTES
    Author: Trevor Jones
    Version: 1.0
    Requires: Az.Accounts, Az.KeyVault modules
    #>
    [CmdletBinding()]
    param (
    # Main prompt parameter
    [Parameter(Mandatory = $true,
    ValueFromPipeline = $true,
    Position = 0)]
    [ValidateNotNullOrEmpty()]
    [string]$Prompt,

    # OpenAI endpoint URL
    [Parameter(Mandatory = $false)]
    [ValidatePattern('^https:\/\/.*')]
    [string]$Endpoint = "https://generativelanguage.googleapis.com/v1beta/models",

    # AI model selection
    [Parameter(Mandatory = $false)]
    [ValidateSet("gemini-2.0-flash-exp","gemini-1.5-flash","gemini-1.5-pro")]
    [string]$Model = "gemini-1.5-pro",

    # Azure Key Vault name
    [Parameter(Mandatory = $false)]
    [ValidateNotNullOrEmpty()]
    [string]$KeyVaultName = "<YourAzureKeyVaultName>",

    # Azure Key Vault secret name
    [Parameter(Mandatory = $false)]
    [ValidateNotNullOrEmpty()]
    [string]$SecretName = "<YourGoogleAPISecretName>",

    # Maximum number of tokens to generate
    [Parameter(Mandatory = $false)]
    [ValidateRange(1, 8192)]
    [int]$MaxTokens = 8192,

    # Token usage tracking switch
    [Parameter(Mandatory = $false)]
    [switch]$IncludeTokenUsage,

    # Response creativity control
    [Parameter(Mandatory = $false)]
    [ValidateRange(0.0, 2.0)]
    [double]$Temperature = 0.2,

    # New chat session control
    [Parameter(Mandatory = $false)]
    [switch]$StartNewChat,

    # AI behavior context
    [Parameter(Mandatory = $false)]
    [ValidateNotNullOrEmpty()]
    [string]$ModelContext = "You are a helpful and friendly assistant with expertise in PowerShell scripting and command line. Assume user is using the operating system 'Windows 11' unless otherwise specified. ",

    # Output format controls
    [Parameter(Mandatory = $false)]
    [switch]$NoMarkdown,

    [Parameter(Mandatory = $false)]
    [switch]$UseBrowser,

    # Response detail level
    [Parameter(Mandatory = $false)]
    [ValidateSet("none", "low", "medium", "high")]
    [string]$Verbosity = "medium"
    )

    begin {
    # Module dependency check
    $requiredModules = @("Az.Accounts", "Az.KeyVault")

    # Find modules that are not installed
    $missingModules = $requiredModules | Where-Object { -not (Get-Module -Name $_ -ListAvailable) }

    # Install missing modules if any
    if ($missingModules) {
    try {
    Install-Module -Name $missingModules -Force -AllowClobber -Scope CurrentUser -Repository PSGallery -ErrorAction Stop
    }
    catch {
    throw "Failed to install module(s) '$($missingModules -join ', ')': $_"
    }
    }
    Import-Module Az.Accounts -ErrorAction Stop
    Import-Module Az.KeyVault -ErrorAction Stop

    # Retrieve secret from Azure Key Vault
    try
    {
    $secureSecretValue = Get-AzKeyVaultSecret -VaultName $KeyVaultName -Name $SecretName -ErrorAction Stop
    }
    catch
    {
    try
    {
    Connect-AzAccount -AuthScope KeyVault -WarningAction SilentlyContinue -ErrorAction Stop
    $secureSecretValue = Get-AzKeyVaultSecret -VaultName $KeyVaultName -Name $SecretName -ErrorAction Stop
    }
    catch
    {
    Write-Error "An error occurred while retrieving the secret from Azure KeyVault: $_"
    return $null
    }
    }

    # Convert the secure string secret to plain text
    if ($PSVersionTable.PSVersion -ge [Version]"7.0") {
    $secretValue = $secureSecretValue.SecretValue | ConvertFrom-SecureString -AsPlainText
    }
    else {
    $secretValue = [PSCredential]::new('dummy', $secureSecretValue.SecretValue).GetNetworkCredential().Password
    }

    # Set verbosity level text
    $verbosityText = switch ($Verbosity) {
    "none" { "Just provide the code and do not provide any explanation of it." }
    "low" { "Please keep the response concise and to the point. Focus on providing code, and just explain it very briefly." }
    "medium" { "Please keep the response concise. Provide a reasonable level of explanation for the code, adding some inline comments." }
    "high" { "Provide a detailed explanation of the code and add inline comments to it." }
    }
    $ModelContext += $verbosityText

    # Initialize chat history
    if ($StartNewChat -or -not (Get-Variable -Name googleaichatmessages -ErrorAction SilentlyContinue)) {
    $global:googleaichatmessages = @()
    }
    }

    process {
    try {
    # Add user prompt to chat history
    $global:googleaichatmessages += @{
    role = "user"
    parts = @(
    @{
    text = $Prompt
    }
    )
    }

    # Construct a body object for the API request
    $body = @{
    "contents" = @($global:googleaichatmessages)
    "generationConfig" = @{
    "temperature" = $Temperature
    "maxOutputTokens" = $MaxTokens
    }
    "systemInstruction" = @{
    "role" = "model"
    "parts" = @(
    @{
    "text" = $ModelContext
    }
    )
    }
    } | ConvertTo-Json -Depth 5

    # Create the headers for the request
    $headers = @{
    "content-type" = "application/json"
    }

    # Contruct the URL for the API request
    $url = "$Endpoint/$model`:generateContent?key=$secretValue"

    # Make API request with comprehensive error handling
    try {
    $response = Invoke-RestMethod -Uri $url -Method Post -Headers $headers -Body $body -ErrorAction Stop
    }
    catch [System.Net.WebException] {
    $statusCode = [int]$_.Exception.Response.StatusCode
    $errorMessage = switch ($statusCode) {
    401 { "Unauthorized: Please check your authentication token" }
    403 { "Forbidden: Access denied to the API endpoint" }
    404 { "Not Found: Invalid endpoint or model deployment" }
    429 { "Rate Limited: Too many requests, please try again later" }
    500 { "Internal Server Error: Azure OpenAI service error" }
    503 { "Service Unavailable: Azure OpenAI service is temporarily unavailable" }
    default {
    $reader = New-Object System.IO.StreamReader($_.Exception.Response.GetResponseStream())
    $reader.ReadToEnd()
    }
    }
    throw "API Request Failed ($statusCode): $errorMessage"
    }
    catch {
    throw "Unexpected error during API request: $_"
    }

    # Update chat history with response
    $global:googleaichatmessages += @{
    role = 'model'
    parts = @(
    @{
    text = $response.candidates[0].content.parts[0].text
    }
    )
    }

    # Format response
    $content = $response.candidates[0].content.parts[0].text
    if ($IncludeTokenUsage) {
    $content += "`n`nPrompt tokens: $($response.usageMetadata.promptTokenCount) | "
    $content += "Candidates tokens: $($response.usageMetadata.candidatesTokenCount) | "
    $content += "Total tokens: $($response.usageMetadata.totalTokenCount)"
    }

    # Handle markdown rendering based on PowerShell version and preferences
    if ($PSVersionTable.PSVersion -ge [Version]"6.1" -and -not $NoMarkdown) {
    if ($UseBrowser) {
    return $content | Show-Markdown -UseBrowser
    }
    return $content | Show-Markdown
    }
    return $content
    }
    catch {
    Write-Error "Unexpected error: $_"
    return $null
    }
    }
    }