diff --git a/teressa-copeland-homes/src/lib/ai/field-placement.ts b/teressa-copeland-homes/src/lib/ai/field-placement.ts index df65324..b9dc808 100644 --- a/teressa-copeland-homes/src/lib/ai/field-placement.ts +++ b/teressa-copeland-homes/src/lib/ai/field-placement.ts @@ -43,7 +43,10 @@ export function aiCoordsToPagePdfSpace( const x = screenX; // PDF y = distance from BOTTOM. screenY is from top, so flip: // pdfY = pageHeight - screenY - fieldHeight (bottom edge of field) - const y = pageHeight - screenY - fieldHeight; + // Clamp to [0, pageHeight - fieldHeight] so AI coords near page edges + // don't produce negative y values that render outside the canvas. + const rawY = pageHeight - screenY - fieldHeight; + const y = Math.max(0, Math.min(rawY, pageHeight - fieldHeight)); return { x, y, width: fieldWidth, height: fieldHeight }; } @@ -60,7 +63,7 @@ const FIELD_PLACEMENT_SCHEMA = { type: 'object', properties: { page: { type: 'integer' }, - fieldType: { type: 'string', enum: ['text', 'checkbox', 'initials', 'date', 'client-signature', 'agent-signature', 'agent-initials'] }, + fieldType: { type: 'string', enum: ['text', 'initials', 'date', 'client-signature', 'agent-signature', 'agent-initials'] }, xPct: { type: 'number' }, yPct: { type: 'number' }, // % from page TOP (AI top-left origin) widthPct: { type: 'number' }, @@ -102,16 +105,18 @@ export async function classifyFieldsWithAI( .join('\n\n'); const response = await openai.chat.completions.create({ - model: 'gpt-4o-mini', + model: 'gpt-4o', messages: [ { role: 'system', content: `You are a real estate document form field extractor. Given extracted text from a PDF page (with context about page number and dimensions), -identify where signature, text, checkbox, initials, and date fields should be placed. +identify where signature, initials, text, and date fields should be placed. Return fields as percentage positions (0-100) from the TOP-LEFT of the page. -Use these field types: text (for typed values), checkbox, initials, date, client-signature, agent-signature, agent-initials. -For text fields that match the client profile, set prefillValue to the known value. Otherwise use empty string.`, +Use these field types: text (for typed values), initials, date, client-signature, agent-signature, agent-initials. +Only place fields where the document clearly requires them — prefer fewer, high-confidence placements. +For text fields that match the client name or property address, set prefillValue to the known value. Otherwise use empty string. +Do NOT place checkbox fields.`, }, { role: 'user', @@ -135,16 +140,17 @@ For text fields that match the client profile, set prefillValue to the known val const textFillData: Record = {}; for (const aiField of raw.fields) { + // Never place checkboxes — positions depend on user input and can't be AI-determined + if (aiField.fieldType === 'checkbox') continue; + const pageInfo = pageTexts.find((p) => p.page === aiField.page); const pageWidth = pageInfo?.width ?? 612; // fallback: US Letter const pageHeight = pageInfo?.height ?? 792; const { x, y } = aiCoordsToPagePdfSpace(aiField, pageWidth, pageHeight); - // Use standard sizes regardless of AI width/height — consistent with FieldPlacer defaults - const isCheckbox = aiField.fieldType === 'checkbox'; - const width = isCheckbox ? 24 : 144; // pts: checkbox=24x24, others=144x36 - const height = isCheckbox ? 24 : 36; + const width = 144; // pts: 2 inches + const height = 36; // pts: 0.5 inches const id = crypto.randomUUID();