А давайте встроим ии в powershell. Делаем умный поисковик спецификаций в командной строке.

А давайте встроим ии в powershell. Делаем умный поисковик спецификаций в командной строке.

Привет, коллеги! Сегодня я хочу показать, как с помощью модели Gemini, интерфейса командной строки gemini-cli и модуля Out-ConsoleGridView создать интерактивный справочник. Он будет принимать на вход идентификатор компонента (марка, модель, категория, артикул и т. п.) и возвращать интерактивную таблицу с характеристиками, сгенерированную моделью Gemini. В конце поста я дам ссылку на код в github. Приятного чтения.

Мы часто сталкиваемся с задачей: нужно быстро узнать точные характеристики — будь то материнская плата, автомат в электрощитке или сетевой коммутатор. В этой статье я покажу, как создать интерактивный справочник, который всегда будет под рукой. По запросу он соберёт сведения, уточнит параметры в интернете и вернёт готовую таблицу. В ней можно будет выбрать интересующие характеристики и, при необходимости, углубить поиск. И все это работает в командной строке.

Впрочем, лучше один раз увидеть:

Модель получает запрос и отдает результат таблицей или пояснительным текстом

Что нам понадобится:
Powershell 7
Gemini Cli - интерфейс командной строки моделей Gemini от Google.
Out-ConsoleGridView - модуль отображения результатов в виде интерактивной таблицы прямо в консоли.

Установка PowerShell.

Стабильная версия:

winget install --id Microsoft.PowerShell --source winget

Предварительная (preview) версия:

winget install --id Microsoft.PowerShell.Preview --source winget

Out-ConsoleGridView

Out-ConsoleGridView — модуль PowerShell, который выводит результаты команд в интерактивную таблицу прямо в консоли. Он работает внутри терминала, без запуска отдельного окна, что позволяет встраивать его в конвейер (pipeline).Установка Out-ConsoleGridView:

Install-Module -Name Microsoft.PowerShell.ConsoleGuiTools -Scope CurrentUser

У Out-ConsoleGridView есть два режима выбора:

Множественный выбор (checkbox, по умолчанию) — можно выделить несколько строк.

Get-Process | Out-ConsoleGridView -OutputMode Multiple

Одиночный выбор (radio) — выбирается только одна строка.

Get-Process | Out-ConsoleGridView -OutputMode Single

Еще пример:

# Выбор процессов в интерактивном режиме $procsToStop = Get-Process | Sort-Object -Property CPU -Descending | Out-ConsoleGridView -OutputMode Multiple # Если что-то было выбрано, передаем объекты на остановку if ($procsToStop) { $procsToStop | Stop-Process -WhatIf }

Что такое Gemini CLI?

Дисклеймер. В этой статье я не рассматриваю все нюансы работы с gemini-cli. Если вам интересно - напишите в комментариях, я опубликую отдельный пост посвящённый gemini-cli

Gemini CLI — это командная строка для взаимодействия с моделями ИИ от Google. Вы запускаете его в своем терминале, и он превращается в чат, который, в отличие от веб-версий, имеет доступ к вашей файловой системе и может запускать команды.

Ключевые возможности:

  • Понимает код: Он может анализировать ваши скрипты, находить в них ошибки и предлагать исправления.
  • Генерирует код: Вы можете попросить его написать PowerShell-скрипт для решения вашей задачи, и он это сделает.
  • Работает с файлами: Может читать файлы, создавать новые, вносить изменения в существующие.
  • Запускает команды: Может выполнять команды оболочки, такие как git или npm.
  • Находит информацию в интернете

Для наших целей самое важное то, что Gemini CLI умеет работать в не интерактивном режиме. То есть мы можем передать ему промпт как аргумент командной строки, и он просто вернет нам ответ, не запуская свой интерактивный чат. Именно эту возможность мы и будем использовать.

Установка и настройка

Чтобы начать, нам нужно подготовить наше окружение. Это делается один раз.

Шаг 1: Установка Node.js Gemini CLI — это приложение, написанное на Node.js (популярная среда для JavaScript). Поэтому сначала нам нужно установить саму Node.js.

  1. Перейдите на официальный сайт: https://nodejs.org/
  2. Скачайте и установите LTS версию. Это самый стабильный и рекомендуемый вариант. Просто следуйте инструкциям установщика.
  3. После установки откройте новое окно PowerShell и проверьте, что все работает:node -v npm. Вы должны увидеть версии, например, v20.12.2 и 10.5.0.

