File size: 4,054 Bytes
cfb0fa4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
<script lang="ts">
	import Modal from '$lib/components/common/Modal.svelte';
	import { getContext } from 'svelte';
	import { getModelHistory } from '$lib/apis/evaluations';
	import ModelActivityChart from './ModelActivityChart.svelte';
	import XMark from '$lib/components/icons/XMark.svelte';
	import Tooltip from '$lib/components/common/Tooltip.svelte';

	export let show = false;
	export let model = null;
	export let onClose: () => void = () => {};

	const i18n = getContext('i18n');

	type TimeRange = '30d' | '1y' | 'all';
	const TIME_RANGES: { key: TimeRange; label: string; days: number }[] = [
		{ key: '30d', label: '30D', days: 30 },
		{ key: '1y', label: '1Y', days: 365 },
		{ key: 'all', label: 'All', days: 0 } // 0 = all time, starts from first feedback
	];

	let selectedRange: TimeRange = '30d';
	let history: Array<{ date: string; won: number; lost: number }> = [];
	let loadingHistory = false;

	const close = () => {
		show = false;
		onClose();
	};

	const loadHistory = async (days: number) => {
		if (!model?.id) return;
		loadingHistory = true;
		try {
			const result = await getModelHistory(localStorage.token, model.id, days);
			history = result?.history ?? [];
		} catch (err) {
			console.error('Failed to load model history:', err);
			history = [];
		}
		loadingHistory = false;
	};

	const selectRange = (range: TimeRange) => {
		selectedRange = range;
		const config = TIME_RANGES.find((r) => r.key === range);
		if (config) {
			loadHistory(config.days);
		}
	};

	// Load history when model changes and modal is shown
	$: if (show && model?.id) {
		selectRange(selectedRange);
	}

	// Use top_tags from backend response (already computed)
	$: topTags = model?.top_tags ?? [];
</script>

<Modal size="md" bind:show>
	{#if model}
		<div class="flex justify-between dark:text-gray-300 px-5 pt-4 pb-2">
			<Tooltip content={`${model.name} (${model.id})`} placement="top-start">
				<div class="text-lg font-medium self-center line-clamp-1">
					{model.name}
				</div>
			</Tooltip>
			<button class="self-center" on:click={close} aria-label="Close">
				<XMark className={'size-5'} />
			</button>
		</div>
		<div class="px-5 pb-4 dark:text-gray-200">
			<!-- Activity Chart -->
			<div class="mb-4">
				<div class="flex items-center justify-between mb-2">
					<div class="text-xs text-gray-500 font-medium uppercase tracking-wide">
						{$i18n.t('Activity')}
					</div>
					<div
						class="inline-flex rounded-full bg-gray-100/80 p-0.5 dark:bg-gray-800/80 backdrop-blur-sm"
					>
						{#each TIME_RANGES as range}
							<button
								type="button"
								class="rounded-full transition-all duration-200 px-2.5 py-0.5 text-xs font-medium {selectedRange ===
								range.key
									? 'bg-white text-gray-900 shadow-sm dark:bg-gray-700 dark:text-white'
									: 'text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200'}"
								on:click={() => selectRange(range.key)}
							>
								{range.label}
							</button>
						{/each}
					</div>
				</div>
				<ModelActivityChart
					{history}
					loading={loadingHistory}
					aggregateWeekly={selectedRange === '1y' || selectedRange === 'all'}
				/>
			</div>

			<div class="mb-4">
				<div class="text-xs text-gray-500 mb-2 font-medium uppercase tracking-wide">
					{$i18n.t('Tags')}
				</div>
				{#if topTags.length}
					<div class="flex flex-wrap gap-1 -mx-1">
						{#each topTags as tagInfo}
							<span class="px-2 py-0.5 rounded-full bg-gray-100 dark:bg-gray-850 text-xs">
								{tagInfo.tag} <span class="text-gray-500 font-medium">{tagInfo.count}</span>
							</span>
						{/each}
					</div>
				{:else}
					<span class="text-gray-500 text-sm">-</span>
				{/if}
			</div>

			<div class="flex justify-end pt-2">
				<button
					class="px-3.5 py-1.5 text-sm font-medium bg-black hover:bg-gray-900 text-white dark:bg-white dark:text-black dark:hover:bg-gray-100 transition rounded-full"
					type="button"
					on:click={close}
				>
					{$i18n.t('Close')}
				</button>
			</div>
		</div>
	{/if}
</Modal>