Template mapping and detect issue fixed

This commit is contained in:
2026-07-14 13:59:00 +05:30
parent 460a1c5c51
commit 360022820d
10 changed files with 264 additions and 40 deletions

16
check_matches.py Normal file
View File

@@ -0,0 +1,16 @@
import sys
import os
sys.path.append(os.path.join(os.getcwd(), 'docengine'))
from app.core.database import SessionLocal
from app.models.document import TemplateMatch
from app.models.template import DocumentFormat
db = SessionLocal()
matches = db.query(TemplateMatch).order_by(TemplateMatch.created_at.desc()).limit(10).all()
print(f"Found {len(matches)} matches.")
for m in matches:
fmt = db.query(DocumentFormat).filter(DocumentFormat.id == m.format_id).first()
fmt_name = fmt.name if fmt else 'Unknown'
print(f"Match: doc_id={m.document_id}, format_id={m.format_id}, name={fmt_name}, score={m.confidence_score}")
print(f"Details: {m.match_details}")

26
debug_match.py Normal file
View File

@@ -0,0 +1,26 @@
import sys
import os
sys.path.append(os.path.join(os.getcwd(), 'docengine'))
from app.core.database import SessionLocal
from app.models.document import Document
from app.services.matching_service import MatchingService
db = SessionLocal()
doc = db.query(Document).order_by(Document.created_at.desc()).first()
if not doc:
print("No documents found.")
sys.exit(0)
print(f"Latest document: {doc.id} (status: {doc.status})")
svc = MatchingService(db)
try:
# Match with min_confidence=0.0 so it returns EVERYTHING
matches = svc.match_document(doc.id, min_confidence=0.0)
print(f"Returned {len(matches)} matches.")
for m in matches:
print(f"Match: format_id={m.format_id}, score={m.confidence_score}")
print(f"Details: {m.match_details}")
except Exception as e:
print(f"Error matching: {e}")

View File

