import { parseTimeScope } from '../temporal-recall-service/time-parser.mjs'; export const RAIN_DEFAULT_DAYS = 3; const TZ_OFFSET_MIN = Number(process.env.TEMPORAL_RECALL_TZ_OFFSET_MIN ?? 480); /** @param {Date} anchor @param {number} deltaDays */ function addDays(anchor, deltaDays) { const shifted = new Date(anchor.getTime() + TZ_OFFSET_MIN * 60_000); const ms = Date.UTC( shifted.getUTCFullYear(), shifted.getUTCMonth(), shifted.getUTCDate() + deltaDays, 0, 0, 0, 0, ) - TZ_OFFSET_MIN * 60_000; return new Date(ms); } /** @param {Date} anchor */ function endOfDay(anchor) { const p = new Date(anchor.getTime() + TZ_OFFSET_MIN * 60_000); const ms = Date.UTC(p.getUTCFullYear(), p.getUTCMonth(), p.getUTCDate() + 1, 0, 0, 0, 0) - TZ_OFFSET_MIN * 60_000; return new Date(ms); } const AMBIGUOUS_TIME_PATTERNS = [ /前几天/u, /那段(?:时间|日子)/u, /上次(?:那)?(?:段|个)/u, /大概.{0,6}(?:昨天|前天|上周|几)/u, /左右/u, /不太确定.{0,8}时间/u, ]; const EXPLICIT_TIME_HINT = /昨天|昨日|今天|今日|明天|明日|前天|后天|上周|这周|本周|这个月|本月|上个月|\d{1,2}\s*月|\d{1,2}\s*[::]\d{2}|最近\s*\d+\s*天|最近一周|最近1周|\d{4}-\d{2}-\d{2}/u; /** * @param {string} query * @param {Date} [now] */ export function resolveRainTimeRange(query, now = new Date()) { const text = String(query ?? '').trim(); for (const pattern of AMBIGUOUS_TIME_PATTERNS) { if (pattern.test(text)) { return { needsClarification: true, clarificationQuestion: '请说明要分析 MeInput 输入记录的起止时间(例如「9月2日 18:00 到 9月4日 10:00」,或「昨天全天」)。若你不补充,我将默认使用近 3 天。', range: null, source: 'ambiguous', label: null, }; } } if (!EXPLICIT_TIME_HINT.test(text)) { const end = endOfDay(now); const start = addDays(now, -RAIN_DEFAULT_DAYS); return { needsClarification: false, range: { start: start.toISOString(), end: end.toISOString() }, source: 'default_3d', label: `近${RAIN_DEFAULT_DAYS}天`, }; } const scope = parseTimeScope(text, now); const isDefaultFallback = scope.rule_hits?.includes('time:default_week') || scope.rule_hits?.includes('time:recent_fuzzy'); if (isDefaultFallback && /最近|近期|这几天/u.test(text) && !/最近\s*\d+\s*天/u.test(text)) { const end = endOfDay(now); const start = addDays(now, -RAIN_DEFAULT_DAYS); return { needsClarification: false, range: { start: start.toISOString(), end: end.toISOString() }, source: 'default_3d', label: `近${RAIN_DEFAULT_DAYS}天`, }; } return { needsClarification: false, range: scope.mention_range, source: 'user_explicit', label: scope.relative_label, }; } export function formatRainTimeRangeLabel(range, meta = {}) { if (!range?.start || !range?.end) return meta.label ?? '未指定'; const start = range.start.slice(0, 16).replace('T', ' '); const end = range.end.slice(0, 16).replace('T', ' '); const suffix = meta.source === 'default_3d' ? '(默认近3天)' : ''; return `${start} ~ ${end}${suffix}`; }