Шаг 2: Установка самого Gemini CLI. Теперь, когда у нас есть npm (менеджер пакетов для Node.js), установка Gemini CLI сводится к одной команде. Выполните ее в PowerShell:

npm install -g @google/gemini-cli

Флаг -g означает «глобальная установка», что сделает команду gemini доступной из любого места в вашей системе.

Шаг 3: Запуск и Аутентификация В первый раз, когда вы запустите Gemini CLI, он попросит вас войти в свой аккаунт Google. Это нужно, чтобы он мог использовать вашу бесплатную квоту.

Просто введите в PowerShell команду:
gemini

  • Он задаст вам вопрос о входе. Выберите "Sign in with Google".
А давайте встроим ии в powershell. Делаем умный поисковик спецификаций в командной строке.
Поздравляю, вы готовы к работе! 
Поздравляю, вы готовы к работе! 

«Ужасный» Invoke-Expression.

Прежде чем мы соединим все вместе, вспомним один из самых опасных командлетов в PowerShell — Invoke-Expression, или его коротким псевдонимом iex.

Invoke-Expression берет текстовую строку и выполняет ее так, как будто это была команда, напечатанная в консоли.

Пример:

$commandString="Get-Process -Name 'chrome'"Invoke-Expression-InputObject $commandString

Эта команда сделает то же самое, что и простой вызов
Get-Process -Name `chrome`.

Почему же он опасный? Потому, что выполнение строки, которую вы не контролируете (например, полученной из интернета или от ИИ), — огромная дыра в безопасности. Если ИИ по ошибке или со злым умыслом вернет команду

Remove-Item -Path C:\ -Recurse -Force

powershell без раздумий ее выполнит.

Но для нашей задачи — создания управляемого и контролируемого моста между запросом на естественном языке и его выполнением — он подходит. Мы будем использовать его с осторожностью, полностью осознавая риски.

Соединяем всё вместе: командлет Invoke-Gemini

Напишем простую PowerShell-функцию, которая позволит нам отправлять промпты одной командой.

