From f7f899dce7c0d474f44e1b45989fbd7895a591da Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 29 Jan 2026 19:00:18 +0000 Subject: [PATCH] fix: Simplify PDF filling - use fillable fields directly The previous approach was overcomplicated with LaTeX templates. Now the system simply: 1. Detects PDF form fields (AcroForm) 2. Sends field names to Gemini for data extraction 3. Gemini returns 'key' matching exact PDF field names 4. Fields are filled directly in the original PDF Removed: - LaTeX template detection logic - G2210-specific field definitions - Complex mode switching The fillable PDF approach is simpler and more reliable. https://claude.ai/code/session_016pQhdznHZ74Fpkvwr3cLBq --- components/ReviewPanel.tsx | 306 +++++++++---------------------------- services/geminiService.ts | 165 ++++---------------- 2 files changed, 104 insertions(+), 367 deletions(-) diff --git a/components/ReviewPanel.tsx b/components/ReviewPanel.tsx index 60aae8d..b064188 100644 --- a/components/ReviewPanel.tsx +++ b/components/ReviewPanel.tsx @@ -1,8 +1,7 @@ -import React, { useState, useEffect, useMemo, useCallback } from 'react'; +import React, { useState, useEffect, useMemo } from 'react'; import { ExtractedField, FileData } from '../types'; -import { Check, Edit2, Download, RefreshCw, FileText, AlertTriangle, XCircle, ArrowRight, PenTool, CheckCircle2, Circle, FileCode, Loader2 } from 'lucide-react'; +import { Check, Edit2, Download, RefreshCw, FileText, AlertTriangle, XCircle, ArrowRight, PenTool, CheckCircle2, Circle, FileCheck } from 'lucide-react'; import { createFilledPdf } from '../services/pdfService'; -import { generateLatexPdf, isLatexServiceAvailable, detectTemplate, base64ToBlob } from '../services/latexService'; import { jsPDF } from "jspdf"; interface ReviewPanelProps { @@ -14,8 +13,6 @@ interface ReviewPanelProps { onReset: () => void; } -type PdfMode = 'overlay' | 'fillable' | 'latex'; - export const ReviewPanel: React.FC = ({ fields: initialFields, formFile, @@ -28,80 +25,28 @@ export const ReviewPanel: React.FC = ({ const [activeField, setActiveField] = useState(null); const [previewUrl, setPreviewUrl] = useState(null); const [filterMode, setFilterMode] = useState<'ALL' | 'ATTENTION'>('ALL'); - const [latexAvailable, setLatexAvailable] = useState(null); - const [pdfMode, setPdfMode] = useState(isFillablePdf ? 'fillable' : 'overlay'); - const [isGenerating, setIsGenerating] = useState(false); - const [latexPdfBase64, setLatexPdfBase64] = useState(null); - - // Detect template from form file name - const detectedTemplate = useMemo(() => detectTemplate(formFile.file.name), [formFile.file.name]); - - // Check LaTeX service availability on mount - useEffect(() => { - const checkLatex = async () => { - const available = await isLatexServiceAvailable(); - setLatexAvailable(available); - // Auto-switch to LaTeX mode if available and template detected - if (available && detectedTemplate && !isFillablePdf) { - setPdfMode('latex'); - } - }; - checkLatex(); - }, [detectedTemplate, isFillablePdf]); // Derived state for progress const verifiedCount = fields.filter(f => f.isVerified).length; const totalCount = fields.length; const progressPercent = Math.round((verifiedCount / totalCount) * 100); - - const fieldsRequiresAttention = useMemo(() => - fields.filter(f => f.validation?.status !== 'VALID'), + + const fieldsRequiresAttention = useMemo(() => + fields.filter(f => f.validation?.status !== 'VALID'), [fields]); - // Generate LaTeX PDF - const generateLatexPreview = useCallback(async () => { - if (!detectedTemplate || pdfMode !== 'latex') return; - - setIsGenerating(true); - try { - const result = await generateLatexPdf(detectedTemplate, fields); - if (result.success && result.pdf) { - setLatexPdfBase64(result.pdf); - const blob = base64ToBlob(result.pdf); - const url = URL.createObjectURL(blob); - setPreviewUrl(url); - } else { - console.error('LaTeX generation failed:', result.error); - // Fallback to overlay mode - setPdfMode('overlay'); - } - } catch (e) { - console.error('LaTeX generation error:', e); - setPdfMode('overlay'); - } finally { - setIsGenerating(false); - } - }, [detectedTemplate, fields, pdfMode]); - - // Generate preview + // Generate preview - fills the original PDF directly useEffect(() => { const updatePreview = async () => { - // LaTeX mode - handled separately with button click - if (pdfMode === 'latex') { - // Only auto-generate if we don't have a preview yet - if (!latexPdfBase64) { - generateLatexPreview(); - } - return; - } - if (formFile.type === 'application/pdf') { try { - const filledPdfBytes = await createFilledPdf(formFile.base64, fields, pdfMode === 'fillable'); + const filledPdfBytes = await createFilledPdf(formFile.base64, fields, isFillablePdf); const blob = new Blob([filledPdfBytes], { type: 'application/pdf' }); const url = URL.createObjectURL(blob); - setPreviewUrl(url); - return () => URL.revokeObjectURL(url); + setPreviewUrl(prev => { + if (prev) URL.revokeObjectURL(prev); + return url; + }); } catch (e) { console.error("Failed to generate PDF preview", e); } @@ -110,17 +55,15 @@ export const ReviewPanel: React.FC = ({ } }; - // Debounce slightly to avoid rapid updates on typing - const timer = setTimeout(updatePreview, 600); + const timer = setTimeout(updatePreview, 500); return () => clearTimeout(timer); - }, [fields, pdfMode, formFile.base64, formFile.type, latexPdfBase64, generateLatexPreview]); + }, [fields, isFillablePdf, formFile.base64, formFile.type, formFile.previewUrl]); const handleUpdate = (index: number, newValue: string) => { const newFields = [...fields]; - newFields[index] = { - ...newFields[index], + newFields[index] = { + ...newFields[index], value: newValue, - // Auto-verify when manually edited isVerified: true, validation: { ...newFields[index].validation!, status: 'VALID', message: 'Manually verified' } }; @@ -129,9 +72,9 @@ export const ReviewPanel: React.FC = ({ const toggleVerify = (index: number) => { const newFields = [...fields]; - newFields[index] = { - ...newFields[index], - isVerified: !newFields[index].isVerified + newFields[index] = { + ...newFields[index], + isVerified: !newFields[index].isVerified }; setFields(newFields); }; @@ -144,30 +87,6 @@ export const ReviewPanel: React.FC = ({ }; const handleDownload = async () => { - // LaTeX mode - regenerate fresh PDF for download - if (pdfMode === 'latex' && detectedTemplate) { - setIsGenerating(true); - try { - const result = await generateLatexPdf(detectedTemplate, fields); - if (result.success && result.pdf) { - const blob = base64ToBlob(result.pdf); - const url = URL.createObjectURL(blob); - const a = document.createElement('a'); - a.href = url; - a.download = `${detectedTemplate}_filled.pdf`; - document.body.appendChild(a); - a.click(); - document.body.removeChild(a); - URL.revokeObjectURL(url); - } else { - alert(`PDF generation failed: ${result.error}`); - } - } finally { - setIsGenerating(false); - } - return; - } - if (formFile.type === 'application/pdf' && previewUrl) { const a = document.createElement('a'); a.href = previewUrl; @@ -187,25 +106,15 @@ export const ReviewPanel: React.FC = ({ } }; - // Regenerate LaTeX preview - const handleRegenerateLatex = () => { - setLatexPdfBase64(null); - generateLatexPreview(); - }; - // Sort: Unverified/Issues first, then verified const displayedFields = fields.map((f, i) => ({ ...f, originalIndex: i })) .sort((a, b) => { - // Priority 1: Attention needed const aNeedsAttn = a.validation?.status !== 'VALID'; const bNeedsAttn = b.validation?.status !== 'VALID'; if (aNeedsAttn && !bNeedsAttn) return -1; if (!aNeedsAttn && bNeedsAttn) return 1; - - // Priority 2: Unverified if (!a.isVerified && b.isVerified) return -1; if (a.isVerified && !b.isVerified) return 1; - return a.originalIndex - b.originalIndex; }) .filter(f => filterMode === 'ALL' || (f.validation?.status !== 'VALID' && !f.isVerified)); @@ -218,106 +127,61 @@ export const ReviewPanel: React.FC = ({

Review & Verify

{summary}

- +
- {/* Verification Progress */}
{verifiedCount} / {totalCount} Verified
-
- - +
- {/* Left Column: Visual Reference */} + {/* Left Column: PDF Preview */}
Preview - {pdfMode === 'latex' && ( + {isFillablePdf ? ( - - LaTeX Template Mode + + Fillable PDF - )} - {pdfMode === 'overlay' && ( - + ) : ( + - Visual Overlay Mode - - )} - {pdfMode === 'fillable' && ( - - - Fillable PDF Mode + Visual Overlay )}
-
- {/* Mode Switcher */} - {latexAvailable && detectedTemplate && ( - - )} - {pdfMode === 'latex' && ( - - )} - {formFile.file.name} -
+ {formFile.file.name}
- {isGenerating && pdfMode === 'latex' ? ( -
- -

Generating LaTeX PDF...

-

Compiling template with your data

-
- ) : previewUrl ? ( - formFile.type === 'application/pdf' || pdfMode === 'latex' ? ( + {previewUrl ? ( + formFile.type === 'application/pdf' ? (