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
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