Files
AX-Copilot-Codex/.decompiledproj/AxCopilot/Views/AgentStatsDashboardWindow.cs

508 lines
15 KiB
C#

using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Shapes;
using AxCopilot.Services;
namespace AxCopilot.Views;
public class AgentStatsDashboardWindow : Window, IComponentConnector
{
private int _currentDays = 1;
internal Border BtnClose;
internal Border FilterToday;
internal Border Filter7d;
internal Border Filter30d;
internal Border FilterAll;
internal UniformGrid SummaryCards;
internal TextBlock DailyChartTitle;
internal Canvas DailyBarChart;
internal Canvas DailyBarLabels;
internal StackPanel ToolFreqPanel;
internal StackPanel TabBreakPanel;
internal StackPanel ModelBreakPanel;
internal TextBlock StatusText;
private bool _contentLoaded;
public AgentStatsDashboardWindow()
{
InitializeComponent();
base.Loaded += delegate
{
LoadStats(_currentDays);
};
}
private void TitleBar_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
//IL_0003: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
Point position = e.GetPosition(this);
if (!(((Point)(ref position)).X > base.ActualWidth - 50.0))
{
if (e.ClickCount == 2)
{
base.WindowState = ((base.WindowState != WindowState.Maximized) ? WindowState.Maximized : WindowState.Normal);
}
else
{
DragMove();
}
}
}
private void BtnClose_Click(object sender, MouseButtonEventArgs e)
{
Close();
}
private void Filter_Click(object sender, MouseButtonEventArgs e)
{
if (sender is Border { Tag: string tag } border && int.TryParse(tag, out var result))
{
_currentDays = result;
UpdateFilterButtons(border);
LoadStats(result);
}
}
private void BtnClearStats_Click(object sender, MouseButtonEventArgs e)
{
MessageBoxResult messageBoxResult = CustomMessageBox.Show("모든 통계 데이터를 삭제하시겠습니까?\n이 작업은 되돌릴 수 없습니다.", "통계 초기화", MessageBoxButton.YesNo, MessageBoxImage.Question);
if (messageBoxResult == MessageBoxResult.Yes)
{
AgentStatsService.Clear();
LoadStats(_currentDays);
}
}
private void LoadStats(int days)
{
AgentStatsService.AgentStatsSummary s = AgentStatsService.Aggregate(days);
RenderSummaryCards(s);
RenderDailyChart(s, days);
RenderToolFreq(s);
RenderBreakdowns(s);
UpdateStatus(s, days);
}
private void RenderSummaryCards(AgentStatsService.AgentStatsSummary s)
{
SummaryCards.Children.Clear();
SummaryCards.Children.Add(MakeSummaryCard("\ue9d9", "총 실행", s.TotalSessions.ToString("N0"), "#A78BFA"));
SummaryCards.Children.Add(MakeSummaryCard("\ue8a7", "도구 호출", s.TotalToolCalls.ToString("N0"), "#3B82F6"));
SummaryCards.Children.Add(MakeSummaryCard("\ue7c8", "총 토큰", FormatTokens(s.TotalTokens), "#10B981"));
SummaryCards.Children.Add(MakeSummaryCard("\ue916", "평균 시간", (s.TotalSessions > 0) ? $"{TimeSpan.FromMilliseconds((double)s.TotalDurationMs / (double)s.TotalSessions):mm\\:ss}" : "—", "#F59E0B"));
}
private Border MakeSummaryCard(string icon, string label, string value, string colorHex)
{
Brush background = (TryFindResource("ItemBackground") as Brush) ?? new SolidColorBrush(Color.FromRgb(42, 42, 64));
Brush foreground = (TryFindResource("PrimaryText") as Brush) ?? Brushes.White;
Brush foreground2 = (TryFindResource("SecondaryText") as Brush) ?? Brushes.Gray;
Color color = (Color)ColorConverter.ConvertFromString(colorHex);
Border border = new Border
{
Background = background,
CornerRadius = new CornerRadius(10.0),
Padding = new Thickness(14.0, 12.0, 14.0, 12.0),
Margin = new Thickness(0.0, 0.0, 8.0, 0.0)
};
StackPanel stackPanel = new StackPanel();
stackPanel.Children.Add(new TextBlock
{
Text = icon,
FontFamily = new FontFamily("Segoe MDL2 Assets"),
FontSize = 16.0,
Foreground = new SolidColorBrush(color),
Margin = new Thickness(0.0, 0.0, 0.0, 6.0)
});
stackPanel.Children.Add(new TextBlock
{
Text = value,
FontSize = 20.0,
FontWeight = FontWeights.Bold,
Foreground = foreground
});
stackPanel.Children.Add(new TextBlock
{
Text = label,
FontSize = 11.0,
Foreground = foreground2,
Margin = new Thickness(0.0, 2.0, 0.0, 0.0)
});
border.Child = stackPanel;
return border;
}
private void RenderDailyChart(AgentStatsService.AgentStatsSummary s, int days)
{
DailyBarChart.Children.Clear();
DailyBarLabels.Children.Clear();
DateTime endDate = DateTime.Today;
int chartDays = days switch
{
0 => 30,
1 => 1,
_ => days,
};
List<DateTime> list = (from i in Enumerable.Range(0, chartDays)
select endDate.AddDays(-(chartDays - 1 - i))).ToList();
int num = list.Select((DateTime d) => s.DailySessions.GetValueOrDefault(d.ToString("yyyy-MM-dd"), 0)).DefaultIfEmpty(0).Max();
if (num == 0)
{
num = 1;
}
Color color = (Color)ColorConverter.ConvertFromString("#4B5EFC");
double num2 = 748.0;
double num3 = 2.0;
double num4 = Math.Max(4.0, (num2 - num3 * (double)list.Count) / (double)list.Count);
double num5 = 100.0;
for (int num6 = 0; num6 < list.Count; num6++)
{
string text = list[num6].ToString("yyyy-MM-dd");
int valueOrDefault = s.DailySessions.GetValueOrDefault(text, 0);
double num7 = Math.Max(2.0, (double)valueOrDefault / (double)num * (num5 - 4.0));
double length = (double)num6 * (num4 + num3);
Rectangle element = new Rectangle
{
Width = num4,
Height = num7,
Fill = new SolidColorBrush(Color.FromArgb(204, color.R, color.G, color.B)),
RadiusX = 3.0,
RadiusY = 3.0,
ToolTip = $"{text}: {valueOrDefault}회"
};
Canvas.SetLeft(element, length);
Canvas.SetTop(element, num5 - num7);
DailyBarChart.Children.Add(element);
if (list.Count <= 7 || list[num6].DayOfWeek == DayOfWeek.Monday)
{
TextBlock textBlock = new TextBlock();
textBlock.Text = list[num6].ToString("MM/dd");
textBlock.FontSize = 9.0;
textBlock.Foreground = (TryFindResource("SecondaryText") as Brush) ?? Brushes.Gray;
TextBlock element2 = textBlock;
Canvas.SetLeft(element2, length);
DailyBarLabels.Children.Add(element2);
}
}
}
private void RenderToolFreq(AgentStatsService.AgentStatsSummary s)
{
ToolFreqPanel.Children.Clear();
if (s.ToolFrequency.Count == 0)
{
ToolFreqPanel.Children.Add(new TextBlock
{
Text = "데이터 없음",
FontSize = 12.0,
Foreground = ((TryFindResource("SecondaryText") as Brush) ?? Brushes.Gray)
});
return;
}
int num = s.ToolFrequency.Values.Max();
Color color = (Color)ColorConverter.ConvertFromString("#3B82F6");
foreach (KeyValuePair<string, int> item in s.ToolFrequency)
{
item.Deconstruct(out var key, out var value);
string text = key;
int num2 = value;
double num3 = (double)num2 / (double)num;
Grid grid = new Grid
{
Margin = new Thickness(0.0, 2.0, 0.0, 2.0)
};
grid.ColumnDefinitions.Add(new ColumnDefinition
{
Width = new GridLength(120.0)
});
grid.ColumnDefinitions.Add(new ColumnDefinition());
grid.ColumnDefinitions.Add(new ColumnDefinition
{
Width = new GridLength(36.0)
});
TextBlock textBlock = new TextBlock();
textBlock.Text = text;
textBlock.FontSize = 11.0;
textBlock.FontFamily = new FontFamily("Consolas");
textBlock.Foreground = (TryFindResource("PrimaryText") as Brush) ?? Brushes.White;
textBlock.TextTrimming = TextTrimming.CharacterEllipsis;
textBlock.VerticalAlignment = VerticalAlignment.Center;
TextBlock element = textBlock;
Grid.SetColumn(element, 0);
Border border = new Border
{
Background = new SolidColorBrush(Color.FromArgb(32, 59, 130, 246)),
CornerRadius = new CornerRadius(3.0),
Height = 10.0,
Margin = new Thickness(6.0, 0.0, 4.0, 0.0),
VerticalAlignment = VerticalAlignment.Center
};
Border border2 = new Border
{
Background = new SolidColorBrush(Color.FromArgb(204, color.R, color.G, color.B)),
CornerRadius = new CornerRadius(3.0),
Height = 10.0,
HorizontalAlignment = HorizontalAlignment.Left
};
border2.Width = num3 * 150.0;
border.Child = border2;
Grid.SetColumn(border, 1);
textBlock = new TextBlock();
textBlock.Text = num2.ToString();
textBlock.FontSize = 11.0;
textBlock.FontWeight = FontWeights.SemiBold;
textBlock.Foreground = (TryFindResource("SecondaryText") as Brush) ?? Brushes.Gray;
textBlock.HorizontalAlignment = HorizontalAlignment.Right;
textBlock.VerticalAlignment = VerticalAlignment.Center;
TextBlock element2 = textBlock;
Grid.SetColumn(element2, 2);
grid.Children.Add(element);
grid.Children.Add(border);
grid.Children.Add(element2);
ToolFreqPanel.Children.Add(grid);
}
}
private void RenderBreakdowns(AgentStatsService.AgentStatsSummary s)
{
TabBreakPanel.Children.Clear();
Dictionary<string, string> dictionary = new Dictionary<string, string>
{
["Cowork"] = "#A78BFA",
["Code"] = "#34D399",
["Chat"] = "#3B82F6"
};
string key;
int value;
foreach (KeyValuePair<string, int> item in s.TabBreakdown.OrderByDescending<KeyValuePair<string, int>, int>((KeyValuePair<string, int> kv) => kv.Value))
{
item.Deconstruct(out key, out value);
string text = key;
int count = value;
string valueOrDefault = dictionary.GetValueOrDefault(text, "#9CA3AF");
TabBreakPanel.Children.Add(MakeBreakRow(text, count, valueOrDefault, s.TabBreakdown.Values.DefaultIfEmpty(1).Max()));
}
if (s.TabBreakdown.Count == 0)
{
TabBreakPanel.Children.Add(MakeEmptyText());
}
ModelBreakPanel.Children.Clear();
foreach (KeyValuePair<string, int> item2 in s.ModelBreakdown.OrderByDescending<KeyValuePair<string, int>, int>((KeyValuePair<string, int> kv) => kv.Value))
{
item2.Deconstruct(out key, out value);
string text2 = key;
int count2 = value;
string label = ((text2.Length > 18) ? (text2.Substring(0, 18) + "…") : text2);
ModelBreakPanel.Children.Add(MakeBreakRow(label, count2, "#F59E0B", s.ModelBreakdown.Values.DefaultIfEmpty(1).Max()));
}
if (s.ModelBreakdown.Count == 0)
{
ModelBreakPanel.Children.Add(MakeEmptyText());
}
}
private UIElement MakeBreakRow(string label, int count, string colorHex, int maxVal)
{
double num = ((maxVal > 0) ? ((double)count / (double)maxVal) : 0.0);
Color color = (Color)ColorConverter.ConvertFromString(colorHex);
StackPanel stackPanel = new StackPanel
{
Margin = new Thickness(0.0, 2.0, 0.0, 2.0)
};
Grid grid = new Grid();
grid.ColumnDefinitions.Add(new ColumnDefinition());
grid.ColumnDefinitions.Add(new ColumnDefinition
{
Width = new GridLength(1.0, GridUnitType.Auto)
});
TextBlock textBlock = new TextBlock();
textBlock.Text = label;
textBlock.FontSize = 11.0;
textBlock.Foreground = (TryFindResource("PrimaryText") as Brush) ?? Brushes.White;
TextBlock element = textBlock;
Grid.SetColumn(element, 0);
textBlock = new TextBlock();
textBlock.Text = count.ToString();
textBlock.FontSize = 11.0;
textBlock.FontWeight = FontWeights.SemiBold;
textBlock.Foreground = (TryFindResource("SecondaryText") as Brush) ?? Brushes.Gray;
TextBlock element2 = textBlock;
Grid.SetColumn(element2, 1);
grid.Children.Add(element);
grid.Children.Add(element2);
stackPanel.Children.Add(grid);
Border border = new Border
{
Background = new SolidColorBrush(Color.FromArgb(32, color.R, color.G, color.B)),
CornerRadius = new CornerRadius(3.0),
Height = 6.0,
Margin = new Thickness(0.0, 3.0, 0.0, 0.0)
};
Border border2 = new Border
{
Background = new SolidColorBrush(Color.FromArgb(204, color.R, color.G, color.B)),
CornerRadius = new CornerRadius(3.0),
Height = 6.0,
HorizontalAlignment = HorizontalAlignment.Left
};
border2.Width = num * 160.0;
border.Child = border2;
stackPanel.Children.Add(border);
return stackPanel;
}
private TextBlock MakeEmptyText()
{
TextBlock textBlock = new TextBlock();
textBlock.Text = "데이터 없음";
textBlock.FontSize = 11.0;
textBlock.Foreground = (TryFindResource("SecondaryText") as Brush) ?? Brushes.Gray;
return textBlock;
}
private void UpdateFilterButtons(Border active)
{
Border[] array = new Border[4] { FilterToday, Filter7d, Filter30d, FilterAll };
foreach (Border border in array)
{
bool flag = border == active;
border.Background = (flag ? new SolidColorBrush(Color.FromRgb(75, 94, 252)) : ((TryFindResource("ItemBackground") as Brush) ?? new SolidColorBrush(Color.FromRgb(48, 48, 69))));
if (border.Child is TextBlock textBlock)
{
textBlock.Foreground = (flag ? Brushes.White : ((TryFindResource("SecondaryText") as Brush) ?? Brushes.Gray));
}
}
}
private void UpdateStatus(AgentStatsService.AgentStatsSummary s, int days)
{
if (1 == 0)
{
}
string text = days switch
{
1 => "오늘",
7 => "최근 7일",
30 => "최근 30일",
_ => "전체 기간",
};
if (1 == 0)
{
}
string value = text;
long fileSize = AgentStatsService.GetFileSize();
StatusText.Text = $"{value} 기준 | 세션 {s.TotalSessions}회, 도구 호출 {s.TotalToolCalls}회, 토큰 {FormatTokens(s.TotalTokens)} | 저장 파일 {FormatFileSize(fileSize)}";
}
private static string FormatTokens(int t)
{
return (t >= 1000000) ? $"{(double)t / 1000000.0:F1}M" : ((t >= 1000) ? $"{(double)t / 1000.0:F1}K" : t.ToString());
}
private static string FormatFileSize(long bytes)
{
return (bytes >= 1048576) ? $"{(double)bytes / 1048576.0:F1}MB" : ((bytes >= 1024) ? $"{(double)bytes / 1024.0:F1}KB" : $"{bytes}B");
}
[DebuggerNonUserCode]
[GeneratedCode("PresentationBuildTasks", "10.0.5.0")]
public void InitializeComponent()
{
if (!_contentLoaded)
{
_contentLoaded = true;
Uri resourceLocator = new Uri("/AxCopilot;component/views/agentstatsdashboardwindow.xaml", UriKind.Relative);
Application.LoadComponent(this, resourceLocator);
}
}
[DebuggerNonUserCode]
[GeneratedCode("PresentationBuildTasks", "10.0.5.0")]
[EditorBrowsable(EditorBrowsableState.Never)]
void IComponentConnector.Connect(int connectionId, object target)
{
switch (connectionId)
{
case 1:
((Border)target).MouseLeftButtonDown += TitleBar_MouseLeftButtonDown;
break;
case 2:
BtnClose = (Border)target;
BtnClose.MouseLeftButtonUp += BtnClose_Click;
break;
case 3:
FilterToday = (Border)target;
FilterToday.MouseLeftButtonUp += Filter_Click;
break;
case 4:
Filter7d = (Border)target;
Filter7d.MouseLeftButtonUp += Filter_Click;
break;
case 5:
Filter30d = (Border)target;
Filter30d.MouseLeftButtonUp += Filter_Click;
break;
case 6:
FilterAll = (Border)target;
FilterAll.MouseLeftButtonUp += Filter_Click;
break;
case 7:
((Border)target).MouseLeftButtonUp += BtnClearStats_Click;
break;
case 8:
SummaryCards = (UniformGrid)target;
break;
case 9:
DailyChartTitle = (TextBlock)target;
break;
case 10:
DailyBarChart = (Canvas)target;
break;
case 11:
DailyBarLabels = (Canvas)target;
break;
case 12:
ToolFreqPanel = (StackPanel)target;
break;
case 13:
TabBreakPanel = (StackPanel)target;
break;
case 14:
ModelBreakPanel = (StackPanel)target;
break;
case 15:
StatusText = (TextBlock)target;
break;
default:
_contentLoaded = true;
break;
}
}
}