Skip to content

Commit

Permalink
Merge pull request #51 from cnblogs/support-microsoft-extensions-ai
Browse files Browse the repository at this point in the history
feat: support microsoft extensions ai
  • Loading branch information
ikesnowy authored Nov 27, 2024
2 parents d96eadd + 8100480 commit 7fbbef9
Show file tree
Hide file tree
Showing 28 changed files with 1,376 additions and 76 deletions.
7 changes: 7 additions & 0 deletions Cnblogs.DashScope.Sdk.sln
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cnblogs.DashScope.Core", "s
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cnblogs.DashScope.Sdk.SnapshotGenerator", "test\Cnblogs.DashScope.Sdk.SnapshotGenerator\Cnblogs.DashScope.Sdk.SnapshotGenerator.csproj", "{5088DE77-1CE3-46FB-B9D0-27A6C9A5EED1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cnblogs.DashScope.AI", "src\Cnblogs.DashScope.AI\Cnblogs.DashScope.AI.csproj", "{5D5AD75A-8084-4738-AC56-B8A23E649452}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -30,6 +32,7 @@ Global
{C910495B-87AB-4AC1-989C-B6720695A139} = {008988ED-0A3B-4272-BCC3-7B4110699345}
{CC389455-A3EA-4F09-B524-4DC351A1E1AA} = {008988ED-0A3B-4272-BCC3-7B4110699345}
{5088DE77-1CE3-46FB-B9D0-27A6C9A5EED1} = {CFC8ECB3-5248-46CD-A56C-EC088F2A3804}
{5D5AD75A-8084-4738-AC56-B8A23E649452} = {008988ED-0A3B-4272-BCC3-7B4110699345}
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{FA6A118A-8D26-4B7A-9952-8504B8A0025B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
Expand All @@ -56,5 +59,9 @@ Global
{5088DE77-1CE3-46FB-B9D0-27A6C9A5EED1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5088DE77-1CE3-46FB-B9D0-27A6C9A5EED1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5088DE77-1CE3-46FB-B9D0-27A6C9A5EED1}.Release|Any CPU.Build.0 = Release|Any CPU
{5D5AD75A-8084-4738-AC56-B8A23E649452}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5D5AD75A-8084-4738-AC56-B8A23E649452}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5D5AD75A-8084-4738-AC56-B8A23E649452}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5D5AD75A-8084-4738-AC56-B8A23E649452}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@ An unofficial DashScope SDK maintained by Cnblogs.

# Quick Start

## Using `Microsoft.Extensions.AI`

Install `Cnblogs.Extensions.AI.DashScope` Package

```csharp
var client = new DashScopeClient("your-api-key").AsChatClient("qwen-max");
var completion = await client.CompleteAsync("hello");
Console.WriteLine(completion)
```

## Console App

Install `Cnblogs.DashScope.Sdk` package.
Expand Down
10 changes: 10 additions & 0 deletions README.zh-Hans.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@

# 快速开始

## 使用 `Microsoft.Extensions.AI` 接口

安装 NuGet 包 `Cnblogs.Extensions.AI.DashScope`

```csharp
var client = new DashScopeClient("your-api-key").AsChatClient("qwen-max");
var completion = await client.CompleteAsync("hello");
Console.WriteLine(completion)
```

## 控制台应用

安装 NuGet 包 `Cnblogs.DashScope.Sdk`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

<ItemGroup>
<ProjectReference Include="..\..\src\Cnblogs.DashScope.Sdk\Cnblogs.DashScope.Sdk.csproj" />
<ProjectReference Include="..\..\src\Cnblogs.DashScope.AI\Cnblogs.DashScope.AI.csproj" />
</ItemGroup>

<ItemGroup>
Expand All @@ -18,4 +19,8 @@
</None>
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.AI" Version="9.0.1-preview.1.24570.5" />
</ItemGroup>

</Project>
65 changes: 47 additions & 18 deletions sample/Cnblogs.DashScope.Sample/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,17 @@
using Cnblogs.DashScope.Sdk.QWen;
using Json.Schema;
using Json.Schema.Generation;
using Microsoft.Extensions.AI;

const string apiKey = "sk-**";
var dashScopeClient = new DashScopeClient(apiKey);
Console.WriteLine("Reading key from environment variable DASHSCOPE_KEY");
var apiKey = Environment.GetEnvironmentVariable("DASHSCOPE_API_KEY");
if (string.IsNullOrEmpty(apiKey))
{
Console.Write("ApiKey > ");
apiKey = Console.ReadLine();
}

