A natural language to SQL query converter
Project description
nlseek
A natural language to Query converter.
Installation
# Using uv
uv pip install nlseek
# Or install from source
uv pip install -e .
Development
# Clone the repository
git clone https://github.com/leaninnovationlabs/nlseek.git
cd nlseek
# Create virtual environment and install dependencies
uv venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
uv pip install -e ".[dev]"
# Run tests
pytest
# Run linter
ruff check src tests
ruff format src tests
# Type checking
mypy src
Usage
Load domain from file
See examples/domains/ecommerce.yaml for a complete domain schema example.
from nlseek import DomainLoader, QueryResolver
# Load a domain schema from YAML files
loader = DomainLoader("/path/to/domains")
domain = loader.get_domain("ecommerce")
# Create a query resolver
resolver = QueryResolver(domain)
# Convert natural language to SQL
result = resolver.resolve("Show me all orders from last week")
print(result.query) # The generated SQL query
print(result.explanation) # Explanation of the query
print(result.tables_used) # Tables referenced
print(result.entities) # Entities identified from the question mapped to columns
print(result.filters) # Filter conditions extracted from the WHERE clause
Load domain from JSON string
from nlseek import DomainLoader, QueryResolver
# Create a loader without a file path
loader = DomainLoader()
# Register a domain from a JSON string
loader.register_domain('''
{
"name": "mydb",
"database_type": "postgres",
"tables": [
{
"name": "users",
"columns": [
{"name": "id", "type": "integer", "primary_key": true},
{"name": "email", "type": "varchar(255)"}
]
}
]
}
''')
# Use the registered domain
domain = loader.get_domain("mydb")
resolver = QueryResolver(domain)
result = resolver.resolve("List all users")
Generate domain from Pydantic models
from pydantic import BaseModel, Field
from nlseek import DomainLoader, QueryResolver
# Define your models (works with Pydantic, SQLModel, etc.)
class User(BaseModel):
"""User account information."""
id: int
email: str
name: str | None = None
class Order(BaseModel):
"""Customer order."""
id: int
user_id: int # Auto-detected as FK to users.id
total: float = Field(description="Order total in USD")
# Generate domain from models
loader = DomainLoader()
loader.register_from_models(
name="mydb",
models=[User, Order],
database_type="postgres",
)
# Use the generated domain
domain = loader.get_domain("mydb")
resolver = QueryResolver(domain)
result = resolver.resolve("Show orders for user with email john@example.com")
The generator automatically:
- Converts class names to table names (
User->users,OrderItem->order_items) - Maps Python types to SQL types (
int->integer,str->varchar(255), etc.) - Detects primary keys (fields named
id) - Infers relationships from foreign key columns (
user_id->users.id) - Extracts descriptions from docstrings and
Field(description=...)
Configuring the AI Model
By default, QueryResolver uses Claude Opus 4. To use a different model, pass a ResolverConfig:
from nlseek import QueryResolver, ResolverConfig
config = ResolverConfig(model="anthropic:claude-sonnet-4-20250514")
resolver = QueryResolver(domain, config=config)
Any model identifier supported by pydantic-ai can be used but need to have the corresponding API key in the .env file.
Quick Demo
The demo loads the examples/domains/ecommerce.yaml schema (customers, products, orders, etc.) and prints the generated SQL, explanation, tables used, entities, and filters.
# More examples
uv run tests/demo.py "Top 5 customers by total spending"
uv run tests/demo.py "Revenue by category for delivered orders"
# Use a different model
uv run tests/demo.py --model "anthropic:claude-sonnet-4-20250514" "Products with low stock"
Response Fields
Each SQLQueryResult includes:
| Field | Type | Description |
|---|---|---|
query_id |
UUID |
Unique identifier for this query result |
query |
str |
The generated SQL query |
explanation |
str |
Brief explanation of what the query does |
tables_used |
list[str] |
Tables referenced in the query |
entities |
dict[str, list[str]] |
Entities from the question mapped to the columns they match |
filters |
list[FilterCondition] |
Filter conditions extracted from the WHERE clause |
Entities
Maps domain-specific values from the user's question to the database columns they were matched against. For example, for the question "Get me information about iphone under electronics":
{
"iphone": ["products.name", "products.description"],
"electronics": ["categories.name"]
}
Filters
Each FilterCondition contains:
| Field | Type | Description |
|---|---|---|
table |
str |
Table name (e.g. products) |
attribute |
str |
Column name (e.g. name) |
operator |
str |
SQL operator (e.g. LIKE, =, >, IN, BETWEEN) |
value |
str |
The filter value (e.g. iphone, electronics) |
For the same query above, the filters would be:
[
{"table": "products", "attribute": "name", "operator": "LIKE", "value": "iphone"},
{"table": "categories", "attribute": "name", "operator": "=", "value": "electronics"}
]
Database Support
Supports the following Query format right now
- mysql
- postgres
- oracle
- ansi sql
Environment Setup
Create a .env file with your Anthropic API key:
ANTHROPIC_API_KEY=your-api-key-here
License
MIT
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 nlseek-0.1.0.tar.gz.
File metadata
- Download URL: nlseek-0.1.0.tar.gz
- Upload date:
- Size: 4.5 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
34fc5d087fa2c9cf72e2b18723fc714b8d41f875e38602034f9cf273c23da792
|
|
| MD5 |
c0cc20fe51f541d459f22786e00802dd
|
|
| BLAKE2b-256 |
c683664044a3bb39ef1572669b91018eb5eadf899a643b6a19a23863a7a5c5ea
|
File details
Details for the file nlseek-0.1.0-py3-none-any.whl.
File metadata
- Download URL: nlseek-0.1.0-py3-none-any.whl
- Upload date:
- Size: 15.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
33a28bd9f7eeddf926df4bdd3d2f82d1d9a9eadcdcb286ee14efc3c6847eaccc
|
|
| MD5 |
2530f8eef3ddeefa2ad83840d2142a56
|
|
| BLAKE2b-256 |
6ce371094a236d0411e83d2683b43734a52def7240f03ac67a813ab952133485
|