Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions Samples/Senparc.AI.Samples.Consoles/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Senparc.AI.Kernel;
using Senparc.AI.Samples.Consoles;
using Senparc.AI.Samples.Consoles.Samples;
using Senparc.AI.Samples.Consoles.Samples.Plugins;
using Senparc.CO2NET;
using Senparc.CO2NET.RegisterServices;

Expand All @@ -29,6 +30,7 @@
services.AddTransient<DallESample>();
services.AddTransient<PlanSample>();
services.AddTransient<SampleSetting>();
services.AddTransient<PluginFromObjectSample>();

var serviceProvider = services.BuildServiceProvider();

Expand All @@ -52,6 +54,7 @@
Console.WriteLine("[3] 训练 Embedding 任务");
Console.WriteLine("[4] Dall·E 绘图(需要配置 OpenAI 或 AzureOpenAI)");
Console.WriteLine("[5] Planner 任务计划");
Console.WriteLine("[6] PluginFromObject 测试");
Console.WriteLine();

var index = Console.ReadLine();
Expand Down Expand Up @@ -124,8 +127,15 @@
case "5":
{
//Plan Sample
var pnalSample = serviceProvider.GetRequiredService<PlanSample>();
await pnalSample.RunAsync();
var planSample = serviceProvider.GetRequiredService<PlanSample>();
await planSample.RunAsync();
}
break;
case "6":
{
//Function Sample
var functionSample = serviceProvider.GetRequiredService<PluginFromObjectSample>();
await functionSample.RunAsync();
}
break;
case "0":
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Senparc.AI.Samples.Consoles.Samples.Plugins
{

[Serializable]
public class GetHtmlResult
{
public double CostMS { get; set; }
public string HTML { get; set; }
public string Url { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using HandlebarsDotNet;
using Microsoft.SemanticKernel;
using Senparc.AI.Kernel;
using Senparc.AI.Kernel.Handlers;

namespace Senparc.AI.Samples.Consoles.Samples.Plugins
{
public class SearchPlugin
{
private readonly IServiceProvider _serviceProvider;
private readonly IWantToRun _iWantToRun;
private readonly SemanticAiHandler _semanticAiHandler;

public SearchPlugin(IServiceProvider serviceProvider = null, IWantToRun iWantToRun = null, SemanticAiHandler semanticAiHandler = null)
{
this._serviceProvider = serviceProvider;
this._iWantToRun = iWantToRun;//此处传入 iWantToRun 对象,可以在 Function 中继续调用 AI 接口
this._semanticAiHandler = semanticAiHandler;
}

//KernelFunction 可以使用静态方法,也可以使用实例方法

[KernelFunction, Description("获取时间")]
public async Task<string> GetURL(KernelArguments arguments)
{
string[] urls = new[] {
"https://www.baidu.com",
"https://sdk.weixin.senparc.com",
"https://weixin.senparc.com/QA"
};

//随机获取一个URL
var url = urls[new Random().Next(0, urls.Length)];
//储存到上下文中
arguments["url"] = url;

await Console.Out.WriteLineAsync($"随机获取 URL:{url}");

return url;
}

[KernelFunction, Description("网页爬虫")]
public static async Task<GetHtmlResult> GetHtml(
KernelArguments arguments,
[Description("URL")]
string url,
[Description("请求头(GET/POST)")]
string method="GET"
)
{
var result = new GetHtmlResult();
try
{
var htmlContent = String.Empty;
var startTime = SystemTime.Now;
if (method.ToUpper() == "POST")
{
htmlContent = await Senparc.CO2NET.HttpUtility.RequestUtility.HttpPostAsync(Senparc.CO2NET.SenparcDI.GetServiceProvider(), url, encoding: Encoding.UTF8, postStream: null);
}
else
{
htmlContent = await Senparc.CO2NET.HttpUtility.RequestUtility.HttpGetAsync(Senparc.CO2NET.SenparcDI.GetServiceProvider(), url, Encoding.UTF8);
}

result.HTML = htmlContent;
result.CostMS = SystemTime.DiffTotalMS(startTime);
result.Url = url;

arguments["html"] = htmlContent;//将结果存入上下文,以便后续使用
}
catch (Exception)
{
throw;
}

await Console.Out.WriteLineAsync("完成 HTML 抓取");
await Console.Out.WriteLineAsync("==========================");
await Console.Out.WriteLineAsync("【从 Function 外部读取】");
await Console.Out.WriteLineAsync($"URL: {result.Url}");
await Console.Out.WriteLineAsync($"耗时:{result.CostMS}ms");
await Console.Out.WriteLineAsync($"HTML:{result.HTML}");

return result;
}

[KernelFunction, Description("网页内容总结")]
public async Task<string> GetSummary(
KernelArguments arguments,
[Description("Html")]
string html
)
{
Console.WriteLine("正在生成 HTML 内容摘要");
//HTML 去除所有HTML标签,仅保留文字
var rawHtml = html.Length > 1000 ? html.Substring(0, 1000) : html;// System.Text.RegularExpressions.Regex.Replace(html, "<[^>]+>", "").Substring(0,300);

arguments["html"] = rawHtml;

//完成 Kernel 基础设置
var (iWantToRun, newFunction) =
_semanticAiHandler.IWantTo()
.ConfigModel(ConfigModel.TextCompletion, "Jeffrey")
.BuildKernel()
.CreateFunctionFromPrompt("请从以下 HTML 代码中摘取重要信息,形成一段网页内容的总结:{{$html}}", promptConfigPara: new Entities.PromptConfigParameter()
{
MaxTokens = 5000,
Temperature = 0.7,
TopP = 0.5
}, functionName: "Summary");

var request = iWantToRun.CreateRequest(true, newFunction);

foreach (var item in arguments)
{
if (item.Value is string strVal)
{
request.SetStoredContext(item.Key, strVal);
}
}

var result = await iWantToRun.RunAsync(request);
await Console.Out.WriteLineAsync("======================");
await Console.Out.WriteLineAsync("内容总结:" + result.Output);
return result.Output;

}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
using System;
using System.Threading.Tasks;
using Microsoft.SemanticKernel;
using Senparc.AI.Interfaces;
using Senparc.AI.Kernel;
using Senparc.AI.Kernel.Handlers;
using Senparc.CO2NET.Extensions;

namespace Senparc.AI.Samples.Consoles.Samples.Plugins
{
public class PluginFromObjectSample
{
private readonly IAiHandler _aiHandler;
private readonly IServiceProvider _serviceProvider;

SemanticAiHandler _semanticAiHandler => (SemanticAiHandler)_aiHandler;

public PluginFromObjectSample(IAiHandler aiHandler, IServiceProvider serviceProvider)
{
this._aiHandler = aiHandler;
this._serviceProvider = serviceProvider;
this._semanticAiHandler.SemanticKernelHelper.ResetHttpClient(enableLog: SampleSetting.EnableHttpClientLog);//同步日志设置状态
}

public async Task RunAsync()
{
await Console.Out.WriteLineAsync(@"您已进入 PluginFromObject,输入 exit 退出。");

var exit = false;
while (!exit)
{
await Console.Out.WriteLineAsync("请输入要测试的序号:");
await Console.Out.WriteLineAsync("[0] 退出");
await Console.Out.WriteLineAsync("[1] 无参数 Plugin");
await Console.Out.WriteLineAsync("[2] 带参数 Plugin");
await Console.Out.WriteLineAsync("[3] 无参数 Plugin + 带参数 Plugin 组成管道序列");

var select = Console.ReadLine();
switch (select)
{
case "0":
exit = true;
break;
case "1":
await RunParameterlessSampleAsync();
break;
case "2":
await RunParametersSampleAsync();
break;
case "3":
await RunPiplelineSampleAsync();
break;
default:
await Console.Out.WriteLineAsync("选择错误,请重新选择!");
continue;
}
}
}

/// <summary>
/// 无参数 Plugin
/// </summary>
/// <returns></returns>
public async Task RunParameterlessSampleAsync()
{
ConsoleKey? input = null;
while (input != ConsoleKey.D0)
{
//完成 Kernel 基础设置
var (iWantToRun, kernelPlugin) =
_semanticAiHandler.IWantTo()//初始化
.ConfigModel(ConfigModel.TextCompletion, "Jeffrey")//配置模型类型
.BuildKernel()//构建 Kernel
.ImportPluginFromObject(new SearchPlugin(), "SearchPlugin");//注册插件

//执行
var functionResult = await iWantToRun.RunAsync(kernelPlugin[nameof(SearchPlugin.GetURL)]);
//说明:此处返回类型为 string,因此可以不使用泛型 RunAsync<string>,直接使用 RunAsync() 即可

await Console.Out.WriteLineAsync($"【外部读取】随机获取 URL:{functionResult.OutputString}");

await Console.Out.WriteLineAsync("任意键继续获取,输入 0 退出");
input = Console.ReadKey().Key;
}
}

/// <summary>
/// 带参数 Plugin
/// </summary>
/// <returns></returns>
public async Task RunParametersSampleAsync()
{
while (true)
{
await Console.Out.WriteLineAsync("请输入需要爬取的完整网址,如 https://sdk.weixin.senparc.com。输入 exit 返回上一级");
var url = Console.ReadLine();

if (url == "exit")
{
break;
}

//检查 URL 是否合法
if (url.IsNullOrEmpty() || !url.StartsWith("http"))
{
await Console.Out.WriteLineAsync("请输入正确的 URL 地址!");
continue;
}

//完成 Kernel 基础设置
var (iWantToRun, kernelPlugin) =
_semanticAiHandler.IWantTo()
.ConfigModel(ConfigModel.TextCompletion, "Jeffrey")
.BuildKernel()
//注册插件
.ImportPluginFromObject(new SearchPlugin(this._serviceProvider, null), "SearchPlugin");

//设置参数(可选)
iWantToRun.StoredAiArguments.Context["url"] = url;
iWantToRun.StoredAiArguments.Context["method"] = "GET";

//创建请求对象
var request = iWantToRun.CreateRequest(true, kernelPlugin[nameof(SearchPlugin.GetHtml)]);

//执行
var functionResult = await iWantToRun.RunAsync<GetHtmlResult>(request);

await Console.Out.WriteLineAsync("==========================");
await Console.Out.WriteLineAsync("【从 Function 外部读取】");
await Console.Out.WriteLineAsync($"URL:{functionResult.Output.Url}");
await Console.Out.WriteLineAsync($"耗时:{functionResult.Output.CostMS}ms");
await Console.Out.WriteLineAsync($"HTML:{functionResult.Output.HTML}");

}
}

/// <summary>
/// 不带参数 Plugin + 带参数 Plugin 组成管道序列
/// </summary>
/// <returns></returns>
public async Task RunPiplelineSampleAsync()
{
while (true)
{
await Console.Out.WriteLineAsync(@"
即将开始执行以下步骤:
1、从一个独立 Function 中随机获取一个 URL
2、自动抓取这个 URL 的内容

输入回车开始,输入 exit 返回上一级
");

var url = Console.ReadLine();

if (url == "exit")
{
break;
}

//完成 Kernel 基础设置
var iWantToRun =
_semanticAiHandler.IWantTo()
.ConfigModel(ConfigModel.TextCompletion, "Jeffrey")
.BuildKernel();

//定义插件
var searchPlugin = new SearchPlugin(this._serviceProvider, iWantToRun,this._semanticAiHandler);

//注册插件
var kernelPlugin = iWantToRun.ImportPluginFromObject(searchPlugin, "SearchPlugin").kernelPlugin;

//设置参数(可选)
//iWantToRun.StoredAiArguments.Context["url"] = url; //URL 由 GetURL 方法返回,无需提供
iWantToRun.StoredAiArguments.Context["method"] = "GET";

//定义需要使用的 Function(可以多个)
var functionPiple = new[] {
kernelPlugin[nameof(searchPlugin.GetURL)],
kernelPlugin[nameof(searchPlugin.GetHtml)],
kernelPlugin[nameof(searchPlugin.GetSummary)]
};

foreach (var function in functionPiple)
{
//创建请求对象
var request = iWantToRun.CreateRequest(true, function);

//执行
var functionResult = await iWantToRun.RunAsync<object>(request);
/* 如果不需要对 request 进行额外设置,此处也可以不构建 request,直接传入 function:
* var functionResult = await iWantToRun.RunAsync<object>(function);
*/
}
}
}

}

}
Loading