sqlseed 0.1.8__tar.gz → 0.1.9__tar.gz
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.
- {sqlseed-0.1.8 → sqlseed-0.1.9}/PKG-INFO +1 -1
- sqlseed-0.1.9/plugins/mcp-server-sqlseed/README.md +49 -0
- sqlseed-0.1.9/plugins/mcp-server-sqlseed/pyproject.toml +47 -0
- sqlseed-0.1.9/plugins/mcp-server-sqlseed/src/mcp_server_sqlseed/__init__.py +7 -0
- sqlseed-0.1.9/plugins/mcp-server-sqlseed/src/mcp_server_sqlseed/__main__.py +6 -0
- sqlseed-0.1.9/plugins/mcp-server-sqlseed/src/mcp_server_sqlseed/config.py +9 -0
- sqlseed-0.1.9/plugins/mcp-server-sqlseed/src/mcp_server_sqlseed/server.py +148 -0
- sqlseed-0.1.9/plugins/sqlseed-ai/README.md +38 -0
- sqlseed-0.1.9/plugins/sqlseed-ai/pyproject.toml +44 -0
- sqlseed-0.1.9/plugins/sqlseed-ai/src/sqlseed_ai/__init__.py +88 -0
- sqlseed-0.1.9/plugins/sqlseed-ai/src/sqlseed_ai/_client.py +31 -0
- sqlseed-0.1.9/plugins/sqlseed-ai/src/sqlseed_ai/_json_utils.py +24 -0
- sqlseed-0.1.9/plugins/sqlseed-ai/src/sqlseed_ai/analyzer.py +304 -0
- sqlseed-0.1.9/plugins/sqlseed-ai/src/sqlseed_ai/config.py +20 -0
- sqlseed-0.1.9/plugins/sqlseed-ai/src/sqlseed_ai/errors.py +119 -0
- sqlseed-0.1.9/plugins/sqlseed-ai/src/sqlseed_ai/examples.py +172 -0
- sqlseed-0.1.9/plugins/sqlseed-ai/src/sqlseed_ai/nl_config.py +80 -0
- sqlseed-0.1.9/plugins/sqlseed-ai/src/sqlseed_ai/provider.py +88 -0
- sqlseed-0.1.9/plugins/sqlseed-ai/src/sqlseed_ai/refiner.py +277 -0
- sqlseed-0.1.9/plugins/sqlseed-ai/src/sqlseed_ai/suggest.py +62 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/pyproject.toml +1 -1
- sqlseed-0.1.9/src/sqlseed/plugins/__init__.py +10 -0
- sqlseed-0.1.9/src/sqlseed/plugins/hookspecs.py +113 -0
- sqlseed-0.1.9/src/sqlseed/plugins/manager.py +37 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/.gitignore +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/CHANGELOG.md +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/LICENSE +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/README.md +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/__init__.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/_utils/__init__.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/_utils/logger.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/_utils/metrics.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/_utils/progress.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/_utils/schema_helpers.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/_utils/sql_safe.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/_version.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/cli/__init__.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/cli/main.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/config/__init__.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/config/loader.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/config/models.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/config/snapshot.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/core/__init__.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/core/column_dag.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/core/constraints.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/core/expression.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/core/mapper.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/core/orchestrator.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/core/relation.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/core/result.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/core/schema.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/core/transform.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/database/__init__.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/database/_protocol.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/database/optimizer.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/database/raw_sqlite_adapter.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/database/sqlite_utils_adapter.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/generators/__init__.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/generators/_protocol.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/generators/base_provider.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/generators/faker_provider.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/generators/mimesis_provider.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/generators/registry.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/generators/stream.py +0 -0
- {sqlseed-0.1.8 → sqlseed-0.1.9}/src/sqlseed/py.typed +0 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# mcp-server-sqlseed
|
|
2
|
+
|
|
3
|
+
[Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server for [sqlseed](https://github.com/sunbos/sqlseed) — enabling AI assistants to generate SQLite test data.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
`mcp-server-sqlseed` exposes sqlseed's capabilities as MCP tools, allowing AI assistants (Claude, Cursor, etc.) to inspect database schemas, generate YAML configurations, and execute data fills seamlessly.
|
|
8
|
+
|
|
9
|
+
### MCP Tools
|
|
10
|
+
|
|
11
|
+
| Tool | Description |
|
|
12
|
+
|------|-------------|
|
|
13
|
+
| `sqlseed_inspect_schema` | Inspect database table structure, columns, indexes, and sample data |
|
|
14
|
+
| `sqlseed_generate_yaml` | Generate a YAML configuration file for data generation |
|
|
15
|
+
| `sqlseed_execute_fill` | Execute data generation and fill a database table |
|
|
16
|
+
|
|
17
|
+
### MCP Resource
|
|
18
|
+
|
|
19
|
+
- `sqlseed://schema/{db_path}/{table_name}` — Read-only schema information for a specific table
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pip install mcp-server-sqlseed
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Configuration
|
|
28
|
+
|
|
29
|
+
Add to your MCP client configuration (e.g., Claude Desktop):
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"mcpServers": {
|
|
34
|
+
"sqlseed": {
|
|
35
|
+
"command": "mcp-server-sqlseed"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Requirements
|
|
42
|
+
|
|
43
|
+
- Python >= 3.10
|
|
44
|
+
- `sqlseed >= 0.1.0`
|
|
45
|
+
- `mcp >= 1.0`
|
|
46
|
+
|
|
47
|
+
## License
|
|
48
|
+
|
|
49
|
+
AGPL-3.0-or-later
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling", "hatch-vcs"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "mcp-server-sqlseed"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
requires-python = ">=3.10"
|
|
9
|
+
description = "MCP server for sqlseed - AI-powered SQLite test data generation"
|
|
10
|
+
readme = "README.md"
|
|
11
|
+
license = "AGPL-3.0-or-later"
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "SunBo", email = "1443584939@qq.com"},
|
|
14
|
+
]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 3 - Alpha",
|
|
17
|
+
"License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Programming Language :: Python :: 3.13",
|
|
23
|
+
]
|
|
24
|
+
dependencies = [
|
|
25
|
+
"sqlseed>=0.1.0",
|
|
26
|
+
"mcp>=1.0",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
[project.urls]
|
|
30
|
+
Homepage = "https://github.com/sunbos/sqlseed"
|
|
31
|
+
Repository = "https://github.com/sunbos/sqlseed/tree/main/plugins/mcp-server-sqlseed"
|
|
32
|
+
|
|
33
|
+
[project.optional-dependencies]
|
|
34
|
+
ai = ["sqlseed-ai"]
|
|
35
|
+
|
|
36
|
+
[project.scripts]
|
|
37
|
+
mcp-server-sqlseed = "mcp_server_sqlseed:main"
|
|
38
|
+
|
|
39
|
+
[tool.hatch.version]
|
|
40
|
+
source = "vcs"
|
|
41
|
+
fallback-version = "0.0.0"
|
|
42
|
+
|
|
43
|
+
[tool.hatch.version.raw-options]
|
|
44
|
+
root = "../.."
|
|
45
|
+
|
|
46
|
+
[tool.hatch.build.targets.wheel]
|
|
47
|
+
packages = ["src/mcp_server_sqlseed"]
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import hashlib
|
|
4
|
+
import json
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from mcp.server.fastmcp import FastMCP
|
|
8
|
+
|
|
9
|
+
mcp = FastMCP("sqlseed")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _serialize_schema_context(ctx: dict[str, Any]) -> dict[str, Any]:
|
|
13
|
+
return {
|
|
14
|
+
"table_name": ctx["table_name"],
|
|
15
|
+
"columns": [
|
|
16
|
+
{
|
|
17
|
+
"name": c.name,
|
|
18
|
+
"type": c.type,
|
|
19
|
+
"nullable": c.nullable,
|
|
20
|
+
"default": c.default,
|
|
21
|
+
"is_primary_key": c.is_primary_key,
|
|
22
|
+
"is_autoincrement": c.is_autoincrement,
|
|
23
|
+
}
|
|
24
|
+
for c in ctx["columns"]
|
|
25
|
+
],
|
|
26
|
+
"foreign_keys": [
|
|
27
|
+
{"column": fk.column, "ref_table": fk.ref_table, "ref_column": fk.ref_column}
|
|
28
|
+
for fk in ctx["foreign_keys"]
|
|
29
|
+
],
|
|
30
|
+
"indexes": ctx["indexes"],
|
|
31
|
+
"sample_data": ctx["sample_data"],
|
|
32
|
+
"all_table_names": ctx["all_table_names"],
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _compute_schema_hash(schema_ctx: dict[str, Any]) -> str:
|
|
37
|
+
hash_input = json.dumps(
|
|
38
|
+
{
|
|
39
|
+
"columns": [
|
|
40
|
+
{"name": c.name, "type": c.type, "nullable": c.nullable}
|
|
41
|
+
for c in schema_ctx["columns"]
|
|
42
|
+
],
|
|
43
|
+
"foreign_keys": [
|
|
44
|
+
{"column": fk.column, "ref_table": fk.ref_table}
|
|
45
|
+
for fk in schema_ctx["foreign_keys"]
|
|
46
|
+
],
|
|
47
|
+
},
|
|
48
|
+
sort_keys=True,
|
|
49
|
+
)
|
|
50
|
+
return hashlib.sha256(hash_input.encode()).hexdigest()[:16]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@mcp.resource("sqlseed://schema/{db_path}/{table_name}")
|
|
54
|
+
def get_schema_resource(db_path: str, table_name: str) -> str:
|
|
55
|
+
from sqlseed.core.orchestrator import DataOrchestrator
|
|
56
|
+
|
|
57
|
+
with DataOrchestrator(db_path) as orch:
|
|
58
|
+
ctx = orch.get_schema_context(table_name)
|
|
59
|
+
serializable_ctx = _serialize_schema_context(ctx)
|
|
60
|
+
return json.dumps(serializable_ctx, ensure_ascii=False, indent=2)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@mcp.tool()
|
|
64
|
+
def sqlseed_inspect_schema(db_path: str, table_name: str | None = None) -> dict[str, Any]:
|
|
65
|
+
"""Inspect database schema. Returns column info, foreign keys, indexes,
|
|
66
|
+
sample data, and schema_hash for specified table or all tables."""
|
|
67
|
+
from sqlseed.core.orchestrator import DataOrchestrator
|
|
68
|
+
|
|
69
|
+
with DataOrchestrator(db_path) as orch:
|
|
70
|
+
tables = [table_name] if table_name else orch._db.get_table_names()
|
|
71
|
+
result: dict[str, Any] = {}
|
|
72
|
+
for tbl in tables:
|
|
73
|
+
ctx = orch.get_schema_context(tbl)
|
|
74
|
+
result[tbl] = _serialize_schema_context(ctx)
|
|
75
|
+
result[tbl]["schema_hash"] = _compute_schema_hash(ctx)
|
|
76
|
+
return result
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@mcp.tool()
|
|
80
|
+
def sqlseed_generate_yaml(db_path: str, table_name: str, max_retries: int = 3) -> str:
|
|
81
|
+
"""Generate YAML config for a table using AI analysis with self-correction.
|
|
82
|
+
Returns YAML string for human review. Requires sqlseed-ai plugin and API key."""
|
|
83
|
+
import yaml
|
|
84
|
+
from sqlseed_ai.analyzer import SchemaAnalyzer
|
|
85
|
+
from sqlseed_ai.refiner import AiConfigRefiner, AISuggestionFailedError
|
|
86
|
+
|
|
87
|
+
analyzer = SchemaAnalyzer()
|
|
88
|
+
refiner = AiConfigRefiner(analyzer, db_path)
|
|
89
|
+
|
|
90
|
+
try:
|
|
91
|
+
result = refiner.generate_and_refine(
|
|
92
|
+
table_name=table_name,
|
|
93
|
+
max_retries=max_retries,
|
|
94
|
+
)
|
|
95
|
+
except AISuggestionFailedError as e:
|
|
96
|
+
return f"# AI suggestion failed: {e}"
|
|
97
|
+
except Exception as e:
|
|
98
|
+
return f"# Error: {e}"
|
|
99
|
+
|
|
100
|
+
if result:
|
|
101
|
+
output = {"db_path": db_path, "provider": "mimesis", "locale": "zh_CN", "tables": [result]}
|
|
102
|
+
return yaml.dump(output, allow_unicode=True, sort_keys=False, default_flow_style=False)
|
|
103
|
+
return "# No AI suggestions available. Ensure sqlseed-ai plugin is installed and API key is configured."
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@mcp.tool()
|
|
107
|
+
def sqlseed_execute_fill(
|
|
108
|
+
db_path: str,
|
|
109
|
+
table_name: str,
|
|
110
|
+
count: int = 1000,
|
|
111
|
+
yaml_config: str | None = None,
|
|
112
|
+
) -> dict[str, Any]:
|
|
113
|
+
"""Execute data generation for a table. Optionally provide YAML config string for column rules."""
|
|
114
|
+
from sqlseed.core.orchestrator import DataOrchestrator
|
|
115
|
+
|
|
116
|
+
with DataOrchestrator(db_path) as orch:
|
|
117
|
+
column_configs = None
|
|
118
|
+
clear_before = False
|
|
119
|
+
seed = None
|
|
120
|
+
|
|
121
|
+
if yaml_config:
|
|
122
|
+
import yaml as _yaml
|
|
123
|
+
|
|
124
|
+
from sqlseed.config.models import GeneratorConfig
|
|
125
|
+
|
|
126
|
+
data = _yaml.safe_load(yaml_config)
|
|
127
|
+
config = GeneratorConfig(**data)
|
|
128
|
+
for t in config.tables:
|
|
129
|
+
if t.name == table_name:
|
|
130
|
+
column_configs = t.columns
|
|
131
|
+
clear_before = t.clear_before
|
|
132
|
+
seed = t.seed
|
|
133
|
+
break
|
|
134
|
+
|
|
135
|
+
result = orch.fill_table(
|
|
136
|
+
table_name=table_name,
|
|
137
|
+
count=count,
|
|
138
|
+
column_configs=column_configs,
|
|
139
|
+
clear_before=clear_before,
|
|
140
|
+
seed=seed,
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
"table_name": result.table_name,
|
|
145
|
+
"count": result.count,
|
|
146
|
+
"elapsed": result.elapsed,
|
|
147
|
+
"errors": result.errors,
|
|
148
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# sqlseed-ai
|
|
2
|
+
|
|
3
|
+
AI-powered data generation plugin for [sqlseed](https://github.com/sunbos/sqlseed).
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
`sqlseed-ai` extends sqlseed with LLM-driven intelligent data generation capabilities. It analyzes your database schema and produces high-quality, context-aware YAML configuration suggestions.
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
- **Schema Analysis** — LLM-powered table structure understanding via `SchemaAnalyzer`
|
|
12
|
+
- **AI Config Refiner** — Self-correcting feedback loop with up to 3 retry rounds
|
|
13
|
+
- **Column-level Suggestions** — Smart per-column generation strategy recommendations
|
|
14
|
+
- **Natural Language Config** — Describe what you want in plain text, get YAML config
|
|
15
|
+
- **Few-shot Examples** — Built-in example library for improved LLM output quality
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install sqlseed-ai
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# Generate AI-suggested YAML config for a table
|
|
27
|
+
sqlseed ai-suggest test.db --table users --output users.yaml
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Requirements
|
|
31
|
+
|
|
32
|
+
- Python >= 3.10
|
|
33
|
+
- `sqlseed >= 0.1.0`
|
|
34
|
+
- An OpenAI-compatible API key (set via `OPENAI_API_KEY` environment variable)
|
|
35
|
+
|
|
36
|
+
## License
|
|
37
|
+
|
|
38
|
+
AGPL-3.0-or-later
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling", "hatch-vcs"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "sqlseed-ai"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
requires-python = ">=3.10"
|
|
9
|
+
description = "AI-powered data generation plugin for sqlseed"
|
|
10
|
+
readme = "README.md"
|
|
11
|
+
license = "AGPL-3.0-or-later"
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "SunBo", email = "1443584939@qq.com"},
|
|
14
|
+
]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 3 - Alpha",
|
|
17
|
+
"License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Programming Language :: Python :: 3.13",
|
|
23
|
+
]
|
|
24
|
+
dependencies = [
|
|
25
|
+
"sqlseed>=0.1.0",
|
|
26
|
+
"openai>=1.0",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
[project.urls]
|
|
30
|
+
Homepage = "https://github.com/sunbos/sqlseed"
|
|
31
|
+
Repository = "https://github.com/sunbos/sqlseed/tree/main/plugins/sqlseed-ai"
|
|
32
|
+
|
|
33
|
+
[project.entry-points."sqlseed"]
|
|
34
|
+
ai = "sqlseed_ai:plugin"
|
|
35
|
+
|
|
36
|
+
[tool.hatch.version]
|
|
37
|
+
source = "vcs"
|
|
38
|
+
fallback-version = "0.0.0"
|
|
39
|
+
|
|
40
|
+
[tool.hatch.version.raw-options]
|
|
41
|
+
root = "../.."
|
|
42
|
+
|
|
43
|
+
[tool.hatch.build.targets.wheel]
|
|
44
|
+
packages = ["src/sqlseed_ai"]
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from sqlseed.plugins.hookspecs import hookimpl
|
|
7
|
+
from sqlseed_ai.analyzer import SchemaAnalyzer
|
|
8
|
+
|
|
9
|
+
_SIMPLE_COL_RE = re.compile(
|
|
10
|
+
r'(^|[_\s])('
|
|
11
|
+
r'name|email|phone|address|url|uuid|'
|
|
12
|
+
r'date|time|datetime|timestamp|boolean|'
|
|
13
|
+
r'int|float|double|real|text|string|'
|
|
14
|
+
r'char|varchar|blob|byte|id|code|title|'
|
|
15
|
+
r'description|status|type|category|count|'
|
|
16
|
+
r'amount|price|value|number|index|order|level'
|
|
17
|
+
r')($|[_\s])',
|
|
18
|
+
re.IGNORECASE,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class AISqlseedPlugin:
|
|
23
|
+
def __init__(self) -> None:
|
|
24
|
+
self._analyzer: SchemaAnalyzer | None = None
|
|
25
|
+
|
|
26
|
+
def _get_analyzer(self) -> SchemaAnalyzer:
|
|
27
|
+
if self._analyzer is None:
|
|
28
|
+
self._analyzer = SchemaAnalyzer()
|
|
29
|
+
return self._analyzer
|
|
30
|
+
|
|
31
|
+
def _is_simple_column(self, column_name: str, column_type: str) -> bool:
|
|
32
|
+
return bool(
|
|
33
|
+
_SIMPLE_COL_RE.search(column_name) or _SIMPLE_COL_RE.search(column_type)
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
@hookimpl
|
|
37
|
+
def sqlseed_ai_analyze_table(
|
|
38
|
+
self,
|
|
39
|
+
table_name: str,
|
|
40
|
+
columns: list[Any],
|
|
41
|
+
indexes: list[dict[str, Any]],
|
|
42
|
+
sample_data: list[dict[str, Any]],
|
|
43
|
+
foreign_keys: list[Any],
|
|
44
|
+
all_table_names: list[str],
|
|
45
|
+
) -> dict[str, Any] | None:
|
|
46
|
+
analyzer = self._get_analyzer()
|
|
47
|
+
return analyzer.analyze_table(
|
|
48
|
+
table_name=table_name,
|
|
49
|
+
columns=columns,
|
|
50
|
+
indexes=indexes,
|
|
51
|
+
sample_data=sample_data,
|
|
52
|
+
foreign_keys=foreign_keys,
|
|
53
|
+
all_table_names=all_table_names,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
@hookimpl
|
|
57
|
+
def sqlseed_pre_generate_templates(
|
|
58
|
+
self,
|
|
59
|
+
table_name: str,
|
|
60
|
+
column_name: str,
|
|
61
|
+
column_type: str,
|
|
62
|
+
count: int,
|
|
63
|
+
sample_data: list[Any],
|
|
64
|
+
) -> list[Any] | None:
|
|
65
|
+
if self._is_simple_column(column_name, column_type):
|
|
66
|
+
return None
|
|
67
|
+
|
|
68
|
+
analyzer = self._get_analyzer()
|
|
69
|
+
try:
|
|
70
|
+
return analyzer.generate_template_values(
|
|
71
|
+
column_name=column_name,
|
|
72
|
+
column_type=column_type,
|
|
73
|
+
count=min(count, 50),
|
|
74
|
+
sample_data=sample_data,
|
|
75
|
+
)
|
|
76
|
+
except Exception:
|
|
77
|
+
return None
|
|
78
|
+
|
|
79
|
+
@hookimpl
|
|
80
|
+
def sqlseed_register_providers(self, registry: Any) -> None:
|
|
81
|
+
pass
|
|
82
|
+
|
|
83
|
+
@hookimpl
|
|
84
|
+
def sqlseed_register_column_mappers(self, mapper: Any) -> None:
|
|
85
|
+
pass
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
plugin = AISqlseedPlugin()
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from sqlseed._utils.logger import get_logger
|
|
6
|
+
|
|
7
|
+
logger = get_logger(__name__)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def get_openai_client(config: Any | None = None) -> Any:
|
|
11
|
+
try:
|
|
12
|
+
from openai import OpenAI
|
|
13
|
+
|
|
14
|
+
from sqlseed_ai.config import AIConfig
|
|
15
|
+
|
|
16
|
+
if config is None:
|
|
17
|
+
config = AIConfig.from_env()
|
|
18
|
+
|
|
19
|
+
api_key = config.api_key if hasattr(config, "api_key") else None
|
|
20
|
+
base_url = config.base_url if hasattr(config, "base_url") else None
|
|
21
|
+
|
|
22
|
+
if not api_key:
|
|
23
|
+
raise ValueError(
|
|
24
|
+
"AI API key not configured. Set SQLSEED_AI_API_KEY or OPENAI_API_KEY environment variable."
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
return OpenAI(api_key=api_key, base_url=base_url)
|
|
28
|
+
except ImportError:
|
|
29
|
+
raise ImportError(
|
|
30
|
+
"openai is not installed. Install it with: pip install sqlseed-ai"
|
|
31
|
+
) from None
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def parse_json_response(content: str) -> dict[str, Any]:
|
|
8
|
+
cleaned = content.strip()
|
|
9
|
+
if cleaned.startswith("```json"):
|
|
10
|
+
cleaned = cleaned[7:]
|
|
11
|
+
if cleaned.startswith("```"):
|
|
12
|
+
cleaned = cleaned[3:]
|
|
13
|
+
if cleaned.endswith("```"):
|
|
14
|
+
cleaned = cleaned[:-3]
|
|
15
|
+
cleaned = cleaned.strip()
|
|
16
|
+
|
|
17
|
+
try:
|
|
18
|
+
result = json.loads(cleaned)
|
|
19
|
+
if isinstance(result, dict):
|
|
20
|
+
return result
|
|
21
|
+
except json.JSONDecodeError:
|
|
22
|
+
pass
|
|
23
|
+
|
|
24
|
+
return {}
|