Files
AnotherReplayReader/Utils/AIAnalyzeUI.cs
2026-06-21 14:42:04 +02:00

90 lines
2.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AnotherReplayReader.Utils
{
internal static class AIAnalyzeUI
{
public record AIAnalyzeProgressData(AIAnalyze.AIChunk Delta, DateTimeOffset? TimeStamp, bool IsExtra);
public class EmaSpeed
{
const double Tau = 5;
private DateTimeOffset lastEventTime = DateTimeOffset.UtcNow;
private DateTimeOffset timeSinceLastSpeedMeasure = DateTimeOffset.UtcNow;
private int bufferedCharactersSinceLastSpeedMeasure = 0;
private double emaSpeed = double.NaN;
public void ProcessEvent(AIAnalyzeProgressData data)
{
if (data.IsExtra)
{
return;
}
if (data.TimeStamp is { } timestamp)
{
lastEventTime = timestamp;
}
bufferedCharactersSinceLastSpeedMeasure += data.Delta.Text.Length;
}
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<AIAnalyze.AIChunk> BuildAIChunkReader(Action<AIAnalyzeProgressData> newContent)
{
void OnAIChunk(AIAnalyze.AIChunk c)
{
if (c.Type == AIAnalyze.AIChunkType.Json)
{
return;
}
newContent(new(Delta: c, TimeStamp: DateTimeOffset.UtcNow, IsExtra: false));
}
return OnAIChunk;
}
}
}