f0ck algos
This commit is contained in:
@@ -707,6 +707,103 @@ export default router => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
group.get(/\/recommendations(?:\/(?<type>videos|all))?$/, async (req, res) => {
|
||||
try {
|
||||
const limit = Math.min(+(req.url.qs?.limit || 20), 50);
|
||||
let mode = req.mode ?? 0;
|
||||
if (req.url.qs && req.url.qs.mode && ['0', '1', '2', '3'].includes(req.url.qs.mode)) {
|
||||
mode = parseInt(req.url.qs.mode);
|
||||
}
|
||||
const ratingsRaw = req.cookies.ratings;
|
||||
const ratingsArr = ratingsRaw ? decodeURIComponent(ratingsRaw).split(/[|,]/).filter(r => ['sfw','nsfw','nsfl','untagged'].includes(r)) : null;
|
||||
|
||||
const mime = req.params?.type === 'videos' ? 'video' : (req.url.qs?.mime || null);
|
||||
|
||||
let excludeIds = [];
|
||||
if (req.url.qs?.exclude_ids) {
|
||||
excludeIds = String(req.url.qs.exclude_ids).split(',').map(Number).filter(n => Number.isInteger(n) && n > 0).slice(0, 150);
|
||||
}
|
||||
|
||||
const sessionTags = req.url.qs?.session_tags || '';
|
||||
const sessionCreators = req.url.qs?.session_creators || '';
|
||||
|
||||
const items = await f0cklib.getPersonalizedRecommendations({
|
||||
limit,
|
||||
mode,
|
||||
ratings: ratingsArr,
|
||||
session: !!req.session,
|
||||
exclude: req.session?.excluded_tags || [],
|
||||
user_id: req.session?.id,
|
||||
is_admin: req.session?.admin,
|
||||
mime,
|
||||
exclude_ids: excludeIds,
|
||||
session_tags: sessionTags,
|
||||
session_creators: sessionCreators
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
items,
|
||||
videos: items
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("[RECOMMENDATIONS] Failed to fetch personalized recommendations:", err);
|
||||
res.json({
|
||||
success: false,
|
||||
items: [],
|
||||
videos: [],
|
||||
error: "Failed to load recommendations"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Track user behavioral signals (dwell time, completion, skips, suggestion clicks)
|
||||
group.post(/\/track\/interaction$/, async (req, res) => {
|
||||
try {
|
||||
let payload = req.post || {};
|
||||
if (!payload || Object.keys(payload).length === 0) {
|
||||
try {
|
||||
const body = await collectBody(req);
|
||||
if (body && body.length > 0) payload = JSON.parse(body.toString());
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
const itemId = parseInt(payload.item_id || payload.itemId, 10);
|
||||
if (!itemId) {
|
||||
return res.json({ success: false, error: "Invalid item_id" }, 400);
|
||||
}
|
||||
|
||||
const duration = parseFloat(payload.duration) || 0;
|
||||
const percent = parseFloat(payload.percent) || 0;
|
||||
const type = String(payload.type || 'dwell');
|
||||
|
||||
// Behavioral weighting: time spent is a primary signal
|
||||
let delta = 1.0;
|
||||
if (type === 'skip' || (duration < 2.5 && percent < 15)) {
|
||||
delta = -1.5;
|
||||
} else if (type === 'click_suggestion') {
|
||||
delta = 2.5;
|
||||
} else if (type === 'finish' || percent >= 75 || duration >= 20) {
|
||||
delta = 3.0;
|
||||
} else if (duration >= 8 || percent >= 35) {
|
||||
delta = 1.5;
|
||||
}
|
||||
|
||||
if (req.session?.id) {
|
||||
f0cklib.updateUserAffinity({
|
||||
user_id: req.session.id,
|
||||
item_id: itemId,
|
||||
scoreDelta: delta
|
||||
}).catch(err => console.error("[TRACK] Affinity update failed:", err));
|
||||
}
|
||||
|
||||
return res.json({ success: true, delta });
|
||||
} catch (err) {
|
||||
console.error("[TRACK] Interaction error:", err);
|
||||
return res.json({ success: false, error: "Tracking failed" }, 500);
|
||||
}
|
||||
});
|
||||
|
||||
group.get(/\/orakel\/user$/, async (req, res) => {
|
||||
try {
|
||||
@@ -1201,6 +1298,7 @@ export default router => {
|
||||
where user_id = ${+req.session.id}
|
||||
and item_id = ${+postid}
|
||||
`;
|
||||
f0cklib.updateUserAffinity({ user_id: req.session.id, item_id: +postid, scoreDelta: -5.0 }).catch(() => {});
|
||||
} else {
|
||||
// add fav — ON CONFLICT DO NOTHING guards against rapid double-taps
|
||||
await db`
|
||||
@@ -1210,6 +1308,7 @@ export default router => {
|
||||
}, 'item_id', 'user_id')}
|
||||
on conflict do nothing
|
||||
`;
|
||||
f0cklib.updateUserAffinity({ user_id: req.session.id, item_id: +postid, scoreDelta: 5.0 }).catch(() => {});
|
||||
}
|
||||
|
||||
const favs = await db`
|
||||
|
||||
Reference in New Issue
Block a user