var dashScopeClient = new DashScopeClient(apiKey!);

Console.WriteLine("Choose the sample you want to run:");
foreach (var sampleType in Enum.GetValues<SampleType>())
Expand Down Expand Up @@ -42,6 +50,12 @@
case SampleType.ChatCompletionWithFiles:
await ChatWithFilesAsync();
break;
case SampleType.MicrosoftExtensionsAi:
await ChatWithMicrosoftExtensions();
break;
case SampleType.MicrosoftExtensionsAiToolCall:
await dashScopeClient.ToolCallWithExtensionAsync();
break;
}

return;
Expand All @@ -68,16 +82,17 @@ async Task TextCompletionStreamAsync(string prompt)

async Task ChatStreamAsync()
{
var history = new List<ChatMessage>();
var history = new List<TextChatMessage>();
while (true)
{
Console.Write("user > ");
var input = Console.ReadLine()!;
history.Add(ChatMessage.User(input));
var stream = dashScopeClient.GetQWenChatStreamAsync(
QWenLlm.QWenMax,
history,
new TextGenerationParameters { IncrementalOutput = true, ResultFormat = ResultFormats.Message });
history.Add(TextChatMessage.User(input));
var stream = dashScopeClient
.GetQWenChatStreamAsync(
QWenLlm.QWenMax,
history,
new TextGenerationParameters { IncrementalOutput = true, ResultFormat = ResultFormats.Message });
var role = string.Empty;
var message = new StringBuilder();
await foreach (var modelResponse in stream)
Expand All @@ -94,25 +109,25 @@ async Task ChatStreamAsync()
}

Console.WriteLine();
history.Add(new ChatMessage(role, message.ToString()));
history.Add(new TextChatMessage(role, message.ToString()));
}

// ReSharper disable once FunctionNeverReturns
}

async Task ChatWithFilesAsync()
{
var history = new List<ChatMessage>();
var history = new List<TextChatMessage>();
Console.WriteLine("uploading file \"test.txt\" ");
var file = new FileInfo("test.txt");
var uploadedFile = await dashScopeClient.UploadFileAsync(file.OpenRead(), file.Name);
Console.WriteLine("file uploaded, id: " + uploadedFile.Id);
Console.WriteLine();

var fileMessage = ChatMessage.File(uploadedFile.Id);
var fileMessage = TextChatMessage.File(uploadedFile.Id);
history.Add(fileMessage);
Console.WriteLine("system > " + fileMessage.Content);
var userPrompt = ChatMessage.User("该文件的内容是什么");
var userPrompt = TextChatMessage.User("该文件的内容是什么");
history.Add(userPrompt);
Console.WriteLine("user > " + userPrompt.Content);
var stream = dashScopeClient.GetQWenChatStreamAsync(
Expand All @@ -135,7 +150,7 @@ async Task ChatWithFilesAsync()
}

Console.WriteLine();
history.Add(new ChatMessage(role, message.ToString()));
history.Add(new TextChatMessage(role, message.ToString()));

Console.WriteLine();
Console.WriteLine("Deleting file by id: " + uploadedFile.Id);
Expand All @@ -145,7 +160,7 @@ async Task ChatWithFilesAsync()

async Task ChatWithToolsAsync()
{
var history = new List<ChatMessage>();
var history = new List<TextChatMessage>();
var tools = new List<ToolDefinition>
{
new(
Expand All @@ -156,19 +171,19 @@ async Task ChatWithToolsAsync()
new JsonSchemaBuilder().FromType<WeatherReportParameters>().Build()))
};
var chatParameters = new TextGenerationParameters() { ResultFormat = ResultFormats.Message, Tools = tools };
var question = ChatMessage.User("请问现在杭州的天气如何?");
var question = TextChatMessage.User("请问现在杭州的天气如何?");
history.Add(question);
Console.WriteLine($"{question.Role} > {question.Content}");

var response = await dashScopeClient.GetQWenChatCompletionAsync(QWenLlm.QWenMax, history, chatParameters);
var toolCallMessage = response.Output.Choices![0].Message;
history.Add(toolCallMessage);
Console.WriteLine(
$"{toolCallMessage.Role} > {toolCallMessage.ToolCalls![0].Function!.Name}{toolCallMessage.ToolCalls[0].Function!.Arguments}");
$"{toolCallMessage.Role} > {toolCallMessage.ToolCalls![0].Function.Name}{toolCallMessage.ToolCalls[0].Function.Arguments}");

