refactor: model independent spread metric rules

This commit is contained in:
wxs
2026-07-10 17:18:01 +08:00
parent 8eebb44551
commit b48e244a99
3 changed files with 121 additions and 41 deletions
+32 -8
View File
@@ -1,4 +1,9 @@
import type { SpreadInfoMetrics, SpreadMetricThresholds } from "./types";
import type {
SpreadInfoConfig,
SpreadInfoMetrics,
SpreadMetricFilterRule,
SpreadMetricThresholds
} from "./types";
interface FetchResponseLike {
json(): Promise<unknown>;
@@ -10,13 +15,6 @@ type FetchLike = (
init?: RequestInit
) => Promise<FetchResponseLike>;
export interface SpreadInfoConfig {
flowType: 0 | 1;
onlyAssign: boolean;
range: 2 | 3;
type: 1 | 2;
}
interface SpreadInfoClientOptions {
baseUrl?: string;
configs?: SpreadInfoConfig[];
@@ -222,6 +220,32 @@ export function matchesSpreadThresholds(
});
}
export function normalizeSpreadInfoConfig(
config: SpreadInfoConfig
): SpreadInfoConfig {
return config.type === 1
? { ...config, flowType: 0, onlyAssign: false }
: { ...config };
}
export function buildSpreadInfoConfigKey(config: SpreadInfoConfig): string {
const normalized = normalizeSpreadInfoConfig(config);
return [
normalized.type,
normalized.onlyAssign ? 1 : 0,
normalized.flowType,
normalized.range
].join(":");
}
export function matchesSpreadMetricRule(
metrics: MappedSpreadInfoResponse,
rule: SpreadMetricFilterRule
): boolean {
const numericValue = readDisplayNumber(metrics[rule.metric]);
return numericValue !== null && numericValue >= rule.threshold;
}
function buildSpreadInfoColumnHeader(
config: SpreadInfoConfig,
metric: SpreadInfoMetricDefinition
+16 -6
View File
@@ -14,6 +14,21 @@ export interface BackendMetrics {
export type SpreadInfoMetrics = Record<string, string>;
export interface SpreadInfoConfig {
flowType: 0 | 1;
onlyAssign: boolean;
range: 2 | 3;
type: 1 | 2;
}
export type SpreadFilterMetric = "finishRate" | "interactionRate";
export interface SpreadMetricFilterRule {
config: SpreadInfoConfig;
metric: SpreadFilterMetric;
threshold: number;
}
export interface SpreadMetricThresholds {
averageCommentCount?: number;
averageDuration?: number;
@@ -25,12 +40,7 @@ export interface SpreadMetricThresholds {
}
export interface SpreadThresholdFilter {
config: {
flowType: 0 | 1;
onlyAssign: boolean;
range: 2 | 3;
type: 1 | 2;
};
config: SpreadInfoConfig;
thresholds: SpreadMetricThresholds;
}
+73 -27
View File
@@ -1,11 +1,13 @@
import { describe, expect, test, vi } from "vitest";
import {
buildSpreadInfoConfigKey,
buildSpreadInfoColumns,
buildSpreadInfoUrl,
createSpreadInfoClient,
DEFAULT_SPREAD_INFO_CONFIGS,
matchesSpreadThresholds,
matchesSpreadMetricRule,
normalizeSpreadInfoConfig,
mapSpreadInfoResponse
} from "../src/content/market/spread-info";
@@ -167,46 +169,90 @@ describe("spread-info", () => {
);
});
test("matches thresholds using display values and requires every filled threshold", () => {
test("normalizes fixed personal-video parameters before grouping", () => {
expect(
matchesSpreadThresholds(
normalizeSpreadInfoConfig({
flowType: 1,
onlyAssign: true,
range: 3,
type: 1
})
).toEqual({
flowType: 0,
onlyAssign: false,
range: 3,
type: 1
});
});
test("uses all normalized video dimensions in the config key", () => {
expect(
buildSpreadInfoConfigKey({
flowType: 1,
onlyAssign: true,
range: 3,
type: 1
})
).toBe(
buildSpreadInfoConfigKey({
flowType: 0,
onlyAssign: false,
range: 3,
type: 1
})
);
expect(
buildSpreadInfoConfigKey({
flowType: 0,
onlyAssign: false,
range: 2,
type: 2
})
).not.toBe(
buildSpreadInfoConfigKey({
flowType: 0,
onlyAssign: false,
range: 3,
type: 2
})
);
});
test("matches only the metric named by one filter rule", () => {
expect(
matchesSpreadMetricRule(
{
averageDuration: "56",
finishRate: "28.24%",
interactionRate: "4.02%",
playMedian: "10913233"
interactionRate: "4.02%"
},
{
averageDuration: 50,
finishRate: 28,
interactionRate: 4,
playMedian: 10000000
config: {
flowType: 0,
onlyAssign: false,
range: 2,
type: 1
},
metric: "finishRate",
threshold: 28
}
)
).toBe(true);
expect(
matchesSpreadThresholds(
{
averageDuration: "56",
finishRate: "28.24%",
interactionRate: "4.02%",
playMedian: "10913233"
},
{
averageDuration: 57
}
)
).toBe(false);
expect(
matchesSpreadThresholds(
matchesSpreadMetricRule(
{
finishRate: "28.24%"
},
{
finishRate: 20,
interactionRate: 1
config: {
flowType: 0,
onlyAssign: false,
range: 2,
type: 1
},
metric: "interactionRate",
threshold: 1
}
)
).toBe(false);