Natural language to any query language, starting with GraphQL
Project description
text2ql
Natural Language to Query Language framework.
text2ql is designed as a pip-installable package for converting natural language into query languages with a plugin architecture. The first implemented target is GraphQL.
Project goals
- Build a reusable core abstraction (
Text2QL) fortext -> queryconversion. - Support multiple target query languages (GraphQL first; SQL/Cypher/SPARQL next).
- Keep provider integrations optional (deterministic local mode, LLM mode as adapters).
- Encourage benchmark/data generation workflows inspired by graph-centric datasets.
Install
Install from PyPI:
pip install text2ql
Install from source (editable):
pip install -e .
For local development and tests:
pip install -e ".[dev]"
Quickstart
from text2ql import Text2QL
service = Text2QL()
result = service.generate(
text="show top 5 client records with mail state enabled",
target="graphql",
schema={
"entities": [
{"name": "customers", "aliases": ["client", "clients"]}
],
"fields": [
{"name": "id"},
{"name": "email", "aliases": ["mail"]},
{"name": "status", "aliases": ["state"]}
],
"default_entity": "customers",
"default_fields": ["id", "email", "status"]
},
mapping={
"filters": {"state": "status"},
"filter_values": {"status": {"enabled": "active"}}
},
)
print(result.query)
print(result.explanation)
Default mode is deterministic.
LLM mode (adapter-based)
from text2ql import Text2QL
from text2ql.providers.openai_compatible import OpenAICompatibleProvider
service = Text2QL(
provider=OpenAICompatibleProvider(model="gpt-4o-mini")
)
result = service.generate(
text="show top 3 clients with mail state enabled",
target="graphql",
schema={"entities": ["customers"], "fields": ["id", "email", "status"]},
mapping={"entities": {"clients": "customers"}, "fields": {"mail": "email"}},
context={"mode": "llm", "language": "english"},
)
Required env var for OpenAICompatibleProvider:
export OPENAI_API_KEY=...
Fallback key name also supported:
export TEXT2QL_API_KEY=...
If LLM output fails constrained JSON validation, text2ql falls back to deterministic mode.
CLI
text2ql "show top 5 client records with mail state enabled" \
--target graphql \
--schema '{"entities":["customers"],"fields":["id","email","status"]}' \
--mapping '{"entities":{"client":"customers"},"fields":{"mail":"email"},"filters":{"state":"status"},"filter_values":{"status":{"enabled":"active"}}}'
You can also load JSON files:
text2ql "show top 5 client records with mail state enabled" \
--schema-file ./schema.json \
--mapping-file ./mapping.json
LLM mode via CLI:
export OPENAI_API_KEY=...
text2ql "show top 3 clients with mail state enabled" \
--mode llm \
--language english \
--llm-provider openai-compatible \
--llm-model gpt-4o-mini \
--llm-max-retries 4 \
--llm-retry-backoff 2.0
If you do not pass --mode llm, CLI runs deterministic mode.
Prompt templates
LLM mode supports prompt template override through request context:
result = service.generate(
text="list users",
context={
"mode": "llm",
"prompt_template": "Convert request to JSON intent. Request: {text}\\nEntities: {entities}\\nFields: {fields}"
},
)
Template placeholders:
{text}{entities}{fields}{field_aliases}{filter_aliases}
Language support:
english(default)en(alias)
Dataset + evaluation hooks
from text2ql import Text2QL, ingest_dataset, generate_synthetic_examples, evaluate_examples
examples = ingest_dataset("examples.jsonl")
synthetic = generate_synthetic_examples(examples, variants_per_example=2)
report = evaluate_examples(Text2QL(), synthetic)
print(report.exact_match_accuracy, report.execution_accuracy)
Dataset format
Supported file types:
.jsonl: one JSON object per line.json: JSON array of objects
Required fields per example:
text(string)expected_query(string)
Optional fields:
target(default:"graphql")schema(object)mapping(object)context(object)metadata(object)
Example .jsonl row:
{"text":"list users","target":"graphql","expected_query":"query GeneratedQuery { user { id name } }"}
Evaluation metrics
exact_match_accuracy: normalized string match (whitespace-insensitive).execution_accuracy: structural GraphQL signature match (entity + filters + selected fields).
Current execution accuracy is a static structural approximation, not live backend execution.
Troubleshooting
Missing API key...: setOPENAI_API_KEY(orTEXT2QL_API_KEY) before LLM mode.JSON file ... must contain an object: schema/mapping files must be top-level JSON objects.Inline JSON value must contain an object:--schema/--mappingpayloads must be JSON objects.HTTP Error 429: Too Many Requests: provider retries with backoff; if retries fail, engine falls back to deterministic mode.- Provider/network errors in LLM mode: verify API URL/model/key and retry.
Testing
python3 -m pytest -m unit
python3 -m pytest -m e2e
python3 -m pytest
Publish to PyPI
Release workflow file:
.github/workflows/release.yml
Publishing modes:
workflow_dispatch-> TestPyPI (publish_target=testpypi)- GitHub Release
published-> PyPI workflow_dispatch-> PyPI (publish_target=pypi)
Setup checklist:
- Replace placeholder URLs in
pyproject.toml(project.urls). - In PyPI and TestPyPI, configure Trusted Publishing for this GitHub repo/workflow.
- In GitHub repo settings, create environments
testpypiandpypi. - Protect
pypienvironment with required reviewers if desired.
Local preflight before release:
python -m pip install --upgrade build twine
python -m build
python -m twine check dist/*
Current architecture
text2ql.core.Text2QL: orchestrator/facade.text2ql.types: request/result schemas.text2ql.engines.*: per-target query generators.text2ql.providers.*: pluggable LLM provider adapters.
Roadmap
- Add
SQL,Cypher,Jsonata,JqandSPARQLengines. - Expand prompts and constraints per target language.
- Add richer synthetic generation using domain-specific rewrite plugins.
- Add execution accuracy against real backends.
- Publish package to PyPI and add CI release workflow.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file text2ql-0.1.1.tar.gz.
File metadata
- Download URL: text2ql-0.1.1.tar.gz
- Upload date:
- Size: 20.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b1ed75ff1d2a5b8d87f36ed66b55fcede866eeec7af39cd585d32ba6017929ea
|
|
| MD5 |
45ad900424f9274862b3d006f12cf30e
|
|
| BLAKE2b-256 |
096e349426daa744ca1a1ffc6d6a7f012c98b87f16694a3b010241c7753c335a
|
Provenance
The following attestation bundles were made for text2ql-0.1.1.tar.gz:
Publisher:
release.yml on riteshakumar/text2ql
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
text2ql-0.1.1.tar.gz -
Subject digest:
b1ed75ff1d2a5b8d87f36ed66b55fcede866eeec7af39cd585d32ba6017929ea - Sigstore transparency entry: 1232991683
- Sigstore integration time:
-
Permalink:
riteshakumar/text2ql@62cb3086e4dd08e8d2c7f14b3c2399e120d36e72 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/riteshakumar
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@62cb3086e4dd08e8d2c7f14b3c2399e120d36e72 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file text2ql-0.1.1-py3-none-any.whl.
File metadata
- Download URL: text2ql-0.1.1-py3-none-any.whl
- Upload date:
- Size: 22.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6eb8f264045afb6ec2143b256b7dbc0e863956c25d6467c618fe9f57aae81021
|
|
| MD5 |
0090050f5c9a817c9a1cf3e0f48ce0c5
|
|
| BLAKE2b-256 |
e4f883a1756f65e3eaedda29eefc96b8fb7446f7ecfd7ce0a07f14f020fc8a96
|
Provenance
The following attestation bundles were made for text2ql-0.1.1-py3-none-any.whl:
Publisher:
release.yml on riteshakumar/text2ql
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
text2ql-0.1.1-py3-none-any.whl -
Subject digest:
6eb8f264045afb6ec2143b256b7dbc0e863956c25d6467c618fe9f57aae81021 - Sigstore transparency entry: 1232991684
- Sigstore integration time:
-
Permalink:
riteshakumar/text2ql@62cb3086e4dd08e8d2c7f14b3c2399e120d36e72 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/riteshakumar
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@62cb3086e4dd08e8d2c7f14b3c2399e120d36e72 -
Trigger Event:
workflow_dispatch
-
Statement type: