fix(13-01): upgrade to gpt-4o, remove checkboxes, clamp AI coords to page bounds
- gpt-4o-mini replaced with gpt-4o for better placement accuracy - checkbox removed from schema enum and filtered in loop (positions are input-dependent) - y coordinate clamped to [0, pageHeight - fieldHeight] to prevent fields rendering outside the PDF canvas when AI returns yPct near 100% Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -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<string, string> = {};
|
||||
|
||||
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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user