sqljev 0.1.0__py3-none-any.whl
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.
- sqljev/__init__.py +6 -0
- sqljev/__main__.py +3 -0
- sqljev/aws_lambda.py +16 -0
- sqljev/cli.py +516 -0
- sqljev/core.py +674 -0
- sqljev/demo.py +307 -0
- sqljev/duckdb.py +56 -0
- sqljev/finetune.py +367 -0
- sqljev/gateway.py +215 -0
- sqljev/spark.py +64 -0
- sqljev-0.1.0.dist-info/METADATA +450 -0
- sqljev-0.1.0.dist-info/RECORD +16 -0
- sqljev-0.1.0.dist-info/WHEEL +4 -0
- sqljev-0.1.0.dist-info/entry_points.txt +2 -0
- sqljev-0.1.0.dist-info/licenses/LICENSE +176 -0
- sqljev-0.1.0.dist-info/licenses/NOTICE +36 -0
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: sqljev
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Ask your SQL rows questions in plain English: jev(), jev_prob(), jev_choice(), jev_score() for SQL Server, PostgreSQL, MySQL, Snowflake, Databricks, BigQuery, Redshift and DuckDB, answered by Laya (open weights, fine-tunable) or TypeSafe Jev.
|
|
5
|
+
Project-URL: Homepage, https://singhpratech.github.io/sqljev/
|
|
6
|
+
Project-URL: Source, https://github.com/singhpratech/sqljev
|
|
7
|
+
Project-URL: Issues, https://github.com/singhpratech/sqljev/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/singhpratech/sqljev/blob/main/CHANGELOG.md
|
|
9
|
+
Project-URL: Fine-tune in Colab, https://colab.research.google.com/github/singhpratech/sqljev/blob/main/notebooks/sqljev_finetune_colab.ipynb
|
|
10
|
+
License-Expression: Apache-2.0
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
License-File: NOTICE
|
|
13
|
+
Keywords: bigquery,databricks,duckdb,fine-tuning,jev,laya,mysql,pg-jev,postgresql,redshift,snowflake,sql,sql-server,text-classification
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Intended Audience :: Science/Research
|
|
17
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
18
|
+
Classifier: Operating System :: OS Independent
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: SQL
|
|
24
|
+
Classifier: Topic :: Database
|
|
25
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
26
|
+
Requires-Python: >=3.10
|
|
27
|
+
Provides-Extra: all
|
|
28
|
+
Requires-Dist: duckdb>=1.1; extra == 'all'
|
|
29
|
+
Requires-Dist: laya>=0.3.20; extra == 'all'
|
|
30
|
+
Requires-Dist: pyarrow>=14; extra == 'all'
|
|
31
|
+
Requires-Dist: sqlalchemy>=2.0; extra == 'all'
|
|
32
|
+
Provides-Extra: db
|
|
33
|
+
Requires-Dist: sqlalchemy>=2.0; extra == 'db'
|
|
34
|
+
Provides-Extra: dev
|
|
35
|
+
Requires-Dist: duckdb>=1.1; extra == 'dev'
|
|
36
|
+
Requires-Dist: pandas>=1.5; extra == 'dev'
|
|
37
|
+
Requires-Dist: pyarrow>=14; extra == 'dev'
|
|
38
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
39
|
+
Requires-Dist: sqlalchemy>=2.0; extra == 'dev'
|
|
40
|
+
Provides-Extra: duckdb
|
|
41
|
+
Requires-Dist: duckdb>=1.1; extra == 'duckdb'
|
|
42
|
+
Requires-Dist: pyarrow>=14; extra == 'duckdb'
|
|
43
|
+
Provides-Extra: laya
|
|
44
|
+
Requires-Dist: laya>=0.3.20; extra == 'laya'
|
|
45
|
+
Provides-Extra: spark
|
|
46
|
+
Requires-Dist: pandas>=1.5; extra == 'spark'
|
|
47
|
+
Requires-Dist: pyarrow>=14; extra == 'spark'
|
|
48
|
+
Requires-Dist: pyspark>=3.4; extra == 'spark'
|
|
49
|
+
Description-Content-Type: text/markdown
|
|
50
|
+
|
|
51
|
+
<p align="center">
|
|
52
|
+
<a href="https://singhpratech.github.io/sqljev/"><img src="https://raw.githubusercontent.com/singhpratech/sqljev/main/site/assets/banner.png" alt="sqljev: ask your SQL rows questions in plain English, answered by Laya" width="100%"></a>
|
|
53
|
+
</p>
|
|
54
|
+
|
|
55
|
+
<p align="center">
|
|
56
|
+
<a href="https://pypi.org/project/sqljev/"><img src="https://img.shields.io/pypi/v/sqljev?color=F0A202&label=pypi" alt="PyPI"></a>
|
|
57
|
+
<a href="https://pypi.org/project/sqljev/"><img src="https://img.shields.io/pypi/pyversions/sqljev?color=152238" alt="Python"></a>
|
|
58
|
+
<a href="https://github.com/singhpratech/sqljev/actions/workflows/ci.yml"><img src="https://github.com/singhpratech/sqljev/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
|
|
59
|
+
<a href="https://github.com/singhpratech/sqljev/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-2F8F5B" alt="License"></a>
|
|
60
|
+
<a href="https://colab.research.google.com/github/singhpratech/sqljev/blob/main/notebooks/sqljev_finetune_colab.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open in Colab"></a>
|
|
61
|
+
</p>
|
|
62
|
+
|
|
63
|
+
<p align="center">
|
|
64
|
+
<a href="https://singhpratech.github.io/sqljev/"><b>Website</b></a> ·
|
|
65
|
+
<a href="#quickstart">Quickstart</a> ·
|
|
66
|
+
<a href="#per-database">Databases</a> ·
|
|
67
|
+
<a href="#benchmark-100000-rows-13-questions">Benchmark</a> ·
|
|
68
|
+
<a href="#fine-tune-laya-on-your-own-tables">Fine-tune</a>
|
|
69
|
+
</p>
|
|
70
|
+
|
|
71
|
+
# sqljev
|
|
72
|
+
|
|
73
|
+
**Ask your SQL rows questions in plain English.** Write the condition the way you would say it, and your
|
|
74
|
+
database does the rest, on **SQL Server, PostgreSQL, MySQL / MariaDB, Snowflake, Databricks, BigQuery, Redshift,
|
|
75
|
+
DuckDB** and anything SQLAlchemy can reach.
|
|
76
|
+
|
|
77
|
+
```sql
|
|
78
|
+
-- Snowflake / Databricks / DuckDB / BigQuery / Redshift: the row goes in as JSON
|
|
79
|
+
SELECT * FROM tickets t WHERE jev(OBJECT_CONSTRUCT(t.*), 'the customer threatens to cancel');
|
|
80
|
+
|
|
81
|
+
SELECT subject, jev_prob(to_json(t), 'the customer is angry') AS p
|
|
82
|
+
FROM tickets t ORDER BY p DESC LIMIT 20;
|
|
83
|
+
|
|
84
|
+
SELECT jev_choice(to_json(t), 'which team should handle this?',
|
|
85
|
+
['billing', 'technical', 'security', 'sales']) AS team, count(*)
|
|
86
|
+
FROM tickets t GROUP BY team;
|
|
87
|
+
|
|
88
|
+
-- SQL Server / Azure SQL
|
|
89
|
+
EXEC jev.judge N'dbo.tickets', N'the customer is angry';
|
|
90
|
+
SELECT * FROM dbo.tickets AS t
|
|
91
|
+
WHERE jev.prob((SELECT t.* FOR JSON PATH, WITHOUT_ARRAY_WRAPPER), N'the customer is angry') >= 0.5;
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Every row is judged by a **System One decision model**, a model that does not generate text but returns
|
|
95
|
+
calibrated probabilities for typed questions (yes/no, choice, score). By default that is
|
|
96
|
+
**[Laya](https://github.com/NandhaKishorM/laya)** (Convai Innovations, Apache 2.0, open weights), running on
|
|
97
|
+
*your* hardware: row data never leaves your network, costs nothing per token, and **you can fine-tune it on
|
|
98
|
+
your own tables**. TypeSafe's hosted [Jev](https://docs.typesafe.ai) is one setting away.
|
|
99
|
+
|
|
100
|
+
Inspired by, and partly ported from, [pg-jev](https://github.com/realZachi/pg-jev), which does this inside
|
|
101
|
+
PostgreSQL. sqljev takes the idea to every other database and swaps in an open model you can train.
|
|
102
|
+
|
|
103
|
+
## Quickstart
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
pip install "sqljev[laya,db]"
|
|
107
|
+
sqljev query "sqlite:///support.db" "SELECT * FROM tickets" --where "the customer is angry" --limit 10
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
That downloads Laya once (~1.7 GB), judges the rows on your machine, and prints the angry tickets with their
|
|
111
|
+
probability. Then pick your database below, or open the [website](https://singhpratech.github.io/sqljev/) for copy-paste setup per database.
|
|
112
|
+
|
|
113
|
+
## What it is for
|
|
114
|
+
|
|
115
|
+
The questions SQL cannot express, asked right inside the queries you already write:
|
|
116
|
+
|
|
117
|
+
| | Example |
|
|
118
|
+
| --- | --- |
|
|
119
|
+
| Support / CRM | `jev(t, 'the customer threatens to cancel')`, route with `jev_choice(... ['billing','technical','sales'])` |
|
|
120
|
+
| Risk & compliance | flag contracts, emails or chat logs: *"mentions a price guarantee"*, *"contains health information"* |
|
|
121
|
+
| Pharma & life sciences | *"the adverse event report mentions liver injury"*, classify free-text indications by therapeutic area |
|
|
122
|
+
| Data cleanup | *"this address is a business, not a residence"*, *"the product description is not in English"* |
|
|
123
|
+
| Triage & ranking | `ORDER BY jev_prob(...)` for the most urgent incidents, likeliest leads, riskiest claims |
|
|
124
|
+
|
|
125
|
+
`jev()` is an ordinary boolean function, so it composes with everything else in SQL: `AND created_at > ...`,
|
|
126
|
+
joins, `GROUP BY`, `LIMIT`. Keep arithmetic, dates and exact matches in SQL; let the model judge *meaning*.
|
|
127
|
+
|
|
128
|
+
## How it works
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
your SQL ──► database UDF / procedure ──► sqljev engine ──► Laya (in-process, GPU/CPU)
|
|
132
|
+
(rows arrive in batches) dedupe · cache · or a gateway, laya-serve, or Jev
|
|
133
|
+
forward-pass batching
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
A SQL question is *one question over many rows*, and everything is organised around that:
|
|
137
|
+
|
|
138
|
+
1. **Rows go in as compact JSON objects** (column → value). NULL columns are dropped, which matters for
|
|
139
|
+
Laya's 512–1,024-token window. Pass only the columns the judgment needs (a view, `struct(subject, body)`).
|
|
140
|
+
2. **Every database already batches UDF calls.** Snowflake, BigQuery, Redshift, Spark and DuckDB hand
|
|
141
|
+
over hundreds to thousands of rows per call, and SQL Server's `jev.judge` sends 500 at a time. Each batch
|
|
142
|
+
becomes one engine call.
|
|
143
|
+
3. **De-duplicate, then cache.** Identical rows are judged once. Answers are cached by row content and
|
|
144
|
+
question, so re-running, changing the threshold or sorting by probability is free, and only rows that
|
|
145
|
+
changed are judged again.
|
|
146
|
+
4. **Shared forward passes.** Misses go to Laya's `predict_batch`, which packs many rows into one forward
|
|
147
|
+
pass (`batch_size`, default 64), sorted by length to minimise padding. Measured on CPU (English
|
|
148
|
+
checkpoint): 0.19 s/row batched vs 0.35 s/row one at a time. On a GPU, Laya is ~33 ms for a single
|
|
149
|
+
decision and ~7 ms per decision batched.
|
|
150
|
+
5. **Streaming when it pays.** `sqljev query --where ... --limit N` judges rows in order with a bounded
|
|
151
|
+
read-ahead, so it stops after the first N matches instead of scanning everything.
|
|
152
|
+
|
|
153
|
+
### Backends
|
|
154
|
+
|
|
155
|
+
| `backend` | Model | Rows per call | Use it for |
|
|
156
|
+
| --- | --- | --- | --- |
|
|
157
|
+
| `local` (default) | Laya in this process | `batch_size` per forward pass (64) | CLI, DuckDB, Spark/Databricks executors, the gateway itself |
|
|
158
|
+
| `gateway` | a `sqljev gateway` (which runs Laya) | 256 per HTTP request | SQL Server, Snowflake UDFs, Redshift Lambda, anything remote |
|
|
159
|
+
| `laya-serve` | stock `laya-serve` (`POST /v1/systemone`) | 1 (Laya reads one state) | an existing Laya deployment |
|
|
160
|
+
| `jev` | TypeSafe Jev, hosted | 20 in one shared state (pg-jev's measured optimum) | best zero-shot accuracy, if data may leave your network |
|
|
161
|
+
|
|
162
|
+
## Benchmark: 100,000 rows, 13 questions
|
|
163
|
+
|
|
164
|
+
Ten synthetic but realistic tables with exact labels (`python -m sqljev.demo`), one plain SQL query per question
|
|
165
|
+
through DuckDB, answered by the **base Laya English checkpoint with no training**, on an RTX 4090 Laptop GPU
|
|
166
|
+
that another model was sharing:
|
|
167
|
+
|
|
168
|
+
| Question | Rows | Accuracy | Always-majority baseline | Rows/s |
|
|
169
|
+
| --- | --- | --- | --- | --- |
|
|
170
|
+
| Contract clause: which type? (5) | 10000 | **0.995** | 0.203 | 1606 |
|
|
171
|
+
| Job post: fully remote? | 10000 | **0.922** | 0.602 | 375 |
|
|
172
|
+
| Support ticket: is the customer angry? | 10000 | **0.894** | 0.697 | 567 |
|
|
173
|
+
| Advisor email: guarantees returns? | 10000 | **0.865** | 0.747 | 514 |
|
|
174
|
+
| Support ticket: which team? | 10000 | **0.854** | 0.352 | 580 |
|
|
175
|
+
| Job post: how senior? (3 levels) | 10000 | **0.853** | 0.336 | 402 |
|
|
176
|
+
| Expense: which category? (5) | 10000 | **0.851** | 0.209 | 607 |
|
|
177
|
+
| Product review: reports a defect? | 10000 | **0.850** | 0.702 | 855 |
|
|
178
|
+
| Product review: sentiment (3 levels) | 10000 | **0.828** | 0.453 | 879 |
|
|
179
|
+
| Adverse event: was it serious? | 10000 | **0.699** | 0.650 | 345 |
|
|
180
|
+
| Two company records: same company? (join) | 20000 | **0.685** | 0.506 | 531 |
|
|
181
|
+
| Adverse event: which body system? (5) | 10000 | **0.680** | 0.203 | 371 |
|
|
182
|
+
| Rental listing: pets allowed? | 10000 | **0.595** | 0.546 | 384 |
|
|
183
|
+
|
|
184
|
+
**140,000 decisions in 271 s (516/s). Re-running all 13 queries: 0.9 s**, every answer from the cache. With an
|
|
185
|
+
instant stand-in model, sqljev's own overhead measured about 98,000 decisions/s: the model is the only cost.
|
|
186
|
+
Reproduce with `python -m sqljev.demo --out bench/bench.duckdb && python bench/run.py --device cuda`.
|
|
187
|
+
|
|
188
|
+
The weak rows are where fine-tuning pays: the model has to learn *your* definition (what counts as "serious"
|
|
189
|
+
in pharmacovigilance, what a pet policy sentence means). See below.
|
|
190
|
+
|
|
191
|
+
## Which model? Laya vs Jev, honestly
|
|
192
|
+
|
|
193
|
+
| | Laya (default) | Jev |
|
|
194
|
+
| --- | --- | --- |
|
|
195
|
+
| License / weights | Apache 2.0, open weights | proprietary API |
|
|
196
|
+
| Where it runs | your server, GPU or CPU | TypeSafe's cloud |
|
|
197
|
+
| Cost | $0 per token | $0.042 / 1M input tokens |
|
|
198
|
+
| Latency | ~33 ms / decision (T4) | ~250 ms / request |
|
|
199
|
+
| **Zero-shot** accuracy (typed-decisions) | 0.362 (base checkpoint) | **0.727** |
|
|
200
|
+
| **Fine-tuned** accuracy (typed-decisions) | **0.766** | not fine-tunable |
|
|
201
|
+
| Wide option sets (Banking77) | 0.425 | **0.870** |
|
|
202
|
+
|
|
203
|
+
*(Figures from Laya's published benchmarks.)* Laya out of the box is good at clear-cut yes/no conditions
|
|
204
|
+
and weaker at fine-grained choices. **Its strength is that you can train it on your data**, and SQL tables
|
|
205
|
+
are full of labels. So sqljev ships the loop:
|
|
206
|
+
|
|
207
|
+
## Fine-tune Laya on your own tables
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
# 1. Labelled rows -> training/eval data. The label column is never shown to the model, and the state and
|
|
211
|
+
# question are built by the same code the runtime uses, so the checkpoint learns exactly what it will be asked.
|
|
212
|
+
sqljev dataset "$DB_URL" "SELECT subject, body, team FROM tickets WHERE team IS NOT NULL" \
|
|
213
|
+
--label team --choice "which team should handle this?" --test-fraction 0.2 -o tickets.jsonl
|
|
214
|
+
# -> tickets.train.jsonl, tickets.test.jsonl (--format typed-decisions for Laya's fine-tuning notebook)
|
|
215
|
+
|
|
216
|
+
# 2. Baseline: how does the base model (or Jev) do on YOUR rows?
|
|
217
|
+
sqljev eval tickets.test.jsonl # Laya base
|
|
218
|
+
sqljev eval tickets.test.jsonl --backend jev # Jev, for comparison
|
|
219
|
+
|
|
220
|
+
# 3. Fine-tune (one GPU; a free Colab T4 is enough. --train-layers 12 for GPUs with less than ~10 GB free)
|
|
221
|
+
sqljev finetune tickets.train.jsonl --out checkpoints/tickets --epochs 3
|
|
222
|
+
|
|
223
|
+
# 4. Measure again on the same held-out rows, then share it with the team
|
|
224
|
+
sqljev eval tickets.test.jsonl --model checkpoints/tickets --min-accuracy 0.85
|
|
225
|
+
HF_TOKEN=... sqljev publish checkpoints/tickets --repo your-org/laya-tickets
|
|
226
|
+
SQLJEV_MODEL=your-org/laya-tickets sqljev gateway --host 0.0.0.0 # every database now uses it
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Measured on the built-in pharma demo (*"the adverse event was serious"*, 3,000 training rows, 1,000 held out):
|
|
230
|
+
**69.4% → 100% after 2 minutes** of training on an RTX 4090 Laptop GPU (`--train-layers 12`, 3 epochs). The demo
|
|
231
|
+
reports come from templates and are easy to learn; expect a smaller jump on real data, and measure it the same way.
|
|
232
|
+
|
|
233
|
+
**No terminal?** Open [`notebooks/sqljev_finetune_colab.ipynb`](https://github.com/singhpratech/sqljev/blob/main/notebooks/sqljev_finetune_colab.ipynb) in
|
|
234
|
+
[Colab](https://colab.research.google.com/github/singhpratech/sqljev/blob/main/notebooks/sqljev_finetune_colab.ipynb),
|
|
235
|
+
pick a question (or the built-in pharma demo) and press *Run all*: it measures, fine-tunes, measures again and
|
|
236
|
+
publishes. The training loop follows Laya's own fine-tuning notebook (proper-scoring-rule policy gradient plus
|
|
237
|
+
cross-entropy, temperature calibration on held-out rows), adapted to a single GPU.
|
|
238
|
+
|
|
239
|
+
`laya-evals run tickets.test.jsonl` works on the same files for calibration (ECE) and per-slice reports.
|
|
240
|
+
|
|
241
|
+
## Install
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
pip install "sqljev[laya,db]" # engine + Laya + SQLAlchemy CLI (Python 3.10+)
|
|
245
|
+
pip install "sqljev" # engine, gateway client, Lambda handler only: stdlib, no dependencies
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
For a GPU, install the matching PyTorch build first. The first use downloads the Laya checkpoint (~1.7 GB)
|
|
249
|
+
from Hugging Face.
|
|
250
|
+
|
|
251
|
+
## Per database
|
|
252
|
+
|
|
253
|
+
<details open><summary><b>Any database: the CLI</b> (Oracle, Db2, Trino, and everything above)</summary>
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
sqljev query "$DB_URL" "SELECT * FROM tickets" --where "the customer is angry" --limit 20
|
|
257
|
+
sqljev query "$DB_URL" "SELECT * FROM tickets" --rank "the customer is angry" --limit 10 --format csv
|
|
258
|
+
sqljev query "$DB_URL" "SELECT * FROM tickets" --choice "which team?" --options billing,technical,sales
|
|
259
|
+
sqljev query "$DB_URL" "SELECT * FROM tickets" --prob "mentions a refund" --columns subject,body
|
|
260
|
+
# Write judgments back as a table you can join in any database:
|
|
261
|
+
sqljev materialize "$DB_URL" "SELECT id, subject, body FROM tickets" --key id \
|
|
262
|
+
--prob "the customer is angry" --into ticket_anger
|
|
263
|
+
```
|
|
264
|
+
</details>
|
|
265
|
+
|
|
266
|
+
<details><summary><b>SQL Server / Azure SQL</b></summary>
|
|
267
|
+
|
|
268
|
+
Run [`sql/sqlserver/install.sql`](https://github.com/singhpratech/sqljev/blob/main/sql/sqlserver/install.sql). It creates schema `jev` with `jev.judge`,
|
|
269
|
+
`jev.prob`, `jev.matches`, `jev.choice`, `jev.score`, `jev.score_norm`, `jev.eval`, `jev.answers_for`
|
|
270
|
+
(set-based join) and `jev.forget`.
|
|
271
|
+
|
|
272
|
+
- **SQL Server 2025 / Azure SQL:** `jev.judge` calls a `sqljev gateway` through
|
|
273
|
+
`sp_invoke_external_rest_endpoint` (HTTPS on 443, publicly trusted certificate). See the header of the script.
|
|
274
|
+
- **SQL Server 2016–2022**, or no outbound HTTPS: fill the same answer table from outside, and every function
|
|
275
|
+
works the same:
|
|
276
|
+
```bash
|
|
277
|
+
sqljev judge "mssql+pymssql://user:pw@host/db" --source dbo.tickets --prob "the customer is angry"
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
Row JSON (`FOR JSON`) and hashes are computed by SQL Server itself, so a row edited later is judged again
|
|
281
|
+
on the next `jev.judge` run, and unchanged rows are skipped.
|
|
282
|
+
</details>
|
|
283
|
+
|
|
284
|
+
<details><summary><b>PostgreSQL</b> (RDS, Aurora, Cloud SQL, AlloyDB, Azure, Supabase, Neon, ...)</summary>
|
|
285
|
+
|
|
286
|
+
Run [`sql/postgres/install.sql`](https://github.com/singhpratech/sqljev/blob/main/sql/postgres/install.sql): no extension, no superuser. Judge once, then read
|
|
287
|
+
with ordinary functions:
|
|
288
|
+
|
|
289
|
+
```bash
|
|
290
|
+
sqljev judge "postgresql://..." --source public.tickets --prob "the customer is angry"
|
|
291
|
+
```
|
|
292
|
+
```sql
|
|
293
|
+
SELECT * FROM tickets t WHERE jev.prob(to_jsonb(t), 'the customer is angry') >= 0.5;
|
|
294
|
+
SELECT jev.choice(to_jsonb(t), 'which team?', ARRAY['billing', 'technical', 'sales']) FROM tickets t;
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Rows are keyed by their `jsonb` content, so edited rows are judged again on the next run. Self-hosted Postgres
|
|
298
|
+
with `plpython3u` can also run [pg-jev](https://github.com/realZachi/pg-jev) on Laya:
|
|
299
|
+
`SET jev.api_url = 'http://<sqljev gateway>:8765/v1/systemone'`.
|
|
300
|
+
</details>
|
|
301
|
+
|
|
302
|
+
<details><summary><b>MySQL / MariaDB</b> (RDS, Aurora, Cloud SQL, Azure)</summary>
|
|
303
|
+
|
|
304
|
+
Run [`sql/mysql/install.sql`](https://github.com/singhpratech/sqljev/blob/main/sql/mysql/install.sql) (stored functions and a `jev_answers` table), then:
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
sqljev judge "mysql+pymysql://..." --source tickets --prob "the customer is angry"
|
|
308
|
+
# prints the exact row expression to use, e.g. JSON_OBJECT('id', t.id, 'subject', t.subject, 'body', t.body)
|
|
309
|
+
```
|
|
310
|
+
```sql
|
|
311
|
+
SELECT * FROM tickets t
|
|
312
|
+
WHERE jev_prob(JSON_OBJECT('id', t.id, 'subject', t.subject, 'body', t.body), 'the customer is angry') >= 0.5;
|
|
313
|
+
```
|
|
314
|
+
</details>
|
|
315
|
+
|
|
316
|
+
<details><summary><b>Snowflake</b></summary>
|
|
317
|
+
|
|
318
|
+
- [`sql/snowflake/install_spcs.sql`](https://github.com/singhpratech/sqljev/blob/main/sql/snowflake/install_spcs.sql): **Laya inside Snowflake** on Snowpark
|
|
319
|
+
Container Services (GPU). Rows never leave your account; service functions batch up to 1,000 rows per call.
|
|
320
|
+
- [`sql/snowflake/install_udf.sql`](https://github.com/singhpratech/sqljev/blob/main/sql/snowflake/install_udf.sql): a vectorized Python UDF (engine inlined)
|
|
321
|
+
calling your gateway or Jev through an External Access Integration.
|
|
322
|
+
|
|
323
|
+
```sql
|
|
324
|
+
SELECT * FROM tickets t WHERE jev(OBJECT_CONSTRUCT(t.*), 'the customer is angry');
|
|
325
|
+
```
|
|
326
|
+
</details>
|
|
327
|
+
|
|
328
|
+
<details><summary><b>Databricks / Spark</b></summary>
|
|
329
|
+
|
|
330
|
+
```python
|
|
331
|
+
import sqljev.spark
|
|
332
|
+
sqljev.spark.register(spark, device="cuda") # Laya on every executor (or backend="gateway")
|
|
333
|
+
```
|
|
334
|
+
```sql
|
|
335
|
+
SELECT * FROM tickets WHERE jev(to_json(struct(subject, body)), 'the customer is angry');
|
|
336
|
+
```
|
|
337
|
+
See [`sql/databricks/README.md`](https://github.com/singhpratech/sqljev/blob/main/sql/databricks/README.md).
|
|
338
|
+
</details>
|
|
339
|
+
|
|
340
|
+
<details><summary><b>BigQuery</b></summary>
|
|
341
|
+
|
|
342
|
+
Remote functions backed by the gateway on Cloud Run (GPU optional):
|
|
343
|
+
[`sql/bigquery/install.sql`](https://github.com/singhpratech/sqljev/blob/main/sql/bigquery/install.sql), [`deploy/cloudrun`](https://github.com/singhpratech/sqljev/blob/main/deploy/cloudrun/README.md).
|
|
344
|
+
```sql
|
|
345
|
+
SELECT * FROM `proj.support.tickets` t WHERE jev.jev(TO_JSON_STRING(t), 'the customer is angry');
|
|
346
|
+
```
|
|
347
|
+
</details>
|
|
348
|
+
|
|
349
|
+
<details><summary><b>Amazon Redshift</b></summary>
|
|
350
|
+
|
|
351
|
+
Lambda UDFs (`sqljev.aws_lambda.handler`, stdlib-only zip) forwarding to a gateway:
|
|
352
|
+
[`sql/redshift/install.sql`](https://github.com/singhpratech/sqljev/blob/main/sql/redshift/install.sql), [`deploy/lambda`](https://github.com/singhpratech/sqljev/blob/main/deploy/lambda/README.md).
|
|
353
|
+
</details>
|
|
354
|
+
|
|
355
|
+
<details><summary><b>DuckDB</b></summary>
|
|
356
|
+
|
|
357
|
+
```python
|
|
358
|
+
import duckdb, sqljev.duckdb
|
|
359
|
+
con = duckdb.connect("support.duckdb"); sqljev.duckdb.register(con)
|
|
360
|
+
con.sql("SELECT * FROM tickets t WHERE jev(to_json(t), 'the customer is angry')")
|
|
361
|
+
```
|
|
362
|
+
</details>
|
|
363
|
+
|
|
364
|
+
## The gateway
|
|
365
|
+
|
|
366
|
+
One small HTTP service that speaks every database's batch protocol and runs Laya in-process:
|
|
367
|
+
|
|
368
|
+
```bash
|
|
369
|
+
sqljev gateway --host 0.0.0.0 --port 8765 # SQLJEV_GATEWAY_TOKEN=... to require a token
|
|
370
|
+
docker build -f deploy/Dockerfile -t sqljev . # checkpoint baked in; CUDA via --build-arg TORCH_INDEX=...
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
| Route | Caller |
|
|
374
|
+
| --- | --- |
|
|
375
|
+
| `POST /v1/eval` | sqljev clients (`backend=gateway`), Snowflake UDF |
|
|
376
|
+
| `POST /sqlserver` | `jev.judge` via `sp_invoke_external_rest_endpoint` |
|
|
377
|
+
| `POST /snowflake/<fn>` | Snowflake service / external functions |
|
|
378
|
+
| `POST /bigquery` | BigQuery remote functions |
|
|
379
|
+
| `POST /redshift` | Redshift Lambda payloads |
|
|
380
|
+
| `POST /v1/systemone` | Jev clients such as pg-jev (Jev's own API, answered by Laya) |
|
|
381
|
+
| `GET /health`, `GET /stats` | probes, cache/throughput stats |
|
|
382
|
+
|
|
383
|
+
## Functions
|
|
384
|
+
|
|
385
|
+
Identical names everywhere (SQL Server uses the `jev.` schema: `jev.prob`, `jev.matches`, ...).
|
|
386
|
+
|
|
387
|
+
| Function | Returns | Purpose |
|
|
388
|
+
| --- | --- | --- |
|
|
389
|
+
| `jev(row, condition [, threshold])` | boolean | `WHERE` predicate; threshold defaults to 0.5 |
|
|
390
|
+
| `jev_prob(row, condition)` | float | probability 0..1 that the row satisfies the condition |
|
|
391
|
+
| `jev_score(row, question, levels)` | float | probability-weighted position on ordered levels (0..n-1) |
|
|
392
|
+
| `jev_score_norm(row, question, levels)` | float | same, normalised to 0..1 |
|
|
393
|
+
| `jev_choice(row, question, options)` | text | the most likely option |
|
|
394
|
+
| `jev_confidence(row, question, kind, options)` | float | confidence of a choice / score answer |
|
|
395
|
+
| `jev_eval(row, question, kind, options)` | json | the full answer: probabilities, confidence |
|
|
396
|
+
|
|
397
|
+
## Settings
|
|
398
|
+
|
|
399
|
+
Environment variables `SQLJEV_<NAME>`, keyword arguments (`Jev(backend="gateway")`,
|
|
400
|
+
`register(con, device="cuda")`) or CLI flags.
|
|
401
|
+
|
|
402
|
+
| Setting | Default | Meaning |
|
|
403
|
+
| --- | --- | --- |
|
|
404
|
+
| `backend` | `local` | `local`, `gateway`, `laya-serve`, `jev` |
|
|
405
|
+
| `model` | Laya router | `english`, `multilingual`, `typed-decisions`, a fine-tuned checkpoint path / Hub id, or a Jev model id |
|
|
406
|
+
| `device` | auto | `cpu`, `cuda`, `mps` (local) |
|
|
407
|
+
| `api_url` | per backend | gateway / laya-serve / Jev endpoint |
|
|
408
|
+
| `api_key` | env | Jev: `TYPESAFE_API_KEY`; gateway: `SQLJEV_GATEWAY_TOKEN`; laya-serve: `LAYA_API_KEY` |
|
|
409
|
+
| `batch_size` | 64 / 256 / 1 / 20 | rows per forward pass (local) or per request |
|
|
410
|
+
| `concurrency` | 1 / 4 / 4 / 16 | parallel requests |
|
|
411
|
+
| `threshold` | 0.5 | for `jev()` |
|
|
412
|
+
| `max_len` | checkpoint | Laya token budget per row (multilingual reads up to 8,192) |
|
|
413
|
+
| `drop_nulls` | true | omit NULL columns from what the model sees |
|
|
414
|
+
| `cache_size` | 200,000 | answers kept in memory (LRU); 0 disables |
|
|
415
|
+
| `max_rows` / `max_chars` | 0 (off) | spend guard: refuse to send more than this |
|
|
416
|
+
| `timeout` / `keepalive` | 60 / 600 s | HTTP backends |
|
|
417
|
+
|
|
418
|
+
## Caveats
|
|
419
|
+
|
|
420
|
+
- **Limit before you judge.** Databases compute the `SELECT` list before `ORDER BY ... LIMIT`, so
|
|
421
|
+
`SELECT jev_prob(...) FROM t ORDER BY id LIMIT 100` judges *every* row. Limit in a subquery first:
|
|
422
|
+
`SELECT jev_prob(...) FROM (SELECT * FROM t ORDER BY id LIMIT 100) t`. In `WHERE`, put cheap predicates first.
|
|
423
|
+
- **Every row that reaches `jev()` is judged** (once, thanks to the cache). No index can answer a
|
|
424
|
+
plain-language condition. Filter with cheap SQL first; `LIMIT` and streaming stop early.
|
|
425
|
+
- **Laya reads 512 tokens** (English) or 1,024 (multilingual, up to 8,192 with `max_len`). Wide rows are cut
|
|
426
|
+
off, so send only the columns that matter.
|
|
427
|
+
- **Zero-shot Laya is not Jev.** Measure on your data with `sqljev eval` before trusting a threshold, and
|
|
428
|
+
fine-tune when it matters.
|
|
429
|
+
- With `backend=jev`, row contents go to a third-party API. Don't use it on data you may not share.
|
|
430
|
+
- Answers can change between checkpoints. Pin `model` when results feed reports.
|
|
431
|
+
|
|
432
|
+
## Development
|
|
433
|
+
|
|
434
|
+
```bash
|
|
435
|
+
uv venv && uv pip install -e ".[dev]"
|
|
436
|
+
pytest # never calls a real model: tests/mock_api.py + a fake laya module
|
|
437
|
+
python scripts/build_sql.py # regenerate sql/snowflake/install_udf.sql after editing core.py
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
Releasing is one command, `scripts/release.sh 0.1.0`: it dates the CHANGELOG entry, runs the tests, tags and
|
|
441
|
+
pushes. GitHub Actions then builds the package, creates the GitHub Release with the wheel and every database's
|
|
442
|
+
install scripts attached, and publishes to PyPI once `PYPI_PUBLISH` is enabled.
|
|
443
|
+
|
|
444
|
+
See [AGENTS.md](https://github.com/singhpratech/sqljev/blob/main/AGENTS.md) for the architecture.
|
|
445
|
+
|
|
446
|
+
## License
|
|
447
|
+
|
|
448
|
+
Apache 2.0. Parts ported from [pg-jev](https://github.com/realZachi/pg-jev) (PostgreSQL License); see
|
|
449
|
+
[NOTICE](https://github.com/singhpratech/sqljev/blob/main/NOTICE). Laya is by Convai Innovations (Apache 2.0). Jev and TypeSafe are trademarks of their
|
|
450
|
+
respective owners; this project is not affiliated with TypeSafe or Convai Innovations.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
sqljev/__init__.py,sha256=ztEPrzWr-t66tPH6f0AI1p-WPF7CTPM8ZEJAT1f0XQo,392
|
|
2
|
+
sqljev/__main__.py,sha256=bYt9eEaoRQWdejEHFD8REx9jxVEdZptECFsV7F49Ink,30
|
|
3
|
+
sqljev/aws_lambda.py,sha256=M6JpJSKnX-j_Dsv4WGfECy1Fs5KDmRQjjqlic3Jb-i4,651
|
|
4
|
+
sqljev/cli.py,sha256=6oF1H3xwSIha7Mg2aSKrduz6EedYTQsP2uBp6K9hfrQ,24808
|
|
5
|
+
sqljev/core.py,sha256=-Lr3JJQrm5UaaUBvdv7oJ81kgq8_Mfue-n5RxhaHicM,29008
|
|
6
|
+
sqljev/demo.py,sha256=_rthrpfDWDLJMC9XN5eZpEg0A-xR-HVbTITZ5T1_-MM,19543
|
|
7
|
+
sqljev/duckdb.py,sha256=v3i73FJHH1TQRTVPH9OjZqeRWweSL-srToORSu_6ObQ,2462
|
|
8
|
+
sqljev/finetune.py,sha256=bmdjf2S-JWjovQmMU0mPva5crADaLlDea-KnVG6fCmQ,17294
|
|
9
|
+
sqljev/gateway.py,sha256=H-zwF4m0sKoxav-0JcPYDiQTZLAz9JO90xg9ahv0kIM,10137
|
|
10
|
+
sqljev/spark.py,sha256=95Ojpo1s-vF9j76tP38DZ8jBulnxgXkcAjrG4IPRKlk,2591
|
|
11
|
+
sqljev-0.1.0.dist-info/METADATA,sha256=kOBbMAZNAY0sGK5dyGaM3zQgK9TGbj7_YLSba8-n4To,24546
|
|
12
|
+
sqljev-0.1.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
13
|
+
sqljev-0.1.0.dist-info/entry_points.txt,sha256=Sdtv8fnWOdLvrdV45yyE62wndL1QEVLA8WEGKx9QDE8,43
|
|
14
|
+
sqljev-0.1.0.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
|
|
15
|
+
sqljev-0.1.0.dist-info/licenses/NOTICE,sha256=nCvmQrFKWqB3JoY2f8y3Id9Ez_TPC7MlILQ9tl71eMs,1810
|
|
16
|
+
sqljev-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|