Add "Loved it" modifier to rating picker
Any rating can now be combined with a "Loved it" toggle. The suffix |loved is appended to the rating string and parsed in normalize_refiner_v2_rating. When active: reward boosted to max(base, 0.85), axis pressure softened 50%, conditioning direction delta raised to 0.45, preferred context applied at 0.30 base_delta. Disabled for Perfect (redundant) and -Just forget it-. Button label shows ♥ when modifier is active. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
d7a1400239
commit
e9a1510db0
+21
-1
@@ -5719,10 +5719,18 @@ V2_RATING_ALIASES = {
|
||||
|
||||
|
||||
def normalize_refiner_v2_rating(value):
|
||||
loved_modifier = False
|
||||
if isinstance(value, str) and value.endswith("|loved"):
|
||||
value = value[:-6]
|
||||
loved_modifier = True
|
||||
if isinstance(value, str):
|
||||
cleaned = V2_RATING_ALIASES.get(value.strip(), value.strip())
|
||||
if cleaned in V2_RATING_PROFILES:
|
||||
return dict(V2_RATING_PROFILES[cleaned], label=cleaned)
|
||||
profile = dict(V2_RATING_PROFILES[cleaned], label=cleaned)
|
||||
if loved_modifier:
|
||||
profile["loved_modifier"] = True
|
||||
profile["reward"] = max(float(profile.get("reward", 0.0)), 0.85)
|
||||
return profile
|
||||
try:
|
||||
value = int(float(cleaned))
|
||||
except (TypeError, ValueError):
|
||||
@@ -8210,6 +8218,8 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
|
||||
elif rating_key == "nailed_it":
|
||||
delta = -0.10
|
||||
entry["forgiven_count"] = int(entry.get("forgiven_count", 0)) + 1
|
||||
elif rating_profile.get("loved_modifier"):
|
||||
delta *= 0.5 # soften axis pressure — quality was good, still try to fix it
|
||||
elif rating_key == "loved_it":
|
||||
continue # axis-blind quality endorsement — don't learn prompt adherence
|
||||
elif rating_key == "awful":
|
||||
@@ -8421,6 +8431,9 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
|
||||
elif rating_profile.get("key") == "nailed_it":
|
||||
positive_axes = {"action", "details"}
|
||||
base_delta = 0.65
|
||||
elif rating_profile.get("loved_modifier"):
|
||||
positive_axes = {"action", "details"}
|
||||
base_delta = 0.30
|
||||
elif rating_profile.get("key") == "loved_it":
|
||||
return "Preferred context: skipped for axis-blind quality endorsement."
|
||||
else:
|
||||
@@ -8612,6 +8625,13 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
|
||||
else:
|
||||
delta = 0.0
|
||||
count_category_evidence = False
|
||||
elif rating_profile.get("loved_modifier"):
|
||||
delta = 0.45 * kind_scale
|
||||
entry["liked_count"] = int(entry.get("liked_count", 0)) + 1
|
||||
rating_evidence["liked"] = int(rating_evidence.get("liked", 0)) + 1
|
||||
for category, score in effective_before.items():
|
||||
if float(score) >= 0.28:
|
||||
weights[category] = float(weights.get(category, 0.0)) + 0.10 * kind_scale
|
||||
elif rating_profile.get("key") == "nailed_it":
|
||||
delta = 0.35 * kind_scale
|
||||
entry["liked_count"] = int(entry.get("liked_count", 0)) + 1
|
||||
|
||||
@@ -108,7 +108,16 @@ function injectStyles() {
|
||||
.fp-picker-opt-reward { font-size: 10px; font-weight: 700; font-variant-numeric: tabular-nums; }
|
||||
.fp-picker-opt-hint { font-size: 9px; color: #888; line-height: 1.3; }
|
||||
.fp-picker-opt:hover .fp-picker-opt-hint { color: #aaa; }
|
||||
.fp-picker-nuclear { padding: 8px 10px; display: grid; grid-template-columns: 1fr 1fr; gap: 5px; }
|
||||
.fp-picker-nuclear { padding: 8px 10px 4px; display: grid; grid-template-columns: 1fr 1fr; gap: 5px; }
|
||||
.fp-picker-loved-row { padding: 6px 10px 8px; border-top: 1px solid rgba(255,255,255,0.06); }
|
||||
.fp-picker-loved-toggle {
|
||||
width: 100%; padding: 7px 10px; border-radius: 6px; cursor: pointer;
|
||||
font: 11px sans-serif; font-weight: 600; text-align: left;
|
||||
background: rgba(255,255,255,0.04); border: 1px solid rgba(255,120,180,0.25); color: #aaa;
|
||||
transition: background 0.1s, border-color 0.1s, color 0.1s;
|
||||
}
|
||||
.fp-picker-loved-toggle:hover { background: rgba(255,120,180,0.10); border-color: rgba(255,120,180,0.5); color: #eee; }
|
||||
.fp-picker-loved-toggle.active { background: rgba(255,120,180,0.18); border-color: rgba(255,120,180,0.75); color: #ffb3d4; }
|
||||
`;
|
||||
document.head.append(s);
|
||||
}
|
||||
@@ -157,6 +166,8 @@ function makeOption(r, currentValue, accent, onPick) {
|
||||
return btn;
|
||||
}
|
||||
|
||||
const NO_LOVED_LABELS = new Set(["Perfect", FORGET_LABEL]);
|
||||
|
||||
function openPicker(ratingWidget, event, onPick) {
|
||||
closePicker();
|
||||
injectStyles();
|
||||
@@ -176,7 +187,13 @@ function openPicker(ratingWidget, event, onPick) {
|
||||
header.append(closeBtn);
|
||||
picker.append(header);
|
||||
|
||||
const current = ratingWidget.value;
|
||||
const rawCurrent = ratingWidget.value || "";
|
||||
const currentLoved = rawCurrent.endsWith("|loved");
|
||||
const currentBase = currentLoved ? rawCurrent.slice(0, -6) : rawCurrent;
|
||||
|
||||
let lovedOn = currentLoved;
|
||||
|
||||
const buildLabel = (base) => NO_LOVED_LABELS.has(base) ? base : (lovedOn ? base + "|loved" : base);
|
||||
|
||||
// Category sections
|
||||
for (const cat of CATEGORIES) {
|
||||
@@ -191,7 +208,7 @@ function openPicker(ratingWidget, event, onPick) {
|
||||
|
||||
const grid = document.createElement("div");
|
||||
grid.className = cat.id === "positive" ? "fp-picker-positive-grid" : "fp-picker-grid";
|
||||
for (const r of cat.ratings) grid.append(makeOption(r, current, cat.accent, onPick));
|
||||
for (const r of cat.ratings) grid.append(makeOption(r, currentBase, cat.accent, (base) => onPick(buildLabel(base))));
|
||||
section.append(grid);
|
||||
picker.append(section);
|
||||
}
|
||||
@@ -200,9 +217,22 @@ function openPicker(ratingWidget, event, onPick) {
|
||||
const nuclearSection = document.createElement("div");
|
||||
nuclearSection.className = "fp-picker-nuclear";
|
||||
nuclearSection.style.setProperty("--accent", "140,100,100");
|
||||
for (const r of NUCLEAR) nuclearSection.append(makeOption(r, current, "140,100,100", onPick));
|
||||
for (const r of NUCLEAR) nuclearSection.append(makeOption(r, currentBase, "140,100,100", (base) => onPick(buildLabel(base))));
|
||||
picker.append(nuclearSection);
|
||||
|
||||
// Loved it toggle
|
||||
const lovedRow = document.createElement("div");
|
||||
lovedRow.className = "fp-picker-loved-row";
|
||||
const lovedToggle = document.createElement("button");
|
||||
lovedToggle.className = "fp-picker-loved-toggle" + (lovedOn ? " active" : "");
|
||||
lovedToggle.textContent = "♥ Loved it — great output regardless of prompt adherence";
|
||||
lovedToggle.addEventListener("click", () => {
|
||||
lovedOn = !lovedOn;
|
||||
lovedToggle.classList.toggle("active", lovedOn);
|
||||
});
|
||||
lovedRow.append(lovedToggle);
|
||||
picker.append(lovedRow);
|
||||
|
||||
document.body.append(picker);
|
||||
|
||||
// Position at mouse, clamped to viewport
|
||||
@@ -250,8 +280,10 @@ function setupRatingPicker(node) {
|
||||
hideWidget(ratingWidget);
|
||||
|
||||
const getLabel = () => {
|
||||
const v = ratingWidget.value;
|
||||
return (!v || v === FORGET_LABEL) ? "Waiting for rating..." : `Rating: ${v}`;
|
||||
const v = ratingWidget.value || "";
|
||||
if (!v || v === FORGET_LABEL) return "Waiting for rating...";
|
||||
if (v.endsWith("|loved")) return `Rating: ${v.slice(0, -6)} ♥`;
|
||||
return `Rating: ${v}`;
|
||||
};
|
||||
|
||||
node.widgets = (node.widgets || []).filter((w) => w.__fpPickerWidget !== true);
|
||||
@@ -280,6 +312,7 @@ function resetRating(node) {
|
||||
node.__fpPickerWidgetRef.name = "Waiting for rating...";
|
||||
node.setDirtyCanvas?.(true, true);
|
||||
}
|
||||
closePicker();
|
||||
}
|
||||
|
||||
// ─── Extension ────────────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user