← Toda la documentación
IA / Servidor

Proveedores, streaming y exportación a DOCX

Complementos del lado del servidor para el AI Toolkit, todos incluidos en el paquete NuGet RichTextBox.AspNetCore (1.0.0-preview.11+). Inyección de dependencias en una línea para conectar un proveedor real, streaming SSE de extremo a extremo y un endpoint de HTML → DOCX.

Resolvers de proveedores integrados

Tres implementaciones listas para usar de IRichTextBoxAiResolver que usan HttpClientFactory, cancelación e ILogger<T>. Elige una y regístrala en Program.cs:

using RichTextBox.AiResolvers;

builder.Services.AddRichTextBox();
builder.Services.AddRichTextBoxOpenAiResolver(opts =>
{
    opts.ApiKey = builder.Configuration["OpenAI:ApiKey"];
    opts.Model  = "gpt-6-luna";
});

Cambia AddRichTextBoxOpenAiResolver por AddRichTextBoxAnthropicResolver o AddRichTextBoxAzureOpenAiResolver. Los tres comparten 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 tiene tres opciones adicionales en AzureOpenAiResolverOptions: Endpoint (https://my-resource.openai.azure.com), DeploymentName (no el modelo) y ApiVersion (opcional).

OpenAiResolver funciona con cualquier endpoint compatible con OpenAI: sobrescribe BaseUrl para Groq, Together.ai u Ollama en local.

Respuestas en streaming (Server-Sent Events)

MapRichTextBoxUploads() también asigna POST /richtextbox/ai/stream (configurable mediante RichTextBoxOptions.AiStreamEndpoint). Los resolvers de OpenAI y Anthropic implementan IStreamingRichTextBoxAiResolver; los proveedores sin streaming recurren de forma transparente a un único frame de datos.

Formato en la conexión

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

Cliente

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

La función auxiliar usa fetch + ReadableStream. Los navegadores sin streaming recurren automáticamente a XHR contra el endpoint sin streaming.

Exportación a DOCX

MapRichTextBoxUploads() también asigna POST /richtextbox/export/docx (configurable mediante DocxExportEndpoint). Está construido sobre DocumentFormat.OpenXml, con licencia MIT. Sin servicios externos.

Solicitud

POST /richtextbox/export/docx
Content-Type: application/json

{
    "html": "<h1>Memo</h1><p>Body.</p>",
    "title": "Memo",
    "fileName": "memo.docx"
}

Respuesta

Flujo binario con Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document y Content-Disposition: attachment; filename=memo.docx.

HTML admitido

  • Párrafos, h1–h6, blockquote, pre, hr
  • Listas ordenadas y no ordenadas anidadas
  • Tablas (con filas de encabezado)
  • En línea: b/strong, i/em, u, s/del, sub, sup, code, br
  • Hipervínculos e imágenes en línea (solo URI data; las URL externas se omiten por seguridad)
  • Atributos de estilo: font-weight, font-style, text-decoration, color, background-color, text-align

Función auxiliar del cliente

editor.aiToolkit.exportDocx({
    url:      "/richtextbox/export/docx",
    fileName: "report.docx",
    title:    "Quarterly report"
});

Resolvers personalizados

Para Bedrock, Gemini, tu propio modelo o cualquier otra cosa, implementa IRichTextBoxAiResolver (y, opcionalmente, IStreamingRichTextBoxAiResolver) y registra tu clase. El resto del AI Toolkit no depende del proveedor.

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>();