Anbieter, Streaming & DOCX-Export
Serverseitige Ergänzungen zum AI Toolkit, alle im NuGet-Paket RichTextBox.AspNetCore enthalten (1.0.0-preview.11+). Eine Zeile DI, um einen echten Anbieter anzubinden, SSE-Streaming durchgängig und ein Endpoint für HTML → DOCX.
Eingebaute Anbieter-Resolver
Drei sofort einsetzbare Implementierungen von IRichTextBoxAiResolver mit HttpClientFactory, Abbruchunterstützung und ILogger<T>. Wählen Sie eine aus und registrieren Sie sie in Program.cs:
using RichTextBox.AiResolvers;
builder.Services.AddRichTextBox();
builder.Services.AddRichTextBoxOpenAiResolver(opts =>
{
opts.ApiKey = builder.Configuration["OpenAI:ApiKey"];
opts.Model = "gpt-6-luna";
});Ersetzen Sie AddRichTextBoxOpenAiResolver durch AddRichTextBoxAnthropicResolver oder AddRichTextBoxAzureOpenAiResolver. Alle drei verwenden gemeinsam 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 hat drei zusätzliche Einstellungen in AzureOpenAiResolverOptions: Endpoint (https://my-resource.openai.azure.com), DeploymentName (nicht das Modell), ApiVersion (optional).
Der OpenAiResolver funktioniert mit jedem OpenAI-kompatiblen Endpoint – überschreiben Sie BaseUrl für Groq, Together.ai oder ein lokales Ollama.
Antworten streamen (Server-Sent Events)
MapRichTextBoxUploads() bildet außerdem POST /richtextbox/ai/stream ab (konfigurierbar über RichTextBoxOptions.AiStreamEndpoint). Die Resolver für OpenAI und Anthropic implementieren IStreamingRichTextBoxAiResolver; Anbieter ohne Streaming weichen transparent auf einen einzelnen Daten-Frame aus.
Übertragungsformat
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\nClient
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 textDie Hilfsfunktion verwendet fetch + ReadableStream. Browser ohne Streaming weichen automatisch auf XHR gegen den Endpoint ohne Streaming aus.
DOCX-Export
MapRichTextBoxUploads() bildet außerdem POST /richtextbox/export/docx ab (konfigurierbar über DocxExportEndpoint). Basiert auf dem MIT-lizenzierten DocumentFormat.OpenXml. Kein externer Dienst.
Request
POST /richtextbox/export/docx
Content-Type: application/json
{
"html": "<h1>Memo</h1><p>Body.</p>",
"title": "Memo",
"fileName": "memo.docx"
}Antwort
Binärer Stream mit Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document und Content-Disposition: attachment; filename=memo.docx.
Unterstütztes HTML
- Absätze,
h1–h6, Blockzitat, pre, hr - Nummerierte & unnummerierte verschachtelte Listen
- Tabellen (mit Kopfzeilen)
- Inline:
b/strong,i/em,u,s/del,sub,sup,code,br - Hyperlinks, eingebettete Bilder (nur Data-URIs – externe URLs werden aus Sicherheitsgründen übersprungen)
- Style-Attribute:
font-weight,font-style,text-decoration,color,background-color,text-align
Hilfsfunktion für den Client
editor.aiToolkit.exportDocx({
url: "/richtextbox/export/docx",
fileName: "report.docx",
title: "Quarterly report"
});Eigene Resolver
Für Bedrock, Gemini, Ihr eigenes Modell oder etwas anderes – implementieren Sie IRichTextBoxAiResolver (und optional IStreamingRichTextBoxAiResolver) und registrieren Sie Ihre Klasse. Der Rest des AI Toolkit ist anbieterunabhängig.
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>();