function Invoke-Gemini { <# .SYNOPSIS Отправляет текстовый промпт в Gemini CLI и возвращает его ответ. #> [CmdletBinding()] param( [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [string]$Prompt ) process { try { # Проверяем, доступна ли команда gemini $geminiCommand = Get-Command gemini -ErrorAction Stop } catch { Write-Error "Команда 'gemini' не найдена. Убедитесь, что Gemini CLI установлен." return } Write-Verbose "Отправка промпта в Gemini CLI..." # Запускаем gemini в неинтерактивном режиме с нашим промптом $output = & $geminiCommand.Source -p $Prompt 2>&1 if (-not $?) { Write-Warning "Команда gemini завершилась с ошибкой." $output | ForEach-Object { Write-Warning $_.ToString() } return } # Возвращаем чистый вывод return $output } }

Скопируйте этот код и вставьте его в свое окно PowerShell, чтобы он стал доступен в текущей сессии.

Давайте зададим ему вопрос на общую тему прямо из нашей PowerShell-консоли.

Invoke-Gemini -Prompt "Расскажи о пяти последних трендах в области машинного обучения"
Ответ gemini
Ответ gemini

Создаем командлет

[CmdletBinding()] param( [Parameter(HelpMessage = "Выберите модель: 'gemini-2.5-flash' (по умолчанию) или 'gemini-2.5-pro'.")] [ValidateSet('gemini-2.5-flash', 'gemini-2.5-pro')] [string]$Model = 'gemini-2.5-flash' ) # --- Шаг 1: Настройка --- $env:GEMINI_API_KEY = "ХХХХХХХХХХХХХХХХХХХХХХХХХХХХХХХХХХХХХХ" if (-not $env:GEMINI_API_KEY) { Write-Error "..."; return } $scriptRoot = Get-Location # --- --- $HistoryDir = Join-Path $scriptRoot ".gemini/.chat_history" # --- КОНЕЦ ИЗМЕНЕНИЯ --- $timestamp = Get-Date -Format "yyyy-MM-dd_HH-mm-ss" $historyFileName = "ai_session_$timestamp.jsonl" $historyFilePath = Join-Path $HistoryDir $historyFileName # --- ФУНКЦИИ --- function Add-History { param([string]$UserPrompt, [string]$ModelResponse) if (-not (Test-Path $HistoryDir)) { New-Item -Path $HistoryDir -ItemType Directory | Out-Null } @{ user = $UserPrompt } | ConvertTo-Json -Compress | Add-Content -Path $historyFilePath @{ model = $ModelResponse } | ConvertTo-Json -Compress | Add-Content -Path $historyFilePath } function Show-History { if (-not (Test-Path $historyFilePath)) { Write-Host "История текущей сессии пуста." -ForegroundColor Yellow; return } Write-Host "`n--- История текущей сессии ---" -ForegroundColor Cyan; Get-Content -Path $historyFilePath; Write-Host "------------------------------------`n" -ForegroundColor Cyan } function Clear-History { if (Test-Path $historyFilePath) { try { Remove-Item -Path $historyFilePath -Force -ErrorAction Stop Write-Host "История текущей сессии ($historyFileName) была удалена." -ForegroundColor Yellow } catch { Write-Warning "Не удалось удалить файл истории: $_" } } else { Write-Host "История текущей сессии пуста, удалять нечего." -ForegroundColor Yellow } } function Show-Help { $helpFilePath = Join-Path $scriptRoot ".gemini/ShowHelp.md" if (Test-Path $helpFilePath) { $helpText = Get-Content -Path $helpFilePath -Raw Write-Host $helpText } else { Write-Warning "Файл справки .gemini/ShowHelp.md не найден." } } function Command-Handler { param([string]$Command) switch ($Command) { '?' { Show-Help; return 'continue' } 'history' { Show-History; return 'continue' } ('clear', 'clear-history') { Clear-History; return 'continue' } 'gemini help' { Write-Host "`n--- Справка Gemini CLI ---`n" -ForegroundColor Cyan & gemini --help Write-Host "`n--------------------------`n" -ForegroundColor Cyan return 'continue' } ('exit', 'quit') { return 'break' } default { return $null } } } function Invoke-GeminiPrompt { param([string]$Prompt, [string]$Model) try { $output = & gemini -m $Model -p $Prompt 2>&1 if (-not $?) { $output | ForEach-Object { Write-Warning $_.ToString() }; return $null } $outputString = ($output -join [Environment]::NewLine).Trim() $cleanedOutput = $outputString -replace "(?m)^Data collection is disabled\.`r?`n" , "" $cleanedOutput = $cleanedOutput -replace "(?m)^Loaded cached credentials\.`r?`n", "" return $cleanedOutput.Trim() } catch { Write-Error "Критическая ошибка при вызове Gemini CLI: $_"; return $null } } # --- Отображение выбранных данных в консольной таблице --- function Show-SelectionTable { param([array]$SelectedData) if ($null -eq $SelectedData -or $SelectedData.Count -eq 0) { return } Write-Host "`n--- ВЫБРАННЫЕ ДАННЫЕ ---" -ForegroundColor Yellow # Если выбран только один элемент, обернуть в массив для единообразной обработки if ($SelectedData -isnot [array]) { $SelectedData = @($SelectedData) } # Получить все уникальные свойства из выбранных объектов $allProperties = @() foreach ($item in $SelectedData) { if ($item -is [PSCustomObject]) { $properties = $item | Get-Member -MemberType Properties | Select-Object -ExpandProperty Name $allProperties = $allProperties + $properties | Sort-Object -Unique } } # Если есть свойства, показать таблицу if ($allProperties.Count -gt 0) { $SelectedData | Format-Table -Property $allProperties -AutoSize -Wrap } else { # Если нет определенных свойств, показать как простой список for ($i = 0; $i -lt $SelectedData.Count; $i++) { Write-Host "[$($i + 1)] $($SelectedData[$i])" -ForegroundColor White } } Write-Host "-------------------------" -ForegroundColor Yellow Write-Host "Выбрано элементов: $($SelectedData.Count)" -ForegroundColor Magenta Write-Host "" } # --- Шаг 2: Проверка окружения --- try { Get-Command gemini -ErrorAction Stop | Out-Null } catch { Write-Error "Команда 'gemini' не найдена..."; return } if (-not (Test-Path (Join-Path $scriptRoot ".gemini/GEMINI.md"))) { Write-Warning "Файл системного промпта .gemini/GEMINI.md не найден. Ответы модели могут быть непредсказуемыми."; } if (-not (Test-Path (Join-Path $scriptRoot ".gemini/ShowHelp.md"))) { Write-Warning "Файл справки .gemini/ShowHelp.md не найден. Команда '?' не будет работать."; } # --- Шаг 3: Основная логика --- Write-Host "AI-поисковик спецификаций. Модель: '$Model'." -ForegroundColor Green Write-Host "Файл сессии будет сохранен в: $historyFilePath" -ForegroundColor Yellow Write-Host "Введите 'exit' для выхода или '?' для помощи." $selectionContextJson = $null while ($true) { if ($selectionContextJson) { Write-Host -NoNewline -ForegroundColor Green "🤖AI [Выборка активна] :) > " } else { Write-Host -NoNewline -ForegroundColor Green "🤖AI :) > " } $UserPrompt = Read-Host $commandResult = Command-Handler -Command $UserPrompt if ($commandResult -eq 'break') { break } if ($commandResult -eq 'continue') { continue } if ([string]::IsNullOrWhiteSpace($UserPrompt)) { continue } Write-Host "Идет поиск и обработка запроса..." -ForegroundColor Gray $historyContent = "" if (Test-Path $historyFilePath) { $historyContent = Get-Content -Path $historyFilePath -Raw -ErrorAction SilentlyContinue } $fullPrompt = @" ### ИСТОРИЯ ДИАЛОГА (КОНТЕКСТ) $historyContent "@ if ($selectionContextJson) { $selectionBlock = @" ### ДАННЫЕ ИЗ ВЫБОРКИ (ДЛЯ АНАЛИЗА) $selectionContextJson "@ $fullPrompt += $selectionBlock $selectionContextJson = $null } $fullPrompt += @" ### НОВАЯ ЗАДАЧА $UserPrompt "@ $ModelResponse = Invoke-GeminiPrompt -Prompt $fullPrompt -Model $Model if ($ModelResponse) { $jsonToParse = $null $jsonPattern = '(?s)```json\s*(.*?)\s*```' if ($ModelResponse -match $jsonPattern) { $jsonToParse = $matches[1] } else { $jsonToParse = $ModelResponse } try { $jsonObject = $jsonToParse | ConvertFrom-Json Write-Host "`n--- Gemini (объект JSON) ---`n" -ForegroundColor Green $gridSelection = $jsonObject | Out-ConsoleGridView -Title "Выберите строки для следующего запроса (OK) или закройте (Cancel)" -OutputMode Multiple if ($null -ne $gridSelection) { Show-SelectionTable -SelectedData $gridSelection $selectionContextJson = $gridSelection | ConvertTo-Json -Compress -Depth 10 Write-Host "Выборка сохранена. Добавьте ваш следующий запрос (например, 'сравни их')." -ForegroundColor Magenta } } catch { Write-Host $ModelResponse -ForegroundColor Cyan } Add-History -UserPrompt $UserPrompt -ModelResponse $ModelResponse } } Write-Host "Завершение работы." -ForegroundColor Green

Как работает AI-поисковик

Проследим весь жизненный цикл нашего скрипта - что происходит с момента запуска и до получения результатов.

Инициализация: подготовка к работе

Скрипт принимает параметр $Model с валидацией - можно выбрать 'gemini-2.5-flash' (по умолчанию, быстрая модель) или 'gemini-2.5-pro' (более мощная). Я рекомендую использовать gemini-2.5-flash по умолчанию, т.к. в модели pro у нас очень ограниченное количество токенов. когда они заканчиваются, модель возвращает ошибку.
При запуске скрипт первым делом настраивает рабочее окружение. Он устанавливает API ключ для доступа к Gemini AI, определяет текущую папку как базовую директорию и создает структуру для хранения файлов. Для каждой сессии создается файл с временной меткой, например ai_session_2025-08-26_14-30-15.jsonl. Это история диалогов.

Затем система проверяет, что все необходимые инструменты установлены. Она ищет Gemini CLI в системе, проверяет наличие файлов конфигурации в папке .gemini/. Особенно важен файл GEMINI.md - он содержит системный промпт для модели и автоматически загружается Gemini CLI при старте. Это стандартное расположение для системных инструкций. Также проверяется файл ShowHelp.md со справочной информацией. Если что-то критично важное отсутствует, скрипт предупреждает пользователя или завершает работу.

Запуск интерактивного режима

После успешной инициализации скрипт выводит приветственное сообщение с указанием выбранной модели ("AI-поисковик спецификаций. Модель: 'gemini-2.5-flash'."), путь к файлу сессии и инструкцию по командам. Затем переходит в интерактивный режим - показывает приглашение и ждет ввода от пользователя. Приглашение выглядит как 🤖AI :) > и меняется на 🤖AI [Выборка активна] :) > когда у системы есть данные для анализа.

