From d2402c798c8d7575d07976cadc5c1c8190f7073e Mon Sep 17 00:00:00 2001 From: Maurice Date: Fri, 28 Aug 2026 13:57:50 +0200 Subject: [PATCH] fix(llm-parse): read an arrival that arrives as a bare clock again fixArrivalDate normalized the arrival and then looked for the time behind a leading date. The model usually sends the arrival as a bare clock, "13:00" with no date on it, and slicing ten characters off that leaves nothing to match, so the function returned early and stopped deriving the arrival date at all. Try the bare 12-hour form first, then fall back to the normalized string, which covers both shapes: "13:00", "01:11 pm", and a full date-time. --- .../llm-parse/router/extraction-router.ts | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/server/src/nest/llm-parse/router/extraction-router.ts b/server/src/nest/llm-parse/router/extraction-router.ts index 1a98d52bd..56dfadf3a 100644 --- a/server/src/nest/llm-parse/router/extraction-router.ts +++ b/server/src/nest/llm-parse/router/extraction-router.ts @@ -18,7 +18,7 @@ * existing `nuExtractToKiReservations` mapper, so nothing downstream changes. */ -import { normalizeLocalDateTime } from '@trek/shared'; +import { normalizeLocalDateTime, parseMeridiemClock } from '@trek/shared'; import type { KiReservation } from '../../booking-import/kitinerary.types'; import { nuExtractToKiReservations } from '../clients/nuextract'; import { FLAT_SCHEMA_BY_TYPE, FLAT_TYPES, FLIGHTS_ARRAY_SCHEMA, UNION_SINGLE_SCHEMA, type FlatType, type FlatLike } from './flat-schemas'; @@ -151,17 +151,16 @@ export function extractTotalPrice(text: string): { price: string; currency?: str */ export function fixArrivalDate(flat: FlatLike): FlatLike { if (!TRANSPORT_TYPES.includes(flat.type)) return flat; - // Both sides go through the 12-hour normalizer first. Reading the arrival - // with a bare /(\d{2}:\d{2})/ used to throw a trailing "PM" away, and the - // comparison below is lexicographic: "04:00" < "12:40" rolled a 13:11 - // arrival onto the next day and turned a short hop into an overnight (#2094). - const depSource = normalizeLocalDateTime(String(flat.departure_time ?? '')); - const arrSource = normalizeLocalDateTime(String(flat.arrival_time ?? '')); - const dep = /(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2})/.exec(depSource); - const arr = /(\d{2}:\d{2})/.exec(arrSource.slice(10)); - if (!dep || !arr) return flat; + const dep = /(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2})/.exec(normalizeLocalDateTime(String(flat.departure_time ?? ''))); + // The arrival reaches us either as a bare clock ("13:00", "01:11 pm") or as a + // full date-time, so try the bare form first and fall back to the normalized + // string. Reading it with a plain /(\d{2}:\d{2})/ used to throw a trailing + // "PM" away, and the comparison below is lexicographic: "01:11" sorts before + // a 09:51 departure, so a short hop was rolled onto the next day (#2094). + const rawArr = String(flat.arrival_time ?? '').trim(); + const arrTime = parseMeridiemClock(rawArr) ?? /(\d{2}:\d{2})/.exec(normalizeLocalDateTime(rawArr))?.[1]; + if (!dep || !arrTime) return flat; const [, depDate, depTime] = dep; - const arrTime = arr[1]; const d = new Date(`${depDate}T00:00:00Z`); if (arrTime < depTime) d.setUTCDate(d.getUTCDate() + 1); flat.arrival_time = `${d.toISOString().slice(0, 10)}T${arrTime}:00`;