180 lines
6.3 KiB
TypeScript
180 lines
6.3 KiB
TypeScript
import type { DocumentType, ExtractionFormState, FieldSelection, ManifestEntry, SchemaResponse } from "../../shared/types";
|
|
import { splitRadicados } from "./pathMapping";
|
|
|
|
export function parseTiffRange(form: Pick<ExtractionFormState, "tiffEnabled" | "tiffStart" | "tiffEnd">): [number, number] | undefined {
|
|
if (!form.tiffEnabled) return undefined;
|
|
const start = Number.parseInt(form.tiffStart || "0", 10);
|
|
const end = Number.parseInt(form.tiffEnd || "0", 10);
|
|
if (!Number.isFinite(start) || !Number.isFinite(end) || start < 0 || end < 0) {
|
|
throw new Error("El rango TIFF debe usar numeros enteros mayores o iguales a 0.");
|
|
}
|
|
if (start === 0 && end === 0) return undefined;
|
|
if (end < start) {
|
|
throw new Error("La pagina final TIFF no puede ser menor que la inicial.");
|
|
}
|
|
return [start, end];
|
|
}
|
|
|
|
export function validDocTypes(docTypes: DocumentType[]): DocumentType[] {
|
|
return docTypes
|
|
.map((item) => ({ name: item.name.trim(), keyword: item.keyword.trim() }))
|
|
.filter((item) => item.name && item.keyword);
|
|
}
|
|
|
|
export function appendTiffRange(form: ExtractionFormState, formData: FormData): void {
|
|
const tiffRange = parseTiffRange(form);
|
|
if (!tiffRange) return;
|
|
formData.set("tiff_start", String(tiffRange[0]));
|
|
formData.set("tiff_end", String(tiffRange[1]));
|
|
}
|
|
|
|
export function buildSchemaUploadForm(
|
|
form: ExtractionFormState,
|
|
file: Blob,
|
|
filename: string,
|
|
docTypeName?: string,
|
|
): FormData {
|
|
const payload = new FormData();
|
|
payload.append("file", file, filename);
|
|
payload.append("structure_mode", form.mode);
|
|
if (docTypeName) payload.append("doc_type_name", docTypeName);
|
|
appendTiffRange(form, payload);
|
|
return payload;
|
|
}
|
|
|
|
export function buildDesktopBatchPayload(
|
|
form: ExtractionFormState,
|
|
selection: FieldSelection,
|
|
manifest: ManifestEntry[],
|
|
model?: string,
|
|
): Record<string, unknown> {
|
|
const tiffRange = parseTiffRange(form);
|
|
const documents = manifest.map((entry) => ({
|
|
radicado: entry.radicado,
|
|
filename: entry.filename,
|
|
doc_type: entry.docType || null,
|
|
}));
|
|
const uniqueRadicados = new Set(manifest.map((entry) => entry.radicado));
|
|
|
|
const payload: Record<string, unknown> = {
|
|
source: "desktop",
|
|
fields: selection.fields,
|
|
alias_map: selection.aliasMap,
|
|
tiff_page_range: tiffRange,
|
|
structure_mode: form.mode,
|
|
retry_on_empty: form.retryOnEmpty,
|
|
documents,
|
|
document_count: uniqueRadicados.size || documents.length,
|
|
model: model || null,
|
|
};
|
|
|
|
if (form.mode === "radicados") {
|
|
payload.doc_types = validDocTypes(form.docTypes);
|
|
if (form.filterEnabled) {
|
|
const allowed = new Set(splitRadicados(form.radicadoFilterText));
|
|
payload.documents = documents.filter((item) => allowed.has(String(item.radicado)));
|
|
payload.document_count = new Set((payload.documents as Array<{ radicado: string }>).map((item) => item.radicado)).size;
|
|
}
|
|
}
|
|
return payload;
|
|
}
|
|
|
|
export function buildEstimateUploadForm(
|
|
form: ExtractionFormState,
|
|
file: Blob,
|
|
filename: string,
|
|
docCount: number,
|
|
selectedPaths: string[],
|
|
model?: string,
|
|
): FormData {
|
|
const payload = new FormData();
|
|
payload.append("file", file, filename);
|
|
payload.append("doc_count", String(Math.max(1, docCount)));
|
|
payload.append("structure_mode", form.mode);
|
|
payload.append("selected_paths", JSON.stringify(selectedPaths));
|
|
if (model) payload.append("model", model);
|
|
appendTiffRange(form, payload);
|
|
return payload;
|
|
}
|
|
|
|
export function buildEstimatePayload(form: ExtractionFormState, schema: SchemaResponse | null, selection: FieldSelection): Record<string, unknown> {
|
|
const base = {
|
|
root_path: form.selectedLocalPath || "desktop://upload",
|
|
structure_mode: form.mode,
|
|
};
|
|
if (form.mode === "radicados") {
|
|
return {
|
|
...base,
|
|
doc_types: validDocTypes(form.docTypes),
|
|
schema_by_type: schema?.schema_by_type,
|
|
selected_paths: selection.fields,
|
|
};
|
|
}
|
|
return {
|
|
...base,
|
|
schema: schema?.schema,
|
|
selected_fields: selection.fields,
|
|
};
|
|
}
|
|
|
|
export function flattenSchema(response: SchemaResponse): { schema: Record<string, string>; sample: unknown } {
|
|
if (response.schema) return { schema: response.schema, sample: response.sample };
|
|
const schema: Record<string, string> = {};
|
|
for (const [typeName, fields] of Object.entries(response.schema_by_type || {})) {
|
|
for (const [path, kind] of Object.entries(fields || {})) {
|
|
schema[`${typeName}/${path}`] = kind;
|
|
}
|
|
}
|
|
const sample = {
|
|
radicado: response.first_radicado,
|
|
...(response.sample_by_type || {}),
|
|
};
|
|
return { schema, sample };
|
|
}
|
|
|
|
export function mergeSchemaResponses(responses: SchemaResponse[]): SchemaResponse {
|
|
if (responses.length === 1) return responses[0];
|
|
const merged: SchemaResponse = {};
|
|
const schemaByType: Record<string, Record<string, string>> = {};
|
|
const sampleByType: Record<string, unknown> = {};
|
|
for (const response of responses) {
|
|
if (response.schema) {
|
|
return response;
|
|
}
|
|
for (const [typeName, fields] of Object.entries(response.schema_by_type || {})) {
|
|
schemaByType[typeName] = fields;
|
|
sampleByType[typeName] = response.sample_by_type?.[typeName];
|
|
}
|
|
if (response.first_radicado) merged.first_radicado = response.first_radicado;
|
|
}
|
|
merged.schema_by_type = schemaByType;
|
|
merged.sample_by_type = sampleByType;
|
|
return merged;
|
|
}
|
|
|
|
export function buildIngestForm(entry: ManifestEntry, file: Blob): FormData {
|
|
const form = new FormData();
|
|
form.append("file", file, entry.filename);
|
|
form.append("radicado", entry.radicado);
|
|
form.append("filename", entry.filename);
|
|
if (entry.docType) form.append("doc_type", entry.docType);
|
|
return form;
|
|
}
|
|
|
|
/**
|
|
* Construye un FormData multipart para /tasks/{id}/ingest-many.
|
|
* Envia N archivos en una sola peticion HTTP, con los metadatos
|
|
* (radicados, filenames, doc_types) como listas separadas por "|"
|
|
* en el mismo orden posicional que los archivos.
|
|
*/
|
|
export function buildIngestFormBulk(entries: ManifestEntry[], files: Blob[]): FormData {
|
|
const form = new FormData();
|
|
entries.forEach((entry, index) => {
|
|
form.append("files", files[index], entry.filename);
|
|
});
|
|
form.append("radicados", entries.map((entry) => entry.radicado).join("|"));
|
|
form.append("filenames", entries.map((entry) => entry.filename).join("|"));
|
|
form.append("doc_types", entries.map((entry) => entry.docType || "").join("|"));
|
|
return form;
|
|
}
|