Skip to content

Commit

Permalink
Merge pull request #11 from cnblogs/provide-pure-api-access-for-sk
Browse files Browse the repository at this point in the history
feat: provide pure api access for semantic kernel
  • Loading branch information
ikesnowy authored Mar 14, 2024
2 parents 0b0b3e3 + c628b31 commit eadc0fb
Show file tree
Hide file tree
Showing 122 changed files with 512 additions and 154 deletions.
7 changes: 7 additions & 0 deletions Cnblogs.DashScope.Sdk.sln
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cnblogs.DashScope.Sample",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cnblogs.DashScope.AspNetCore", "src\Cnblogs.DashScope.AspNetCore\Cnblogs.DashScope.AspNetCore.csproj", "{C910495B-87AB-4AC1-989C-B6720695A139}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cnblogs.DashScope.Core", "src\Cnblogs.DashScope.Core\Cnblogs.DashScope.Core.csproj", "{CC389455-A3EA-4F09-B524-4DC351A1E1AA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -24,6 +26,7 @@ Global
{BC102292-E664-47F5-B0C7-C4D7A2301002} = {CFC8ECB3-5248-46CD-A56C-EC088F2A3804}
{8885149A-78F0-4C8E-B9AA-87A46EA69219} = {2E15D1EC-4A07-416E-8BE6-D907F509FD35}
{C910495B-87AB-4AC1-989C-B6720695A139} = {008988ED-0A3B-4272-BCC3-7B4110699345}
{CC389455-A3EA-4F09-B524-4DC351A1E1AA} = {008988ED-0A3B-4272-BCC3-7B4110699345}
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{FA6A118A-8D26-4B7A-9952-8504B8A0025B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
Expand All @@ -42,5 +45,9 @@ Global
{C910495B-87AB-4AC1-989C-B6720695A139}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C910495B-87AB-4AC1-989C-B6720695A139}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C910495B-87AB-4AC1-989C-B6720695A139}.Release|Any CPU.Build.0 = Release|Any CPU
{CC389455-A3EA-4F09-B524-4DC351A1E1AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CC389455-A3EA-4F09-B524-4DC351A1E1AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CC389455-A3EA-4F09-B524-4DC351A1E1AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CC389455-A3EA-4F09-B524-4DC351A1E1AA}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
113 changes: 108 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ English | [简体中文](https://github.com/cnblogs/dashscope-sdk/blob/main/READ

An unofficial DashScope SDK maintained by Cnblogs.

# Usage
**Warning**: this project is under active development, **Breaking Changes** may introduced without notice or major version change. Make sure you read the Release Notes before upgrading.

# Quick Start

## Console App

Install Cnblogs.DashScope.Sdk package.
Install `Cnblogs.DashScope.Sdk` package.

```csharp
var client = new DashScopeClient("your-api-key");
Expand Down Expand Up @@ -55,8 +57,109 @@ public class YourService(IDashScopeClient client)
- Text Generation API(qwen-turbo, qwen-max, etc.) - `dashScopeClient.GetQwenCompletionAsync()` and `dashScopeClient.GetQWenCompletionStreamAsync()`
- BaiChuan Models - Use `dashScopeClient.GetBaiChuanTextCompletionAsync()`
- LLaMa2 Models - `dashScopeClient.GetLlama2TextCompletionAsync()`
- Multimodal Generation API(qwen-vl-max, etc.) - `dashScopeClient.GetQWenMultimodalCompletionAsync` and `dashScopeClient.GetQWenMultimodalCompletionStreamAsync`
- Multimodal Generation API(qwen-vl-max, etc.) - `dashScopeClient.GetQWenMultimodalCompletionAsync()` and `dashScopeClient.GetQWenMultimodalCompletionStreamAsync()`
- Wanx Models(Image generation, background generation, etc)
- Image Synthesis - `CreateWanxImageSynthesisTaskAsync()` and `GetWanxImageSynthesisTaskAsync()`
- Image Generation - `CreateWanxImageGenerationTaskAsync` and `GetWanxImageGenerationTaskAsync()`
- Background Image Generation - `CreateWanxBackgroundGenerationTaskAsync` and `GetWanxBackgroundGenerationTaskAsync`
- Image Generation - `CreateWanxImageGenerationTaskAsync()` and `GetWanxImageGenerationTaskAsync()`
- Background Image Generation - `CreateWanxBackgroundGenerationTaskAsync()` and `GetWanxBackgroundGenerationTaskAsync()`


# Examples

Visit [tests](./test) for more usage of each api.

## Single Text Completion

```csharp
var prompt = "hello"
var completion = await client.GetQWenCompletionAsync(QWenLlm.QWenMax, prompt);
Console.WriteLine(completion.Output.Text);
```

## Multi-round chat

```csharp
var history = new List<ChatMessage>
{
new("user", "Please remember this number, 42"),
new("assistant", "I have remembered this number."),
new("user", "What was the number I metioned before?")
}
var parameters = new TextGenerationParameters()
{
ResultFormat = ResultFormats.Message
};
var completion = await client.GetQWenChatCompletionAsync(QWenLlm.QWenMax, history, parameters);
Console.WriteLine(completion.Output.Choices[0].Message.Content); // The number is 42
```

## Function Call

Creates a function with parameters

```csharp
string GetCurrentWeather(GetCurrentWeatherParameters parameters)
{
// actual implementation should be different.
return "Sunny, 14" + parameters.Unit switch
{
TemperatureUnit.Celsius => "",
TemperatureUnit.Fahrenheit => ""
};
}

public record GetCurrentWeatherParameters(
[property: Required]
[property: Description("The city and state, e.g. San Francisco, CA")]
string Location,
[property: JsonConverter(typeof(EnumStringConverter<TemperatureUnit>))]
TemperatureUnit Unit = TemperatureUnit.Celsius);

public enum TemperatureUnit
{
Celsius,
Fahrenheit
}
```

Append tool information to chat messages.

```csharp
var tools = new List<ToolDefinition>()
{
new(
ToolTypes.Function,
new FunctionDefinition(
nameof(GetCurrentWeather),
"Get the weather abount given location",
new JsonSchemaBuilder().FromType<GetCurrentWeatherParameters>().Build()))
};

var history = new List<ChatMessage>
{
new("user", "What is the weather today in C.A?")
};

var parameters = new TextGenerationParamters()
{
ResultFormat = ResultFormats.Message,
Tools = tools
};

// send question with available tools.
var completion = await client.GetQWenChatCompletionAsync(QWenLlm.QWenMax, history, parameters);
history.Add(completion.Output.Choice[0].Message);

// model responding with tool calls.
Console.WriteLine(completion.Output.Choice[0].Message.ToolCalls[0].Function.Name); // GetCurrentWeather
// calling tool that model requests and append result into history.
var result = GetCurrentWeather(JsonSerializer.Deserialize<GetCurrentWeatherParameters>(completion.Output.Choice[0].Message.ToolCalls[0].Function.Arguments));
history.Add(new("tool", result, nameof(GetCurrentWeather)));

// get back answers.
completion = await client.GetQWenChatCompletionAsync(QWenLlm.QWenMax, history, parameters);
Console.WriteLine(completion.Output.Choice[0].Message.Content);
```

Append the tool calling result with `tool` role, then model will generate answers based on tool calling result.
109 changes: 104 additions & 5 deletions README.zh-Hans.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@

# Cnblogs.DashScopeSDK

由博客园维护并使用的非官方灵积服务 SDK
由博客园维护并使用的非官方灵积服务 SDK

# 使用方法
使用前注意:当前项目正在积极开发中,小版本也可能包含破坏性更改,升级前请查看对应版本 Release Note 进行迁移。

# 快速开始

## 控制台应用

Expand Down Expand Up @@ -55,8 +57,105 @@ public class YourService(IDashScopeClient client)
- 通义千问(`qwen-turbo``qwen-max` 等) - `dashScopeClient.GetQwenCompletionAsync()` and `dashScopeClient.GetQWenCompletionStreamAsync()`
- 百川开源大模型 - Use `dashScopeClient.GetBaiChuanTextCompletionAsync()`
- LLaMa2 大语言模型 - `dashScopeClient.GetLlama2TextCompletionAsync()`
- 通义千问 VL 和通义千问 Audio(`qwen-vl-max``qwen-audio`) - `dashScopeClient.GetQWenMultimodalCompletionAsync` and `dashScopeClient.GetQWenMultimodalCompletionStreamAsync`
- 通义千问 VL 和通义千问 Audio(`qwen-vl-max``qwen-audio`) - `dashScopeClient.GetQWenMultimodalCompletionAsync()` and `dashScopeClient.GetQWenMultimodalCompletionStreamAsync()`
- 通义万相系列
- 文生图 - `CreateWanxImageSynthesisTaskAsync()` and `GetWanxImageSynthesisTaskAsync()`
- 人像风格重绘 - `CreateWanxImageGenerationTaskAsync` and `GetWanxImageGenerationTaskAsync()`
- 图像背景生成 - `CreateWanxBackgroundGenerationTaskAsync` and `GetWanxBackgroundGenerationTaskAsync`
- 人像风格重绘 - `CreateWanxImageGenerationTaskAsync()` and `GetWanxImageGenerationTaskAsync()`
- 图像背景生成 - `CreateWanxBackgroundGenerationTaskAsync()` and `GetWanxBackgroundGenerationTaskAsync()`


# 示例

查看 [测试](./test) 获得更多 API 使用示例。

## 单轮对话

```csharp
var prompt = "你好"
var completion = await client.GetQWenCompletionAsync(QWenLlm.QWenMax, prompt);
Console.WriteLine(completion.Output.Text);
```

## 多轮对话

```csharp
var history = new List<ChatMessage>
{
new("user", "Please remember this number, 42"),
new("assistant", "I have remembered this number."),
new("user", "What was the number I metioned before?")
}
var parameters = new TextGenerationParameters()
{
ResultFormat = ResultFormats.Message
};
var completion = await client.GetQWenChatCompletionAsync(QWenLlm.QWenMax, history, parameters);
Console.WriteLine(completion.Output.Choices[0].Message.Content); // The number is 42
```

## 工具调用

创建一个可供模型使用的方法。

```csharp
string GetCurrentWeather(GetCurrentWeatherParameters parameters)
{
// implementation is irrenlvent
return "Sunny"
}

public record GetCurrentWeatherParameters(
[property: Required]
[property: Description("The city and state, e.g. San Francisco, CA")]
string Location,
[property: JsonConverter(typeof(EnumStringConverter<TemperatureUnit>))]
TemperatureUnit Unit = TemperatureUnit.Celsius);

public enum TemperatureUnit
{
Celsius,
Fahrenheit
}
```

对话时带上方法的名称、描述和参数列表,参数列表以 JSON Schema 的形式提供。

```csharp
var tools = new List<ToolDefinition>()
{
new(
ToolTypes.Function,
new FunctionDefinition(
nameof(GetCurrentWeather),
"获取当前天气",
new JsonSchemaBuilder().FromType<GetCurrentWeatherParameters>().Build()))
};

var history = new List<ChatMessage>
{
new("user", "杭州现在天气如何?")
};

var parameters = new TextGenerationParamters()
{
ResultFormat = ResultFormats.Message,
Tools = tools
};

// 向模型提问并提供可用的方法
var completion = await client.GetQWenChatCompletionAsync(QWenLlm.QWenMax, history, parameters);

// 模型试图调用方法
Console.WriteLine(completion.Output.Choice[0].Message.ToolCalls[0].Function.Name); // GetCurrentWeather
history.Add(completion.Output.Choice[0].Message);

// 调用方法并将结果保存到聊天记录中
var result = GetCurrentWeather(JsonSerializer.Deserialize<GetCurrentWeatherParameters>(completion.Output.Choice[0].Message.ToolCalls[0].Function.Arguments));
history.Add(new("tool", result, nameof(GetCurrentWeather)));

// 模型根据调用结果返回答案
completion = await client.GetQWenChatCompletionAsync(QWenLlm.QWenMax, history, parameters);
Console.WriteLine(completion.Output.Choice[0].Message.Content) // 现在浙江省杭州市的天气是大部多云,气温为 18 摄氏度。
```

当模型认为应当调用工具时,返回消息中 `ToolCalls` 会提供调用的详情,本地在调用完成后可以把结果以 `tool` 角色返回。
54 changes: 53 additions & 1 deletion sample/Cnblogs.DashScope.Sample/Program.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
using System.Text;
using System.Text.Json;
using Cnblogs.DashScope.Core;
using Cnblogs.DashScope.Sample;
using Cnblogs.DashScope.Sdk;
using Cnblogs.DashScope.Sdk.QWen;
using Json.Schema;
using Json.Schema.Generation;

const string apiKey = "your api key";
const string apiKey = "sk-eeff76d62cc946e5af8d1444f079a34e";
var dashScopeClient = new DashScopeClient(apiKey);

Console.WriteLine("Choose the sample you want to run:");
Expand All @@ -12,6 +16,7 @@
Console.WriteLine($"{(int)sampleType}.{sampleType.GetDescription()}");
}

Console.WriteLine();
Console.Write("Choose an option: ");
var type = (SampleType)int.Parse(Console.ReadLine()!);

Expand All @@ -31,6 +36,9 @@
case SampleType.ChatCompletion:
await ChatStreamAsync();
break;
case SampleType.ChatCompletionWithTool:
await ChatWithToolsAsync();
break;
}

return;
Expand Down Expand Up @@ -88,3 +96,47 @@ async Task ChatStreamAsync()

// ReSharper disable once FunctionNeverReturns
}

async Task ChatWithToolsAsync()
{
var history = new List<ChatMessage>();
var tools = new List<ToolDefinition>
{
new(
ToolTypes.Function,
new FunctionDefinition(
nameof(GetWeather),
"获得当前天气",
new JsonSchemaBuilder().FromType<WeatherReportParameters>().Build()))
};
var chatParameters = new TextGenerationParameters() { ResultFormat = ResultFormats.Message, Tools = tools };
var question = new ChatMessage("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}");

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

var answer = await dashScopeClient.GetQWenChatCompletionAsync(QWenLlm.QWenMax, history, chatParameters);
Console.WriteLine($"{answer.Output.Choices![0].Message.Role} > {answer.Output.Choices[0].Message.Content}");

string GetWeather(WeatherReportParameters parameters)
{
return "大部多云,气温 "
+ parameters.Unit switch
{
TemperatureUnit.Celsius => "18 摄氏度",
TemperatureUnit.Fahrenheit => "64 华氏度",
_ => throw new InvalidOperationException()
};
}
}
3 changes: 3 additions & 0 deletions sample/Cnblogs.DashScope.Sample/SampleType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,7 @@ public enum SampleType

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

[Description("Conversation with tools")]
ChatCompletionWithTool
}
1 change: 1 addition & 0 deletions sample/Cnblogs.DashScope.Sample/SampleTypeDescriptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public static string GetDescription(this SampleType sampleType)
SampleType.TextCompletion => "Simple prompt completion",
SampleType.TextCompletionSse => "Simple prompt completion with incremental output",
SampleType.ChatCompletion => "Conversation between user and assistant",
SampleType.ChatCompletionWithTool => "Function call sample",
_ => throw new ArgumentOutOfRangeException(nameof(sampleType), sampleType, "Unsupported sample option")
};
}
Expand Down
19 changes: 19 additions & 0 deletions sample/Cnblogs.DashScope.Sample/WeatherReportParameters.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System.Text.Json.Serialization;
using Json.More;
using Json.Schema.Generation;

namespace Cnblogs.DashScope.Sample;

public record WeatherReportParameters(
[property: Required]
[property: Description("要获取天气的省市名称,例如浙江省杭州市")]
string Location,
[property: JsonConverter(typeof(EnumStringConverter<TemperatureUnit>))]
[property: Description("温度单位")]
TemperatureUnit Unit = TemperatureUnit.Celsius);

public enum TemperatureUnit
{
Celsius,
Fahrenheit
}
Loading

0 comments on commit eadc0fb

Please sign in to comment.