Skip to content

feat: add application call #77

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Mar 17, 2025
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
69 changes: 69 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ public class YourService(IDashScopeClient client)
- Image Generation - `CreateWanxImageGenerationTaskAsync()` and `GetWanxImageGenerationTaskAsync()`
- Background Image Generation - `CreateWanxBackgroundGenerationTaskAsync()` and `GetWanxBackgroundGenerationTaskAsync()`
- File API that used by Qwen-Long - `dashScopeClient.UploadFileAsync()` and `dashScopeClient.DeleteFileAsync`
- Application call - `GetApplicationResponseAsync()` and `GetApplicationResponseStreamAsync()`

# Examples

Expand Down Expand Up @@ -208,3 +209,71 @@ Delete file if needed
```csharp
var deletionResult = await dashScopeClient.DeleteFileAsync(uploadedFile.Id);
```

## Application call

Use `GetApplicationResponseAsync` to call an application.

Use `GetApplicationResponseStreamAsync` for streaming output.

```csharp
var request =
new ApplicationRequest()
{
Input = new ApplicationInput() { Prompt = "Summarize this file." },
Parameters = new ApplicationParameters()
{
TopK = 100,
TopP = 0.8f,
Seed = 1234,
Temperature = 0.85f,
RagOptions = new ApplicationRagOptions()
{
PipelineIds = ["thie5bysoj"],
FileIds = ["file_d129d632800c45aa9e7421b30561f447_10207234"]
}
}
};
var response = await client.GetApplicationResponseAsync("your-application-id", request);
Console.WriteLine(response.Output.Text);
```

`ApplicationRequest` use an `Dictionary<string, object?>` as `BizParams` by default.

```csharp
var request =
new ApplicationRequest()
{
Input = new ApplicationInput()
{
Prompt = "Summarize this file.",
BizParams = new Dictionary<string, object?>()
{
{ "customKey1", "custom-value" }
}
}
};
var response = await client.GetApplicationResponseAsync("your-application-id", request);
Console.WriteLine(response.Output.Text);
```

You can use the generic version `ApplicationRequest<TBizParams>` for strong-typed `BizParams`. But keep in mind that client use `snake_case` by default when doing json serialization, you may need to use `[JsonPropertyName("camelCase")]` for other type of naming policy.

```csharp
public record TestApplicationBizParam(
[property: JsonPropertyName("sourceCode")]
string SourceCode);

var request =
new ApplicationRequest<TestApplicationBizParam>()
{
Input = new ApplicationInput<TestApplicationBizParam>()
{
Prompt = "Summarize this file.",
BizParams = new TestApplicationBizParam("test")
}
};
var response = await client.GetApplicationResponseAsync("your-application-id", request);
Console.WriteLine(response.Output.Text);
```

69 changes: 69 additions & 0 deletions README.zh-Hans.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ public class YourService(IDashScopeClient client)
- 人像风格重绘 - `CreateWanxImageGenerationTaskAsync()` and `GetWanxImageGenerationTaskAsync()`
- 图像背景生成 - `CreateWanxBackgroundGenerationTaskAsync()` and `GetWanxBackgroundGenerationTaskAsync()`
- 适用于 QWen-Long 的文件 API `dashScopeClient.UploadFileAsync()` and `dashScopeClient.DeleteFileAsync`
- 应用调用 `dashScopeClient.GetApplicationResponseAsync` 和 `dashScopeClient.GetApplicationResponseStreamAsync()`
- 其他使用相同 Endpoint 的模型

# 示例
Expand Down Expand Up @@ -204,3 +205,71 @@ Console.WriteLine(completion.Output.Choices[0].Message.Content);
```csharp
var deletionResult = await dashScopeClient.DeleteFileAsync(uploadedFile.Id);
```

## 应用调用

`GetApplicationResponseAsync` 用于进行应用调用。

`GetApplicationResponseStreamAsync` 用于流式调用。

```csharp
var request =
new ApplicationRequest()
{
Input = new ApplicationInput() { Prompt = "Summarize this file." },
Parameters = new ApplicationParameters()
{
TopK = 100,
TopP = 0.8f,
Seed = 1234,
Temperature = 0.85f,
RagOptions = new ApplicationRagOptions()
{
PipelineIds = ["thie5bysoj"],
FileIds = ["file_d129d632800c45aa9e7421b30561f447_10207234"]
}
}
};
var response = await client.GetApplicationResponseAsync("your-application-id", request);
Console.WriteLine(response.Output.Text);
```

`ApplicationRequest` 默认使用 `Dictionary<string, object?>` 作为 `BizParams` 的类型。

