@littlebigbrain/create 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/LICENSE +55 -0
  2. package/README.md +73 -2
  3. package/bin/create-littlebigbrain.mjs +9 -0
  4. package/lib/create.mjs +244 -0
  5. package/package.json +46 -4
  6. package/project/setup.ts +18 -0
  7. package/project/try.ts +30 -0
  8. package/project/worker.ts +23 -0
  9. package/templates/_shared/testing.ts +521 -0
  10. package/templates/documents-link/README.md +146 -0
  11. package/templates/documents-link/link.ts +580 -0
  12. package/templates/documents-link/samples/ausstattungsliste.pdf +76 -0
  13. package/templates/documents-link/samples/baubeschreibung.pdf +54 -0
  14. package/templates/documents-link/samples/expected.json +404 -0
  15. package/templates/documents-link/samples/pages/ausstattungsliste.json +1150 -0
  16. package/templates/documents-link/samples/pages/baubeschreibung.json +802 -0
  17. package/templates/documents-link/samples/pages/raumblaetter.json +1580 -0
  18. package/templates/documents-link/samples/raumblaetter.pdf +109 -0
  19. package/templates/documents-link/samples.ts +31 -0
  20. package/templates/documents-link/workflow.test.ts +497 -0
  21. package/templates/documents-link/workflow.ts +467 -0
  22. package/templates/documents-map/README.md +212 -0
  23. package/templates/documents-map/map.ts +1135 -0
  24. package/templates/documents-map/samples/ausstattungsliste.pdf +76 -0
  25. package/templates/documents-map/samples/baubeschreibung.pdf +54 -0
  26. package/templates/documents-map/samples/expected.json +50 -0
  27. package/templates/documents-map/samples/pages/raumblaetter.json +1580 -0
  28. package/templates/documents-map/samples/raumblaetter.pdf +109 -0
  29. package/templates/documents-map/samples/trace.json +613 -0
  30. package/templates/documents-map/samples.ts +182 -0
  31. package/templates/documents-map/workflow.test.ts +770 -0
  32. package/templates/documents-map/workflow.ts +1199 -0
  33. package/templates/ontology-fit/README.md +81 -0
  34. package/templates/ontology-fit/samples/expected.md +88 -0
  35. package/templates/ontology-fit/samples/texts.json +22 -0
  36. package/templates/ontology-fit/samples.ts +40 -0
  37. package/templates/ontology-fit/workflow.test.ts +270 -0
  38. package/templates/ontology-fit/workflow.ts +416 -0
  39. package/templates/review/README.md +158 -0
  40. package/templates/review/decision.ts +483 -0
  41. package/templates/review/samples/expected.json +37 -0
  42. package/templates/review/samples/proposals.json +35 -0
  43. package/templates/review/samples.ts +154 -0
  44. package/templates/review/workflow.test.ts +438 -0
  45. package/templates/review/workflow.ts +459 -0
  46. package/templates/values-extract/README.md +81 -0
  47. package/templates/values-extract/samples/expected.json +148 -0
  48. package/templates/values-extract/samples/records.json +26 -0
  49. package/templates/values-extract/samples.ts +27 -0
  50. package/templates/values-extract/workflow.test.ts +279 -0
  51. package/templates/values-extract/workflow.ts +419 -0
  52. package/templates/versions.json +3 -0