var toolResponse = GetWeather(
JsonSerializer.Deserialize<WeatherReportParameters>(toolCallMessage.ToolCalls[0].Function!.Arguments!)!);
var toolMessage = ChatMessage.Tool(toolResponse, nameof(GetWeather));
JsonSerializer.Deserialize<WeatherReportParameters>(toolCallMessage.ToolCalls[0].Function.Arguments!)!);
var toolMessage = TextChatMessage.Tool(toolResponse, nameof(GetWeather));
history.Add(toolMessage);
Console.WriteLine($"{toolMessage.Role} > {toolMessage.Content}");

Expand All @@ -186,3 +201,17 @@ string GetWeather(WeatherReportParameters parameters)
};
}
}

async Task ChatWithMicrosoftExtensions()
{
Console.WriteLine("Requesting model...");
var chatClient = dashScopeClient.AsChatClient("qwen-max");
List<ChatMessage> conversation =
[
new(ChatRole.System, "You are a helpful AI assistant"),
new(ChatRole.User, "What is AI?")
];
var response = await chatClient.CompleteAsync(conversation);
var serializerOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web) { WriteIndented = true };
Console.WriteLine(JsonSerializer.Serialize(response, serializerOptions));
}
15 changes: 6 additions & 9 deletions sample/Cnblogs.DashScope.Sample/SampleType.cs
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
using System.ComponentModel;

namespace Cnblogs.DashScope.Sample;
namespace Cnblogs.DashScope.Sample;

public enum SampleType
{
[Description("Simple prompt completion")]
TextCompletion,

[Description("Simple prompt completion with incremental output")]
TextCompletionSse,

[Description("Conversation between user and assistant")]
ChatCompletion,

[Description("Conversation with tools")]
ChatCompletionWithTool,

[Description("Conversation with files")]
ChatCompletionWithFiles
ChatCompletionWithFiles,

MicrosoftExtensionsAi,

MicrosoftExtensionsAiToolCall
}
2 changes: 2 additions & 0 deletions sample/Cnblogs.DashScope.Sample/SampleTypeDescriptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ public static string GetDescription(this SampleType sampleType)
SampleType.ChatCompletion => "Conversation between user and assistant",
SampleType.ChatCompletionWithTool => "Function call sample",
SampleType.ChatCompletionWithFiles => "File upload sample using qwen-long",
SampleType.MicrosoftExtensionsAi => "Use with Microsoft.Extensions.AI",
SampleType.MicrosoftExtensionsAiToolCall => "Use tool call with Microsoft.Extensions.AI interfaces",
_ => throw new ArgumentOutOfRangeException(nameof(sampleType), sampleType, "Unsupported sample option")
};
}
Expand Down
25 changes: 25 additions & 0 deletions sample/Cnblogs.DashScope.Sample/ToolCallWithExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System.ComponentModel;
using System.Text.Json;
using Cnblogs.DashScope.Core;
using Microsoft.Extensions.AI;

namespace Cnblogs.DashScope.Sample;

public static class ToolCallWithExtensions
{
public static async Task ToolCallWithExtensionAsync(this IDashScopeClient dashScopeClient)
{
[Description("Gets the weather")]
string GetWeather() => Random.Shared.NextDouble() > 0.5 ? "It's sunny" : "It's raining";

var chatOptions = new ChatOptions { Tools = [AIFunctionFactory.Create(GetWeather)] };

var client = dashScopeClient.AsChatClient("qwen-max").AsBuilder().UseFunctionInvocation().Build();
await foreach (var message in client.CompleteStreamingAsync("What is weather today?", chatOptions))
{
Console.WriteLine(JsonSerializer.Serialize(message));
}

Console.WriteLine();
}
}
16 changes: 16 additions & 0 deletions src/Cnblogs.DashScope.AI/Cnblogs.DashScope.AI.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Product>Cnblogs.DashScope.AI</Product>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>Cnblogs;Dashscope;Microsoft.Extensions.AI;Sdk;Embedding;</PackageTags>
<Description>Implementation of generative AI abstractions for DashScope endpoints.</Description>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Cnblogs.DashScope.Sdk\Cnblogs.DashScope.Sdk.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.AI.Abstractions" Version="9.0.1-preview.1.24570.5"/>
</ItemGroup>

</Project>
Loading

0 comments on commit 7fbbef9

Please sign in to comment.