Template mapping and detect issue fixed
This commit is contained in:
16
check_matches.py
Normal file
16
check_matches.py
Normal 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
26
debug_match.py
Normal 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}")
|
||||
@@ -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(
|
||||
"/{template_id}/mappings/save",
|
||||
response_model=SuccessResponse,
|
||||
@@ -109,6 +166,15 @@ def save_mappings(
|
||||
table_repo = TableFormatRepository(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)
|
||||
cell_map = {c.field_name: c for c in cells}
|
||||
table_format = None
|
||||
|
||||
@@ -145,6 +145,11 @@ class FingerprintService:
|
||||
if not template.table_formats:
|
||||
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 {
|
||||
"items": [
|
||||
{
|
||||
@@ -156,15 +161,36 @@ class FingerprintService:
|
||||
"rows": tf.rows,
|
||||
"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:
|
||||
"""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:
|
||||
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 {
|
||||
"items": [
|
||||
{
|
||||
@@ -215,44 +241,49 @@ class FingerprintService:
|
||||
weights.append(3.0)
|
||||
|
||||
# Logo coordinates similarity
|
||||
logo_score = self._compare_coordinates(
|
||||
fingerprint1.logo_coordinates,
|
||||
fingerprint2_data.get("logo_coordinates"),
|
||||
)
|
||||
scores.append(logo_score)
|
||||
weights.append(2.0)
|
||||
if fingerprint1.logo_coordinates and fingerprint1.logo_coordinates.get("items"):
|
||||
logo_score = self._compare_coordinates(
|
||||
fingerprint1.logo_coordinates,
|
||||
fingerprint2_data.get("logo_coordinates"),
|
||||
)
|
||||
scores.append(logo_score)
|
||||
weights.append(2.0)
|
||||
|
||||
# Header coordinates similarity
|
||||
header_score = self._compare_coordinates(
|
||||
fingerprint1.header_coordinates,
|
||||
fingerprint2_data.get("header_coordinates"),
|
||||
)
|
||||
scores.append(header_score)
|
||||
weights.append(2.0)
|
||||
if fingerprint1.header_coordinates and fingerprint1.header_coordinates.get("items"):
|
||||
header_score = self._compare_coordinates(
|
||||
fingerprint1.header_coordinates,
|
||||
fingerprint2_data.get("header_coordinates"),
|
||||
)
|
||||
scores.append(header_score)
|
||||
weights.append(2.0)
|
||||
|
||||
# Footer coordinates similarity
|
||||
footer_score = self._compare_coordinates(
|
||||
fingerprint1.footer_coordinates,
|
||||
fingerprint2_data.get("footer_coordinates"),
|
||||
)
|
||||
scores.append(footer_score)
|
||||
weights.append(1.5)
|
||||
if fingerprint1.footer_coordinates and fingerprint1.footer_coordinates.get("items"):
|
||||
footer_score = self._compare_coordinates(
|
||||
fingerprint1.footer_coordinates,
|
||||
fingerprint2_data.get("footer_coordinates"),
|
||||
)
|
||||
scores.append(footer_score)
|
||||
weights.append(1.5)
|
||||
|
||||
# Table coordinates similarity
|
||||
table_score = self._compare_coordinates(
|
||||
fingerprint1.table_coordinates,
|
||||
fingerprint2_data.get("table_coordinates"),
|
||||
)
|
||||
scores.append(table_score)
|
||||
weights.append(2.5)
|
||||
if fingerprint1.table_coordinates and fingerprint1.table_coordinates.get("items"):
|
||||
table_score = self._compare_coordinates(
|
||||
fingerprint1.table_coordinates,
|
||||
fingerprint2_data.get("table_coordinates"),
|
||||
)
|
||||
scores.append(table_score)
|
||||
weights.append(2.0)
|
||||
|
||||
# Cell coordinates similarity
|
||||
cell_score = self._compare_coordinates(
|
||||
fingerprint1.cell_coordinates,
|
||||
fingerprint2_data.get("cell_coordinates"),
|
||||
)
|
||||
scores.append(cell_score)
|
||||
weights.append(1.5)
|
||||
if fingerprint1.cell_coordinates and fingerprint1.cell_coordinates.get("items"):
|
||||
cell_score = self._compare_coordinates(
|
||||
fingerprint1.cell_coordinates,
|
||||
fingerprint2_data.get("cell_coordinates"),
|
||||
)
|
||||
scores.append(cell_score)
|
||||
weights.append(1.5)
|
||||
|
||||
# Weighted average
|
||||
total_weight = sum(weights)
|
||||
|
||||
@@ -81,8 +81,12 @@ export class TemplateService {
|
||||
);
|
||||
}
|
||||
|
||||
createTemplate(data: { template_name: string, source_document_id?: string, fields: TemplateField[] }): Observable<Template> {
|
||||
return this.http.post<Template>(`${this.apiUrl}/templates`, data);
|
||||
createTemplate(payload: any): Observable<any> {
|
||||
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> {
|
||||
|
||||
@@ -47,6 +47,9 @@ export class TemplatesComponent implements OnInit {
|
||||
|
||||
// UI State
|
||||
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 };
|
||||
fieldTypes = [
|
||||
{ label: 'TEXT', value: 'TEXT' },
|
||||
@@ -67,6 +70,11 @@ export class TemplatesComponent implements OnInit {
|
||||
onFileUpload(event: any) {
|
||||
const file = event.target.files[0];
|
||||
if (file) {
|
||||
this.currentTemplateId = null;
|
||||
this.templateName = '';
|
||||
this.templateFields = [];
|
||||
this.mappings = {};
|
||||
|
||||
this.templateService.uploadDocument(file).subscribe({
|
||||
next: (res) => {
|
||||
this.documentId = res.id || res.pk_document_id;
|
||||
@@ -126,11 +134,12 @@ export class TemplatesComponent implements OnInit {
|
||||
const match = matches[0];
|
||||
this.messageService.add({ severity: 'info', summary: 'Template Recognized', detail: `Confidence: ${(match.confidence_score * 100).toFixed(1)}%` });
|
||||
|
||||
this.templateService.getTemplate(match.format_id).subscribe({
|
||||
next: (templateData) => {
|
||||
this.templateName = templateData.name;
|
||||
this.templateFields = [];
|
||||
this.mappings = {};
|
||||
this.templateService.getTemplate(match.format_id).subscribe({
|
||||
next: (templateData) => {
|
||||
this.templateName = templateData.name;
|
||||
this.currentTemplateId = match.format_id;
|
||||
this.templateFields = [];
|
||||
this.mappings = {};
|
||||
|
||||
if (templateData.cells) {
|
||||
templateData.cells.forEach((cell: any) => {
|
||||
@@ -221,11 +230,17 @@ export class TemplatesComponent implements OnInit {
|
||||
return;
|
||||
}
|
||||
|
||||
this.templateService.createTemplate({
|
||||
const payload = {
|
||||
template_name: this.templateName,
|
||||
source_document_id: this.documentId || undefined,
|
||||
fields: this.templateFields
|
||||
}).subscribe({
|
||||
};
|
||||
|
||||
const saveRequest = this.currentTemplateId
|
||||
? this.templateService.updateTemplate(this.currentTemplateId, payload)
|
||||
: this.templateService.createTemplate(payload);
|
||||
|
||||
saveRequest.subscribe({
|
||||
next: (res: any) => {
|
||||
const templateId = res.pk_template_id;
|
||||
|
||||
|
||||
14
print_cells.py
Normal file
14
print_cells.py
Normal 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
13
print_fp.py
Normal 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
18
print_fp2.py
Normal 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!")
|
||||
21
regenerate_fingerprints.py
Normal file
21
regenerate_fingerprints.py
Normal 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.")
|
||||
Reference in New Issue
Block a user