```csharp
var request =
new ApplicationRequest()
{
Input = new ApplicationInput()
{
Prompt = "Summarize this file.",
BizParams = new Dictionary<string, object?>()
{
{ "customKey1", "custom-value" }
}
}
};
var response = await client.GetApplicationResponseAsync("your-application-id", request);
Console.WriteLine(response.Output.Text);
```

如需强类型支持,可以使用泛型类 `ApplicationRequest<TBizParams>`。
注意 SDK 在 JSON 序列化时使用 `snake_case`。如果你的应用采用其他的命名规则,请使用 `[JsonPropertyName("camelCase")]` 来手动指定序列化时的属性名称。

```csharp
public record TestApplicationBizParam(
[property: JsonPropertyName("sourceCode")]
string SourceCode);

var request =
new ApplicationRequest<TestApplicationBizParam>()
{
Input = new ApplicationInput<TestApplicationBizParam>()
{
Prompt = "Summarize this file.",
BizParams = new TestApplicationBizParam("test")
}
};
var response = await client.GetApplicationResponseAsync("your-application-id", request);
Console.WriteLine(response.Output.Text);
```
15 changes: 11 additions & 4 deletions src/Cnblogs.DashScope.AspNetCore/ServiceCollectionInjector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,8 @@ public static IHttpClientBuilder AddDashScopeClient(this IServiceCollection serv
var apiKey = section["apiKey"]
?? throw new InvalidOperationException("There is no apiKey provided in given section");
var baseAddress = section["baseAddress"];
return string.IsNullOrEmpty(baseAddress)
? services.AddDashScopeClient(apiKey)
: services.AddDashScopeClient(apiKey, baseAddress);
var workspaceId = section["workspaceId"];
return services.AddDashScopeClient(apiKey, baseAddress, workspaceId);
}

/// <summary>
Expand All @@ -49,16 +48,24 @@ public static IHttpClientBuilder AddDashScopeClient(this IServiceCollection serv
/// <param name="services">The service collection to add service to.</param>
/// <param name="apiKey">The DashScope api key.</param>
/// <param name="baseAddress">The DashScope api base address, you may change this value if you are using proxy.</param>
/// <param name="workspaceId">Default workspace id to use.</param>
/// <returns></returns>
public static IHttpClientBuilder AddDashScopeClient(
this IServiceCollection services,
string apiKey,
string baseAddress = "https://dashscope.aliyuncs.com/api/v1/")
string? baseAddress = null,
string? workspaceId = null)
{
baseAddress ??= "https://dashscope.aliyuncs.com/api/v1/";
return services.AddHttpClient<IDashScopeClient, DashScopeClientCore>(
h =>
{
h.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
if (string.IsNullOrWhiteSpace(workspaceId) == false)
{
h.DefaultRequestHeaders.Add("X-DashScope-WorkSpace", workspaceId);
}

h.BaseAddress = new Uri(baseAddress);
});
}
Expand Down
20 changes: 20 additions & 0 deletions src/Cnblogs.DashScope.Core/ApplicationDocReference.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace Cnblogs.DashScope.Core;

/// <summary>
/// One reference for application output.
/// </summary>
/// <param name="IndexId">The index id of the doc.</param>
/// <param name="Title">Text slice title.</param>
/// <param name="DocId">Unique id of the doc been referenced.</param>
/// <param name="DocName">Name of the doc been referenced.</param>
/// <param name="Text">Referenced content.</param>
/// <param name="Images">Image URLs beed referenced.</param>
/// <param name="PageNumber">Page numbers of referenced content belongs to.</param>
public record ApplicationDocReference(
string IndexId,
string Title,
string DocId,
string DocName,
string Text,
List<string>? Images,
List<int>? PageNumber);
47 changes: 47 additions & 0 deletions src/Cnblogs.DashScope.Core/ApplicationInput.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
namespace Cnblogs.DashScope.Core;

/// <summary>
/// Inputs for application call.
/// </summary>
/// <typeparam name="TBizParams">Type of the BizContent.</typeparam>
public class ApplicationInput<TBizParams>
where TBizParams : class
{
/// <summary>
/// The prompt for model to generate response upon. Optional when <see cref="Messages"/> has been set.
/// </summary>
/// <remarks>
/// Prompt will be appended to <see cref="Messages"/> when both set.
/// </remarks>
public string? Prompt { get; set; }

/// <summary>
/// The session id for conversation history. This will be ignored if <see cref="Messages"/> has been set.
/// </summary>
public string? SessionId { get; set; }

/// <summary>
/// The conversation history.
/// </summary>
public IEnumerable<ApplicationMessage>? Messages { get; set; }

/// <summary>
/// The id of memory when enabled.
/// </summary>
public string? MemoryId { get; set; }

/// <summary>
/// List of image urls for inputs.
/// </summary>
public IEnumerable<string>? ImageList { get; set; }

/// <summary>
/// User defined content.
/// </summary>
public TBizParams? BizParams { get; set; } = null;
}