Обработка пользовательского ввода

Каждый ввод пользователя сначала проверяется на служебные команды через функцию Command-Handler. Эта функция распознает команды ? (справка из файла ShowHelp.md), history (показать историю сессии), clear и clear-history (очистить файл истории), gemini help (справка по CLI), exit и quit (выход). Если это служебная команда, она выполняется немедленно без обращения к AI, и цикл продолжается.

Если это обычный запрос, система начинает формировать контекст для отправки в Gemini. Она читает всю историю текущей сессии из JSONL файла (если он существует), добавляет блок с данными из предыдущей выборки (если есть активная выборка), и объединяет все это с новым запросом пользователя в структурированный промпт с разделами "ИСТОРИЯ ДИАЛОГА", "ДАННЫЕ ИЗ ВЫБОРКИ" и "НОВАЯ ЗАДАЧА". После использования данные выборки обнуляются.

Взаимодействие с искусственным интеллектом

Сформированный промпт отправляется в Gemini через командную строку с помощью вызова & gemini -m $Model -p $Prompt 2>&1. Система захватывает весь вывод (включая ошибки через 2>&1), проверяет код возврата и очищает результат от служебных сообщений CLI ("Data collection is disabled" и "Loaded cached credentials"). Если происходит ошибка на этом этапе, пользователь получает предупреждение, но скрипт продолжает работать.

