jevy-graph 0.1.0__tar.gz

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 (33) hide show
  1. jevy_graph-0.1.0/.env.example +2 -0
  2. jevy_graph-0.1.0/.github/workflows/ci.yml +23 -0
  3. jevy_graph-0.1.0/.github/workflows/release.yml +36 -0
  4. jevy_graph-0.1.0/.gitignore +15 -0
  5. jevy_graph-0.1.0/CHANGELOG.md +16 -0
  6. jevy_graph-0.1.0/LICENSE +21 -0
  7. jevy_graph-0.1.0/PKG-INFO +253 -0
  8. jevy_graph-0.1.0/README.md +213 -0
  9. jevy_graph-0.1.0/demo/app.js +480 -0
  10. jevy_graph-0.1.0/demo/index.html +54 -0
  11. jevy_graph-0.1.0/demo/styles.css +238 -0
  12. jevy_graph-0.1.0/launch/LAUNCH_CHECKLIST.md +47 -0
  13. jevy_graph-0.1.0/launch/RELEASE_NOTES.md +30 -0
  14. jevy_graph-0.1.0/pyproject.toml +38 -0
  15. jevy_graph-0.1.0/scripts/benchmark.py +118 -0
  16. jevy_graph-0.1.0/src/jevy_graph/__init__.py +13 -0
  17. jevy_graph-0.1.0/src/jevy_graph/__main__.py +4 -0
  18. jevy_graph-0.1.0/src/jevy_graph/cli.py +94 -0
  19. jevy_graph-0.1.0/src/jevy_graph/compiler.py +87 -0
  20. jevy_graph-0.1.0/src/jevy_graph/config.py +16 -0
  21. jevy_graph-0.1.0/src/jevy_graph/demo_server.py +200 -0
  22. jevy_graph-0.1.0/src/jevy_graph/extract.py +2056 -0
  23. jevy_graph-0.1.0/src/jevy_graph/jev.py +666 -0
  24. jevy_graph-0.1.0/src/jevy_graph/models.py +51 -0
  25. jevy_graph-0.1.0/src/jevy_graph/normalize.py +112 -0
  26. jevy_graph-0.1.0/src/jevy_graph/rdf.py +131 -0
  27. jevy_graph-0.1.0/src/jevy_graph/structured.py +742 -0
  28. jevy_graph-0.1.0/tests/__init__.py +0 -0
  29. jevy_graph-0.1.0/tests/test_compiler.py +65 -0
  30. jevy_graph-0.1.0/tests/test_demo_server.py +97 -0
  31. jevy_graph-0.1.0/tests/test_extract.py +97 -0
  32. jevy_graph-0.1.0/tests/test_jev.py +238 -0
  33. jevy_graph-0.1.0/tests/test_rdf.py +94 -0
