/** 置入模式:超過此天數的貼文不適合留言推薦(求助通常已解決) */ export const PLACEMENT_MAX_POST_AGE_DAYS = 30; /** 置入黃金窗口:7 天內留言區仍活躍、需求多半未關閉 */ export const PLACEMENT_IDEAL_MAX_AGE_DAYS = 7; /** 網搜 after: 篩選用,略寬於黃金窗口以補足結果 */ export const PLACEMENT_WEB_SEARCH_MAX_AGE_DAYS = 14; /** 置入模式:Brave 網搜單次海巡最多查詢次數 */ export const PLACEMENT_WEB_SEARCH_MAX_QUERIES = 8; /** 置入模式:Brave 網搜找到足夠貼文後即停止 */ export const PLACEMENT_WEB_SEARCH_TARGET_POSTS = 20; /** 置入模式:Threads API/瀏覽器已找到足夠貼文時,跳過 Brave 網搜 */ export const PLACEMENT_WEB_SEARCH_SKIP_IF_POSTS = 15; /** 一般模式:Brave 網搜單次海巡最多查詢次數 */ export const DEFAULT_WEB_SEARCH_MAX_QUERIES = 12; export function postAgeDays(postedAt: Date, now = Date.now()): number { return (now - postedAt.getTime()) / (1000 * 60 * 60 * 24); } export function postAgeHours(postedAt: Date, now = Date.now()): number { return (now - postedAt.getTime()) / (1000 * 60 * 60); } export function isPostFreshEnough( postedAt: Date | null | undefined, maxAgeDays: number = PLACEMENT_MAX_POST_AGE_DAYS ): boolean { if (!postedAt) return true; return postAgeDays(postedAt) <= maxAgeDays; } /** 0–100:置入排序用,越近期分數越高 */ export function computePlacementRecencyScore( postedAt: Date | null | undefined, now = Date.now() ): number { if (!postedAt) return 35; const hours = postAgeHours(postedAt, now); if (hours <= 6) return 100; if (hours <= 24) return 95; if (hours <= 48) return 88; if (hours <= 72) return 80; const days = postAgeDays(postedAt, now); if (days <= PLACEMENT_IDEAL_MAX_AGE_DAYS) return 70; if (days <= 14) return 50; if (days <= PLACEMENT_MAX_POST_AGE_DAYS) return 30; return 0; } export function formatGoogleAfterDate(maxAgeDays: number, now = Date.now()): string { const date = new Date(now - maxAgeDays * 24 * 60 * 60 * 1000); const y = date.getUTCFullYear(); const m = String(date.getUTCMonth() + 1).padStart(2, "0"); const d = String(date.getUTCDate()).padStart(2, "0"); return `${y}-${m}-${d}`; } export function formatPostAgeLabel(postedAt?: Date | null): string { if (!postedAt) return "發文日期未知"; const days = Math.floor(postAgeDays(postedAt)); if (days <= 0) return "今天"; if (days === 1) return "昨天"; if (days < 7) return `${days} 天前`; if (days < 30) return `約 ${Math.floor(days / 7)} 週前`; return `${days} 天前`; } export function formatPlacementTimingHint(postedAt?: Date | null): string { if (!postedAt) return "發文時間未知(置入窗口不明,需保守評估)"; const hours = postAgeHours(postedAt); if (hours <= 24) return "剛發不久,置入窗口最佳"; if (hours <= 72) return "近 3 天內,置入窗口良好"; const days = Math.floor(postAgeDays(postedAt)); if (days <= PLACEMENT_IDEAL_MAX_AGE_DAYS) return "一週內,仍可置入"; if (days <= PLACEMENT_MAX_POST_AGE_DAYS) return "已超過一週,置入窗口收窄"; return "過舊,不建議置入"; }