/// <summary>
/// Inputs for application call.
/// </summary>
public class ApplicationInput : ApplicationInput<Dictionary<string, object?>>;
30 changes: 30 additions & 0 deletions src/Cnblogs.DashScope.Core/ApplicationMessage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
namespace Cnblogs.DashScope.Core;

/// <summary>
/// A single message for application call.
/// </summary>
/// <param name="Role">The role of this message belongs to.</param>
/// <param name="Content">The content of the message.</param>
public record ApplicationMessage(string Role, string Content)
{
/// <summary>
/// Creates a user message.
/// </summary>
/// <param name="content">Content of the message.</param>
/// <returns></returns>
public static ApplicationMessage User(string content) => new("user", content);

/// <summary>
/// Creates a system message.
/// </summary>
/// <param name="content">Content of the message.</param>
/// <returns></returns>
public static ApplicationMessage System(string content) => new("system", content);

/// <summary>
/// Creates a assistant message.
/// </summary>
/// <param name="content">Content of the message.</param>
/// <returns></returns>
public static ApplicationMessage Assistant(string content) => new("assistant", content);
}
9 changes: 9 additions & 0 deletions src/Cnblogs.DashScope.Core/ApplicationModelUsage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Cnblogs.DashScope.Core;

/// <summary>
/// Token usages for one model.
/// </summary>
/// <param name="ModelId">The id of the model.</param>
/// <param name="InputTokens">Total input tokens of this model.</param>
/// <param name="OutputTokens">Total output tokens from this model.</param>
public record ApplicationModelUsage(string ModelId, int InputTokens, int OutputTokens);
16 changes: 16 additions & 0 deletions src/Cnblogs.DashScope.Core/ApplicationOutput.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace Cnblogs.DashScope.Core;

/// <summary>
/// The output of application call.
/// </summary>
/// <param name="Text">Output text from application.</param>
/// <param name="FinishReason">Finish reason from application.</param>
/// <param name="SessionId">Unique id of current session.</param>
/// <param name="Thoughts">Thoughts from application.</param>
/// <param name="DocReferences">Doc references from application output.</param>
public record ApplicationOutput(
string Text,
string FinishReason,
string SessionId,
List<ApplicationOutputThought>? Thoughts,
List<ApplicationDocReference>? DocReferences);
24 changes: 24 additions & 0 deletions src/Cnblogs.DashScope.Core/ApplicationOutputThought.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
namespace Cnblogs.DashScope.Core;

/// <summary>
/// The model thought output.
/// </summary>
/// <param name="Thought">The thought content of the model.</param>
/// <param name="ActionType">Type of the action. e.g. <c>agentRag</c>, <c>reasoning</c>.</param>
/// <param name="ActionName">The name of the action.</param>
/// <param name="Action">The action been executed.</param>
/// <param name="ActionInputStream">The streaming result of action input.</param>
/// <param name="ActionInput">The input of the action.</param>
/// <param name="Observation">Lookup or plugin output.</param>
/// <param name="Response">Reasoning output when using DeepSeek-R1.</param>
/// <param name="Arguments">Arguments of the action.</param>
public record ApplicationOutputThought(
string? Thought,
string? ActionType,
string? ActionName,
string? Action,
string? ActionInputStream,
string? ActionInput,
string? Observation,
string? Response,
string? Arguments);
37 changes: 37 additions & 0 deletions src/Cnblogs.DashScope.Core/ApplicationParameters.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
namespace Cnblogs.DashScope.Core;

/// <summary>
/// Parameters for application call.
/// </summary>
public class ApplicationParameters : IIncrementalOutputParameter, ISeedParameter, IProbabilityParameter
{
/// <inheritdoc />
public bool? IncrementalOutput { get; set; }

/// <summary>
/// Output format for flow application. Can be <c>full_thoughts</c> or <c>agent_format</c>. Defaults to <c>full_thoughts</c>.
/// </summary>
public string? FlowStreamMode { get; set; }

/// <summary>
/// Options for RAG applications.
/// </summary>
public ApplicationRagOptions? RagOptions { get; set; }

/// <inheritdoc />
public ulong? Seed { get; set; }

/// <inheritdoc />
public float? TopP { get; set; }

/// <inheritdoc />
public int? TopK { get; set; }

/// <inheritdoc />
public float? Temperature { get; set; }

/// <summary>
/// Controls whether output contains think block.
/// </summary>
public bool? HasThoughts { get; set; }
}
Loading