using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace AnotherReplayReader.Utils { internal static class AIAnalyzeUI { public static List Debug { get; } = []; public record AIAnalyzeProgressData(AIAnalyze.AIChunk Delta, DateTimeOffset? TimeStamp, bool IsExtra); public class EmaSpeed { const double Tau = 2; private DateTimeOffset lastEventTime = DateTimeOffset.UtcNow; private DateTimeOffset timeSinceLastSpeedMeasure = DateTimeOffset.UtcNow; private int bufferedCharactersSinceLastSpeedMeasure = 0; private double emaSpeed = double.NaN; public void ProcessEvent(int textLength, DateTimeOffset? eventTime) { if (eventTime is { } value) { lastEventTime = value; } bufferedCharactersSinceLastSpeedMeasure += textLength; } public double GetDisplaySpeed(DateTimeOffset now) { // ========================= // 2. 计算 instant speed(真实时间) // ========================= double instant = 0; double dt = (now - timeSinceLastSpeedMeasure).TotalSeconds; if (/*bufferedCharactersSinceLastSpeedMeasure > 0 && */dt > 0.05) { instant = bufferedCharactersSinceLastSpeedMeasure / dt; // reset window bufferedCharactersSinceLastSpeedMeasure = 0; timeSinceLastSpeedMeasure = now; } double alpha = 1 - Math.Exp(-dt / Tau); if (double.IsNaN(emaSpeed)) { emaSpeed = instant; } else { emaSpeed += alpha * (instant - emaSpeed); } double idle = (now - lastEventTime).TotalSeconds; double display = emaSpeed; //if (idle > 0.5) //{ // double decay = Math.Exp(-(idle - 0.5) / Tau); // display *= decay; //} return display; } } public static Action BuildAIChunkReader(Action newContent) { var sb = new StringBuilder(); Debug.Add(sb); void OnAIChunk(AIAnalyze.AIChunk c) { if (c.Type == AIAnalyze.AIChunkType.Json) { sb.AppendLine(c.Text); return; } newContent(new(Delta: c, TimeStamp: DateTimeOffset.UtcNow, IsExtra: false)); } return OnAIChunk; } } }