Обработка ответа AI

Полученный от AI ответ система пытается интерпретировать как JSON. Сначала она ищет блок кода в формате json..., извлекает содержимое и пытается его распарсить. Если такого блока нет, парсит весь ответ целиком. При успешном парсинге данные отображаются в интерактивной таблице Out-ConsoleGridView с заголовком "Выберите строки для следующего запроса (OK) или закройте (Cancel)" и множественным выбором. Если JSON не распознается (ошибка парсинга), ответ показывается как обычный текст в голубом цвете.

Работа с выборкой данных

Когда пользователь выбирает строки в таблице и нажимает OK, система выполняет несколько действий. Сначала вызывается функция Show-SelectionTable, которая анализирует структуру выбранных данных: если это объекты с свойствами, она определяет все уникальные поля и показывает данные через Format-Table с автоподбором размера и переносом. Если это простые значения, отображает их как нумерованный список. Затем выводит счетчик выбранных элементов и сообщение "Выборка сохранена. Добавьте ваш следующий запрос (например, 'сравни их')".

Выбранные данные преобразуются в сжатый JSON с глубиной вложенности 10 уровней и сохраняются в переменной $selectionContextJson для использования в следующих запросах к AI.

Ведение истории

Каждая пара "запрос пользователя - ответ AI" сохраняется в файл истории в формате JSONL. Это обеспечивает непрерывность диалога - AI "помнит" весь предыдущий разговор и может ссылаться на ранее обсуждавшиеся темы.

Цикл продолжается

После обработки запроса система возвращается к ожиданию нового ввода. Если у пользователя есть активная выборка, это отражается в приглашении командной строки. Цикл продолжается до тех пор, пока пользователь не введет команду выхода.

Практический пример работы

Представим, что пользователь запускает скрипт и вводит "RTX 4070 Ti Super":

  1. Подготовка контекста: Система берет системный промпт из файла, добавляет историю (пока пустую) и новый запрос
  2. Обращение к AI: Полный промпт отправляется в Gemini с просьбой найти характеристики видеокарт
  3. Получение данных: AI возвращает JSON с массивом объектов, содержащих информацию о различных моделях RTX 4070 Ti Super
  4. Интерактивная таблица: Пользователь видит таблицу с производителями, характеристиками, ценами и выбирает 2-3 интересующие модели
  5. Отображение выборки: В консоли появляется таблица с выбранными моделями, приглашение меняется на [Выборка активна]
  6. Уточняющий запрос: Пользователь пишет "сравни производительность в играх"
  7. Контекстный анализ: AI получает и исходный запрос, и выбранные модели, и новый вопрос - дает детальное сравнение именно этих карт

