Skip to main content

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) for text -> query conversion.
  • 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

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...: set OPENAI_API_KEY (or TEXT2QL_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/--mapping payloads 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:

  1. workflow_dispatch -> TestPyPI (publish_target=testpypi)
  2. GitHub Release published -> PyPI
  3. workflow_dispatch -> PyPI (publish_target=pypi)

Setup checklist:

  1. Replace placeholder URLs in pyproject.toml (project.urls).
  2. In PyPI and TestPyPI, configure Trusted Publishing for this GitHub repo/workflow.
  3. In GitHub repo settings, create environments testpypi and pypi.
  4. Protect pypi environment 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

  1. Add SQL, Cypher, Jsonata, Jq and SPARQL engines.
  2. Expand prompts and constraints per target language.
  3. Add richer synthetic generation using domain-specific rewrite plugins.
  4. Add execution accuracy against real backends.
  5. Publish package to PyPI and add CI release workflow.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

text2ql-0.1.0.tar.gz (20.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

text2ql-0.1.0-py3-none-any.whl (22.8 kB view details)

Uploaded Python 3

File details

Details for the file text2ql-0.1.0.tar.gz.

File metadata

  • Download URL: text2ql-0.1.0.tar.gz
  • Upload date:
  • Size: 20.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for text2ql-0.1.0.tar.gz
Algorithm Hash digest
SHA256 7f4e6344feda5c7304c445b68ba9e4b39bfcc9afc76f4adcdd22a950ade83f48
MD5 9d8dc2bfe508758fef36a6649a95bf52
BLAKE2b-256 95cf689cd223ea31f5ac3c1607d4008198f41d8a1862e33b8d2596bab04d287d

See more details on using hashes here.

Provenance

The following attestation bundles were made for text2ql-0.1.0.tar.gz:

Publisher: release.yml on riteshakumar/text2ql

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file text2ql-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: text2ql-0.1.0-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

Hashes for text2ql-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0d10d24c0e1630e8c3faa1bee1eeaa9f4b0100dc29423a28fe0e0b33c56ef173
MD5 2d5fe388ba012fdee342e8c423e1ea1c
BLAKE2b-256 1085a2de7f31ed2a14ae48df029e079761f585017d9c66ac4259e771f4f14c60

See more details on using hashes here.

Provenance

The following attestation bundles were made for text2ql-0.1.0-py3-none-any.whl:

Publisher: release.yml on riteshakumar/text2ql

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page