基于SemanticKernel和OneApi搭建智能PowerShell小助手

在日常使用中,经常忘记Powershell指令,总是需要去查询。在万物皆可AI得时代,我们可以利用大模型来搭建自己的小助手。
先看执行效果:
在这里插入图片描述
下面进入正式环节。
首先,使用国内大模型需要使用one-api或者chatnio等进行转发,这里就不多介绍了
本篇使用的agent技术是微软的SemanticKernel,可以参考相关文章: AI框架SemanticKernel

创建Plugin

先创建实现效果的Plugin,这里主要实现一个获取指令的作用

    public class WinCmdPlugin
    {
        public async Task<string> GetCmd(Kernel kernel, string goal)
        {
            string prompt = """
                用户正在使用Windows操作系统,他需要用powershell执行一些指令。请根据他输入的目的输出指令。
                ###
                输出是一个字符串格式,只需要包含所需要执行的命令,不需要输出其他任何内容
                ###
                例:
                输入:打开cmd
                输出:cmd
                ###
                注意
                必须严格输出windows操作系统上powershell能执行的指令。如果无可用指令,直接返回空字符串,不需要返回其他任何内容!!!
                返回的指令结果严禁带上任何标点符号等。只需要指令本身
                ###
                用户输入: {{$input}}
                ###
                输出:
                """;
            var function = kernel.CreateFunctionFromPrompt(prompt);
            var args = new KernelArguments
            {
                ["input"] = goal,
            };
            var res = await function.InvokeAsync(kernel, args);
            return res.ToString().TrimEnd('。');

        }
    }

创建代理

由于使用了转发,建立一个HttpClientHandler来实现请求转发到国内模型处理

public class OpenAIHttpclientHandler : HttpClientHandler
{

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        if (request.RequestUri.LocalPath == "/v1/chat/completions")
        {
            UriBuilder uriBuilder = new(request.RequestUri)
            {
                Scheme = "http",
                Host = "Your OneApi Host",//你的Oneapi地址
                Port = 3000 //你的Oneapi端口
            };
            request.RequestUri = uriBuilder.Uri;
        }
        return await base.SendAsync(request, cancellationToken);
    }
}

主程序部分

由于是一个控制台程序,所以直接在program上进行完整功能。这里需要把model和key改成自己的model和key
这里因为就一个功能,没有必要注入到kernel中。当然,你也可以选择直接把相应plugin的function注册到kernel中执行,实际效果都是差不多的。

// See https://aka.ms/new-console-template for more information
using Caedmon.Semantic.Semantic.Handlers;
using Microsoft.SemanticKernel;
using System.Diagnostics;
using WinHelper;

Console.WriteLine("您好,我是Powershell执行小帮手。我能将你的需求转化成powershell指令,并提示你是否执行。在指令生成后,你可以选择直接执行指令");
var cls = new WinCmdPlugin();

var builder = Kernel.CreateBuilder();

builder.AddOpenAIChatCompletion(modelId: "your api model", apiKey: "your api key", httpClient: new HttpClient(new OpenAIHttpclientHandler()));

var cmd = string.Empty;
if (args.Length > 0)
{
    cmd = args[0].ToString();
}

while (true)
{
    if (string.IsNullOrWhiteSpace(cmd))
    {
        Console.Write("请输入你需要的指令> ");
        cmd = Console.ReadLine();
        continue;
    }

    if (string.Equals(cmd, "clear", StringComparison.OrdinalIgnoreCase))
    {
        Console.Clear();
        Console.WriteLine("您好,我是Powershell执行小帮手。我能将你的需求转化成powershell指令,并提示你是否执行。在指令生成后,你可以选择直接执行指令");
        cmd = string.Empty;
        continue;
    }
    var kernel = builder.Build();
    var data = await cls.GetCmd(kernel, cmd);
    if (string.IsNullOrWhiteSpace(data))
    {
        Console.WriteLine("很遗憾,未能发现适合的指令。请尝试重新描述需求,提供更完整的命令");
        cmd = string.Empty;
        continue;
    }
    Console.WriteLine($"获取到指令:{data}");
    Console.Write("是否执行?(Y/N)");
    var key = Console.ReadKey();
    Console.WriteLine();
    if (key.KeyChar == 'Y' || key.KeyChar == 'y')
    {
        var process = new Process()
        {
            StartInfo = new ProcessStartInfo
            {
                FileName = "powershell.exe",
                Arguments = $"/c {data}",
                RedirectStandardOutput = true,
                UseShellExecute = false,
                CreateNoWindow = true
            }
        };
        process.Start();
        string output = process.StandardOutput.ReadToEnd();
        process.WaitForExit(5000);
        Console.WriteLine(output);
    }
    cmd = string.Empty;
    Console.WriteLine();
}

程序安装

使用Costura.Fody减少依赖项,由于我们要实现powershell嵌入效果,这里我们把编译的exe和powershell脚本放一起
在这里插入图片描述
其中powershell脚本如下:
主要是将文件拷贝到指定目录,将该exe注册到powershell的helper命令。

# 获取当前脚本的目录  
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition  
  
# 定义目标目录  
$targetDir = "C:\Windows\System32\winhelper"  
  
# 检查目标目录是否存在,如果不存在则创建它  
if (!(Test-Path -Path $targetDir)) {  
    New-Item -ItemType Directory -Path $targetDir | Out-Null  
}  
  
# 拷贝当前脚本目录下的所有文件到目标目录  
Get-ChildItem -Path $scriptDir -File | Copy-Item -Destination $targetDir -Force -ErrorAction SilentlyContinue
Write-Host "拷贝文件成功"

# 获取PowerShell配置文件的路径  
$profilePath = $PROFILE  
  
# 如果配置文件不存在,则创建一个新的配置文件  
if (-not (Test-Path -Path $profilePath)) {  
    # 这里我们假设配置文件是一个PS1文件,这是最常见的类型  
    # 如果你的环境有所不同,你可能需要更改文件扩展名  
    New-Item -ItemType File -Path $profilePath -Force | Out-Null  
}  
  
# 写入别名指令到配置文件  
$aliasInstruction = "`nNew-Alias helper 'C:\Windows\System32\winhelper\WinHelper.exe' -Option AllScope"  
$aliasInstruction | Add-Content -Path $profilePath  
  
# 完成后通知用户  
Write-Host "Alias 'helper' has been added to your PowerShell profile at $profilePath"

最后,使用powershell管理员模式执行脚本。执行完后,重启powershell,使用helper命令即可打开

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

萌新上路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值