Завершение работы

При вводе exit или quit скрипт корректно завершается, сохранив всю историю сессии в файл. Пользователь может в любой момент вернуться к этому диалогу, просмотрев содержимое соответствующего файла в папке .chat_history.

Вся эта сложная логика скрыта от пользователя за простым интерфейсом командной строки. Человек просто задает вопросы и получает структурированные ответы, а система берет на себя всю работу по поддержанию контекста, парсингу данных и управлению состоянием диалога.

Настройка.

# --- Шаг 1: Настройка --- $env:GEMINI_API_KEY = "XXXXXXXXXXXXXXXXXXXXXXXXX" if (-not $env:GEMINI_API_KEY) { Write-Error "нет API ключа!"; return } $scriptRoot = Get-Location # --- ИЗМЕНЕНИЕ: Переменная переименована --- $HistoryDir = Join-Path $scriptRoot ".gemini/.chat_history" # --- КОНЕЦ ИЗМЕНЕНИЯ --- $timestamp = Get-Date -Format "yyyy-MM-dd_HH-mm-ss" $historyFileName = "ai_session_$timestamp.jsonl" $historyFilePath = Join-Path $HistoryDir $historyFileName

Назначение строк:

  • $env:GEMINI_API_KEY = "..." - устанавливает API ключ для доступа к Gemini AI
  • if (-not $env:GEMINI_API_KEY) - проверяет наличие ключа, завершает работу если его нет. Вы можете изменить логику обработки, а также использовать привычные для вас хранилища: .env, $PATH.
  • $scriptRoot = Get-Location - получает текущую рабочую директорию
  • $HistoryDir = Join-Path... - формирует путь к папке для хранения истории диалогов (.gemini/.chat_history)
  • $timestamp = Get-Date... - создает временную метку в формате 2025-08-26_14-30-15
  • $historyFileName = "ai_session_$timestamp.jsonl" - генерирует уникальное имя файла сессии
  • $historyFilePath = Join-Path... - создает полный путь к файлу истории текущей сессии

Проверка окружения - что должно быть установлено.

# --- Шаг 2: Проверка окружения --- try { Get-Command gemini -ErrorAction Stop | Out-Null } catch { Write-Error "Команда 'gemini' не найдена..."; return } if (-not (Test-Path (Join-Path $scriptRoot ".gemini/GEMINI.md"))) { Write-Warning "Файл системного промпта .gemini/GEMINI.md не найден..." } if (-not (Test-Path (Join-Path $scriptRoot ".gemini/ShowHelp.md"))) { Write-Warning "Файл справки .gemini/ShowHelp.md не найден..." }

Что проверяется:

  • Наличие Gemini CLI в системе - без него скрипт не работает
  • Файл GEMINI.md - содержит системный промпт (инструкции для AI)
  • Файл ShowHelp.md - справка для пользователя (команда ?)

Основная функция взаимодействия с AI.

function Invoke-GeminiPrompt { param([string]$Prompt, [string]$Model) try { $output = & gemini -m $Model -p $Prompt 2>&1 if (-not $?) { $output | ForEach-Object { Write-Warning $_.ToString() }; return $null } $outputString = ($output -join [Environment]::NewLine).Trim() $cleanedOutput = $outputString -replace "(?m)^Data collection is disabled\.`r?`n" , "" $cleanedOutput = $cleanedOutput -replace "(?m)^Loaded cached credentials\.`r?`n", "" return $cleanedOutput.Trim() } catch { Write-Error "Критическая ошибка при вызове Gemini CLI: $_"; return $null } }

Задачи функции:

  • Вызывает Gemini CLI с указанной моделью и промптом
  • Захватывает все выводы (включая ошибки)
  • Очищает результат от служебных сообщений CLI
  • Возвращает чистый ответ AI или $null при ошибке

Функции управления историей.

