refactor(monitoring): simplify brand dashboard and harden citation rendering

- drop brand_time_buckets and sparkline/coverage UI; dashboard now returns a single day
- compute mention rate from total actual samples instead of averaging per-platform rates
- canonicalize ai_platform_id across services and aggregate platform-overview snapshots
- strip mojibake and non-answer noise from callback payloads and question detail answers
- keep Kimi citations panel-only; still store raw search_results for audit
- render linked [n] inline citations for qwen/yuanbao answers with scroll-to-source behavior
- restrict立即采集 to today's business date with a clear i18n hint
- refresh content-citations into an ant-design table with truncation and hover styling

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-23 09:11:53 +08:00
parent ce028c56bf
commit 4f4f063200
13 changed files with 1469 additions and 744 deletions
@@ -93,3 +93,68 @@ func TestFilterMonitoringPlatformsFallsBackToDisplayName(t *testing.T) {
{ID: "doubao", Name: "豆包"},
}, filtered)
}
func TestNormalizeMonitoringPlatformIDCanonicalizesLatestIDs(t *testing.T) {
assert.Equal(t, "qwen", normalizeMonitoringPlatformID(" QWEN "))
assert.Equal(t, "wenxin", normalizeMonitoringPlatformID("WenXin"))
assert.Equal(t, "yuanbao", normalizeMonitoringPlatformID("yuanbao"))
}
func TestFilterMonitoringPlatformsMatchesCanonicalPlatform(t *testing.T) {
platforms := []monitoringPlatformMetadata{
{ID: "qwen", Name: "通义千问"},
}
selected := "qwen"
filtered := filterMonitoringPlatforms(platforms, &selected)
assert.Equal(t, []monitoringPlatformMetadata{
{ID: "qwen", Name: "通义千问"},
}, filtered)
}
func TestIntersectMonitoringPlatformsAcceptsCanonicalIDs(t *testing.T) {
enabled := []monitoringPlatformMetadata{
{ID: "qwen", Name: "通义千问"},
{ID: "wenxin", Name: "文心一言"},
}
filtered, err := intersectMonitoringPlatforms(enabled, []string{"qwen", "wenxin"})
require.NoError(t, err)
assert.Equal(t, []monitoringPlatformMetadata{
{ID: "qwen", Name: "通义千问"},
{ID: "wenxin", Name: "文心一言"},
}, filtered)
}
func TestReconcileEnabledMonitoringPlatformsBackfillsSupportedCatalog(t *testing.T) {
assert.Equal(t, []string{"yuanbao", "kimi", "wenxin", "deepseek", "doubao", "qwen"}, reconcileEnabledMonitoringPlatforms([]string{"deepseek", "qwen", "doubao"}))
}
func TestApplyDerivedRatesToOverviewSnapshotUsesAllSamplesForMentionRate(t *testing.T) {
day := time.Date(2026, 4, 22, 0, 0, 0, 0, monitoringBusinessLocation())
snapshot := monitoringOverviewSnapshot{Date: day}
derived := newMonitoringDerivedMetrics()
derived.ByDate["2026-04-22"] = monitoringDerivedRateStats{
Total: 4,
MentionedCount: 1,
Top1Count: 1,
FirstRecommend: 1,
PositiveMentions: 1,
}
derived.ByDatePlatform["2026-04-22"] = map[string]monitoringDerivedRateStats{
"qwen": {Total: 1, MentionedCount: 1},
"deepseek": {Total: 3, MentionedCount: 0},
}
applyDerivedRatesToOverviewSnapshot(&snapshot, derived)
require.True(t, snapshot.MentionRate.Valid)
require.True(t, snapshot.Top1MentionRate.Valid)
require.True(t, snapshot.FirstRecommendRate.Valid)
require.True(t, snapshot.PositiveMentionRate.Valid)
assert.InDelta(t, 0.25, snapshot.MentionRate.Float64, 0.0001)
assert.InDelta(t, 0.25, snapshot.Top1MentionRate.Float64, 0.0001)
assert.InDelta(t, 0.25, snapshot.FirstRecommendRate.Float64, 0.0001)
assert.InDelta(t, 0.25, snapshot.PositiveMentionRate.Float64, 0.0001)
}