服务商、流式输出与 DOCX 导出
AI Toolkit 的服务器端配套功能,全部包含在 RichTextBox.AspNetCore NuGet 包(1.0.0-preview.11+)中。一行依赖注入即可接入真实的服务商,提供端到端的 SSE 流式输出,以及一个 HTML → DOCX 端点。
内置的服务商解析器
三个即插即用的 IRichTextBoxAiResolver 实现,使用了 HttpClientFactory、取消机制和 ILogger<T>。选择其中一个,在 Program.cs 中注册:
using RichTextBox.AiResolvers;
builder.Services.AddRichTextBox();
builder.Services.AddRichTextBoxOpenAiResolver(opts =>
{
opts.ApiKey = builder.Configuration["OpenAI:ApiKey"];
opts.Model = "gpt-6-luna";
});可以把 AddRichTextBoxOpenAiResolver 换成 AddRichTextBoxAnthropicResolver 或 AddRichTextBoxAzureOpenAiResolver。三者共用 AiResolverOptions:
public class AiResolverOptions
{
public string ApiKey { get; set; } // required
public string? Model { get; set; } // provider-specific default
public string? BaseUrl { get; set; } // for proxies / Ollama / Groq
public int MaxTokens { get; set; } = 1024;
public double Temperature { get; set; } = 0.4;
public string? SystemSuffix { get; set; } // appended to every mode's system prompt
public TimeSpan Timeout { get; set; } = 60s;
}Azure 在 AzureOpenAiResolverOptions 上另有三个选项:Endpoint(https://my-resource.openai.azure.com)、DeploymentName(不是模型名)和 ApiVersion(可选)。
OpenAiResolver 适用于任何兼容 OpenAI 的端点——对于 Groq、Together.ai 或本地 Ollama,覆盖 BaseUrl 即可。
流式响应(Server-Sent Events)
MapRichTextBoxUploads() 还会映射 POST /richtextbox/ai/stream(可通过 RichTextBoxOptions.AiStreamEndpoint 配置)。OpenAI 和 Anthropic 解析器实现了 IStreamingRichTextBoxAiResolver;不支持流式输出的服务商会透明地退回为单个数据帧。
传输格式
data: <json-encoded delta string>\n\n
data: <json-encoded delta string>\n\n
...
event: response
data: { ...RichTextBoxAiResponse payload... }\n\n
event: done
data: {}\n\n客户端
var stream = editor.aiToolkit.streamRequest({
url: "/richtextbox/ai/stream",
body: { mode: "rewrite", selectionText: "..." },
onDelta: function (chunk, full) { /* render progressively */ },
onResponse: function (payload) { /* final structured result */ },
onDone: function (fullText) { },
onError: function (err) { }
});
// stream.abort() — cancel mid-response
// stream.promise — resolves with the concatenated full text该辅助函数使用 fetch + ReadableStream。不支持流式读取的浏览器会自动退回为通过 XHR 请求非流式端点。
DOCX 导出
MapRichTextBoxUploads() 还会映射 POST /richtextbox/export/docx(可通过 DocxExportEndpoint 配置)。基于 MIT 许可的 DocumentFormat.OpenXml 构建,不依赖外部服务。
请求
POST /richtextbox/export/docx
Content-Type: application/json
{
"html": "<h1>Memo</h1><p>Body.</p>",
"title": "Memo",
"fileName": "memo.docx"
}响应
二进制流,带有 Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document 和 Content-Disposition: attachment; filename=memo.docx。
支持的 HTML
- 段落、
h1–h6、blockquote、pre、hr - 有序和无序的嵌套列表
- 表格(含表头行)
- 内联:
b/strong、i/em、u、s/del、sub、sup、code、br - 超链接、内联图片(仅限 data URI——出于安全考虑跳过外部 URL)
- 样式属性:
font-weight、font-style、text-decoration、color、background-color、text-align
客户端辅助函数
editor.aiToolkit.exportDocx({
url: "/richtextbox/export/docx",
fileName: "report.docx",
title: "Quarterly report"
});自定义解析器
对于 Bedrock、Gemini、您自己的模型或其他任何服务——实现 IRichTextBoxAiResolver(以及可选的 IStreamingRichTextBoxAiResolver)并注册您的类即可。AI Toolkit 的其余部分都与服务商无关。
public sealed class MyBedrockResolver : IRichTextBoxAiResolver
{
public async ValueTask<RichTextBoxAiResponse> ResolveAsync(
RichTextBoxAiRequest request, CancellationToken cancellationToken = default)
{
// ...call Bedrock, map response to RichTextBoxAiResponseBuilder...
}
}
builder.Services.AddRichTextBox();
builder.Services.AddSingleton<IRichTextBoxAiResolver, MyBedrockResolver>();