@@ -83,6 +83,63 @@ def create_template(
} }
@router.put(
"/{template_id}",
response_model=dict,
summary="Update Template",
description="Update an existing template name and its fields.",
)
def update_template(
template_id: uuid.UUID,
payload: TemplateCreateRequest,
current_user: CurrentUser,
db: Session = Depends(get_db),
) -> dict:
"""Update a template."""
template_repo = TemplateRepository(db)
template = template_repo.get_by_id(template_id)
if not template:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Template '{template_id}' not found",
)
if template.name != payload.template_name:
template.name = payload.template_name
from app.models.template import DocumentCell
db.query(DocumentCell).filter(DocumentCell.format_id == template_id).delete()
saved_fields = []
cell_repo = DocumentCellRepository(db)
for index, field in enumerate(payload.fields):
cell = cell_repo.create_cell(
format_id=template.id,
page_number=1,
row_no=0,
column_no=0,
field_name=field.field_label,
data_type=field.field_type,
x=0.0,
y=0.0,
width=0.0,
height=0.0,
is_dynamic=True
)
saved_fields.append({
"field_label": cell.field_name,
"field_type": cell.data_type
})
db.commit()
return {
"pk_template_id": str(template.id),
"template_name": template.name,
"fields": saved_fields
}
@router.post( @router.post(
"/{template_id}/mappings/save", "/{template_id}/mappings/save",
response_model=SuccessResponse, response_model=SuccessResponse,
@@ -109,6 +166,15 @@ def save_mappings(
table_repo = TableFormatRepository(db) table_repo = TableFormatRepository(db)
table_col_repo = TableColumnRepository(db) table_col_repo = TableColumnRepository(db)
# Delete existing field mappings and table formats for this template
from app.models.template import DocumentRegion, TableFormat
db.query(DocumentRegion).filter(
DocumentRegion.format_id == template_id,
DocumentRegion.region_type == "field_mapping"
).delete()
db.query(TableFormat).filter(TableFormat.format_id == template_id).delete()
db.flush()
cells = cell_repo.get_template_cells(template_id) cells = cell_repo.get_template_cells(template_id)
cell_map = {c.field_name: c for c in cells} cell_map = {c.field_name: c for c in cells}
table_format = None table_format = None

View File

@@ -145,6 +145,11 @@ class FingerprintService:
if not template.table_formats: if not template.table_formats:
return None return None
# Filter out dummy tables created by manual mappings (width=1000, height=1000)
valid_tables = [tf for tf in template.table_formats if tf.width != 1000.0 and tf.height != 1000.0]
if not valid_tables:
return None
return { return {
"items": [ "items": [
{ {
@@ -156,15 +161,36 @@ class FingerprintService:
"rows": tf.rows, "rows": tf.rows,
"columns": tf.columns, "columns": tf.columns,
} }
for tf in template.table_formats for tf in valid_tables
] ]
} }
def _extract_cell_coordinates(self, template: DocumentFormat) -> dict[str, Any] | None: def _extract_cell_coordinates(self, template: DocumentFormat) -> dict[str, Any] | None:
"""Extract cell coordinates from template.""" """Extract cell coordinates from template."""
# For manually mapped templates, prefer the actual mapped regions
field_regions = [r for r in template.regions if r.region_type == "field_mapping"]
if field_regions:
return {
"items": [
{
"page": r.page_number,
"x": r.x,
"y": r.y,
"width": r.width,
"height": r.height,
}
for r in field_regions
]
}
# Otherwise fallback to template cells, but skip if they are all 0,0 (unmapped placeholders)
if not template.cells: if not template.cells:
return None return None
has_real_coords = any(c.width > 0 or c.height > 0 for c in template.cells)
if not has_real_coords:
return None
return { return {
"items": [ "items": [
{ {
@@ -215,6 +241,7 @@ class FingerprintService:
weights.append(3.0) weights.append(3.0)
# Logo coordinates similarity # Logo coordinates similarity
if fingerprint1.logo_coordinates and fingerprint1.logo_coordinates.get("items"):
logo_score = self._compare_coordinates( logo_score = self._compare_coordinates(
fingerprint1.logo_coordinates, fingerprint1.logo_coordinates,
fingerprint2_data.get("logo_coordinates"), fingerprint2_data.get("logo_coordinates"),
@@ -223,6 +250,7 @@ class FingerprintService:
weights.append(2.0) weights.append(2.0)
# Header coordinates similarity # Header coordinates similarity
if fingerprint1.header_coordinates and fingerprint1.header_coordinates.get("items"):
header_score = self._compare_coordinates( header_score = self._compare_coordinates(
fingerprint1.header_coordinates, fingerprint1.header_coordinates,
fingerprint2_data.get("header_coordinates"), fingerprint2_data.get("header_coordinates"),
@@ -231,6 +259,7 @@ class FingerprintService:
weights.append(2.0) weights.append(2.0)
# Footer coordinates similarity # Footer coordinates similarity
if fingerprint1.footer_coordinates and fingerprint1.footer_coordinates.get("items"):
footer_score = self._compare_coordinates( footer_score = self._compare_coordinates(
fingerprint1.footer_coordinates, fingerprint1.footer_coordinates,
fingerprint2_data.get("footer_coordinates"), fingerprint2_data.get("footer_coordinates"),
@@ -239,14 +268,16 @@ class FingerprintService:
weights.append(1.5) weights.append(1.5)
# Table coordinates similarity # Table coordinates similarity
if fingerprint1.table_coordinates and fingerprint1.table_coordinates.get("items"):
table_score = self._compare_coordinates( table_score = self._compare_coordinates(
fingerprint1.table_coordinates, fingerprint1.table_coordinates,
fingerprint2_data.get("table_coordinates"), fingerprint2_data.get("table_coordinates"),
) )
scores.append(table_score) scores.append(table_score)
weights.append(2.5) weights.append(2.0)
# Cell coordinates similarity # Cell coordinates similarity
if fingerprint1.cell_coordinates and fingerprint1.cell_coordinates.get("items"):
cell_score = self._compare_coordinates( cell_score = self._compare_coordinates(
fingerprint1.cell_coordinates, fingerprint1.cell_coordinates,
fingerprint2_data.get("cell_coordinates"), fingerprint2_data.get("cell_coordinates"),

View File

@@ -81,8 +81,12 @@ export class TemplateService {
); );
} }
createTemplate(data: { template_name: string, source_document_id?: string, fields: TemplateField[] }): Observable<Template> { createTemplate(payload: any): Observable<any> {
return this.http.post<Template>(`${this.apiUrl}/templates`, data); return this.http.post<any>(`${this.apiUrl}/templates`, payload);
}
updateTemplate(templateId: string, payload: any): Observable<any> {
return this.http.put<any>(`${this.apiUrl}/templates/${templateId}`, payload);
} }
saveMappings(templateId: string, mappings: any[]): Observable<any> { saveMappings(templateId: string, mappings: any[]): Observable<any> {

View File

@@ -47,6 +47,9 @@ export class TemplatesComponent implements OnInit {
// UI State // UI State
displayAddField: boolean = false; displayAddField: boolean = false;
isScanning: boolean = false;
scanProgress: number = 0;
currentTemplateId: string | null = null;
newField: TemplateField = { field_label: '', field_type: 'TEXT', display_order: 0, required_flag: false }; newField: TemplateField = { field_label: '', field_type: 'TEXT', display_order: 0, required_flag: false };
fieldTypes = [ fieldTypes = [
{ label: 'TEXT', value: 'TEXT' }, { label: 'TEXT', value: 'TEXT' },
@@ -67,6 +70,11 @@ export class TemplatesComponent implements OnInit {
onFileUpload(event: any) { onFileUpload(event: any) {
const file = event.target.files[0]; const file = event.target.files[0];
if (file) { if (file) {
this.currentTemplateId = null;
this.templateName = '';
this.templateFields = [];
this.mappings = {};
this.templateService.uploadDocument(file).subscribe({ this.templateService.uploadDocument(file).subscribe({
next: (res) => { next: (res) => {
this.documentId = res.id || res.pk_document_id; this.documentId = res.id || res.pk_document_id;
@@ -129,6 +137,7 @@ export class TemplatesComponent implements OnInit {
this.templateService.getTemplate(match.format_id).subscribe({ this.templateService.getTemplate(match.format_id).subscribe({
next: (templateData) => { next: (templateData) => {
this.templateName = templateData.name; this.templateName = templateData.name;
this.currentTemplateId = match.format_id;
this.templateFields = []; this.templateFields = [];
this.mappings = {}; this.mappings = {};
@@ -221,11 +230,17 @@ export class TemplatesComponent implements OnInit {
return; return;
} }
this.templateService.createTemplate({ const payload = {
template_name: this.templateName, template_name: this.templateName,
source_document_id: this.documentId || undefined, source_document_id: this.documentId || undefined,
fields: this.templateFields fields: this.templateFields
}).subscribe({ };
const saveRequest = this.currentTemplateId
? this.templateService.updateTemplate(this.currentTemplateId, payload)
: this.templateService.createTemplate(payload);
saveRequest.subscribe({
next: (res: any) => { next: (res: any) => {
const templateId = res.pk_template_id; const templateId = res.pk_template_id;

14
print_cells.py Normal file
View File

@@ -0,0 +1,14 @@
import sys
import os
sys.path.append(os.path.join(os.getcwd(), 'docengine'))
from app.core.database import SessionLocal
from app.models.template import DocumentFormat
db = SessionLocal()
t = db.query(DocumentFormat).filter(DocumentFormat.is_active == True).first()
if t:
print(f"Template Name: {t.name}")
print(f"Number of cells: {len(t.cells)}")
for c in t.cells:
print(f"Cell: x={c.x}, y={c.y}, w={c.width}, h={c.height}")

13
print_fp.py Normal file
View File

@@ -0,0 +1,13 @@
import sys
import os
sys.path.append(os.path.join(os.getcwd(), 'docengine'))
from app.core.database import SessionLocal
from app.models.template import DocumentFormat
db = SessionLocal()
t = db.query(DocumentFormat).filter(DocumentFormat.is_active == True).first()
if t:
print(f"Template Name: {t.name}, Fingerprint is None: {t.fingerprint is None}")
else:
print("No active templates.")

18
print_fp2.py Normal file
View File

@@ -0,0 +1,18 @@
import sys
import os
import json
sys.path.append(os.path.join(os.getcwd(), 'docengine'))
from app.core.database import SessionLocal
from app.models.template import TemplateFingerprint
from app.models.template import DocumentFormat
db = SessionLocal()
t = db.query(DocumentFormat).filter(DocumentFormat.is_active == True).first()
if t:
fp = db.query(TemplateFingerprint).filter(TemplateFingerprint.format_id == t.id).first()
if fp:
print(f"Cell Coords items: {len(fp.cell_coordinates.get('items', [])) if fp.cell_coordinates else 'None'}")
print(json.dumps(fp.cell_coordinates, indent=2))
else:
print("No TemplateFingerprint row found!")

View File

@@ -0,0 +1,21 @@
import sys
import os
sys.path.append(os.path.join(os.getcwd(), 'docengine'))
from app.core.database import SessionLocal
from app.models.template import DocumentFormat
from app.services.fingerprint_service import FingerprintService
db = SessionLocal()
templates = db.query(DocumentFormat).filter(DocumentFormat.is_active == True).all()
fp_service = FingerprintService(db)
count = 0
for t in templates:
# Refresh the relations
db.refresh(t)
fp_service.generate_fingerprint(t)
count += 1
db.commit()
print(f"Regenerated fingerprints for {count} active templates.")