@@ -0,0 +1,2 @@
1
+ TYPESAFE_API_KEY=
2
+
@@ -0,0 +1,23 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ test:
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ matrix:
15
+ python-version: ["3.11", "3.13"]
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ - uses: actions/setup-python@v5
19
+ with:
20
+ python-version: ${{ matrix.python-version }}
21
+ - run: python -m pip install .
22
+ - run: python -m unittest discover -s tests -q
23
+ - run: printf 'Alice founded Acme.' | jevy-graph --no-verify > /dev/null
@@ -0,0 +1,36 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ build:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ - uses: actions/setup-python@v5
16
+ with:
17
+ python-version: "3.13"
18
+ - run: python -m pip install --upgrade build
19
+ - run: python -m build
20
+ - uses: actions/upload-artifact@v4
21
+ with:
22
+ name: python-package-distributions
23
+ path: dist/
24
+
25
+ publish:
26
+ needs: build
27
+ runs-on: ubuntu-latest
28
+ environment: pypi
29
+ permissions:
30
+ id-token: write
31
+ steps:
32
+ - uses: actions/download-artifact@v4
33
+ with:
34
+ name: python-package-distributions
35
+ path: dist/
36
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,15 @@
1
+ .env
2
+ .env.*
3
+ !.env.example
4
+ .DS_Store
5
+ .venv/
6
+ __pycache__/
7
+ *.py[cod]
8
+ *.egg-info/
9
+ .coverage
10
+ htmlcov/
11
+ .pytest_cache/
12
+ .ruff_cache/
13
+ build/
14
+ dist/
15
+ out/
@@ -0,0 +1,16 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 - 2026-09-22
4
+
5
+ Initial public release.
6
+
7
+ - Deterministic extraction of bounded subject/predicate/object candidates from
8
+ prose, lists, tables, equations, and measurements.
9
+ - Jev-backed candidate selection and independent support and entity-boundary
10
+ verification.
11
+ - Source-grounded RDF/Turtle output with evidence, provenance, polarity, and
12
+ calibrated scores.
13
+ - Dependency-free Python API and CLI.
14
+ - Local streaming graph demo with PDF, DOCX, Markdown, CSV, and text uploads.
15
+ - Cancellation-aware parallel batching and compact processing for large
16
+ documents.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sai Venna
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,253 @@
1
+ Metadata-Version: 2.5
2
+ Name: jevy-graph
3
+ Version: 0.1.0
4
+ Summary: A small, source-grounded text-to-RDF compiler verified by Jev.
5
+ Project-URL: Homepage, https://github.com/saivivekvenna/jevy-graph
6
+ Project-URL: Issues, https://github.com/saivivekvenna/jevy-graph/issues
7
+ Project-URL: Source, https://github.com/saivivekvenna/jevy-graph
8
+ Project-URL: Changelog, https://github.com/saivivekvenna/jevy-graph/blob/main/CHANGELOG.md
9
+ Author: Sai Venna
10
+ License: MIT License
11
+
12
+ Copyright (c) 2026 Sai Venna
13
+
14
+ Permission is hereby granted, free of charge, to any person obtaining a copy
15
+ of this software and associated documentation files (the "Software"), to deal
16
+ in the Software without restriction, including without limitation the rights
17
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18
+ copies of the Software, and to permit persons to whom the Software is
19
+ furnished to do so, subject to the following conditions:
20
+
21
+ The above copyright notice and this permission notice shall be included in all
22
+ copies or substantial portions of the Software.
23
+
24
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30
+ SOFTWARE.
31
+ License-File: LICENSE
32
+ Keywords: information-extraction,jev,knowledge-graph,rdf
33
+ Classifier: Development Status :: 3 - Alpha
34
+ Classifier: License :: OSI Approved :: MIT License
35
+ Classifier: Programming Language :: Python :: 3
36
+ Classifier: Programming Language :: Python :: 3.11
37
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
38
+ Requires-Python: >=3.11
39
+ Description-Content-Type: text/markdown
40
+
41
+ # Jevy Graph
42
+
43
+ [![CI](https://github.com/saivivekvenna/jevy-graph/actions/workflows/ci.yml/badge.svg)](https://github.com/saivivekvenna/jevy-graph/actions/workflows/ci.yml)
44
+
45
+ Jevy Graph compiles documents into source-grounded RDF. It discovers atomic
46
+ relations locally, asks [Jev](https://typesafe.ai/) to resolve ambiguous entity
47
+ boundaries and predicates, verifies every selected claim, and emits Turtle with
48
+ evidence and provenance.
49
+
50
+ The compiler is designed for high-recall extraction from ordinary prose,
51
+ scientific papers, legal text, tables, measurements, and equations. It does not
52
+ require an ontology or a document-specific schema.
53
+
54
+ ## 19-second demo
55
+
56
+ [![Watch Jevy Graph compile a document into a knowledge graph](https://raw.githubusercontent.com/saivivekvenna/jevy-graph/main/assets/jevy-graph-launch.png)](https://github.com/saivivekvenna/jevy-graph/blob/main/assets/jevy-graph-launch.mp4)
57
+
58
+ Click the preview for the short version, or watch the
59
+ [full 72-second demo](https://github.com/saivivekvenna/jevy-graph/blob/main/assets/jevy-graph-demo.mp4).
60
+
61
+ ## Features
62
+
63
+ - Multiple atomic claims from one sentence, clause, list, or table row
64
+ - Normalized entities and stable predicates without external entity linking
65
+ - Modality, negation, conditions, sections, pages, and evidence spans preserved
66
+ - Jev selection and verification streamed in parallel batches
67
+ - RDF statements with calibrated support and entity-quality scores
68
+ - CLI, Python API, and a real-time Cytoscape demo
69
+ - No runtime Python dependencies
70
+
71
+ ## How it works
72
+
73
+ ```text
74
+ document
75
+ -> deterministic clause, table, equation, and measurement extraction
76
+ -> bounded subject / predicate / object candidates
77
+ -> Jev candidate selection
78
+ -> Jev support and boundary verification
79
+ -> thresholding and deduplication
80
+ -> source-grounded RDF/Turtle
81
+ ```
82
+
83
+ Jev never invents free-form graph text. It chooses among candidates generated
84
+ from the document, then independently scores the selected relationship. Frames
85
+ with one valid interpretation skip the selection call but are still verified.
86
+
87
+ ## Quick start
88
+
89
+ Jevy Graph requires Python 3.11 or newer and a TypeSafe API key.
90
+
91
+ ```bash
92
+ git clone https://github.com/saivivekvenna/jevy-graph.git
93
+ cd jevy-graph
94
+ python3 -m venv .venv
95
+ source .venv/bin/activate
96
+ python -m pip install -e .
97
+ cp .env.example .env
98
+ ```
99
+
100
+ Add your key to `.env`:
101
+
102
+ ```dotenv
103
+ TYPESAFE_API_KEY=your-key-here
104
+ ```
105
+
106
+ Compile UTF-8 text to Turtle:
107
+
108
+ ```bash
109
+ jevy-graph document.txt -o graph.ttl
110
+ ```
111
+
112
+ For a local-only extraction smoke test that does not call Jev:
113
+
114
+ ```bash
115
+ printf 'Alice founded Acme. Acme is located in Toronto.' \
116
+ | jevy-graph --no-verify
117
+ ```
118
+
119
+ ## Demo
120
+
121
+ The demo accepts PDF, DOCX, Markdown, CSV, and plain-text files. Normal uploads
122
+ stream verified claims as their Jev batches finish. Documents that produce at
123
+ least 2,000 relation frames use larger compute batches and mount the completed
124
+ graph once. Selection and verification overlap across batches; every emitted
125
+ claim still passes both support and entity-boundary checks. Large uploads send
126
+ fixed candidate fields once per question instead of repeating them in every
127
+ option. No candidate options are removed by this encoding.
128
+
129
+ Starting a new upload cancels the previous request. Already running Jev calls
130
+ may finish, but pending batches stop when the server detects the disconnect.
131
+ The final API event includes Jev-reported token usage and request/retry counts.
132
+
133
+ An elapsed timer measures upload through backend completion, excluding final
134
+ graph layout. Hover over an edge or leaf node to read its source text and triple
135
+ in the labeled footer without highlighting or hiding the rest of the graph.
136
+
137
+ ```bash
138
+ jevy-graph-demo
139
+ ```
140
+
141
+ Open <http://localhost:8080/demo/>. PDF support requires `pdftotext`, available
142
+ from Poppler (`brew install poppler` on macOS or `apt install poppler-utils` on
143
+ Debian and Ubuntu).
144
+
145
+ The API key stays on the server and is never sent to the browser.
146
+
147
+ ## Python API
148
+
149
+ ```python
150
+ import os
151
+
152
+ from jevy_graph import Thresholds, compile_text
153
+ from jevy_graph.jev import JevClient
154
+
155
+ client = JevClient(os.environ["TYPESAFE_API_KEY"])
156
+ result = compile_text(
157
+ "Alice founded Acme.",
158
+ client=client,
159
+ thresholds=Thresholds(support=0.45, entity=0.10, joint=0.70),
160
+ )
161
+
162
+ print(result.turtle)
163
+ print(result.accepted)
164
+ ```
165
+
166
+ Omit `client` for deterministic, unverified extraction.
167
+
168
+ ## RDF model
169
+
170
+ Each accepted positive relationship is emitted as a direct semantic edge and
171
+ as an `rdf:Statement` carrying its provenance:
172
+
173
+ ```turtle
174
+ <urn:jevy:entity:alice-...> <urn:jevy:relation:founded> <urn:jevy:entity:acme-...> .
175
+
176
+ <urn:jevy:claim:...> a rdf:Statement ;
177
+ rdf:subject <urn:jevy:entity:alice-...> ;
178
+ rdf:predicate <urn:jevy:relation:founded> ;
179
+ rdf:object <urn:jevy:entity:acme-...> ;
180
+ jevy:evidence "Alice founded Acme." ;
181
+ jevy:support "0.950000"^^xsd:decimal ;
182
+ jevy:entityQuality "0.910000"^^xsd:decimal .
183
+ ```
184
+
185
+ Negative claims are reified with `jevy:polarity "negative"` without asserting
186
+ the positive edge. Numeric values are emitted as typed literals when possible.
187
+
188
+ ## Scope
189
+
190
+ The CLI reads UTF-8 text. The demo additionally converts PDF and DOCX uploads.
191
+ The extractor handles ordinary prose, legal lists, scientific sections,
192
+ layout-preserving tables, assignments, equations, and measurements.
193
+
194
+ External knowledge-base linking, ontology alignment, OCR, and scanned PDFs are
195
+ out of scope. Entity normalization is intentionally conservative unless the
196
+ document explicitly declares an alias.
197
+
198
+ ## Development
199
+
200
+ ```bash
201
+ python -m unittest discover -s tests -q
202
+ ```
203
+
204
+ Pull requests should include a focused regression test for behavior changes.
205
+ Keep extraction deterministic and keep API credentials out of fixtures, logs,
206
+ and commits.
207
+
208
+ ### Performance checks
209
+
210
+ Use a new process to measure a first upload. No graph layout or browser rendering
211
+ is included; extraction, Jev processing, and final filtering are timed separately.
212
+ The benchmark writes source-grounded claims and metrics to the ignored `out/`
213
+ directory. `--live` makes paid API calls; without it only extraction is measured.
214
+
215
+ ```bash
216
+ PYTHONPATH=src python scripts/benchmark.py document.pdf \
217
+ --live --compact --workers 12 --batch-size 48 --output out/benchmark.json
218
+ ```
219
+
220
+ Use `--sample 512` for a bounded comparison, or `--reference` to run selection
221
+ for all frames before verification. Frame and candidate hashes allow checking
222
+ that an optimization preserves the entire deterministic candidate set.
223
+
224
+ Measured locally on September 21, 2026 (first upload, Python 3.14):
225
+
226
+ | Document / configuration | Accepted claims | Compute time | Reported input tokens |
227
+ | --- | ---: | ---: | ---: |
228
+ | Odyssey PDF, original implementation | ~5,150 | ~75.3s | Not recorded |
229
+ | Odyssey PDF, pipelined, original question format | 5,164 | 49.1s | 21,417,219 |
230
+ | Odyssey PDF, compact fixed fields and paced requests | 5,123 | 45.3s | 19,178,128 |
231
+ | Constitution PDF, normal streaming configuration | 449 | 3.84s | 1,221,971 |
232
+
233
+ All Odyssey configurations used 14,881 frames. The optimized extractor produced
234
+ identical frame and candidate hashes to the original. The 45.3s run included
235
+ 23 rate-limit retries, so network conditions and account limits materially
236
+ affect timing. Model decisions vary between calls: claim counts are a regression
237
+ signal, not proof of complete coverage or correctness. The full uncompressed and
238
+ compact runs shared 3,950 exact claims, so matching volumes should not be read as
239
+ identical outputs. Ten-second processing of
240
+ the full Odyssey has not been demonstrated with verification preserved.
241
+
242
+ ## Privacy and security
243
+
244
+ The demo binds to `127.0.0.1` by default and is intended for local use. Document
245
+ text used in Jev decisions is sent to TypeSafe's API. Review TypeSafe's policies
246
+ before processing sensitive material, and add authentication plus upload
247
+ hardening before exposing the demo server publicly.
248
+
249
+ Never commit `.env`; it is ignored by Git.
250
+
251
+ ## License
252
+
253
+ [MIT](LICENSE)
@@ -0,0 +1,213 @@
1
+ # Jevy Graph
2
+
3
+ [![CI](https://github.com/saivivekvenna/jevy-graph/actions/workflows/ci.yml/badge.svg)](https://github.com/saivivekvenna/jevy-graph/actions/workflows/ci.yml)
4
+
5
+ Jevy Graph compiles documents into source-grounded RDF. It discovers atomic
6
+ relations locally, asks [Jev](https://typesafe.ai/) to resolve ambiguous entity
7
+ boundaries and predicates, verifies every selected claim, and emits Turtle with
8
+ evidence and provenance.
9
+
10
+ The compiler is designed for high-recall extraction from ordinary prose,
11
+ scientific papers, legal text, tables, measurements, and equations. It does not
12
+ require an ontology or a document-specific schema.
13
+
14
+ ## 19-second demo
15
+
16
+ [![Watch Jevy Graph compile a document into a knowledge graph](https://raw.githubusercontent.com/saivivekvenna/jevy-graph/main/assets/jevy-graph-launch.png)](https://github.com/saivivekvenna/jevy-graph/blob/main/assets/jevy-graph-launch.mp4)
17
+
18
+ Click the preview for the short version, or watch the
19
+ [full 72-second demo](https://github.com/saivivekvenna/jevy-graph/blob/main/assets/jevy-graph-demo.mp4).
20
+
21
+ ## Features
22
+
23
+ - Multiple atomic claims from one sentence, clause, list, or table row
24
+ - Normalized entities and stable predicates without external entity linking
25
+ - Modality, negation, conditions, sections, pages, and evidence spans preserved
26
+ - Jev selection and verification streamed in parallel batches
27
+ - RDF statements with calibrated support and entity-quality scores
28
+ - CLI, Python API, and a real-time Cytoscape demo
29
+ - No runtime Python dependencies
30
+
31
+ ## How it works
32
+
33
+ ```text
34
+ document
35
+ -> deterministic clause, table, equation, and measurement extraction
36
+ -> bounded subject / predicate / object candidates
37
+ -> Jev candidate selection
38
+ -> Jev support and boundary verification
39
+ -> thresholding and deduplication
40
+ -> source-grounded RDF/Turtle
41
+ ```
42
+
43
+ Jev never invents free-form graph text. It chooses among candidates generated
44
+ from the document, then independently scores the selected relationship. Frames
45
+ with one valid interpretation skip the selection call but are still verified.
46
+
47
+ ## Quick start
48
+
49
+ Jevy Graph requires Python 3.11 or newer and a TypeSafe API key.
50
+
51
+ ```bash
52
+ git clone https://github.com/saivivekvenna/jevy-graph.git
53
+ cd jevy-graph
54
+ python3 -m venv .venv
55
+ source .venv/bin/activate
56
+ python -m pip install -e .
57
+ cp .env.example .env
58
+ ```
59
+
60
+ Add your key to `.env`:
61
+
62
+ ```dotenv
63
+ TYPESAFE_API_KEY=your-key-here
64
+ ```
65
+
66
+ Compile UTF-8 text to Turtle:
67
+
68
+ ```bash
69
+ jevy-graph document.txt -o graph.ttl
70
+ ```
71
+
72
+ For a local-only extraction smoke test that does not call Jev:
73
+
74
+ ```bash
75
+ printf 'Alice founded Acme. Acme is located in Toronto.' \
76
+ | jevy-graph --no-verify
77
+ ```
78
+
79
+ ## Demo
80
+
81
+ The demo accepts PDF, DOCX, Markdown, CSV, and plain-text files. Normal uploads
82
+ stream verified claims as their Jev batches finish. Documents that produce at
83
+ least 2,000 relation frames use larger compute batches and mount the completed
84
+ graph once. Selection and verification overlap across batches; every emitted
85
+ claim still passes both support and entity-boundary checks. Large uploads send
86
+ fixed candidate fields once per question instead of repeating them in every
87
+ option. No candidate options are removed by this encoding.
88
+
89
+ Starting a new upload cancels the previous request. Already running Jev calls
90
+ may finish, but pending batches stop when the server detects the disconnect.
91
+ The final API event includes Jev-reported token usage and request/retry counts.
92
+
93
+ An elapsed timer measures upload through backend completion, excluding final
94
+ graph layout. Hover over an edge or leaf node to read its source text and triple
95
+ in the labeled footer without highlighting or hiding the rest of the graph.
96
+
97
+ ```bash
98
+ jevy-graph-demo
99
+ ```
100
+
101
+ Open <http://localhost:8080/demo/>. PDF support requires `pdftotext`, available
102
+ from Poppler (`brew install poppler` on macOS or `apt install poppler-utils` on
103
+ Debian and Ubuntu).
104
+
105
+ The API key stays on the server and is never sent to the browser.
106
+
107
+ ## Python API
108
+
109
+ ```python
110
+ import os
111
+
112
+ from jevy_graph import Thresholds, compile_text
113
+ from jevy_graph.jev import JevClient
114
+
115
+ client = JevClient(os.environ["TYPESAFE_API_KEY"])
116
+ result = compile_text(
117
+ "Alice founded Acme.",
118
+ client=client,
119
+ thresholds=Thresholds(support=0.45, entity=0.10, joint=0.70),
120
+ )
121
+
122
+ print(result.turtle)
123
+ print(result.accepted)
124
+ ```
125
+
126
+ Omit `client` for deterministic, unverified extraction.
127
+
128
+ ## RDF model
129
+
130
+ Each accepted positive relationship is emitted as a direct semantic edge and
131
+ as an `rdf:Statement` carrying its provenance:
132
+
133
+ ```turtle
134
+ <urn:jevy:entity:alice-...> <urn:jevy:relation:founded> <urn:jevy:entity:acme-...> .
135
+
136
+ <urn:jevy:claim:...> a rdf:Statement ;
137
+ rdf:subject <urn:jevy:entity:alice-...> ;
138
+ rdf:predicate <urn:jevy:relation:founded> ;
139
+ rdf:object <urn:jevy:entity:acme-...> ;
140
+ jevy:evidence "Alice founded Acme." ;
141
+ jevy:support "0.950000"^^xsd:decimal ;
142
+ jevy:entityQuality "0.910000"^^xsd:decimal .
143
+ ```
144
+
145
+ Negative claims are reified with `jevy:polarity "negative"` without asserting
146
+ the positive edge. Numeric values are emitted as typed literals when possible.
147
+
148
+ ## Scope
149
+
150
+ The CLI reads UTF-8 text. The demo additionally converts PDF and DOCX uploads.
151
+ The extractor handles ordinary prose, legal lists, scientific sections,
152
+ layout-preserving tables, assignments, equations, and measurements.
153
+
154
+ External knowledge-base linking, ontology alignment, OCR, and scanned PDFs are
155
+ out of scope. Entity normalization is intentionally conservative unless the
156
+ document explicitly declares an alias.
157
+
158
+ ## Development
159
+
160
+ ```bash
161
+ python -m unittest discover -s tests -q
162
+ ```
163
+
164
+ Pull requests should include a focused regression test for behavior changes.
165
+ Keep extraction deterministic and keep API credentials out of fixtures, logs,
166
+ and commits.
167
+
168
+ ### Performance checks
169
+
170
+ Use a new process to measure a first upload. No graph layout or browser rendering
171
+ is included; extraction, Jev processing, and final filtering are timed separately.
172
+ The benchmark writes source-grounded claims and metrics to the ignored `out/`
173
+ directory. `--live` makes paid API calls; without it only extraction is measured.
174
+
175
+ ```bash
176
+ PYTHONPATH=src python scripts/benchmark.py document.pdf \
177
+ --live --compact --workers 12 --batch-size 48 --output out/benchmark.json
178
+ ```
179
+
180
+ Use `--sample 512` for a bounded comparison, or `--reference` to run selection
181
+ for all frames before verification. Frame and candidate hashes allow checking
182
+ that an optimization preserves the entire deterministic candidate set.
183
+
184
+ Measured locally on September 21, 2026 (first upload, Python 3.14):
185
+
186
+ | Document / configuration | Accepted claims | Compute time | Reported input tokens |
187
+ | --- | ---: | ---: | ---: |
188
+ | Odyssey PDF, original implementation | ~5,150 | ~75.3s | Not recorded |
189
+ | Odyssey PDF, pipelined, original question format | 5,164 | 49.1s | 21,417,219 |
190
+ | Odyssey PDF, compact fixed fields and paced requests | 5,123 | 45.3s | 19,178,128 |
191
+ | Constitution PDF, normal streaming configuration | 449 | 3.84s | 1,221,971 |
192
+
193
+ All Odyssey configurations used 14,881 frames. The optimized extractor produced
194
+ identical frame and candidate hashes to the original. The 45.3s run included
195
+ 23 rate-limit retries, so network conditions and account limits materially
196
+ affect timing. Model decisions vary between calls: claim counts are a regression
197
+ signal, not proof of complete coverage or correctness. The full uncompressed and
198
+ compact runs shared 3,950 exact claims, so matching volumes should not be read as
199
+ identical outputs. Ten-second processing of
200
+ the full Odyssey has not been demonstrated with verification preserved.
201
+
202
+ ## Privacy and security
203
+
204
+ The demo binds to `127.0.0.1` by default and is intended for local use. Document
205
+ text used in Jev decisions is sent to TypeSafe's API. Review TypeSafe's policies
206
+ before processing sensitive material, and add authentication plus upload
207
+ hardening before exposing the demo server publicly.
208
+
209
+ Never commit `.env`; it is ignored by Git.
210
+
211
+ ## License
212
+
213
+ [MIT](LICENSE)