156 lines
3.5 KiB
TypeScript
156 lines
3.5 KiB
TypeScript
export type FetchRequestStatus =
|
|
| "pending"
|
|
| "processing"
|
|
| "paused"
|
|
| "raw_expenses_done"
|
|
| "enriched_done"
|
|
| "completed"
|
|
| "failed";
|
|
|
|
export type SourceType = "file" | "pdf" | "xlsx" | "csv" | "email";
|
|
|
|
export interface FileSource {
|
|
type?: SourceType;
|
|
path: string;
|
|
bank: string;
|
|
raw_lines?: string[];
|
|
txn_blocks?: Record<string, any>;
|
|
txn_dicts?: Record<string, any>[];
|
|
txn_dict_count?: number;
|
|
txn_dicts_count?: number;
|
|
}
|
|
|
|
export interface PdfSource extends FileSource {
|
|
type: "pdf";
|
|
}
|
|
|
|
export interface XlsxSource extends FileSource {
|
|
type: "xlsx";
|
|
}
|
|
|
|
export interface CsvSource extends FileSource {
|
|
type: "csv";
|
|
}
|
|
|
|
export interface EmailSource {
|
|
type: "email";
|
|
bank: string;
|
|
from_email?: string;
|
|
subject?: string;
|
|
raw_terms?: string[];
|
|
txn_dict_count?: number;
|
|
txn_dicts_count?: number;
|
|
}
|
|
|
|
export type PipelineType = "heuristic" | "llm" | "llama_parse";
|
|
|
|
export type TrustFallback = "amount" | "balance";
|
|
|
|
export interface FetchRequestCreate {
|
|
source: PdfSource | XlsxSource | CsvSource | EmailSource;
|
|
account_name: string;
|
|
pipeline?: PipelineType;
|
|
trust_fallback?: TrustFallback | null;
|
|
payor_username?: string;
|
|
start_date?: string;
|
|
end_date?: string;
|
|
}
|
|
|
|
export interface FetchRequestUpdate {
|
|
status?: FetchRequestStatus;
|
|
error_message?: string | null;
|
|
}
|
|
|
|
export interface FetchRequest extends FetchRequestCreate {
|
|
id: string;
|
|
status: FetchRequestStatus;
|
|
fingerprint: string;
|
|
completed_at?: string | null;
|
|
error_message?: string | null;
|
|
retry_count?: number;
|
|
created_at: string;
|
|
}
|
|
|
|
export interface UploadResult {
|
|
original_filename: string;
|
|
saved_as: string;
|
|
content_type: string;
|
|
url: string;
|
|
absolute_path: string;
|
|
}
|
|
|
|
export interface AmbiguityCandidate {
|
|
amount: number;
|
|
balance: number;
|
|
}
|
|
|
|
export interface PendingAmbiguity {
|
|
id: string;
|
|
fetch_request: string;
|
|
step_index?: number;
|
|
line: string;
|
|
ocr_amount: number;
|
|
ocr_balance: number;
|
|
prev_balance: number;
|
|
candidates: AmbiguityCandidate[];
|
|
chosen?: AmbiguityCandidate | null;
|
|
resolved_at?: string | null;
|
|
status: "pending" | "resolved";
|
|
created_at: string;
|
|
}
|
|
|
|
export interface ResolveAmbiguityPayload {
|
|
chosen: {
|
|
amount: number;
|
|
balance: number;
|
|
};
|
|
}
|
|
|
|
export type SSEEventStep =
|
|
| "load_content" | "raw_lines" | "txn_blocks" | "txn_dicts"
|
|
| "resume_extract" | "extract" | "paused" | "complete" | "enrich"
|
|
| "save_expenses" | "pipeline";
|
|
|
|
export type SSEEventStatus =
|
|
| "started" | "completed" | "skipped" | "paused" | "progress" | "failed";
|
|
|
|
export interface ProgressMessage {
|
|
lines?: number;
|
|
blocks?: number;
|
|
count?: number;
|
|
unit?: string;
|
|
raw_ocr_line?: string;
|
|
error?: string;
|
|
}
|
|
|
|
export interface SSEEvent {
|
|
step: SSEEventStep;
|
|
status: SSEEventStatus;
|
|
message: ProgressMessage;
|
|
}
|
|
|
|
export interface FetchRequestFilters {
|
|
status?: FetchRequestStatus[];
|
|
account_name?: string;
|
|
source_type?: SourceType;
|
|
}
|
|
|
|
export function formatApiError(err: any): string {
|
|
if (!err?.response) return err?.message || "Request failed";
|
|
const data = err.response.data;
|
|
const status = err.response.status;
|
|
|
|
if (status === 422 && Array.isArray(data?.detail)) {
|
|
return data.detail.map((d: any) => {
|
|
const field = d.loc?.filter((s: string) => s !== "body").pop() || "field";
|
|
if (d.type === "value_error.missing") return `Missing: ${field}`;
|
|
return `${field}: ${d.msg}`;
|
|
}).join("; ");
|
|
}
|
|
|
|
if (typeof data?.detail === "string") return data.detail;
|
|
return `Request failed (${status})`;
|
|
}
|
|
|
|
export const RETRY_MAX = 3;
|