From 6b082fdb5902030e879268bea91d609aa4e1b251 Mon Sep 17 00:00:00 2001 From: Costin Busioc Date: Wed, 17 Jun 2026 10:00:11 +0300 Subject: [PATCH 1/2] Add repo scaffolding and natural-language-to-SQL example - Root files: .gitignore, LICENSE, README.md - qvac-natural-language-to-sql: Electron app that turns plain-English questions into local SQL via the QVAC SDK (Qwen3 4B) over an in-memory SQLite (sql.js) bank dataset. --- .gitignore | 24 + LICENSE | 201 + README.md | 46 + qvac-natural-language-to-sql/.gitignore | 23 + qvac-natural-language-to-sql/LICENSE | 178 + qvac-natural-language-to-sql/README.md | 110 + qvac-natural-language-to-sql/RECIPE.md | 192 + .../docs/screenshots/01-home.png | Bin 0 -> 358697 bytes .../docs/screenshots/02-results.png | Bin 0 -> 407499 bytes .../docs/screenshots/03-technical-sql.png | Bin 0 -> 423497 bytes qvac-natural-language-to-sql/main.js | 188 + .../package-lock.json | 9250 +++++++++++++++++ qvac-natural-language-to-sql/package.json | 23 + qvac-natural-language-to-sql/preload.js | 22 + qvac-natural-language-to-sql/renderer/ai.js | 89 + qvac-natural-language-to-sql/renderer/app.jsx | 279 + .../renderer/assets/icon-copy.svg | 11 + .../renderer/assets/logo.svg | 8 + .../renderer/bank-data.js | 344 + .../renderer/colors_and_type.css | 180 + .../renderer/components.jsx | 328 + qvac-natural-language-to-sql/renderer/db.js | 61 + .../renderer/fonts/Inconsolata-400.woff2 | Bin 0 -> 29020 bytes .../renderer/fonts/Inconsolata-500.woff2 | Bin 0 -> 29020 bytes .../renderer/fonts/Inconsolata-600.woff2 | Bin 0 -> 29020 bytes .../renderer/fonts/Inconsolata-700.woff2 | Bin 0 -> 29020 bytes .../renderer/fonts/Inter-300.woff2 | Bin 0 -> 48432 bytes .../renderer/fonts/Inter-400.woff2 | Bin 0 -> 48432 bytes .../renderer/fonts/Inter-500.woff2 | Bin 0 -> 48432 bytes .../renderer/fonts/Inter-600.woff2 | Bin 0 -> 48432 bytes .../renderer/fonts/Inter-700.woff2 | Bin 0 -> 48432 bytes .../renderer/index.html | 30 + .../renderer/qvac-natural-language-to-sql.css | 647 ++ 33 files changed, 12234 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 qvac-natural-language-to-sql/.gitignore create mode 100644 qvac-natural-language-to-sql/LICENSE create mode 100644 qvac-natural-language-to-sql/README.md create mode 100644 qvac-natural-language-to-sql/RECIPE.md create mode 100644 qvac-natural-language-to-sql/docs/screenshots/01-home.png create mode 100644 qvac-natural-language-to-sql/docs/screenshots/02-results.png create mode 100644 qvac-natural-language-to-sql/docs/screenshots/03-technical-sql.png create mode 100644 qvac-natural-language-to-sql/main.js create mode 100644 qvac-natural-language-to-sql/package-lock.json create mode 100644 qvac-natural-language-to-sql/package.json create mode 100644 qvac-natural-language-to-sql/preload.js create mode 100644 qvac-natural-language-to-sql/renderer/ai.js create mode 100644 qvac-natural-language-to-sql/renderer/app.jsx create mode 100644 qvac-natural-language-to-sql/renderer/assets/icon-copy.svg create mode 100644 qvac-natural-language-to-sql/renderer/assets/logo.svg create mode 100644 qvac-natural-language-to-sql/renderer/bank-data.js create mode 100644 qvac-natural-language-to-sql/renderer/colors_and_type.css create mode 100644 qvac-natural-language-to-sql/renderer/components.jsx create mode 100644 qvac-natural-language-to-sql/renderer/db.js create mode 100644 qvac-natural-language-to-sql/renderer/fonts/Inconsolata-400.woff2 create mode 100644 qvac-natural-language-to-sql/renderer/fonts/Inconsolata-500.woff2 create mode 100644 qvac-natural-language-to-sql/renderer/fonts/Inconsolata-600.woff2 create mode 100644 qvac-natural-language-to-sql/renderer/fonts/Inconsolata-700.woff2 create mode 100644 qvac-natural-language-to-sql/renderer/fonts/Inter-300.woff2 create mode 100644 qvac-natural-language-to-sql/renderer/fonts/Inter-400.woff2 create mode 100644 qvac-natural-language-to-sql/renderer/fonts/Inter-500.woff2 create mode 100644 qvac-natural-language-to-sql/renderer/fonts/Inter-600.woff2 create mode 100644 qvac-natural-language-to-sql/renderer/fonts/Inter-700.woff2 create mode 100644 qvac-natural-language-to-sql/renderer/index.html create mode 100644 qvac-natural-language-to-sql/renderer/qvac-natural-language-to-sql.css diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..73ddf5b --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# Dependencies +node_modules/ + +# Environment / secrets +.env +.env.* +!.env.example + +# Claude Code / agent tooling (not part of the examples) +.claude/ +CLAUDE.md +CLAUDE.local.md + +# OS / editor cruft +.DS_Store +*.log +npm-debug.log* +.idea/ +.vscode/ + +# Build / packaging output +dist/ +out/ +build/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d716944 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2026 Tether Data, S.A. de C.V. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..60e9dc5 --- /dev/null +++ b/README.md @@ -0,0 +1,46 @@ +# QVAC Examples + +Example applications and code samples built with the [QVAC SDK](https://docs.qvac.tether.io/) — Tether's toolkit for running AI locally, privately, and on-device. + +Each example here is a focused, self-contained app demonstrating one real-world use case for local AI: what becomes possible when intelligence runs on your own machine instead of someone else's cloud — no data leaving the device, no permission required. + +## ⚠️ These are examples, not products + +The apps in this repository are **prototypes and demonstrations**. + +- Provided **as-is, with no support, no warranty, and no SLA**. +- **Not maintained as products** — they may break, lag behind the SDK, or be removed. +- **Not security-audited** — do **not** use them in production or with real, sensitive data. +- They exist to **illustrate use cases and teach**. + +See [LICENSE](./LICENSE) for the full Apache 2.0 terms, including the disclaimer of warranty. + +## What's inside + +Every example lives in its own directory named `qvac-{app-name}` and is fully self-contained — its own code, its own setup steps, and its own README explaining what it does and why local AI matters for that use case. + +| App | Description | +|-----|-------------| +| [`qvac-natural-language-to-sql`](./qvac-natural-language-to-sql) | Ask a banking database questions in plain English and watch a local AI (Qwen3 4B) write the SQL, then run it on-device against an in-memory SQLite bank. The schema and your question are the only things the model ever sees — no row data, no cloud, no API keys. | + +## Running an example + +Each app documents its own prerequisites and run steps: + +1. Open the app's directory (`qvac-{app-name}/`). +2. Read its `README.md`. +3. Follow the install and run instructions there. + +## About QVAC + +QVAC is an open-source, cross-platform ecosystem for building local-first, peer-to-peer AI applications and systems. With QVAC, you can run AI tasks like LLMs, speech, RAG, and more locally across Linux, macOS, Windows, Android, and iOS — or delegate inference to peers using its built-in P2P capabilities. + +Learn more at [qvac.tether.io](https://qvac.tether.io/), read the docs at [docs.qvac.tether.io](https://docs.qvac.tether.io/), or explore the SDK on [GitHub](https://github.com/tetherto/qvac). + +## License + +Licensed under the Apache License, Version 2.0. See [LICENSE](./LICENSE). + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +Copyright © 2026 Tether Data, S.A. de C.V. diff --git a/qvac-natural-language-to-sql/.gitignore b/qvac-natural-language-to-sql/.gitignore new file mode 100644 index 0000000..0f8b45d --- /dev/null +++ b/qvac-natural-language-to-sql/.gitignore @@ -0,0 +1,23 @@ +# Dependencies +node_modules/ + +# Environment / secrets +.env +.env.* + +# Local Claude Code settings (exposes local paths) +.claude/settings.local.json + +# OS / editor cruft +.DS_Store +*.log +npm-debug.log* + +# Build / packaging output +dist/ +out/ +build/ + +# Vendored sql.js artifacts (generated by `npm run vendor:sqljs`) +renderer/sql-wasm.js +renderer/sql-wasm.wasm diff --git a/qvac-natural-language-to-sql/LICENSE b/qvac-natural-language-to-sql/LICENSE new file mode 100644 index 0000000..5d5f683 --- /dev/null +++ b/qvac-natural-language-to-sql/LICENSE @@ -0,0 +1,178 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + +Copyright 2026 Tether Data, S.A. de C.V. diff --git a/qvac-natural-language-to-sql/README.md b/qvac-natural-language-to-sql/README.md new file mode 100644 index 0000000..949a10d --- /dev/null +++ b/qvac-natural-language-to-sql/README.md @@ -0,0 +1,110 @@ +# QVAC Natural Language to SQL + +Ask a banking database questions in plain English and watch a local AI write the SQL — then run it, on-device, against an in-memory bank. "Top 3 clients in Frankfurt with the biggest debt" becomes a real `SELECT`, executes locally, and returns rows. No cloud, no API keys for the model, no data leaving your machine. + +Everything intelligent runs on your machine. The LLM (Qwen3 4B via the QVAC SDK) is 100% local: no cloud AI, no per-token cost, no prompt logging on someone else's servers. The database is a local SQLite instance running in WebAssembly, in-process. For the core experience, nothing touches the internet except the one-time model download. + +> **This is an example, not a product.** It's a self-contained prototype that demonstrates what the QVAC SDK makes possible. It ships as-is, with **no support, no warranty, and no SLA**. See [About this example](#about-this-example). + +## Screenshots + +> **A potential look, not a fixed design.** These shots are here to give you a visual idea of where the app ends up. The [recipe](./RECIPE.md) walks through building it from scratch, so what you produce may differ slightly in layout, copy, or styling — that's expected. + +**Ask in plain English.** The home screen: a question box, example prompts, and the live schema in the sidebar. The badge reassures you everything stays on-device. + +![Home screen — ask your data a question in plain English](./docs/screenshots/01-home.png) + +**See the answer.** The model returns a plain-English summary of what the query will do; running it executes locally and shows the rows — real numbers from the in-memory bank. + +![Results — plain-English explanation and the rows returned by the local query](./docs/screenshots/02-results.png) + +**Flip on "I'm technical".** Reveal and edit the generated `SELECT` before running it. The SQL is the model's; the results come from actually executing it on-device. + +![Technical mode — the editable generated SQL](./docs/screenshots/03-technical-sql.png) + +## What you get + +- **English → SQL, locally.** Type a question; the local Qwen3 model reads your database *schema* (never the row data) and writes a single `SELECT`. The query then runs on-device against the in-memory database and shows you the rows. +- **A realistic bank dataset.** A seeded SQLite database with five linked tables — customers, accounts, transactions, loans, and an audit log — across several German cities. Enough structure to ask interesting questions (debt, overdue loans, balances, joins) without any real customer data. +- **"I'm technical" mode.** Off by default, you get a plain-English summary of what the query does. Flip it on to see and *edit* the generated SQL before running it. +- **Read-only by design.** Anything that mutates data (`DELETE`, `DROP`, `UPDATE`, `INSERT`, `ALTER`, `PRAGMA`, …) is blocked before it ever reaches the engine. This demo only reads. +- **Query history.** Recent questions, their SQL, and explanations are kept in the session so you can re-run them with one click. +- **Privacy you can see.** The schema and your question are the only things the model ever receives. The data lives in the renderer's memory; the app is served from a `127.0.0.1`-only static server that isn't reachable from the network. + +## Why local AI matters here + +Banking data is exactly the kind of data you can't paste into a cloud chatbot. A natural-language-to-SQL assistant is genuinely useful for analysts and support staff — but only if the question, the schema, and the results never leave the building. Running the model on-device removes the compliance problem at the root: there is no outbound request to review, no third-party data-processing agreement, no token bill. This example is a small, honest demonstration of that pattern. + +## Requirements + +- **Node.js 22.17 or higher** +- A **GPU-capable machine** (macOS Apple Silicon, Linux with Vulkan, or Windows with Vulkan). CPU fallback works but is slow. +- **~3 GB free disk** for the model cache (Qwen3 4B Q4_K_M, downloaded and cached on first run) +- An **internet connection on first run** — once to download the model, and to fetch the pinned front-end libraries (React + sql.js) from CDN. After that the model is cached; see [Running fully offline](#running-fully-offline). + +Check your machine first: + +```bash +npx -y @qvac/sdk doctor +``` + +## Quickstart + +```bash +npm install +npm start +``` + +A desktop window opens. The first question triggers a one-time model download and load (a few minutes, cached afterwards); the status banner shows progress. Once the model is ready, type a question — or tap one of the example chips — and hit **Ask**, then **Run query**. + +Try: + +- *Top 3 clients in Frankfurt with the biggest debt* +- *Show all overdue loans with the customer name and monthly payment* +- *Which customers in Munich owe the most?* + +## How it works (and what it is not) + +- The app is an **Electron** desktop app. The local model (Qwen3 4B Q4_K_M) is loaded in the **main process** via `@qvac/sdk` and exposed to the UI over a narrow IPC bridge — only a `generateSQL(prompt)` call and model-loading progress cross the boundary. +- The database is **SQLite compiled to WebAssembly** (`sql.js`), seeded in memory when the app starts. Every query executes in-process; there is no database server and no network call. +- For each question, the app builds a prompt from the **schema plus your question** and asks the model to reply with JSON: a `SELECT` query and a one-sentence explanation. **Row data is never sent to the model** — only the table/column shapes. +- The returned SQL is checked against a read-only guard *before* it runs. Mutating statements are refused. +- The model writes SQL; it does **not** invent results. The numbers you see are produced by executing the query against the local database. + +This is a demo of local-AI orchestration over a realistic schema — not a production query tool, not financial software, and not advice. Generated SQL can be wrong or suboptimal; that's why technical mode lets you read and edit it before running. + +## The sample data + +A self-contained, fictional dataset seeded entirely on-device (the demo's "today" is 2026-06-08): + +| Table | Rows | What's in it | +| -------------- | ---- | --------------------------------------------------------- | +| `customers` | 25 | name, city, age, last KYC refresh | +| `accounts` | 30 | checking/savings, balance, outstanding debt (EUR) | +| `transactions` | 84 | deposits, withdrawals, transfers, fees | +| `loans` | 20 | mortgage/personal/auto; principal, rate, status, due date | +| `audit_log` | 60 | login, export, admin, and flagged-activity events | + +It contains **no real people, accounts, or credentials** — it exists only to make the natural-language queries interesting. + +## Running fully offline + +The model is cached after the first download, so the AI works offline from then on. The renderer currently loads `sql.js` and React/Babel from CDN. To vendor the SQLite engine locally: + +```bash +npm run vendor:sqljs +``` + +## About this example + +This app lives in [`qvac-examples`](https://github.com/tetherto/qvac-examples), Tether's open-source collection of focused prototypes that show what the QVAC SDK can do with local AI. It is: + +- **An example, not a product.** Small, readable, and meant to be run from clean — not customer-facing software. +- **Unsupported.** Provided as-is, with no support, warranty, or guarantees. Issues and questions may not receive a response. +- **A starting point.** Fork it, read it, adapt it. The point is to make the local-AI pattern concrete. + +## License + +Code licensed under the Apache License, Version 2.0. See [LICENSE](./LICENSE). + +This example depends on `@qvac/sdk`, `electron`, and `sql.js`; using it is subject to each of their respective licenses. diff --git a/qvac-natural-language-to-sql/RECIPE.md b/qvac-natural-language-to-sql/RECIPE.md new file mode 100644 index 0000000..17e2eb8 --- /dev/null +++ b/qvac-natural-language-to-sql/RECIPE.md @@ -0,0 +1,192 @@ +# Recipe · QVAC Natural Language to SQL + + + +> **Legal note (for the human using this recipe, not a build instruction):** This recipe is an illustrative example only and provided “as is.” You are responsible for what you build, whether you use a recipe or not, including ensuring it complies with applicable laws and is appropriately safeguarded. Use of this recipe is subject to the Tether.io Website Terms. + + +> **What this is:** a spec for a local desktop app where you ask your data questions in plain English and get SQL back, running fully on your machine via the QVAC SDK. +> +> **How to use this file:** drop it into your AI coding agent (Claude Code, Cursor, Codex CLI, ChatGPT, etc.) and say *"Build this for me."* This recipe pins the exact QVAC SDK calls (the one part an agent cannot guess) and guides the rest. Write idiomatic code for the structure and the UI; do not improvise the SDK surface. +> +> **Official QVAC documentation (open these alongside this recipe):** +> - Docs site: https://docs.qvac.tether.io/ +> - Full docs concatenated for AI agents: https://docs.qvac.tether.io/llms-full.txt (drop this in your agent's context for complete SDK awareness) +> - Source repo: https://github.com/tetherto/qvac +> - Reference implementation: https://github.com/tetherto/qvac-examples + +--- + +## What you get + +A local Electron desktop app where you: + +- Type a question in plain English. A local Qwen3 4B model reads only the database schema (never the row data) and writes a single SELECT. +- Watch the query run against an in-memory SQLite database, with the rows in a results table. The maths is computed locally, never guessed by the model. +- Explore a fictional demo bank: a few linked tables (customers, accounts, transactions, loans, audit log), seeded on-device, with no real people. +- Toggle a technical mode: off, you see a plain-English summary of the query; on, you see and can edit the SQL before running. +- Stay read-only by design: any statement that would mutate data is blocked before it reaches the engine. + +Everything runs on the user's GPU. No cloud calls, no API keys. The first run downloads the model (about 3 GB) into the QVAC cache; later runs reuse it. + +## Why this works + +Banking-style data is exactly what you cannot paste into a cloud chatbot. A natural-language-to-SQL helper is genuinely useful, but only if the question, the schema, and the results never leave the machine. Running the model on-device removes the compliance problem at the source: no outbound request to review, no data agreement, no token bill. Two design choices keep it safe: only the schema and the question ever reach the model (never row data), and a read-only guard refuses any non-SELECT statement, so a wrong or adversarial generation cannot change the database. + +## Requirements + +- **Node.js** 22.17 or higher (Node 25 verified) +- A GPU-capable machine. QVAC supports all three major platforms: + - **Linux** (x64 or arm64) with a Vulkan-capable GPU (NVIDIA, AMD, or Intel): primary target + - **Windows** (x64) with a Vulkan-capable GPU: fully supported + - **macOS** (Apple Silicon) with Metal: fully supported + - CPU fallback works on all three but inference is slow +- **About 3 GB free disk** for the model cache (Qwen3 4B Q4_K_M) +- **No API keys**, no cloud account +- Verify the machine with `npx -y @qvac/sdk doctor` before scaffolding + +## Recommended hardware & compatibility check + +One resident LLM (Qwen3 4B Q4_K_M, 16k context). + +| | Minimum | Recommended | +|---|---|---| +| RAM | 8 GB (use the 1.7B model) | 16 GB or more | +| GPU | integrated / CPU fallback (slow) | discrete Vulkan GPU, or Apple Silicon (Metal) | +| Disk free | about 3 GB | about 5 GB | +| OS | macOS 14+, Windows 10+, Linux | same | + +The agent MUST confirm the machine meets this before installing or loading anything (see Hard rules). On 8 GB, use `QWEN3_1_7B_INST_Q4` instead of the 4B. + +## QVAC SDK reference + +- Package: `@qvac/sdk` (npm). Pin to the version installed at build time (0.12.x or newer). +- License: Apache 2.0 +- Docs site: https://docs.qvac.tether.io/ +- **Full docs as one file for AI agents:** https://docs.qvac.tether.io/llms-full.txt +- Exports used: `loadModel`, `unloadModel`, `completion`, and the constant `QWEN3_4B_INST_Q4_K_M` +- Model cache: `~/.qvac/models/` on macOS/Linux, `%USERPROFILE%\.qvac\models\` on Windows (auto-managed) +- Backends: Vulkan (Linux + Windows), Metal (macOS Apple Silicon) + +## SDK API the agent needs to know (pin this exactly) + +This is the part you must NOT improvise. Copy these shapes. Validate against `node_modules/@qvac/sdk/dist/examples/quickstart.js` and `llamacpp-dynamic-tools.js`; if unsure, fetch llms-full.txt and grep it. + +```javascript +import { loadModel, completion, unloadModel, QWEN3_4B_INST_Q4_K_M } from "@qvac/sdk"; + +// 1) Load once. onProgress reports download + load percentage (0..100). +const modelId = await loadModel({ + modelSrc: QWEN3_4B_INST_Q4_K_M, // QWEN3_1_7B_INST_Q4 on an 8 GB machine + modelType: "llm", + modelConfig: { ctx_size: 16384 }, + onProgress: (p) => console.log(p.percentage), +}); + +// 2) Generate. Non-streaming: await result.text (a documented convenience field). +const result = completion({ modelId, history: [{ role: "user", content: prompt }] }); +const text = await result.text; +// Streaming variant: completion({ modelId, history, stream: true }) then for await (const t of result.tokenStream). + +// 3) Free on shutdown. +await unloadModel({ modelId }); +``` + +**Electron integration gotcha (pin this too):** `@qvac/sdk` is an ES module. In an Electron CommonJS main process, load it with dynamic `import("@qvac/sdk")`, never `require()`, and do NOT set `"type": "module"` in package.json (that breaks the Electron entry point). + +## Project structure + +A small Electron app. The model runs in the main process; the UI runs in the renderer and reaches the model over a narrow IPC bridge. + +``` +qvac-natural-language-to-sql/ +├── package.json +├── main.js ← Electron main: dynamic-import the SDK, load the model, IPC +├── preload.js ← contextBridge: expose generateSQL + model status to the renderer +└── renderer/ + ├── index.html ← loads sql.js + the UI + ├── bank-data.js ← schema (for the prompt) + seed SQL (fictional data) + ├── db.js ← in-memory SQLite (sql.js / WASM) + read-only guard + ├── ai.js ← prompt builder + model-output JSON parser + └── app, components, styles (your stack of choice, QVAC palette) +``` + +## Dependencies + +```bash +npm init -y +npm pkg set main=main.js +npm install @qvac/sdk +npm install --save-dev electron +npm install sql.js # SQLite compiled to WebAssembly +``` + +Do NOT set `"type": "module"` (see the Electron gotcha above). + +## How to build it + +The SDK calls above are fixed. Everything below is the app to assemble around them; write it idiomatically for your stack. + +1. **Main process (`main.js`).** On app ready: dynamic `import("@qvac/sdk")`, start loading the model and forward `onProgress` to the renderer so the user sees download and load status. Open one `BrowserWindow` with `contextIsolation: true` and a preload, then load the renderer (`loadFile` is simplest; if the sql.js WASM fails to fetch over `file://`, serve `renderer/` from a `127.0.0.1`-only static server instead). Register one IPC handler, `generate-sql`, that runs the completion shown above and returns `result.text`. Unload the model on quit. +2. **Bridge (`preload.js`).** Via `contextBridge`, expose only three things: `generateSQL(prompt)`, a model-status getter, and a progress subscription. Nothing else, and no network access. +3. **Database (`renderer/db.js`).** Boot an in-memory `sql.js` database and run the seed once. Add a read-only guard that throws before executing any statement matching this regex, and surface a clear "blocked" notice when it fires: + ```javascript + const FORBIDDEN = /\b(DELETE|DROP|UPDATE|INSERT|ALTER|TRUNCATE|REPLACE|CREATE|ATTACH|PRAGMA|VACUUM)\b/i; + ``` +4. **Demo data (`renderer/bank-data.js`).** Export two things: the schema as structured data (tables plus typed columns) for the prompt, and a seed SQL string (CREATE plus INSERT). Generate fictional data only, no real people or credentials: roughly 25 customers, 30 accounts, 84 transactions, 20 loans, 60 audit rows, with foreign keys that line up so joins return meaningful results. +5. **The brain (`renderer/ai.js`).** Build the prompt from the schema and the question only, never row data. Ask for a single SELECT plus a one-sentence explanation as strict JSON, then extract the `{...}` and parse it. Two Qwen3 specifics: prefix the prompt with `/no_think`, and strip any `...` block from the output before parsing. Prompt shape: + ``` + /no_think + You are a SQLite expert. Given the schema and question, write a single SELECT query. Today=. + + Schema: + + + Question: + + Reply with ONLY valid JSON (no markdown): + {"sql":"","explanation":""}`; + } + + function formatSQL(raw) { + if (!raw) return raw; + // Collapse all whitespace to single spaces + let s = raw.replace(/\s+/g, ' ').trim(); + // Break before major clause keywords (longer patterns first to prevent partial matches) + s = s.replace( + /\b((?:LEFT|RIGHT|FULL|INNER|CROSS)\s+(?:OUTER\s+)?JOIN|ORDER\s+BY|GROUP\s+BY|UNION\s+ALL|FROM|WHERE|JOIN|ON|HAVING|LIMIT|OFFSET|UNION|EXCEPT|INTERSECT)\b/gi, + '\n$1' + ); + // Indent AND / OR so conditions stay readable + s = s.replace(/\b(AND|OR)\b/gi, '\n $1'); + return s.replace(/^\n+/, ''); + } + + function parseModelJSON(raw) { + if (!raw) throw new Error("Empty response from the model."); + let text = String(raw).trim(); + // Strip ... blocks (Qwen3 reasoning mode) + text = text.replace(/[\s\S]*?<\/think>/gi, "").trim(); + // Strip markdown fences + text = text.replace(/^```(?:json)?/i, "").replace(/```$/i, "").trim(); + const start = text.indexOf("{"); + const end = text.lastIndexOf("}"); + if (start === -1 || end === -1) { + throw new Error("Could not find a JSON object in the model response."); + } + const slice = text.slice(start, end + 1); + let obj; + try { + obj = JSON.parse(slice); + } catch (e) { + throw new Error("The model returned malformed JSON. Try rephrasing."); + } + if (!obj.sql || typeof obj.sql !== "string") { + throw new Error("The model response did not include a SQL query."); + } + return { + sql: formatSQL(obj.sql.trim()), + explanation: (obj.explanation || "").trim(), + }; + } + + async function generate(schema, question) { + const prompt = buildPrompt(schema, question); + + // Local QVAC model via IPC bridge (Electron main process). On-device only. + if (window.QVAC_BRIDGE && window.QVAC_BRIDGE.generateSQL) { + const raw = await window.QVAC_BRIDGE.generateSQL(prompt); + return parseModelJSON(raw); + } + + throw new Error("No local model available in this environment."); + } + + return { generate, buildPrompt, parseModelJSON, schemaToText }; +})(); diff --git a/qvac-natural-language-to-sql/renderer/app.jsx b/qvac-natural-language-to-sql/renderer/app.jsx new file mode 100644 index 0000000..03c32ac --- /dev/null +++ b/qvac-natural-language-to-sql/renderer/app.jsx @@ -0,0 +1,279 @@ +/* ============================================================ + QVAC Natural Language to SQL — application root + state + Everything is React state. No
. No routing. No login. + Local AI: Qwen3 4B runs in Electron main process via @qvac/sdk. + ============================================================ */ +const { useState, useEffect, useRef, useCallback } = React; + +const EXAMPLES = [ + "Top 3 clients in Frankfurt with the biggest debt", + "Show all overdue loans with the customer name and monthly payment", +]; + +let HID = 0; + +function App() { + const [booting, setBooting] = useState(true); + const [loaded, setLoaded] = useState(false); + const [counts, setCounts] = useState({}); + + // Local model loading state (managed by main process) + const [modelStatus, setModelStatus] = useState( + window.QVAC_BRIDGE + ? { state: "loading", progress: 0, label: "Starting local model…" } + : { state: "error", progress: 0, label: "Local model unavailable" } + ); + const modelReady = modelStatus.state === "ready" || modelStatus.state === "error"; + + const [question, setQuestion] = useState(""); + const [technical, setTechnical] = useState(false); + + const [generating, setGenerating] = useState(false); + const [plan, setPlan] = useState(null); + const [sql, setSql] = useState(""); + const [running, setRunning] = useState(false); + const [result, setResult] = useState(null); + const [error, setError] = useState(null); + const [history, setHistory] = useState([]); + + const taRef = useRef(null); + + const refreshCounts = useCallback(() => { + const c = {}; + window.BANK_SCHEMA.forEach((t) => { c[t.table] = window.QVACdb.rowCount(t.table); }); + setCounts(c); + }, []); + + // Boot the local SQLite engine once. + useEffect(() => { + let alive = true; + window.QVACdb.init() + .then(() => { + if (!alive) return; + setLoaded(true); + refreshCounts(); + setBooting(false); + }) + .catch((e) => { + if (!alive) return; + setError({ kind: "error", msg: "Could not start the local database engine. " + e.message }); + setBooting(false); + }); + return () => { alive = false; }; + }, [refreshCounts]); + + // Subscribe to model loading progress from the main process. + useEffect(() => { + if (!window.QVAC_BRIDGE || !window.QVAC_BRIDGE.onModelProgress) return; + + // Get current status immediately (in case model loaded before renderer) + window.QVAC_BRIDGE.getModelStatus().then((s) => { + if (s) setModelStatus(s); + }).catch(() => {}); + + // Subscribe to future updates + window.QVAC_BRIDGE.onModelProgress((s) => { + setModelStatus(s); + }); + }, []); + + const reloadSchema = () => { + window.QVACdb.init().then(() => { setLoaded(true); refreshCounts(); }); + }; + + const resetOutputs = () => { setPlan(null); setSql(""); setResult(null); setError(null); }; + + const ask = async (qArg) => { + const q = (qArg ?? question).trim(); + if (!q || generating) return; + if (!modelReady && modelStatus.state !== "error") { + setError({ kind: "error", msg: "The local model is still loading. Please wait a moment." }); + return; + } + setQuestion(q); + resetOutputs(); + setGenerating(true); + try { + const out = await window.QVACai.generate(window.BANK_SCHEMA, q); + try { + window.QVACdb.guard(out.sql); + } catch (guardErr) { + setError({ kind: "block", msg: "QVAC Natural Language to SQL is read-only. Only SELECT queries are allowed." }); + return; + } + setPlan({ explanation: out.explanation }); + setSql(out.sql); + setHistory((h) => [{ id: ++HID, question: q, sql: out.sql, explanation: out.explanation }, ...h].slice(0, 30)); + } catch (e) { + setError({ kind: "error", msg: e.message || "The model could not generate a query." }); + } finally { + setGenerating(false); + } + }; + + const run = (sqlArg) => { + const q = (sqlArg ?? sql).trim(); + if (!q || running) return; + setRunning(true); + setError(null); + setResult(null); + setTimeout(() => { + try { + const res = window.QVACdb.run(q); + setResult(res); + } catch (e) { + if (e.code === "READ_ONLY") { + setError({ kind: "block", msg: e.message }); + } else { + setError({ kind: "error", msg: "That query could not run: " + e.message }); + } + } finally { + setRunning(false); + } + }, 260); + }; + + const pickHistory = (h) => { + setQuestion(h.question); + setPlan({ explanation: h.explanation }); + setSql(h.sql); + setError(null); + run(h.sql); + }; + + const onKey = (e) => { + if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); ask(); } + }; + + const askDisabled = !question.trim() || generating || (!modelReady && modelStatus.state !== "error"); + + if (booting) { + return ( +
+ qvac +
+
Starting local database engine…
+
+ ); + } + + return ( +
+ + +
+
+ + QVAC Natural Language to SQL — Ask your data + + + Your schema, queries & results never leave this device + +
+ + + +
+
+

Ask in English.
QVAC writes the SQL.

+ +
+