using System.Diagnostics; using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Gott.Models; using Microsoft.AspNetCore.Http; namespace Gott.Services; /// /// Shared SSE-Streaming-Utilities für AnthropicService und OpenAiService. /// public static class SseHelper { /// /// Schreibt ein SSE-Event (wirft bei CancellationToken). /// public static async Task WriteSseEvent(HttpResponse response, string eventType, object data, CancellationToken ct = default) { ct.ThrowIfCancellationRequested(); var json = JsonSerializer.Serialize(data); await response.WriteAsync($"event: {eventType}\ndata: {json}\n\n", ct); await response.Body.FlushAsync(ct); } /// /// Versucht ein SSE-Event zu schreiben, ignoriert Fehler (Client disconnected). /// public static async Task TryWriteSse(HttpResponse response, string eventType, object data, CancellationToken ct) { try { if (!ct.IsCancellationRequested) await WriteSseEvent(response, eventType, data, ct); } catch { // Client bereits disconnected – ignorieren } } /// /// Finalisiert eine Chain in der Datenbank (Token-Counts, Stopgrund, Dauer). /// public static async Task FinalizeChain(DatabaseService db, ChainRecord chain, TokenUsage usage, int iterations, string stopReason, Stopwatch sw, string streamErrorInfo = null) { chain.InputTokens = usage.InputTokens; chain.OutputTokens = usage.OutputTokens; chain.CacheCreationTokens = usage.CacheCreationTokens; chain.CacheReadTokens = usage.CacheReadTokens; chain.Iterations = iterations; chain.StopReason = stopReason; chain.StreamErrorInfo = streamErrorInfo; chain.DurationMs = sw.ElapsedMilliseconds; await db.UpdateChain(chain); } /// /// Kürzt Tool-Results auf max. Zeichenzahl. /// public const int MaxToolResultChars = 20_000; public static string TruncateToolResult(string result) { return result.Length > MaxToolResultChars ? result[..MaxToolResultChars] + $"\n\n[... gekürzt, {result.Length - MaxToolResultChars} weitere Zeichen ...]" : result; } } /// /// Token-Zähler für eine Chat-Session (Input, Output, Cache). /// public class TokenUsage { public long InputTokens { get; set; } public long OutputTokens { get; set; } public long CacheCreationTokens { get; set; } public long CacheReadTokens { get; set; } } /// /// Ergebnis einer Tool-Ausführung. /// public record ToolResult(string Id, string Result, bool IsError);