mirror of
https://github.com/tiennm99/miti99bot.git
synced 2026-04-27 18:20:40 +00:00
fd5a1d2903
BGE embeddings occupy a narrow cone in vector space, so raw cosine of two unrelated words already sits at ~0.40-0.55. Displaying `raw * 100` made every random guess read as 40-70% warm, which defeated the warmth UX. format.js now applies a normalized sigmoid (FLOOR 0.40, CENTER 0.60, SCALE 8) to remap raw cosine → displayed 0-100. Unrelated pairs drop to ≤30, loose relation lands around 40-55, clear synonyms hit 85+, and exact match stays at 100. Emoji buckets were rebased onto the calibrated score; formatWarmth lost its sign column (calibrated output is always non-negative). render.js rounds once and feeds the integer to both formatWarmth and warmthEmoji so the display value and bucket stay in sync. Constants are empirical — retune if swapping to a non-BGE model.
92 lines
2.8 KiB
JavaScript
92 lines
2.8 KiB
JavaScript
import { describe, expect, it } from "vitest";
|
|
import { calibrate, formatWarmth, warmthEmoji } from "../../../src/modules/semantle/format.js";
|
|
|
|
describe("semantle/format", () => {
|
|
describe("calibrate", () => {
|
|
it("maps raw cosine <= floor to 0", () => {
|
|
expect(calibrate(0.4)).toBe(0);
|
|
expect(calibrate(0.2)).toBe(0);
|
|
expect(calibrate(-1)).toBe(0);
|
|
});
|
|
|
|
it("maps raw cosine = 1 to 100", () => {
|
|
expect(calibrate(1)).toBe(100);
|
|
});
|
|
|
|
it("is monotonically increasing between floor and 1", () => {
|
|
let prev = calibrate(0.4);
|
|
for (let r = 0.41; r <= 1.001; r += 0.02) {
|
|
const s = calibrate(r);
|
|
expect(s).toBeGreaterThanOrEqual(prev);
|
|
prev = s;
|
|
}
|
|
});
|
|
|
|
it("compresses mid-range cosines so unrelated-baseline reads low", () => {
|
|
// Unrelated BGE pairs cluster around 0.45-0.55 — should still look cold.
|
|
expect(calibrate(0.5)).toBeLessThan(25);
|
|
expect(calibrate(0.55)).toBeLessThan(35);
|
|
});
|
|
|
|
it("rewards clearly-related cosines with high scores", () => {
|
|
expect(calibrate(0.75)).toBeGreaterThan(70);
|
|
expect(calibrate(0.85)).toBeGreaterThan(85);
|
|
expect(calibrate(0.95)).toBeGreaterThan(95);
|
|
});
|
|
|
|
it("stays clamped to [0, 100]", () => {
|
|
expect(calibrate(2)).toBe(100);
|
|
expect(calibrate(-5)).toBe(0);
|
|
});
|
|
});
|
|
|
|
describe("formatWarmth", () => {
|
|
it("formats integer percent with zero-padding at width 2", () => {
|
|
expect(formatWarmth(0)).toBe("00");
|
|
expect(formatWarmth(7)).toBe("07");
|
|
expect(formatWarmth(73)).toBe("73");
|
|
});
|
|
|
|
it("returns '100' without padding at the max", () => {
|
|
expect(formatWarmth(100)).toBe("100");
|
|
});
|
|
|
|
it("rounds to nearest integer", () => {
|
|
expect(formatWarmth(50.4)).toBe("50");
|
|
expect(formatWarmth(50.5)).toBe("51");
|
|
expect(formatWarmth(99.5)).toBe("100");
|
|
});
|
|
});
|
|
|
|
describe("warmthEmoji", () => {
|
|
it("returns 🥶 for score < 15", () => {
|
|
expect(warmthEmoji(0)).toBe("🥶");
|
|
expect(warmthEmoji(14.9)).toBe("🥶");
|
|
});
|
|
|
|
it("returns 😐 for score in [15, 40)", () => {
|
|
expect(warmthEmoji(15)).toBe("😐");
|
|
expect(warmthEmoji(30)).toBe("😐");
|
|
expect(warmthEmoji(39.9)).toBe("😐");
|
|
});
|
|
|
|
it("returns 🌡️ for score in [40, 70)", () => {
|
|
expect(warmthEmoji(40)).toBe("🌡️");
|
|
expect(warmthEmoji(55)).toBe("🌡️");
|
|
expect(warmthEmoji(69.9)).toBe("🌡️");
|
|
});
|
|
|
|
it("returns 🔥 for score in [70, 90)", () => {
|
|
expect(warmthEmoji(70)).toBe("🔥");
|
|
expect(warmthEmoji(80)).toBe("🔥");
|
|
expect(warmthEmoji(89.9)).toBe("🔥");
|
|
});
|
|
|
|
it("returns 🎯 for score >= 90", () => {
|
|
expect(warmthEmoji(90)).toBe("🎯");
|
|
expect(warmthEmoji(99)).toBe("🎯");
|
|
expect(warmthEmoji(100)).toBe("🎯");
|
|
});
|
|
});
|
|
});
|