function Add-History { param([string]$UserPrompt, [string]$ModelResponse) if (-not (Test-Path $HistoryDir)) { New-Item -Path $HistoryDir -ItemType Directory | Out-Null } @{ user = $UserPrompt } | ConvertTo-Json -Compress | Add-Content -Path $historyFilePath @{ model = $ModelResponse } | ConvertTo-Json -Compress | Add-Content -Path $historyFilePath } function Show-History { if (-not (Test-Path $historyFilePath)) { Write-Host "История текущей сессии пуста." -ForegroundColor Yellow; return } Write-Host "`n--- История текущей сессии ---" -ForegroundColor Cyan Get-Content -Path $historyFilePath Write-Host "------------------------------------`n" -ForegroundColor Cyan } function Clear-History { if (Test-Path $historyFilePath) { Remove-Item -Path $historyFilePath -Force -ErrorAction Stop Write-Host "История текущей сессии ($historyFileName) была удалена." -ForegroundColor Yellow } }

Назначение:

  • Add-History - сохраняет пары "вопрос-ответ" в JSONL формате
  • Show-History - показывает содержимое файла истории
  • Clear-History - удаляет файл истории текущей сессии

Функция отображения выбранных данных.

function Show-SelectionTable { param([array]$SelectedData) if ($null -eq $SelectedData -or $SelectedData.Count -eq 0) { return } Write-Host "`n--- ВЫБРАННЫЕ ДАННЫЕ ---" -ForegroundColor Yellow # Получить все уникальные свойства из выбранных объектов $allProperties = @() foreach ($item in $SelectedData) { if ($item -is [PSCustomObject]) { $properties = $item | Get-Member -MemberType Properties | Select-Object -ExpandProperty Name $allProperties = $allProperties + $properties | Sort-Object -Unique } } # Показать таблицу или список if ($allProperties.Count -gt 0) { $SelectedData | Format-Table -Property $allProperties -AutoSize -Wrap } else { for ($i = 0; $i -lt $SelectedData.Count; $i++) { Write-Host "[$($i + 1)] $($SelectedData[$i])" -ForegroundColor White } } Write-Host "-------------------------" -ForegroundColor Yellow Write-Host "Выбрано элементов: $($SelectedData.Count)" -ForegroundColor Magenta }

Задача функции: После выбора элементов в Out-ConsoleGridView показывает их в консоли в виде аккуратной таблицы, чтобы пользователь видел, что именно выбрал.

Основной рабочий цикл.

while ($true) { # Показ приглашения с индикацией состояния if ($selectionContextJson) { Write-Host -NoNewline -ForegroundColor Green "🤖AI [Выборка активна] :) > " } else { Write-Host -NoNewline -ForegroundColor Green "🤖AI :) > " } $UserPrompt = Read-Host # Обработка служебных команд $commandResult = Command-Handler -Command $UserPrompt if ($commandResult -eq 'break') { break } if ($commandResult -eq 'continue') { continue } # Формирование полного промпта с контекстом $fullPrompt = @" ### ИСТОРИЯ ДИАЛОГА (КОНТЕКСТ) $historyContent ### ДАННЫЕ ИЗ ВЫБОРКИ (ДЛЯ АНАЛИЗА) $selectionContextJson ### НОВАЯ ЗАДАЧА $UserPrompt "@ # Вызов AI и обработка ответа $ModelResponse = Invoke-GeminiPrompt -Prompt $fullPrompt -Model $Model # Попытка парсинга JSON и показ интерактивной таблицы try { $jsonObject = $jsonToParse | ConvertFrom-Json $gridSelection = $jsonObject | Out-ConsoleGridView -Title "Выберите строки..." -OutputMode Multiple if ($null -ne $gridSelection) { Show-SelectionTable -SelectedData $gridSelection $selectionContextJson = $gridSelection | ConvertTo-Json -Compress -Depth 10 } } catch { Write-Host $ModelResponse -ForegroundColor Cyan } Add-History -UserPrompt $UserPrompt -ModelResponse $ModelResponse }

Ключевые особенности:

  • Индикатор [Выборка активна] показывает, что есть данные для анализа
  • Каждый запрос включает всю историю диалога для поддержания контекста
  • AI получает и историю, и выбранные пользователем данные
  • Результат пытается отобразиться как интерактивная таблица
  • При неудаче парсинга JSON показывается обычный текст

Структура рабочих файлов

Скрипт создает следующую структуру:

А давайте встроим ии в powershell. Делаем умный поисковик спецификаций в командной строке.

Файл GEMINI.md в папке .gemini/ - это стандартное расположение системного промпта для Gemini CLI. При каждом запуске модель автоматически загружает инструкции из этого файла, что определяет её поведение и формат ответов.

Системная инструкция (GEMINI.md):

Код командлета:

Удачи!

Начать дискуссию