cowriter.psm1
function Start-Cowriter { [Alias('Cowriter')] [CmdletBinding()] param ( [string] $Xaml = "$PSScriptRoot/files/xaml/cowriter.xaml", [string] $OllamaUrl = 'http://127.0.0.1:11434/api', [string] $SystemPrompt = "$PSScriptRoot/files/prompts/system.txt" ) Add-Type -AssemblyName PresentationFramework # Load XAML [xml]$xaml = Get-Content -Raw -Path $Xaml $reader = (New-Object System.Xml.XmlNodeReader $xaml) $script:window = [Windows.Markup.XamlReader]::Load($reader) $mainText = $window.FindName("MainText") $lineNumbers = $window.FindName("LineNumbers") # Logic for the text lines $lines_loaded = { $visibleLines = [Math]::Ceiling($mainText.ViewportHeight / $mainText.FontSize) $totalLines = [Math]::Max($mainText.LineCount, $visibleLines) $nums = "" for ($i=1; $i -le $totalLines; $i++) { $nums += "$i`n" } $lineNumbers.Text = $nums } $lines_textChanged = { $visibleLines = [Math]::Ceiling($mainText.ViewportHeight / $mainText.FontSize) $totalLines = [Math]::Max($mainText.LineCount, $visibleLines) $textLines = $mainText.Text -split "`n" $nums = "" for ($i=1; $i -le $totalLines; $i++) { $nums += "$i`n" } $lineNumbers.Text = $nums } $mainText.Add_Loaded($lines_loaded) $mainText.Add_TextChanged($lines_textChanged) # Logic for the formatting buttons $boldButton = $window.FindName("BoldButton") $italicButton = $window.FindName("ItalicButton") $underlineButton = $window.FindName("UnderlineButton") $bulletButton = $window.FindName("BulletButton") $numberButton = $window.FindName("NumberButton") # Bold $boldButton.Add_Click({ $mainText.Selection.ApplyPropertyValue([System.Windows.Documents.Inline]::FontWeightProperty, [System.Windows.FontWeights]::Bold) }) # Italic $italicButton.Add_Click({ $mainText.Selection.ApplyPropertyValue([System.Windows.Documents.Inline]::FontStyleProperty, [System.Windows.FontStyles]::Italic) }) # Underline $underlineButton.Add_Click({ $mainText.Selection.ApplyPropertyValue([System.Windows.Documents.Inline]::TextDecorationsProperty, [System.Windows.TextDecorations]::Underline) }) $script:chatInput = $window.FindName('ChatInput') $script:sendButton = $window.FindName('SendButton') $sendButton.Add_Loaded({ $this.IsEnabled = $false }) $chatInput.Add_TextChanged({ $script:sendButton.IsEnabled = -not [string]::IsNullOrWhiteSpace($script:chatInput.Text) }) $script:chatHistory = $window.FindName('ChatHistory') $chatHistory.Tag = @{ Messages = [System.Collections.ArrayList]::new() } [void] $chatHistory.Tag['Messages'].Add(@{ role = 'system' content = [string] (Get-Content $SystemPrompt) }) $script:addChatBubble = { param ( [Parameter(Position=0)] [string] $Message, [ValidateSet('User','AI')] [string] $Type = 'User', [int] $CornerRadius = 10, [int] $Padding = 8, [int] $Margin = 4, [int] $MaxWidth = 400, [System.Windows.TextWrapping] $TextWrapping = 'Wrap', $ChatHistory = $script:chatHistory ) $Background = switch ($Type) { 'User' { 'LightBlue' } 'AI' { 'LightGray' } } [System.Windows.HorizontalAlignment] $HorizontalAlignment = switch ($Type) { 'User' { 'Right' } 'AI' { 'Left' } } $ChatHistory.AddChild( [System.Windows.Controls.Border] @{ CornerRadius = $CornerRadius Padding = $Padding Margin = $Margin HorizontalAlignment = $HorizontalAlignment Background = $Background MaxWidth = $MaxWidth Child = [System.Windows.Controls.TextBlock] @{ Text = $Message TextWrapping = $TextWrapping } Tag = @{ Type = $Type } } ) } $script:sendMessage = { if ([string]::IsNullOrWhiteSpace($script:chatInput.Text)) { return } $message = $script:chatInput.Text $script:sendButton.IsEnabled = $false . $script:addChatBubble -Type User -Message $message $script:chatInput.Clear() [void] $script:chatHistory.Tag['Messages'].Add(@{ role = 'user' content = $message }) [System.Management.Automation.PowerShell]::Create().AddScript({ param ( $w, $ch, $q, $m = 'llama3.2', $OllamaUrl, $ml ) $body = @{ model = $m messages = $ml # prompt = $q stream = $false } | ConvertTo-Json -Depth 10 -Compress try { $result = Invoke-RestMethod "$OllamaUrl/chat" -method post -body $body -ErrorAction Stop $message = $result.message $content = $message.content } catch { $content = "Error: $($_.Exception.Message)" } $w.Dispatcher.Invoke({ $ch.AddChild( [System.Windows.Controls.Border] @{ CornerRadius = 10 Padding = 8 Margin = 4 HorizontalAlignment = 'Left' Background = 'LightGray' MaxWidth = 400 Child = [System.Windows.Controls.TextBlock] @{ Text = $content TextWrapping = 'Wrap' } Tag = @{ Type = 'AI' } } ) [void] $ch.Tag['Messages'].Add($message) }) }).AddParameters(@{ w = $script:window ch = $script:chatHistory q = $message OllamaUrl = $OllamaUrl ml = $script:chatHistory.Tag['Messages'] }).BeginInvoke() } $sendButton.Add_Click($sendMessage) $chatInput.Add_KeyDown({ param($sender, $e) if ($e.Key -in [System.Windows.Input.Key]::Enter, [System.Windows.Input.Key]::Return) { $script:sendMessage.Invoke() $e.Handled = $true } }) # Show window $window.ShowDialog() } |