2.5 KiB
Appointment Screenshot Date Handling
The date in appointment screenshots sits in the top middle (e.g., "Wednesday Jun 10, 2026"). All appointments in one screenshot are for the same day.
Current approach: User-selected date (no OCR date extraction)
The user picks the date via a date picker before scanning. The date is injected into the LLM system prompt so the AI never tries to extract it from garbled OCR text. This eliminates an entire Tesseract OCR pass (~30s savings) and frees tokens for better appointment extraction.
Date picker UI element
<div class="mb-4">
<label for="scan-appointment-date" class="...">Appointment Date</label>
<input type="date" id="scan-appointment-date" class="...">
<p class="text-xs text-purple-500 mt-1">All appointments in this screenshot are for this date.</p>
</div>
Located between the model selector and upload area in #scan-screenshot-modal.
Default to today
When the modal opens, the date picker defaults to today if not already set:
const dateInput = document.getElementById('scan-appointment-date');
if (dateInput && !dateInput.value) dateInput.value = new Date().toISOString().split('T')[0];
Reading in handleFile
const selectedDate = document.getElementById('scan-appointment-date')?.value
|| new Date().toISOString().split('T')[0];
System prompt injection
The LLM prompt includes the date explicitly so it never wastes tokens deciphering the header:
### ALL APPOINTMENTS ARE FOR: 2026-06-14
And rule #1 changed from "Find the date in the header..." to:
1. appointmentDate: Use "2026-06-14" for EVERY appointment. Do not read dates from the text.
The prompt is built with string concatenation: '...### ALL APPOINTMENTS ARE FOR: ' + selectedDate + '\n\n### COLUMN LAYOUT...'
Fallback in mapping
The final appointment mapping uses selectedDate as fallback:
appointmentDate: /^\d{4}-\d{2}-\d{2}$/.test(a.appointmentDate) ? a.appointmentDate : selectedDate,
Removed: Two-pass OCR date extraction
The previous approach (removed June 2026) used a second Tesseract pass with PSM 7 on a cropped top-20% image. This was fragile — OCR artifacts, wrong PSM, and table-row false positives made it unreliable. The user-picker approach is faster, more reliable, and simpler.
One remaining detail
The preprocessed object still creates a header blob during preprocessing (top 20% crop)
but it is no longer used. It can be cleaned up in a future refactor.