feat: add support for relative time parsing in reminder command
This commit is contained in:
@@ -13,6 +13,66 @@ function humanizeDate(d: Date) {
|
|||||||
return d.toLocaleString('es-ES', { timeZone: 'UTC', hour12: false });
|
return d.toLocaleString('es-ES', { timeZone: 'UTC', hour12: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function parseRelativeDelay(text: string): { when: Date, reminderText: string } | null {
|
||||||
|
const lower = text.toLowerCase();
|
||||||
|
|
||||||
|
// 1) "en menos de 1h" -> 59 minutos
|
||||||
|
let m = lower.match(/en\s+menos\s+de\s+1\s*h(ora(s)?)?/i);
|
||||||
|
if (m) {
|
||||||
|
const minutes = 59;
|
||||||
|
const when = new Date(Date.now() + minutes * 60 * 1000);
|
||||||
|
const reminderText = text.replace(m[0], '').trim() || text;
|
||||||
|
return { when, reminderText };
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) "en menos de X min" -> (X-1) minutos
|
||||||
|
m = lower.match(/en\s+menos\s+de\s+(\d+)\s*m(in(utos)?)?/i);
|
||||||
|
if (m) {
|
||||||
|
const minutes = Math.max(1, parseInt(m[1], 10) - 1);
|
||||||
|
const when = new Date(Date.now() + minutes * 60 * 1000);
|
||||||
|
const reminderText = text.replace(m[0], '').trim() || text;
|
||||||
|
return { when, reminderText };
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3) "en X minutos" / "en Xm"
|
||||||
|
m = lower.match(/en\s+(\d+)\s*m(in(utos)?)?/i);
|
||||||
|
if (m) {
|
||||||
|
const minutes = Math.max(1, parseInt(m[1], 10));
|
||||||
|
const when = new Date(Date.now() + minutes * 60 * 1000);
|
||||||
|
const reminderText = text.replace(m[0], '').trim() || text;
|
||||||
|
return { when, reminderText };
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4) "en X horas" / "en Xh"
|
||||||
|
m = lower.match(/en\s+(\d+)\s*h(ora(s)?)?/i);
|
||||||
|
if (m) {
|
||||||
|
const hours = Math.max(1, parseInt(m[1], 10));
|
||||||
|
const when = new Date(Date.now() + hours * 60 * 60 * 1000);
|
||||||
|
const reminderText = text.replace(m[0], '').trim() || text;
|
||||||
|
return { when, reminderText };
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5) Post-fijo corto: "15m" o "45 min" al final
|
||||||
|
m = lower.match(/(\d+)\s*m(in(utos)?)?$/i);
|
||||||
|
if (m) {
|
||||||
|
const minutes = Math.max(1, parseInt(m[1], 10));
|
||||||
|
const when = new Date(Date.now() + minutes * 60 * 1000);
|
||||||
|
const reminderText = text.slice(0, m.index).trim() || text;
|
||||||
|
return { when, reminderText };
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6) Post-fijo corto: "1h" o "2 horas" al final
|
||||||
|
m = lower.match(/(\d+)\s*h(ora(s)?)?$/i);
|
||||||
|
if (m) {
|
||||||
|
const hours = Math.max(1, parseInt(m[1], 10));
|
||||||
|
const when = new Date(Date.now() + hours * 60 * 60 * 1000);
|
||||||
|
const reminderText = text.slice(0, m.index).trim() || text;
|
||||||
|
return { when, reminderText };
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
export const command: CommandMessage = {
|
export const command: CommandMessage = {
|
||||||
name: 'recordar',
|
name: 'recordar',
|
||||||
type: 'message',
|
type: 'message',
|
||||||
@@ -32,39 +92,46 @@ export const command: CommandMessage = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parsear en español, forzando fechas futuras cuando sea ambiguo
|
// 1) Soporte rápido para tiempos relativos: "en 10 minutos", "15m", "1h", "en menos de 1h"
|
||||||
|
const rel = parseRelativeDelay(text);
|
||||||
|
let when: Date | null = null;
|
||||||
|
let reminderText = text;
|
||||||
|
if (rel) {
|
||||||
|
when = rel.when;
|
||||||
|
reminderText = rel.reminderText;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) Si no hubo match relativo, usar parser natural (chrono) en español
|
||||||
|
if (!when) {
|
||||||
const ref = new Date();
|
const ref = new Date();
|
||||||
const results = chrono.es.parse(text, ref, { forwardDate: true });
|
const results = chrono.es.parse(text, ref, { forwardDate: true });
|
||||||
if (!results.length) {
|
if (!results.length) {
|
||||||
await message.reply('❌ No pude entender cuándo. Intenta algo como: "mañana 9am", "el miércoles 17:00", "en 2 horas".');
|
await message.reply('❌ No pude entender cuándo. Intenta algo como: "en 10 minutos", "mañana 9am", "el miércoles 17:00".');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const r = results[0];
|
const r = results[0];
|
||||||
const when = r.date();
|
when = r.date();
|
||||||
|
|
||||||
if (!when || isNaN(when.getTime())) {
|
if (!when || isNaN(when.getTime())) {
|
||||||
await message.reply('❌ La fecha/hora no es válida.');
|
await message.reply('❌ La fecha/hora no es válida.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Evitar fechas pasadas
|
|
||||||
if (when.getTime() <= Date.now()) {
|
|
||||||
await message.reply('❌ La fecha/hora ya pasó. Especifica una fecha futura.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extraer el texto del recordatorio eliminando el fragmento reconocido de fecha
|
// Extraer el texto del recordatorio eliminando el fragmento reconocido de fecha
|
||||||
const matched = r.text || '';
|
const matched = r.text || '';
|
||||||
let reminderText = text;
|
|
||||||
if (matched) {
|
if (matched) {
|
||||||
const idx = text.toLowerCase().indexOf(matched.toLowerCase());
|
const idx = text.toLowerCase().indexOf(matched.toLowerCase());
|
||||||
if (idx >= 0) {
|
if (idx >= 0) {
|
||||||
reminderText = (text.slice(0, idx) + text.slice(idx + matched.length)).trim();
|
reminderText = (text.slice(0, idx) + text.slice(idx + matched.length)).trim() || text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Si quedó vacío, usar el texto completo
|
}
|
||||||
if (!reminderText) reminderText = text;
|
|
||||||
|
// Validaciones de futuro y límites mínimos
|
||||||
|
if (when.getTime() <= Date.now() + 20 * 1000) { // al menos 20s al futuro
|
||||||
|
await message.reply('❌ Especifica un tiempo al futuro (al menos ~20 segundos).');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Guardar en Appwrite
|
// Guardar en Appwrite
|
||||||
const iso = new Date(when.getTime()).toISOString();
|
const iso = new Date(when.getTime()).toISOString();
|
||||||
@@ -86,4 +153,3 @@ export const command: CommandMessage = {
|
|||||||
await message.reply(`✅ Recordatorio guardado para: ${whenHuman} UTC\nMensaje: ${reminderText}`);
|
await message.reply(`✅ Recordatorio guardado para: ${whenHuman} UTC\nMensaje: ${reminderText}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user