diff --git a/aidoc.ps1 b/aidoc.ps1
new file mode 100644
index 0000000..02eba82
--- /dev/null
+++ b/aidoc.ps1
@@ -0,0 +1,246 @@
+<#
+ Uma pequeno dilema meu: Um produto ou serviço só muito bom, se ele consegue suprir as demandas dos próprios criados!
+ E, baseado nisso, temos o script AI DOC!
+
+ ESte script usa o próprio PowershAI para gerar docs em outros idiomas
+ ele é um utilitário para facilitar porta a documentação original para outros idiomas, que ainda não possuem uma tradução revisada por alguém expert no idioma de destino.
+
+ Ele pode ser utilizado sempre que qusier gerar novos arquivos de documentação, ou atualizar existentes.
+ Para manter a qualidade, recomendamos o uso com LLM avançados, como GPT-4o-mini, llam 3.1, ou gemini flash.
+ Importante que o modelo suporte longos contextos!
+
+ O script causa atualizações de arquivos no projeto, então, é preciso seguir o fluxo normalmente:
+ - commit no git
+ - bump de versão
+ - publicar
+
+ Imagine que este script seja seu assistente de tradução do PowershAI!
+ Use e abuse!
+#>
+param(
+ $SourceLang = $null
+ ,$TargetLang = $null
+ ,[switch]$KeepProvider
+ ,$Provider = "openai"
+)
+
+$ErrorActionPreference = "Stop";
+
+function JoinPath {
+ return ($Args -Join [IO.Path]::DirectorySeparatorChar)
+}
+
+function JoinPath {
+ return ($Args -Join [IO.Path]::DirectorySeparatorChar)
+}
+
+$ProjectRoot = $PSScriptRoot;
+
+write-host "Loading local powershai module";
+import-module -force (JoinPath $ProjectRoot powershai)
+
+if(!$SourceLang){
+ throw "Must specifuy -SourceLang"
+}
+
+if(!$TargetLang){
+ throw "Must specifuy -TargetLang"
+}
+
+$SourcePath = JoinPath $ProjectRoot docs $SourceLang;
+$TargetPath = JoinPath $ProjectRoot docs $TargetLang
+
+if(-not(Test-Path $SourcePath)){
+ throw "Invalid Lang: $SourceLang, PathNotfound = $SourcePath";
+}
+
+if(-not(Test-Path $TargetPath)){
+ throw "Invalid Lang: $TargetLang, PathNotfound = $TargetPath";
+}
+
+
+$TranslationMapFile = JoinPath $TargetPath AiTranslations.json
+
+if(Test-Path $TranslationMapFile){
+ $TranslationMap = Get-Content -Raw $TranslationMapFile | ConvertFrom-Json;
+} else {
+ $TranslationMap = @{}
+}
+
+# List all source files!
+$SourceFiles = gci -rec (JoinPath $sourcePath *.md)
+
+$NewMap = @{};
+
+if(!$KeepProvider){
+ write-host "Enforcing provider $Provider";
+ Set-AiProvider $provider;
+}
+
+
+
+
+foreach($SrcFile in $SourceFiles){
+
+ $SrcRelPath = $SrcFile.FullName.replace($SourcePath,'') -replace '^.',''
+ $FileId = $SrcRelPath.replace('\','/');
+
+ $TargetFilePath = JoinPath $TargetPath $SrcRelPath;
+ $TargetFile = Get-Item $TargetFilePath -EA SilentlyContinue;
+
+ write-host "File: $SrcRelPath";
+
+ write-host " Calculating Hash..."
+ $SrcHash = Get-FileHash $SrcFile;
+
+ $TranslationInfo = $TranslationMap.$FileId;
+
+ $TargetHash = $null
+ $FileBackup = $null
+ if($TargetFile){
+ write-host " Target exists!"
+ $FileBackup = Get-Content $TargetFile;
+
+ # check if file is auto updated!
+ # aCalculate hash!
+ $TargetHash = Get-FileHash $TargetFile
+
+ # Checa se o arquivo foi geraod automaticamente!
+ if(!$TranslationInfo){
+ write-host " File not generated by AiDoc! Skipping...";
+ continue;
+ }
+
+ # Get hash!
+ $AiHash = $TranslationInfo.TargetHash;
+
+ if($AiHash -ne $TargetHash.Hash){
+ write-host " FileChanged. Will not be updated...";
+ continue;
+ }
+
+ # Neste ponto, assume que o arquivo pode ser atualizavel!s
+ }
+
+ #Atualiza o map!
+ #Mesmo que nao haja atualizcoes nessa iteracao, garantimos que os dados serão escrito na proxima vez em que o arquivo de map for atualziado!
+ #Se ele nunca for atualizado, então, não tem problema, significa que o valor antigo não foi sobrescrito!
+ $NewMap[$FileId] = $TranslationInfo;
+
+ # Checa se mudou!
+ if($TranslationInfo.SrcHash -eq $SrcHash.Hash){
+ write-host " Nothing changed... Skipping";
+ continue;
+ }
+
+
+ write-host " Translating file...";
+ $FileContent = Get-Content -Raw $SrcFile;
+
+ # Divide o markdown em blocos, para evitar ultrassar o size do modelo!
+ $BlockSize = 6000;
+ $FullTranslation = "";
+
+ $Control = @{
+ buffer = @()
+ TotalChars = 0
+ text = ""
+ }
+
+ Function Translate {
+ $BufferText = $Control.buffer -Join "`n";
+ $Control.buffer = @();
+ $Control.TotalChars = 0;
+
+ write-host " Buffer:" $BufferText.length;
+
+ $system = @(
+ "Traduza o texto do usuário para a linguagem de código $($TargetLang). Retorne APENAS o texto traduzido."
+ "Manter o conteúdo original entre . Traduzir comentários de código, nomes de funções de exemplo. Não traduzir nomes de comandos do PowershAI."
+ ) -Join "`n"
+
+ $prompt = @(
+ "s: $system"
+ $BufferText
+ )
+
+ write-host " Invoking AI..."
+ $result = Get-AiChat -prompt $prompt
+ $translated = $result.choices[0].message.content;
+ write-host " Translated: $($translated.length) chars"
+ $Control.text += $translated
+ }
+
+ if($FileContent.length -gt $BlockSize){
+ $FileLines = $FileContent -split "`r?`n"
+ foreach($line in $FileLines){
+
+ $LineLen = $Line.length;
+ $EstTotal = $Control.TotalChars + $LineLen;
+
+ if($EstTotal -ge $BlockSize){
+ Translate
+ }
+
+ $Control.buffer += $line;
+ $Control.TotalChars += $LineLen;
+ }
+ } else {
+ $Control.buffer = $FileContent;
+ }
+
+ Translate
+
+ $Translated = $Control.text
+ write-host " Translated Length: $($Translated.length)";
+
+ write-host " Creating target directories..."
+ $Paths = Split-Path $TargetFilePath -Parent;
+ $null = New-Item -ItemType Directory -Path $Paths -force;
+
+
+
+ try {
+ write-host " Updating target content..."
+ $Translated | Set-Content -Encoding UTF8 -Path $TargetFilePath
+
+ # check if file is auto updated!
+ # aCalculate hash!
+ $TargetNewHash = Get-FileHash $TargetFilePath
+
+ write-host " Creating new map..."
+ $NewMap[$FileId] = @{
+ SrcHash = $SrcHash.Hash
+ TargetHash = $TargetNewHash.Hash;
+ }
+
+ write-host " Updating $TranslationMapFile";
+ $TranslationMapJson = $NewMap | ConvertTo-Json
+ Set-Content -Path $TranslationMapFile -Value $TranslationMapJson
+ } catch {
+ # Restore file backup!
+ if($FileBackup){
+ write-warning " Restoring file backup due to errors..."
+ $FileBackup | Set-Content -Encoding UTF8 -Path $TargetFilePath
+ }
+
+ throw;
+ }
+
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/powershai/powershai.psm1 b/powershai/powershai.psm1
index ef02d94..f2587f7 100644
--- a/powershai/powershai.psm1
+++ b/powershai/powershai.psm1
@@ -111,6 +111,45 @@ function SetType($obj, $name){
}
}
+# retorna a lista de parametros do caller!
+function GetMyParams(){
+
+ $cmd = Get-PSCallStack
+ $Caller = $cmd[1];
+
+ $CmdParams = @($Caller.InvocationInfo.MyCommand.Parameters.values)
+
+ $ParamList = @{};
+
+ function GetCommonParams
+ {
+ [CmdletBinding()]
+ param()
+ $MyInvocation.MyCommand.Parameters.Keys
+ }
+
+ $CommonParams = GetCommonParams
+
+ foreach($Param in $CmdParams){
+ if($Caller.InvocationInfo.MyCommand.CmdletBinding){
+ if($Param.name -in $CommonParams){
+ continue;
+ }
+ }
+
+ $ParamList[$Param.name] = Get-Variable -Name $Param.name -Scope 1 -ValueOnly -EA SilentlyContinue
+
+ }
+
+
+
+ return @{
+ bound = $ParamList
+ args = $Caller.InvocationInfo.UnboundArguments
+ caller = $Caller
+ }
+}
+
<#
.DESCRIPTION
FAciltia a criação de exceptions customizadas!
@@ -1297,6 +1336,16 @@ function New-PowershaiParameters {
#O provider deve implementar o suporte a esse.
#Para usá-lo você deve saber os detalhes de implementação do provider e como a API dele funciona!
$RawParams = @{}
+
+
+ ,# Controla o template usado ao injetar dados de contexto!
+ # Este parâmetro é um scriptblock que deve retornar uma string com o contexto a ser injetado no prompt!
+ # Os parâmetros do scriptblock são:
+ # FormattedObject - O objeto que representa o chat ativo, já formatado com o Formatter configurado
+ # CmdParams - Os parâmetros passados para Send-PowershaAIChat. É o mesmo objeto retorndo por GetMyParams
+ # Chat - O chat no qual os dados estão sendo enviados.
+ # Se nulo, irá gerar um default. Verifique o cmdlet Send-PowershaiChat para detalhes
+ $ContextFormat = $null
)
# Get the command name
@@ -1770,14 +1819,26 @@ function ConvertTo-PowershaiContextTable {
$POWERSHAI_FORMATTERS_SHORTCUTS['table'] = 'ConvertTo-PowershaiContextTable'
-
+<#
+ .DESCRIPTION
+ Formato um objeto para ser injetado no contexto!
+ Este cmdlet é usado pelo Send-PowershaiChat quando o contexto é ativado.
+ Você pode invocá-lo diretamente caso queira manualmente injetar dados e/ou debugar o processo!
+#>
function Format-PowershaiContext {
[CmdletBinding()]
param(
- $obj
- ,$params
- ,$func
- ,$ChatId = "."
+ #Objeto qualquer a ser injetado
+ $obj
+
+ ,#Parâmetro a ser passado para a função formatter
+ $params
+
+ ,#Função q ser nivocada. Se não especificado usa o defualt do chat.
+ $func
+
+ ,#Chat em qual operar
+ $ChatId = "."
)
write-verbose "Getting ChatId..."
@@ -1816,13 +1877,34 @@ function Format-PowershaiContext {
}
<#
+ .SYNOPSIS
+ Envia uma mensagem em um Chat do Powershai
+
.DESCRIPTION
- Envia uma mensagem para o modelo do provider configurado e escreve a resposta na tela!
+ Este cmdlet permite que você envie uma nova mensagem para o LLM do provider atual.
+ Por padrão, ele envia no chat ativo. Você pode sobrescrever o chat usando o parâmetro -Chat. Se não houver um chat ativo, ele irá usar o default.
+
+ Diversos parâmetros do Chat afetam como este comando. Veja o comando Get-PowershaiChatParameter para mais info sobre os parâmetros do chat.
+ Além dos parâmetros do chat, os próprios parâmetros do comando podem sobrescrever comportamento. Para mais detalhes, consule a documentação de cada parâmetro deste cmdlet usando get-help.
+
+ Para simplicidade, e manter a liha de comando limmpa, permitindo o usuário focar mais no prompt e nos dados, alguns alias são dosponibilizados.
+ Estes alias podem ativar certos parâmetros.
+ São eles:
+ ia
+ Abreviação de "Inteligência Artifical" em português. Este é um alias simples e não muda nenum parâmetro. Ele ajuda a reduzir bastante a linha de comando.
+ ai
+ Abreviação de "Artificial Inteligence", em inglês. Este também e um alias simples e muda nenhum parâmetro. Ajuda a reduzir bastante a linha de comando.
+
+ iat,ait
+ O mesmo que Send-PowershaAIChat -Temporary
+
+ io,ao
+ O mesmo que Send-PowershaAIChat -Object
#>
function Send-PowershaiChat {
- [CmdletBinding()]
+ [CmdletBinding(PositionalBinding=$false)]
param(
- [parameter(mandatory=$false, position=1)]
+ [parameter(mandatory=$false, position=0, ValueFromRemainingArguments)]
# o prompt a ser enviado ao modelo
$prompt
@@ -1866,14 +1948,40 @@ function Send-PowershaiChat {
,# Parametros da funcao de formatacao
$FormatterParams = $null
+
+ ,# Retorna as mensagens de volta no pipeline, sem escrever direto na tela!
+ # Esta opção assume que o usuário irá ser o responsável por dar o correto destino da mensagem!
+ # O objeto passado ao pipeline terá as seguintes propriedades:
+ # text - O texto (ou trecho) do texto retornado pelo modelo
+ # formatted - O texto formatado, incluindo o prompt, como se fosse escrito direto na tela (sem as cores)
+ # event - O evento. Indica o evento que originou. São os mesmos eventos documentaados em Invoke-AiChatTools
+ # interaction - O objeto interaction gerado por Invoke-AiChatTools
+ [switch]$PassThru
)
begin {
$ErrorActionPreference = "Stop";
- $MyInvok = $MyInvocation;
- $CallName = $MyInvok.InvocationName;
+ $prompt = @($prompt) -Join " "
+
+ $MyInvok = $MyInvocation;
+ $CallName = $MyInvok.InvocationName;
+ $MyRealName = $MyInvocation.MyCommand.Name;
+ $CurrentName = $CallName;
+ $MyParameters = GetMyParams
+
+ # resolve até chegar no command!
+ $LoopProtection = 50;
+ while($CurrentName -ne $MyRealName -and $LoopProtection--){
+ $CallName = $CurrentName;
+ $CurrentName = (Get-Alias $CurrentName).Definition
+ }
+
+ if($LoopProtection -lt 0){
+ write-warning "Cannot determined alias. This can be a bug!";
+ }
+
if($CallName -eq "io"){
write-verbose "Invoked vias io alias. Setting Object to true!";
@@ -1898,6 +2006,44 @@ function Send-PowershaiChat {
$AllContext = @()
$IsPipeline = $PSCmdlet.MyInvocation.ExpectingInput
+ $MainCmdlet = $PsCmdLet;
+
+ $ChatMyParams = Get-PowershaiChatParameter -ChatId $ActiveChat.id
+ $CurrentChatParams = @{
+ all = @{}
+ direct = @{}
+ };
+
+ $ChatMyParams | %{
+ if($_.direct){
+ verbose "Adding direct param $($_.name)";
+ $CurrentChatParams.direct[$_.name] = $_.value;
+ }
+
+ $CurrentChatParams.all[$_.name] = $_.value;
+ }
+
+ $ContextFormat = $CurrentChatParams.all.ContextFormat;
+
+ if(!$ContextFormat){
+ $ContextFormat = {
+ param($Params)
+
+ $ContextObject = $Params.FormattedObject;
+ $UserPrompt = $Params.CmdParams.bound.prompt;
+
+ @(
+ "Responda a mensagem com base nas informacoes de contexto que estao na tag "
+ ""
+ $ContextObject
+ ""
+ "Mensagem:"
+ $UserPrompt
+ )
+ }
+ }
+
+
function ProcessPrompt {
param($prompt)
@@ -1921,6 +2067,7 @@ function Send-PowershaiChat {
function FormatPrompt {
+
$str = PowerShaiProviderFunc "FormatPrompt" -Ignore -FuncParams @{
model = $model
}
@@ -1958,10 +2105,24 @@ function Send-PowershaiChat {
$prempt = FormatPrompt;
$str = "`$($prempt)$text`n`n"
}
+
+ if($PassThru){
+ $MessageOutput = @{
+ event = $EventName
+ text = $text
+ formatted = $str
+ interaction = $interaction
+ }
+
+ $MainCmdlet.WriteObject($MessageOutput);
+ return;
+ }
if($str){
write-host @WriteParams $Str;
}
+
+
}
#Get active chat!
@@ -1975,21 +2136,12 @@ function Send-PowershaiChat {
$ChatStats = $Chat.stats;
$ChatMetadata = $Chat.metadata;
$UserFirstName = $Chat.UserInfo.AllNames[0];
- $AllParams = Get-PowershaiChatParameter -ChatId $ActiveChat.id
$ChatContext = $Chat.context;
write-verbose "Iniciando..."
- $ChatUserParams = @{}
- $DirectParams = @{}
- $AllParams | %{
- if($_.direct){
- verbose "Adding direct param $($_.name)";
- $DirectParams[$_.name] = $_.value;
- }
-
- $ChatUserParams[$_.name] = $_.value;
- }
+ $ChatUserParams = $CurrentChatParams.all
+ $DirectParams = $CurrentChatParams.Direct;
$VerboseEnabled = $ChatUserParams.VerboseEnabled;
$ShowFullSend = $ChatUserParams.ShowFullSend
@@ -2124,6 +2276,11 @@ function Send-PowershaiChat {
$funcName = $interaction.toolResults[-1].name
+ if($PassThru){
+ $MainCmdlet.WriteObject(@{event="func";interaction=$interaction});
+ return;
+ }
+
write-host -ForegroundColor Blue "$funcName{" -NoNewLine
if($Chat.params.ShowArgs){
@@ -2142,6 +2299,11 @@ function Send-PowershaiChat {
$LastResult = $funcName = $interaction.toolResults[-1].resp.content;
+ if($PassThru){
+ $MainCmdlet.WriteObject(@{event="funcresult";interaction=$interaction});
+ return;
+ }
+
if($Chat.params.PrintToolsResults){
write-host "Result:"
write-host $LastResult
@@ -2152,6 +2314,11 @@ function Send-PowershaiChat {
exec = {
param($interaction)
+ if($PassThru){
+ $MainCmdlet.WriteObject(@{event="exec";interaction=$interaction});
+ return;
+ }
+
write-host -ForegroundColor Blue "}"
write-host ""
}
@@ -2208,9 +2375,9 @@ function Send-PowershaiChat {
$Chat.history += $HistoryEntry
if($Object){
- write-verbose "Object mode! Parsing json..."
+ verbose "Object mode! Parsing json..."
$JsonContent = @($Ret.answer)[0].choices[0].message.content
- write-verbose "Converting json to object: $JsonContent";
+ verbose "Converting json to object: $JsonContent";
$JsonObject = $JsonContent | ConvertFrom-Json;
$ResultObj = $JsonObject;
@@ -2295,22 +2462,24 @@ function Send-PowershaiChat {
function ProcessContext {
param($context)
- IF($PrintContext){
+ if($PrintContext){
write-host -ForegroundColor Blue Contexto:
write-host -ForegroundColor Blue $Context;
}
- write-verbose "Adding to context: $($Context|out-string)"
- $FinalPrompt = @(
- "Responda a mensagem com base nas informacoes de contexto que estao na tag "
- ""
- $context
- ""
- "Mensagem:"
- $prompt
- )
- ProcessPrompt $FinalPrompt
+
+ $ContextScriptParams = @{
+ FormattedObject = $Context
+ CmdParams = $MyParameters
+ Chat = $ActiveChat
+ }
+
+
+ $ContextPrompt = & $ContextFormat $ContextScriptParams
+
+ write-verbose "Adding to context: $($Context|out-string)"
+ ProcessPrompt $ContextPrompt
}
@@ -2903,10 +3072,15 @@ function Get-AiUserToolbox {
Set-Alias -Name PowerShai -Value Start-PowershaiChat
+
Set-Alias -Name ia -Value Send-PowershaiChat
Set-Alias -Name iat -Value Send-PowershaiChat
Set-Alias -Name io -Value Send-PowershaiChat
-Set-Alias -Name iaf -Value Update-PowershaiChatFunctions
+
+Set-Alias -Name ai -Value ia
+Set-Alias -Name ait -Value iat
+Set-Alias -Name ao -Value io
+
<#
function prompt {