@@ -0,0 +1,182 @@
1
+ // The samples of documents-map, for `npm run try`: the three PDFs of the invented school building
2
+ // tender of documents-link, and the trace a correct documents-link run writes on them
3
+ // (samples/trace.json: the entries, the mentions and their links). LBB's documents.parse reads the
4
+ // PDFs, so the questions show the rows of each page. This file then commits the trace, so the map
5
+ // runs on known links without a link run first. samples/README.md in the repository describes them.
6
+ import { readdir, readFile } from "node:fs/promises";
7
+ import { join } from "node:path";
8
+ import { entityRef, type LbbClient, type Schemas } from "@littlebigbrain/client";
9
+
10
+ /** The graph's own ontology before the run: rooms, their equipment, and the sections of the specification. */
11
+ export const sampleOntology: Schemas["OntologyEvolveOp"][] = [
12
+ { op: "add_entity_type", name: "Room" },
13
+ { op: "add_entity_type", name: "Equipment" },
14
+ { op: "add_entity_type", name: "SpecSection" },
15
+ { op: "add_relation", name: "HAS_EQUIPMENT", domain: ["Room"], range: ["Equipment"] },
16
+ { op: "add_relation", name: "SPECIFIED_IN", domain: ["Room"], range: ["SpecSection"] },
17
+ ];
18
+
19
+ /** The classes, properties and relations of the trace, as documents-link adds them. */
20
+ export const traceOntology: Schemas["OntologyEvolveOp"][] = [
21
+ { op: "add_entity_type", name: "Document" },
22
+ { op: "add_entity_type", name: "DocEntry" },
23
+ { op: "add_entity_type", name: "DocMention" },
24
+ ...Object.entries({
25
+ identifier: "keyword",
26
+ context: "text",
27
+ line_id: "keyword",
28
+ span: "keyword",
29
+ kind: "keyword",
30
+ line_text: "text",
31
+ page: "i64",
32
+ x0: "f64",
33
+ y0: "f64",
34
+ x1: "f64",
35
+ y1: "f64",
36
+ }).map(([name, value_type]) => ({ op: "add_property" as const, name, value_type })),
37
+ { op: "add_relation", name: "DEFINED_IN", domain: ["DocEntry"], range: ["Document"] },
38
+ { op: "add_relation", name: "MENTIONED_IN", domain: ["DocMention"], range: ["Document"] },
39
+ { op: "add_relation", name: "REFERS_TO", domain: ["DocMention"], range: ["DocEntry"] },
40
+ { op: "add_relation", name: "SAME_ITEM_AS", domain: ["DocMention"], range: ["DocEntry"] },
41
+ ];
42
+
43
+ /** The trace of samples/trace.json. */
44
+ export interface SampleTrace {
45
+ documents: { name: string; sha256: string; pages: number }[];
46
+ entries: {
47
+ document: string;
48
+ identifier: string;
49
+ context: string;
50
+ line_id: string;
51
+ page: number;
52
+ box: number[];
53
+ }[];
54
+ mentions: {
55
+ document: string;
56
+ span: string;
57
+ kind: string;
58
+ line_id: string;
59
+ line_text: string;
60
+ page: number;
61
+ box: number[];
62
+ link: { relation: string; document: string; identifier: string; confidence: number } | null;
63
+ }[];
64
+ }
65
+
66
+ const boxOf = (page: number, box: number[]) => ({
67
+ page,
68
+ x0: box[0]!,
69
+ y0: box[1]!,
70
+ x1: box[2]!,
71
+ y1: box[3]!,
72
+ });
73
+
74
+ /**
75
+ * The commit of the trace, as documents-link writes it: each entry `DEFINED_IN` its document, each
76
+ * mention `MENTIONED_IN` its document, and each link with its confidence and its line as evidence.
77
+ * `documents` gives each file name's `Document` IRI and SHA-256.
78
+ */
79
+ export function traceCommit(
80
+ trace: SampleTrace,
81
+ documents: Map<string, { iri: string; sha256: string }>,
82
+ ): Schemas["TripletCommitFile"] {
83
+ const doc = (name: string) => {
84
+ const found = documents.get(name);
85
+ if (!found) throw new Error(`${name} is not uploaded`);
86
+ return { ...found, ref: entityRef(found.iri, "Document", name) };
87
+ };
88
+ const entry = (name: string, identifier: string) => ({
89
+ type: "DocEntry",
90
+ name: identifier,
91
+ key: `entry:${doc(name).sha256}:${identifier}`,
92
+ });
93
+ const mention = (m: SampleTrace["mentions"][number]) => ({
94
+ type: "DocMention",
95
+ name: m.span,
96
+ key: `mention:${doc(m.document).sha256}:${m.line_id}:${m.span}`,
97
+ });
98
+ return {
99
+ entity_properties: [
100
+ ...trace.entries.map((e) => ({
101
+ ...entry(e.document, e.identifier),
102
+ properties: {
103
+ identifier: e.identifier,
104
+ context: e.context,
105
+ line_id: e.line_id,
106
+ ...boxOf(e.page, e.box),
107
+ },
108
+ })),
109
+ ...trace.mentions.map((m) => ({
110
+ ...mention(m),
111
+ properties: {
112
+ span: m.span,
113
+ kind: m.kind,
114
+ line_id: m.line_id,
115
+ line_text: m.line_text,
116
+ ...boxOf(m.page, m.box),
117
+ },
118
+ })),
119
+ ],
120
+ triplets: [
121
+ ...trace.entries.map((e) => ({
122
+ source: entry(e.document, e.identifier),
123
+ relation: "DEFINED_IN",
124
+ target: doc(e.document).ref,
125
+ })),
126
+ ...trace.mentions.map((m) => ({
127
+ source: mention(m),
128
+ relation: "MENTIONED_IN",
129
+ target: doc(m.document).ref,
130
+ })),
131
+ ...trace.mentions.flatMap((m) =>
132
+ m.link
133
+ ? [
134
+ {
135
+ source: mention(m),
136
+ relation: m.link.relation,
137
+ target: entry(m.link.document, m.link.identifier),
138
+ confidence: m.link.confidence,
139
+ evidence: {
140
+ text: m.line_text,
141
+ source_id: m.document,
142
+ region: { ...boxOf(m.page, m.box), confidence: m.link.confidence },
143
+ },
144
+ },
145
+ ]
146
+ : [],
147
+ ),
148
+ ],
149
+ };
150
+ }
151
+
152
+ /** Upload the sample PDFs, wait until LBB has parsed them, then commit the ontology and the trace. */
153
+ export async function loadSamples(client: LbbClient, dir: string): Promise<void> {
154
+ await client.workflows.starters.use({ starter: "documents.parse" });
155
+ const names = (await readdir(dir)).filter((name) => name.endsWith(".pdf")).sort();
156
+ for (const name of names) {
157
+ const bytes = new Uint8Array(await readFile(join(dir, name)));
158
+ await client.files.upload(bytes, { name, contentType: "application/pdf" });
159
+ console.log(`Uploaded ${name}`);
160
+ }
161
+ for (let waited = 0; ; waited += 2) {
162
+ const { files } = await client.files.list();
163
+ const parsed = files.filter((f) => names.includes(f.name) && f.parse?.status === "parsed");
164
+ if (parsed.length === names.length) {
165
+ const documents = new Map(parsed.map((f) => [f.name, { iri: f.document, sha256: f.sha256 }]));
166
+ const trace = JSON.parse(await readFile(join(dir, "trace.json"), "utf8")) as SampleTrace;
167
+ await client.ontology.evolve({ ops: [...traceOntology, ...sampleOntology] });
168
+ await client.commit(traceCommit(trace, documents), {
169
+ idempotencyKey: "documents-map-samples",
170
+ });
171
+ console.log(
172
+ `Committed the trace: ${trace.entries.length} entries, ${trace.mentions.length} mentions, ${trace.mentions.filter((m) => m.link).length} links`,
173
+ );
174
+ return;
175
+ }
176
+ if (waited >= 180)
177
+ throw new Error(
178
+ "The samples were not parsed within 3 minutes: is documents.parse available?",
179
+ );
180
+ await new Promise((resolve) => setTimeout(resolve, 2_000));
181
+ }
182
+ }