74 lines
2.5 KiB
Markdown
74 lines
2.5 KiB
Markdown
# 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
|
|
|
|
```html
|
|
<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:
|
|
|
|
```js
|
|
const dateInput = document.getElementById('scan-appointment-date');
|
|
if (dateInput && !dateInput.value) dateInput.value = new Date().toISOString().split('T')[0];
|
|
```
|
|
|
|
### Reading in handleFile
|
|
|
|
```js
|
|
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:
|
|
|
|
```js
|
|
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.
|