aditya0103 commited on
Commit
8c75a7a
·
1 Parent(s): 6267e20

fix(ci): unblock UI job — anchor gitignore, include ui/src/libLast CI's Cannot find module @/lib/api (and @/lib/samples) turned outto be a gitignore over-match, not a tsconfig issue. .gitignore had barelib/ and lib64/ from its Python section — those aren't anchored, sothey silently matched ui/src/lib/ too, and neither api.ts nor samples.tsever made it into a commit. CI's fresh clone had an empty ui/src/lib/,tsc -b failed on the missing modules, docker-build gated behind and skipped.- .gitignore: anchor lib/ and lib64/ to repo root as /lib/, /lib64/- Force-add ui/src/lib/api.ts + ui/src/lib/samples.ts- Cascading fix: 'Parameter s implicitly has any' in Dropzone was because samples.ts couldn't resolve, so SampleDoc type didn't flow into the SAMPLE_DOCS.map callback. Present-again = inferred-again.

Browse files
Files changed (3) hide show
  1. .gitignore +2 -2
  2. ui/src/lib/api.ts +65 -0
  3. ui/src/lib/samples.ts +41 -0
.gitignore CHANGED
@@ -18,8 +18,8 @@ dist/
18
  downloads/
19
  eggs/
20
  .eggs/
21
- lib/
22
- lib64/
23
  parts/
24
  sdist/
25
  var/
 
18
  downloads/
19
  eggs/
20
  .eggs/
21
+ /lib/
22
+ /lib64/
23
  parts/
24
  sdist/
25
  var/
ui/src/lib/api.ts ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Thin fetch client for the FastAPI backend.
3
+ *
4
+ * Dev: Vite proxies /api/* to http://localhost:8000. See vite.config.ts.
5
+ * Prod: set VITE_API_BASE to your deployed API's origin.
6
+ */
7
+ import type { APIErrorEnvelope, DocType, ExtractResponse } from "@/types";
8
+
9
+ const API_BASE = (import.meta.env.VITE_API_BASE as string | undefined) ?? "/api";
10
+
11
+ export class APIError extends Error {
12
+ code: string;
13
+ requestId?: string | null;
14
+ details?: Record<string, unknown>;
15
+
16
+ constructor(envelope: APIErrorEnvelope["error"]) {
17
+ super(envelope.message);
18
+ this.code = envelope.code;
19
+ this.requestId = envelope.request_id;
20
+ this.details = envelope.details;
21
+ }
22
+ }
23
+
24
+ async function parseError(res: Response): Promise<never> {
25
+ let envelope: APIErrorEnvelope | null = null;
26
+ try {
27
+ envelope = (await res.json()) as APIErrorEnvelope;
28
+ } catch {
29
+ /* body wasn't JSON */
30
+ }
31
+ if (envelope?.error) throw new APIError(envelope.error);
32
+ throw new APIError({ code: `http_${res.status}`, message: res.statusText });
33
+ }
34
+
35
+ export interface ExtractArgs {
36
+ file: File;
37
+ docType: DocType;
38
+ model?: string;
39
+ }
40
+
41
+ export async function extract({ file, docType, model }: ExtractArgs): Promise<ExtractResponse> {
42
+ const form = new FormData();
43
+ form.append("file", file, file.name);
44
+ form.append("doc_type", docType);
45
+ if (model) form.append("model", model);
46
+
47
+ const res = await fetch(`${API_BASE}/extract`, {
48
+ method: "POST",
49
+ body: form,
50
+ });
51
+ if (!res.ok) await parseError(res);
52
+ return (await res.json()) as ExtractResponse;
53
+ }
54
+
55
+ export async function listSchemas(): Promise<{ doc_types: string[] }> {
56
+ const res = await fetch(`${API_BASE}/schemas`);
57
+ if (!res.ok) await parseError(res);
58
+ return await res.json();
59
+ }
60
+
61
+ export async function health(): Promise<{ status: string }> {
62
+ const res = await fetch(`${API_BASE}/health`);
63
+ if (!res.ok) await parseError(res);
64
+ return await res.json();
65
+ }
ui/src/lib/samples.ts ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Sample documents surfaced as one-click "Try it" buttons on the landing page.
3
+ * Each sample points at a file in /public/samples/ that ships with the frontend.
4
+ */
5
+
6
+ import type { DocType } from "@/types";
7
+
8
+ export interface SampleDoc {
9
+ id: string;
10
+ label: string;
11
+ docType: DocType;
12
+ path: string;
13
+ description: string;
14
+ }
15
+
16
+ export const SAMPLE_DOCS: SampleDoc[] = [
17
+ {
18
+ id: "coffee-receipt",
19
+ label: "Coffee receipt",
20
+ docType: "receipt",
21
+ path: "/samples/coffee_receipt.png",
22
+ description: "A short cafe receipt — merchant, total, tax.",
23
+ },
24
+ {
25
+ id: "software-invoice",
26
+ label: "Software invoice",
27
+ docType: "invoice",
28
+ path: "/samples/software_invoice.pdf",
29
+ description: "A B2B software invoice with line items and net-30 terms.",
30
+ },
31
+ ];
32
+
33
+ export async function loadSampleAsFile(sample: SampleDoc): Promise<File> {
34
+ const res = await fetch(sample.path);
35
+ if (!res.ok) {
36
+ throw new Error(`Failed to load sample: ${sample.path}`);
37
+ }
38
+ const blob = await res.blob();
39
+ const filename = sample.path.split("/").pop() ?? "sample";
40
+ return new File([blob], filename, { type: blob.type });
41
+ }