Initial commit to new repository
This commit is contained in:
204
.decompiledproj/AxCopilot/Services/AgentStatsService.cs
Normal file
204
.decompiledproj/AxCopilot/Services/AgentStatsService.cs
Normal file
@@ -0,0 +1,204 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AxCopilot.Services;
|
||||
|
||||
public static class AgentStatsService
|
||||
{
|
||||
public record AgentSessionRecord
|
||||
{
|
||||
[JsonPropertyName("ts")]
|
||||
public DateTime Timestamp { get; init; } = DateTime.Now;
|
||||
|
||||
[JsonPropertyName("tab")]
|
||||
public string Tab { get; init; } = "";
|
||||
|
||||
[JsonPropertyName("model")]
|
||||
public string Model { get; init; } = "";
|
||||
|
||||
[JsonPropertyName("calls")]
|
||||
public int ToolCalls { get; init; }
|
||||
|
||||
[JsonPropertyName("ok")]
|
||||
public int SuccessCount { get; init; }
|
||||
|
||||
[JsonPropertyName("fail")]
|
||||
public int FailCount { get; init; }
|
||||
|
||||
[JsonPropertyName("itok")]
|
||||
public int InputTokens { get; init; }
|
||||
|
||||
[JsonPropertyName("otok")]
|
||||
public int OutputTokens { get; init; }
|
||||
|
||||
[JsonPropertyName("ms")]
|
||||
public long DurationMs { get; init; }
|
||||
|
||||
[JsonPropertyName("tools")]
|
||||
public List<string> UsedTools { get; init; } = new List<string>();
|
||||
}
|
||||
|
||||
public record AgentStatsSummary
|
||||
{
|
||||
public int TotalSessions { get; init; }
|
||||
|
||||
public int TotalToolCalls { get; init; }
|
||||
|
||||
public int TotalTokens { get; init; }
|
||||
|
||||
public int TotalInputTokens { get; init; }
|
||||
|
||||
public int TotalOutputTokens { get; init; }
|
||||
|
||||
public long TotalDurationMs { get; init; }
|
||||
|
||||
public Dictionary<string, int> ToolFrequency { get; init; } = new Dictionary<string, int>();
|
||||
|
||||
public Dictionary<string, int> ModelBreakdown { get; init; } = new Dictionary<string, int>();
|
||||
|
||||
public Dictionary<string, int> TabBreakdown { get; init; } = new Dictionary<string, int>();
|
||||
|
||||
public Dictionary<string, int> DailySessions { get; init; } = new Dictionary<string, int>();
|
||||
|
||||
public Dictionary<string, int> DailyTokens { get; init; } = new Dictionary<string, int>();
|
||||
}
|
||||
|
||||
private static readonly string StatsDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "AxCopilot", "stats");
|
||||
|
||||
private static readonly string StatsFile = Path.Combine(StatsDir, "agent_stats.json");
|
||||
|
||||
private static readonly JsonSerializerOptions _jsonOpts = new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = false,
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
||||
};
|
||||
|
||||
public static void RecordSession(AgentSessionRecord record)
|
||||
{
|
||||
Task.Run(delegate
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!Directory.Exists(StatsDir))
|
||||
{
|
||||
Directory.CreateDirectory(StatsDir);
|
||||
}
|
||||
string text = JsonSerializer.Serialize(record, _jsonOpts);
|
||||
File.AppendAllText(StatsFile, text + "\n");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogService.Warn("통계 기록 실패: " + ex.Message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static AgentStatsSummary Aggregate(int days = 0)
|
||||
{
|
||||
List<AgentSessionRecord> records = LoadRecords(days);
|
||||
return BuildSummary(records);
|
||||
}
|
||||
|
||||
public static List<AgentSessionRecord> LoadRecords(int days = 0)
|
||||
{
|
||||
if (!File.Exists(StatsFile))
|
||||
{
|
||||
return new List<AgentSessionRecord>();
|
||||
}
|
||||
DateTime dateTime = ((days > 0) ? DateTime.Now.AddDays(-days) : DateTime.MinValue);
|
||||
List<AgentSessionRecord> list = new List<AgentSessionRecord>();
|
||||
foreach (string item in File.ReadLines(StatsFile))
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(item))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
try
|
||||
{
|
||||
AgentSessionRecord agentSessionRecord = JsonSerializer.Deserialize<AgentSessionRecord>(item, _jsonOpts);
|
||||
if (agentSessionRecord != null && agentSessionRecord.Timestamp >= dateTime)
|
||||
{
|
||||
list.Add(agentSessionRecord);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private static AgentStatsSummary BuildSummary(List<AgentSessionRecord> records)
|
||||
{
|
||||
Dictionary<string, int> dictionary = new Dictionary<string, int>();
|
||||
Dictionary<string, int> dictionary2 = new Dictionary<string, int>();
|
||||
Dictionary<string, int> dictionary3 = new Dictionary<string, int>();
|
||||
Dictionary<string, int> dictionary4 = new Dictionary<string, int>();
|
||||
Dictionary<string, int> dictionary5 = new Dictionary<string, int>();
|
||||
int num = 0;
|
||||
int num2 = 0;
|
||||
int num3 = 0;
|
||||
long num4 = 0L;
|
||||
foreach (AgentSessionRecord record in records)
|
||||
{
|
||||
num += record.ToolCalls;
|
||||
num2 += record.InputTokens;
|
||||
num3 += record.OutputTokens;
|
||||
num4 += record.DurationMs;
|
||||
foreach (string usedTool in record.UsedTools)
|
||||
{
|
||||
dictionary[usedTool] = dictionary.GetValueOrDefault(usedTool) + 1;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(record.Model))
|
||||
{
|
||||
dictionary2[record.Model] = dictionary2.GetValueOrDefault(record.Model) + 1;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(record.Tab))
|
||||
{
|
||||
dictionary3[record.Tab] = dictionary3.GetValueOrDefault(record.Tab) + 1;
|
||||
}
|
||||
string key = record.Timestamp.ToString("yyyy-MM-dd");
|
||||
dictionary4[key] = dictionary4.GetValueOrDefault(key) + 1;
|
||||
dictionary5[key] = dictionary5.GetValueOrDefault(key) + record.InputTokens + record.OutputTokens;
|
||||
}
|
||||
return new AgentStatsSummary
|
||||
{
|
||||
TotalSessions = records.Count,
|
||||
TotalToolCalls = num,
|
||||
TotalTokens = num2 + num3,
|
||||
TotalInputTokens = num2,
|
||||
TotalOutputTokens = num3,
|
||||
TotalDurationMs = num4,
|
||||
ToolFrequency = dictionary.OrderByDescending((KeyValuePair<string, int> kv) => kv.Value).Take(10).ToDictionary((KeyValuePair<string, int> kv) => kv.Key, (KeyValuePair<string, int> kv) => kv.Value),
|
||||
ModelBreakdown = dictionary2,
|
||||
TabBreakdown = dictionary3,
|
||||
DailySessions = dictionary4,
|
||||
DailyTokens = dictionary5
|
||||
};
|
||||
}
|
||||
|
||||
public static long GetFileSize()
|
||||
{
|
||||
return File.Exists(StatsFile) ? new FileInfo(StatsFile).Length : 0;
|
||||
}
|
||||
|
||||
public static void Clear()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (File.Exists(StatsFile))
|
||||
{
|
||||
File.Delete(StatsFile);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogService.Warn("통계 삭제 실패: " + ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user