sqlseed 0.1.20__tar.gz → 0.2.0__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.20 → sqlseed-0.2.0}/CHANGELOG.md +1 -1
- {sqlseed-0.1.20 → sqlseed-0.2.0}/CHANGELOG.zh-CN.md +1 -1
- {sqlseed-0.1.20 → sqlseed-0.2.0}/PKG-INFO +32 -6
- {sqlseed-0.1.20 → sqlseed-0.2.0}/README.md +31 -5
- {sqlseed-0.1.20 → sqlseed-0.2.0}/README.zh-CN.md +35 -13
- {sqlseed-0.1.20 → sqlseed-0.2.0}/examples/notebooks/02-column-mapping.ipynb +1 -1
- sqlseed-0.2.0/scripts/_create_demo_db.py +52 -0
- sqlseed-0.2.0/scripts/quickstart.py +179 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/cli/main.py +11 -5
- {sqlseed-0.1.20 → sqlseed-0.2.0}/.gitignore +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/LICENSE +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/examples/build_demo_db.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/examples/notebooks/01-quickstart.ipynb +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/examples/notebooks/03-generators.ipynb +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/examples/notebooks/04-database-advanced.ipynb +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/examples/notebooks/05-dag-and-constraints.ipynb +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/examples/notebooks/06-config-deep-dive.ipynb +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/examples/notebooks/07-ai-plugin.ipynb +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/examples/notebooks/08-mcp-server.ipynb +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/examples/notebooks/09-plugin-hooks.ipynb +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/examples/notebooks/10-cli-reference.ipynb +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/examples/notebooks/11-utilities.ipynb +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/examples/notebooks/12-testing-patterns.ipynb +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/pyproject.toml +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/__init__.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/_utils/__init__.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/_utils/logger.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/_utils/metrics.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/_utils/paths.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/_utils/progress.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/_utils/schema_helpers.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/_utils/sql_safe.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/_version.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/cli/__init__.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/config/__init__.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/config/loader.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/config/models.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/config/snapshot.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/core/__init__.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/core/column_dag.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/core/constraints.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/core/enrichment.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/core/expression.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/core/mapper.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/core/orchestrator.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/core/plugin_mediator.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/core/relation.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/core/result.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/core/schema.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/core/transform.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/core/unique_adjuster.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/database/__init__.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/database/_base_adapter.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/database/_compat.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/database/_helpers.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/database/_protocol.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/database/optimizer.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/database/raw_sqlite_adapter.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/database/sqlite_utils_adapter.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/generators/__init__.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/generators/_dispatch.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/generators/_json_helpers.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/generators/_protocol.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/generators/_string_helpers.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/generators/base_provider.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/generators/faker_provider.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/generators/mimesis_provider.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/generators/registry.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/generators/stream.py +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/src/sqlseed/py.typed +0 -0
- {sqlseed-0.1.20 → sqlseed-0.2.0}/uv.lock +0 -0
|
@@ -119,7 +119,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
119
119
|
- `ColumnMapper` exact match rules expanded from 68 to 74
|
|
120
120
|
|
|
121
121
|
#### AI Plugin (sqlseed-ai)
|
|
122
|
-
- Auto model selection: `_model_selector` picks the best
|
|
122
|
+
- Auto model selection: `_model_selector` picks the best Gemma 4 model by priority (26B MoE → 31B Dense → 4B → 2B), with multi-backend support (Google AI Studio, LM Studio, Ollama)
|
|
123
123
|
- Structured output: `response_format: json_object` forces LLM to return JSON
|
|
124
124
|
- Few-shot example library: 4 typical scenarios (users, projects, orders, employees)
|
|
125
125
|
- `AiConfigRefiner` self-correction loop: auto-detects and fixes invalid configs, up to 3 retries
|
|
@@ -119,7 +119,7 @@
|
|
|
119
119
|
- `ColumnMapper` 精确匹配规则从 68 扩展到 74 条
|
|
120
120
|
|
|
121
121
|
#### AI 插件(sqlseed-ai)
|
|
122
|
-
- 自动模型选择:`_model_selector`
|
|
122
|
+
- 自动模型选择:`_model_selector` 按 Gemma 4 优先级自动选择(26B MoE → 31B Dense → 4B → 2B),支持多后端(Google AI Studio、LM Studio、Ollama)
|
|
123
123
|
- 结构化输出:`response_format: json_object` 强制 LLM 返回 JSON
|
|
124
124
|
- Few-shot 示例库:4 个典型场景(用户表、银行卡表、订单表、员工表)
|
|
125
125
|
- `AiConfigRefiner` 自纠正闭环:自动检测并修复无效配置,最多 3 轮重试
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sqlseed
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Declarative SQLite test data generation toolkit
|
|
5
5
|
Project-URL: Homepage, https://github.com/sunbos/sqlseed
|
|
6
6
|
Project-URL: Documentation, https://github.com/sunbos/sqlseed#readme
|
|
@@ -240,6 +240,12 @@ mypy src/sqlseed/
|
|
|
240
240
|
|
|
241
241
|
## 🚀 Quick Start
|
|
242
242
|
|
|
243
|
+
### Interactive Quickstart
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
python scripts/quickstart.py
|
|
247
|
+
```
|
|
248
|
+
|
|
243
249
|
### Try with Demo Database
|
|
244
250
|
|
|
245
251
|
Want to try sqlseed right away? Build the demo database:
|
|
@@ -712,7 +718,6 @@ pip install sqlseed-ai
|
|
|
712
718
|
|
|
713
719
|
# Set API key
|
|
714
720
|
export SQLSEED_AI_API_KEY="your-api-key"
|
|
715
|
-
export SQLSEED_AI_BASE_URL="https://your-llm-api-endpoint"
|
|
716
721
|
|
|
717
722
|
# AI analysis and config generation
|
|
718
723
|
sqlseed ai-suggest app.db --table projects --output projects.yaml
|
|
@@ -720,9 +725,27 @@ sqlseed ai-suggest app.db --table projects --output projects.yaml
|
|
|
720
725
|
# AI suggestions with self-correction (3 rounds by default)
|
|
721
726
|
sqlseed ai-suggest app.db --table projects --output projects.yaml --verify
|
|
722
727
|
|
|
723
|
-
# Specify model (defaults to
|
|
724
|
-
sqlseed ai-suggest app.db --table projects --output projects.yaml --model
|
|
728
|
+
# Specify model (defaults to Gemma 4 26B via Google AI Studio)
|
|
729
|
+
sqlseed ai-suggest app.db --table projects --output projects.yaml --model gemma-4-26b-it
|
|
730
|
+
|
|
731
|
+
# Use local LM Studio / Ollama
|
|
732
|
+
sqlseed ai-suggest app.db --table projects --output projects.yaml --backend lm_studio --model google/gemma-4-e4b
|
|
733
|
+
```
|
|
725
734
|
|
|
735
|
+
**Gemma 4 Native Function Calling (GEMMA_TOOLS)**:
|
|
736
|
+
|
|
737
|
+
sqlseed-ai supports Gemma 4 model family (2B/4B/26B/31B) with Native Function Calling via GEMMA_TOOLS protocol. Supported backends:
|
|
738
|
+
|
|
739
|
+
| Backend | Description | Configuration |
|
|
740
|
+
| :------ | :---------- | :------------ |
|
|
741
|
+
| **Google AI Studio** | Official API, recommended for Gemma 4 26B/31B | `--backend google_ai_studio` or `SQLSEED_AI_BACKEND=google_ai_studio` |
|
|
742
|
+
| **LM Studio** | Local inference, suitable for Gemma 4 2B/4B | `--backend lm_studio` or `SQLSEED_AI_BACKEND=lm_studio` |
|
|
743
|
+
| **Ollama** | Local inference, suitable for Gemma 4 2B/4B/26B | `--backend ollama` or `SQLSEED_AI_BACKEND=ollama` |
|
|
744
|
+
| **OpenAI-compatible** | Generic OpenAI-compatible endpoint (e.g., OpenRouter, DeepSeek) | `--backend openai_compat` or `SQLSEED_AI_BACKEND=openai_compat` |
|
|
745
|
+
|
|
746
|
+
> **💡 OpenRouter (Free)**: For users without a paid API key, OpenRouter provides free models. Set `SQLSEED_AI_BACKEND=openai_compat`, `SQLSEED_AI_BASE_URL=https://openrouter.ai/api/v1`, and `SQLSEED_AI_MODEL=<free-model-name>`.
|
|
747
|
+
|
|
748
|
+
```bash
|
|
726
749
|
# Skip cache
|
|
727
750
|
sqlseed ai-suggest app.db --table projects --output projects.yaml --no-cache
|
|
728
751
|
```
|
|
@@ -738,7 +761,7 @@ sqlseed ai-suggest app.db --table projects --output projects.yaml --no-cache
|
|
|
738
761
|
6. Up to 3 self-correction rounds, outputs validated YAML config
|
|
739
762
|
```
|
|
740
763
|
|
|
741
|
-
> **💡 Environment Variables**: Supports `SQLSEED_AI_API_KEY`, `SQLSEED_AI_BASE_URL`, `SQLSEED_AI_MODEL`. Also supports `OPENAI_API_KEY` / `OPENAI_BASE_URL` as fallback. Defaults to
|
|
764
|
+
> **💡 Environment Variables**: Supports `SQLSEED_AI_API_KEY`, `SQLSEED_AI_BASE_URL`, `SQLSEED_AI_MODEL`, `SQLSEED_AI_BACKEND`. Also supports `OPENAI_API_KEY` / `OPENAI_BASE_URL` as fallback. Defaults to Gemma 4 26B via Google AI Studio. Supported backends: `google_ai_studio`, `lm_studio`, `ollama`, `openai_compat`.
|
|
742
765
|
|
|
743
766
|
***
|
|
744
767
|
|
|
@@ -777,6 +800,9 @@ python -m mcp_server_sqlseed
|
|
|
777
800
|
| 🔍 Tool | `sqlseed_inspect_schema` | Inspect schema (columns, FK, indexes, samples, schema_hash) |
|
|
778
801
|
| 🤖 Tool | `sqlseed_generate_yaml` | AI-driven YAML config generation with self-correction. Supports `api_key`/`base_url`/`model` overrides |
|
|
779
802
|
| ⚡ Tool | `sqlseed_execute_fill` | Execute data generation (supports YAML config string, includes `enrich` option) |
|
|
803
|
+
| 🧠 Tool | `sqlseed_gemma4_analyze` | Analyze schema using Gemma 4 with Native Function Calling |
|
|
804
|
+
| 🧠 Tool | `sqlseed_gemma4_agent_fill` | End-to-end Agent workflow (analyze -> config -> fill) |
|
|
805
|
+
| 🧠 Tool | `sqlseed_list_gemma_models` | List available Gemma 4 models and backend status |
|
|
780
806
|
|
|
781
807
|
This means you can tell your AI assistant:
|
|
782
808
|
|
|
@@ -1053,7 +1079,7 @@ Tests cover all core modules, with path structure mirroring `src/`: `test_core/`
|
|
|
1053
1079
|
| `sqlseed[faker]` | + faker>=30.0 | Faker data engine |
|
|
1054
1080
|
| `sqlseed[mimesis]` | + mimesis>=18.0 | Mimesis data engine (recommended) |
|
|
1055
1081
|
| `sqlseed[docs]` | + mkdocs-material, mkdocstrings | Documentation build |
|
|
1056
|
-
| `sqlseed-ai` | sqlseed, **openai>=1.0** | AI plugin, auto-registered via entry-point |
|
|
1082
|
+
| `sqlseed-ai` | sqlseed, **openai>=1.0**, **google-generativeai>=0.8** | AI plugin (Gemma 4 Native Function Calling), auto-registered via entry-point |
|
|
1057
1083
|
| `mcp-server-sqlseed` | sqlseed, **mcp>=1.0** | MCP server, standalone CLI tool |
|
|
1058
1084
|
| `mcp-server-sqlseed[ai]` | + sqlseed-ai | MCP server with AI support |
|
|
1059
1085
|
|
|
@@ -180,6 +180,12 @@ mypy src/sqlseed/
|
|
|
180
180
|
|
|
181
181
|
## 🚀 Quick Start
|
|
182
182
|
|
|
183
|
+
### Interactive Quickstart
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
python scripts/quickstart.py
|
|
187
|
+
```
|
|
188
|
+
|
|
183
189
|
### Try with Demo Database
|
|
184
190
|
|
|
185
191
|
Want to try sqlseed right away? Build the demo database:
|
|
@@ -652,7 +658,6 @@ pip install sqlseed-ai
|
|
|
652
658
|
|
|
653
659
|
# Set API key
|
|
654
660
|
export SQLSEED_AI_API_KEY="your-api-key"
|
|
655
|
-
export SQLSEED_AI_BASE_URL="https://your-llm-api-endpoint"
|
|
656
661
|
|
|
657
662
|
# AI analysis and config generation
|
|
658
663
|
sqlseed ai-suggest app.db --table projects --output projects.yaml
|
|
@@ -660,9 +665,27 @@ sqlseed ai-suggest app.db --table projects --output projects.yaml
|
|
|
660
665
|
# AI suggestions with self-correction (3 rounds by default)
|
|
661
666
|
sqlseed ai-suggest app.db --table projects --output projects.yaml --verify
|
|
662
667
|
|
|
663
|
-
# Specify model (defaults to
|
|
664
|
-
sqlseed ai-suggest app.db --table projects --output projects.yaml --model
|
|
668
|
+
# Specify model (defaults to Gemma 4 26B via Google AI Studio)
|
|
669
|
+
sqlseed ai-suggest app.db --table projects --output projects.yaml --model gemma-4-26b-it
|
|
670
|
+
|
|
671
|
+
# Use local LM Studio / Ollama
|
|
672
|
+
sqlseed ai-suggest app.db --table projects --output projects.yaml --backend lm_studio --model google/gemma-4-e4b
|
|
673
|
+
```
|
|
665
674
|
|
|
675
|
+
**Gemma 4 Native Function Calling (GEMMA_TOOLS)**:
|
|
676
|
+
|
|
677
|
+
sqlseed-ai supports Gemma 4 model family (2B/4B/26B/31B) with Native Function Calling via GEMMA_TOOLS protocol. Supported backends:
|
|
678
|
+
|
|
679
|
+
| Backend | Description | Configuration |
|
|
680
|
+
| :------ | :---------- | :------------ |
|
|
681
|
+
| **Google AI Studio** | Official API, recommended for Gemma 4 26B/31B | `--backend google_ai_studio` or `SQLSEED_AI_BACKEND=google_ai_studio` |
|
|
682
|
+
| **LM Studio** | Local inference, suitable for Gemma 4 2B/4B | `--backend lm_studio` or `SQLSEED_AI_BACKEND=lm_studio` |
|
|
683
|
+
| **Ollama** | Local inference, suitable for Gemma 4 2B/4B/26B | `--backend ollama` or `SQLSEED_AI_BACKEND=ollama` |
|
|
684
|
+
| **OpenAI-compatible** | Generic OpenAI-compatible endpoint (e.g., OpenRouter, DeepSeek) | `--backend openai_compat` or `SQLSEED_AI_BACKEND=openai_compat` |
|
|
685
|
+
|
|
686
|
+
> **💡 OpenRouter (Free)**: For users without a paid API key, OpenRouter provides free models. Set `SQLSEED_AI_BACKEND=openai_compat`, `SQLSEED_AI_BASE_URL=https://openrouter.ai/api/v1`, and `SQLSEED_AI_MODEL=<free-model-name>`.
|
|
687
|
+
|
|
688
|
+
```bash
|
|
666
689
|
# Skip cache
|
|
667
690
|
sqlseed ai-suggest app.db --table projects --output projects.yaml --no-cache
|
|
668
691
|
```
|
|
@@ -678,7 +701,7 @@ sqlseed ai-suggest app.db --table projects --output projects.yaml --no-cache
|
|
|
678
701
|
6. Up to 3 self-correction rounds, outputs validated YAML config
|
|
679
702
|
```
|
|
680
703
|
|
|
681
|
-
> **💡 Environment Variables**: Supports `SQLSEED_AI_API_KEY`, `SQLSEED_AI_BASE_URL`, `SQLSEED_AI_MODEL`. Also supports `OPENAI_API_KEY` / `OPENAI_BASE_URL` as fallback. Defaults to
|
|
704
|
+
> **💡 Environment Variables**: Supports `SQLSEED_AI_API_KEY`, `SQLSEED_AI_BASE_URL`, `SQLSEED_AI_MODEL`, `SQLSEED_AI_BACKEND`. Also supports `OPENAI_API_KEY` / `OPENAI_BASE_URL` as fallback. Defaults to Gemma 4 26B via Google AI Studio. Supported backends: `google_ai_studio`, `lm_studio`, `ollama`, `openai_compat`.
|
|
682
705
|
|
|
683
706
|
***
|
|
684
707
|
|
|
@@ -717,6 +740,9 @@ python -m mcp_server_sqlseed
|
|
|
717
740
|
| 🔍 Tool | `sqlseed_inspect_schema` | Inspect schema (columns, FK, indexes, samples, schema_hash) |
|
|
718
741
|
| 🤖 Tool | `sqlseed_generate_yaml` | AI-driven YAML config generation with self-correction. Supports `api_key`/`base_url`/`model` overrides |
|
|
719
742
|
| ⚡ Tool | `sqlseed_execute_fill` | Execute data generation (supports YAML config string, includes `enrich` option) |
|
|
743
|
+
| 🧠 Tool | `sqlseed_gemma4_analyze` | Analyze schema using Gemma 4 with Native Function Calling |
|
|
744
|
+
| 🧠 Tool | `sqlseed_gemma4_agent_fill` | End-to-end Agent workflow (analyze -> config -> fill) |
|
|
745
|
+
| 🧠 Tool | `sqlseed_list_gemma_models` | List available Gemma 4 models and backend status |
|
|
720
746
|
|
|
721
747
|
This means you can tell your AI assistant:
|
|
722
748
|
|
|
@@ -993,7 +1019,7 @@ Tests cover all core modules, with path structure mirroring `src/`: `test_core/`
|
|
|
993
1019
|
| `sqlseed[faker]` | + faker>=30.0 | Faker data engine |
|
|
994
1020
|
| `sqlseed[mimesis]` | + mimesis>=18.0 | Mimesis data engine (recommended) |
|
|
995
1021
|
| `sqlseed[docs]` | + mkdocs-material, mkdocstrings | Documentation build |
|
|
996
|
-
| `sqlseed-ai` | sqlseed, **openai>=1.0** | AI plugin, auto-registered via entry-point |
|
|
1022
|
+
| `sqlseed-ai` | sqlseed, **openai>=1.0**, **google-generativeai>=0.8** | AI plugin (Gemma 4 Native Function Calling), auto-registered via entry-point |
|
|
997
1023
|
| `mcp-server-sqlseed` | sqlseed, **mcp>=1.0** | MCP server, standalone CLI tool |
|
|
998
1024
|
| `mcp-server-sqlseed[ai]` | + sqlseed-ai | MCP server with AI support |
|
|
999
1025
|
|
|
@@ -178,6 +178,14 @@ mypy src/sqlseed/
|
|
|
178
178
|
|
|
179
179
|
## 🚀 快速开始
|
|
180
180
|
|
|
181
|
+
### 一键体验脚本
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
python scripts/quickstart.py
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
该脚本会自动创建示例数据库、填充数据并展示结果,适合首次体验。
|
|
188
|
+
|
|
181
189
|
### 使用示例数据库体验
|
|
182
190
|
|
|
183
191
|
想立即体验 sqlseed?构建示例数据库:
|
|
@@ -553,22 +561,27 @@ sqlseed ai-suggest app.db --table projects --output projects.yaml
|
|
|
553
561
|
# 带自纠正的 AI 建议(默认 3 轮修正)
|
|
554
562
|
sqlseed ai-suggest app.db --table projects --output projects.yaml --verify
|
|
555
563
|
|
|
556
|
-
#
|
|
557
|
-
sqlseed ai-suggest app.db --table projects -o projects.yaml --model
|
|
564
|
+
# 指定模型(支持多后端:Google AI Studio、LM Studio、Ollama、OpenAI-compatible)
|
|
565
|
+
sqlseed ai-suggest app.db --table projects -o projects.yaml --model gemma-4-26b-it --backend google_ai_studio
|
|
566
|
+
sqlseed ai-suggest app.db --table projects -o projects.yaml --model gemma-4-31b-it --backend google_ai_studio
|
|
567
|
+
sqlseed ai-suggest app.db --table projects -o projects.yaml --model google/gemma-4-e4b --backend lm_studio
|
|
568
|
+
sqlseed ai-suggest app.db --table projects -o projects.yaml --model gemma-4-4b-it --backend ollama
|
|
558
569
|
```
|
|
559
570
|
|
|
560
|
-
**
|
|
571
|
+
**Gemma 4 原生函数调用(GEMMA_TOOLS)**:
|
|
561
572
|
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
4
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
573
|
+
sqlseed-ai 支持 Gemma 4 系列模型(2B/4B/26B/31B)通过 GEMMA_TOOLS 协议实现原生函数调用,无需 JSON Mode 模拟。支持的后端:
|
|
574
|
+
|
|
575
|
+
| 后端 | 说明 | 配置方式 |
|
|
576
|
+
| :--- | :--- | :--- |
|
|
577
|
+
| **Google AI Studio** | 官方 API,推荐 Gemma 4 26B/31B | `--backend google_ai_studio` 或 `SQLSEED_AI_BACKEND=google_ai_studio` |
|
|
578
|
+
| **LM Studio** | 本地推理,适合 Gemma 4 2B/4B | `--backend lm_studio` 或 `SQLSEED_AI_BACKEND=lm_studio` |
|
|
579
|
+
| **Ollama** | 本地推理,适合 Gemma 4 2B/4B/26B | `--backend ollama` 或 `SQLSEED_AI_BACKEND=ollama` |
|
|
580
|
+
| **OpenAI-compatible** | 通用 OpenAI 兼容端点(如 OpenRouter、DeepSeek) | `--backend openai_compat` 或 `SQLSEED_AI_BACKEND=openai_compat` |
|
|
570
581
|
|
|
571
|
-
> **💡
|
|
582
|
+
> **💡 OpenRouter(免费方案)**:没有付费 API Key 的用户,可以使用 OpenRouter 的免费模型。设置 `SQLSEED_AI_BACKEND=openai_compat`、`SQLSEED_AI_BASE_URL=https://openrouter.ai/api/v1`、`SQLSEED_AI_MODEL=<免费模型名>`。
|
|
583
|
+
|
|
584
|
+
> **💡 环境变量**:支持 `SQLSEED_AI_API_KEY`、`SQLSEED_AI_BASE_URL`、`SQLSEED_AI_MODEL`、`SQLSEED_AI_BACKEND`。也支持 `OPENAI_API_KEY` / `OPENAI_BASE_URL` 作为回退。
|
|
572
585
|
|
|
573
586
|
***
|
|
574
587
|
|
|
@@ -598,6 +611,9 @@ pip install mcp-server-sqlseed[ai]
|
|
|
598
611
|
| 🔍 Tool | `sqlseed_inspect_schema` | 检查 Schema(列、外键、索引、样本数据、schema_hash) |
|
|
599
612
|
| 🤖 Tool | `sqlseed_generate_yaml` | AI 驱动的 YAML 配置生成(含自纠正) |
|
|
600
613
|
| ⚡ Tool | `sqlseed_execute_fill` | 执行数据生成(支持 YAML 配置字符串,含 `enrich` 选项) |
|
|
614
|
+
| 🤖 Tool | `sqlseed_gemma4_analyze` | Gemma 4 原生函数调用分析 Schema(GEMMA_TOOLS 协议) |
|
|
615
|
+
| 🤖 Tool | `sqlseed_gemma4_agent_fill` | Gemma 4 Agent 模式端到端数据生成(分析→配置→填充) |
|
|
616
|
+
| 📋 Tool | `sqlseed_list_gemma_models` | 列出可用的 Gemma 4 模型及后端支持情况 |
|
|
601
617
|
|
|
602
618
|
***
|
|
603
619
|
|
|
@@ -679,6 +695,12 @@ sqlseed ai-suggest app.db -t users -o users.yaml --verify
|
|
|
679
695
|
sqlseed ai-suggest app.db -t users -o users.yaml --api-key sk-xxx --base-url https://api.openai.com/v1
|
|
680
696
|
sqlseed ai-suggest app.db -t users -o users.yaml --max-retries 0
|
|
681
697
|
sqlseed ai-suggest app.db -t users -o users.yaml --no-cache
|
|
698
|
+
|
|
699
|
+
# ═══ AI 后端选择 ═══
|
|
700
|
+
sqlseed ai-suggest app.db -t users -o users.yaml --backend google_ai_studio --model gemma-4-26b-it
|
|
701
|
+
sqlseed ai-suggest app.db -t users -o users.yaml --backend ollama --model gemma-4-4b-it
|
|
702
|
+
sqlseed ai-suggest app.db -t users -o users.yaml --backend lm_studio --model google/gemma-4-e4b
|
|
703
|
+
sqlseed ai-suggest app.db -t users -o users.yaml --backend openai_compat --model your-model --base-url https://your-api-endpoint
|
|
682
704
|
```
|
|
683
705
|
|
|
684
706
|
***
|
|
@@ -805,7 +827,7 @@ mypy src/sqlseed/ # 类型检查
|
|
|
805
827
|
| `sqlseed[faker]` | + faker>=30.0 | Faker 数据引擎 |
|
|
806
828
|
| `sqlseed[mimesis]` | + mimesis>=18.0 | Mimesis 数据引擎(推荐) |
|
|
807
829
|
| `sqlseed[docs]` | + mkdocs-material, mkdocstrings | 文档构建 |
|
|
808
|
-
| `sqlseed-ai` | sqlseed, **openai>=1.0** | AI 插件,通过 entry-point
|
|
830
|
+
| `sqlseed-ai` | sqlseed, **openai>=1.0**, **google-generativeai>=0.8** | AI 插件,通过 entry-point 自动注册,支持 Gemma 4 GEMMA_TOOLS |
|
|
809
831
|
| `mcp-server-sqlseed` | sqlseed, **mcp>=1.0** | MCP 服务器,独立 CLI 工具 |
|
|
810
832
|
| `mcp-server-sqlseed[ai]` | + sqlseed-ai | MCP 服务器含 AI 支持 |
|
|
811
833
|
|
|
@@ -1353,7 +1353,7 @@
|
|
|
1353
1353
|
" fk_columns = {fk.column for fk in fk_info}\n",
|
|
1354
1354
|
" print(\"members 表列映射分析:\")\n",
|
|
1355
1355
|
" for col in col_info:\n",
|
|
1356
|
-
" if col.name.endswith(\"_id\"
|
|
1356
|
+
" if col.name.endswith((\"_id\", \"_no\")):\n",
|
|
1357
1357
|
" is_fk = col.name in fk_columns\n",
|
|
1358
1358
|
" gen_type = \"foreign_key\" if is_fk else \"integer/string\"\n",
|
|
1359
1359
|
" print(f\" {col.name}: {gen_type} (FK={is_fk})\")"
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Create demo database with 3 tables for quickstart script."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import sqlite3
|
|
6
|
+
import sys
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def main() -> None:
|
|
11
|
+
db_path_str = sys.argv[1] if len(sys.argv) > 1 else "quickstart_demo.db"
|
|
12
|
+
db_path = Path(db_path_str)
|
|
13
|
+
if db_path.exists():
|
|
14
|
+
db_path.unlink()
|
|
15
|
+
|
|
16
|
+
conn = sqlite3.connect(str(db_path))
|
|
17
|
+
conn.executescript("""
|
|
18
|
+
CREATE TABLE users (
|
|
19
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
20
|
+
name TEXT NOT NULL,
|
|
21
|
+
email TEXT NOT NULL UNIQUE,
|
|
22
|
+
age INTEGER,
|
|
23
|
+
city TEXT,
|
|
24
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
25
|
+
);
|
|
26
|
+
CREATE TABLE projects (
|
|
27
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
28
|
+
name TEXT NOT NULL,
|
|
29
|
+
description TEXT,
|
|
30
|
+
status TEXT DEFAULT 'Planning',
|
|
31
|
+
owner_id INTEGER REFERENCES users(id),
|
|
32
|
+
budget REAL,
|
|
33
|
+
deadline DATE,
|
|
34
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
35
|
+
);
|
|
36
|
+
CREATE TABLE orders (
|
|
37
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
38
|
+
user_id INTEGER REFERENCES users(id),
|
|
39
|
+
project_id INTEGER REFERENCES projects(id),
|
|
40
|
+
amount REAL NOT NULL,
|
|
41
|
+
status TEXT DEFAULT 'pending',
|
|
42
|
+
order_date DATE,
|
|
43
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
44
|
+
);
|
|
45
|
+
""")
|
|
46
|
+
conn.commit()
|
|
47
|
+
conn.close()
|
|
48
|
+
print(f" Database created: {db_path} (3 tables: users, projects, orders)")
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
if __name__ == "__main__":
|
|
52
|
+
main()
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""sqlseed + Gemma 4 one-click setup script (cross-platform).
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
python scripts/quickstart.py [--backend lm_studio|ollama|google] [--model MODEL_NAME]
|
|
6
|
+
python scripts/quickstart.py --skip-install # Skip pip install, use current env
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import argparse
|
|
12
|
+
import os
|
|
13
|
+
import subprocess
|
|
14
|
+
import sys
|
|
15
|
+
import urllib.request
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
PROJECT_ROOT = Path(__file__).resolve().parent.parent
|
|
19
|
+
DB_PATH = PROJECT_ROOT / "quickstart_demo.db"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def run(cmd: list[str], check: bool = True) -> subprocess.CompletedProcess[str]:
|
|
23
|
+
"""Run a command and print it."""
|
|
24
|
+
print(f" $ {' '.join(str(c) for c in cmd)}")
|
|
25
|
+
return subprocess.run(cmd, check=check, text=True)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def check_lm_studio() -> bool:
|
|
29
|
+
"""Check if LM Studio is running."""
|
|
30
|
+
try:
|
|
31
|
+
with urllib.request.urlopen("http://127.0.0.1:1234/v1/models", timeout=3) as r:
|
|
32
|
+
return r.status == 200
|
|
33
|
+
except OSError:
|
|
34
|
+
return False
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def check_ollama() -> bool:
|
|
38
|
+
"""Check if Ollama is running."""
|
|
39
|
+
try:
|
|
40
|
+
with urllib.request.urlopen("http://localhost:11434/api/tags", timeout=3) as r:
|
|
41
|
+
return r.status == 200
|
|
42
|
+
except OSError:
|
|
43
|
+
return False
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def sqlseed_cmd(python: str) -> list[str]:
|
|
47
|
+
"""Build a sqlseed CLI invocation."""
|
|
48
|
+
return [python, "-c", "from sqlseed.cli.main import cli; cli()", "--"]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _fill_data(python: str) -> None:
|
|
52
|
+
"""Fill the demo database with sample data using sqlseed CLI."""
|
|
53
|
+
cmd = sqlseed_cmd(python)
|
|
54
|
+
for table, count in (("users", 500), ("projects", 200), ("orders", 1000)):
|
|
55
|
+
run([*cmd, "fill", str(DB_PATH), "-t", table, "-n", str(count)])
|
|
56
|
+
|
|
57
|
+
print()
|
|
58
|
+
print(" Data fill complete!")
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _run_ai_analysis_step(args: argparse.Namespace, python: str) -> None:
|
|
62
|
+
"""Run the Gemma 4 AI schema analysis step."""
|
|
63
|
+
print("[5/5] Gemma 4 AI Schema Analysis...")
|
|
64
|
+
print(f" Backend: {args.backend}")
|
|
65
|
+
print(f" Model: {args.model}")
|
|
66
|
+
print()
|
|
67
|
+
|
|
68
|
+
os.environ["SQLSEED_AI_BACKEND"] = args.backend
|
|
69
|
+
os.environ["SQLSEED_AI_MODEL"] = args.model
|
|
70
|
+
|
|
71
|
+
ai_ok = False
|
|
72
|
+
if args.backend == "lm_studio":
|
|
73
|
+
if check_lm_studio():
|
|
74
|
+
ai_ok = True
|
|
75
|
+
else:
|
|
76
|
+
print(" Skipped: LM Studio is not running")
|
|
77
|
+
print(" Please start LM Studio and load a Gemma 4 model")
|
|
78
|
+
print(" Download: https://lmstudio.ai/")
|
|
79
|
+
elif args.backend == "ollama":
|
|
80
|
+
if check_ollama():
|
|
81
|
+
ai_ok = True
|
|
82
|
+
else:
|
|
83
|
+
print(" Skipped: Ollama is not running")
|
|
84
|
+
print(" Example: ollama pull gemma4:4b")
|
|
85
|
+
elif args.backend == "google":
|
|
86
|
+
if os.environ.get("GOOGLE_API_KEY"):
|
|
87
|
+
ai_ok = True
|
|
88
|
+
else:
|
|
89
|
+
print(" Skipped: GOOGLE_API_KEY not set")
|
|
90
|
+
print(" Example: export GOOGLE_API_KEY=your-key")
|
|
91
|
+
|
|
92
|
+
if ai_ok:
|
|
93
|
+
output_yaml = str(PROJECT_ROOT / "projects_config.yaml")
|
|
94
|
+
cmd = sqlseed_cmd(python)
|
|
95
|
+
run([*cmd, "ai-suggest", str(DB_PATH), "-t", "projects", "-o", output_yaml, "--timeout", "300"])
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def main() -> None:
|
|
99
|
+
parser = argparse.ArgumentParser(description="GemmaSQLSeed one-click setup")
|
|
100
|
+
parser.add_argument(
|
|
101
|
+
"--backend",
|
|
102
|
+
choices=["lm_studio", "ollama", "google"],
|
|
103
|
+
default=os.environ.get("SQLSEED_AI_BACKEND", "lm_studio"),
|
|
104
|
+
help="AI backend (default: lm_studio)",
|
|
105
|
+
)
|
|
106
|
+
parser.add_argument(
|
|
107
|
+
"--model",
|
|
108
|
+
default=os.environ.get("SQLSEED_AI_MODEL", "google/gemma-4-e4b"),
|
|
109
|
+
help="Model name (default: google/gemma-4-e4b)",
|
|
110
|
+
)
|
|
111
|
+
parser.add_argument(
|
|
112
|
+
"--skip-install",
|
|
113
|
+
action="store_true",
|
|
114
|
+
help="Skip dependency installation, use current Python environment",
|
|
115
|
+
)
|
|
116
|
+
args = parser.parse_args()
|
|
117
|
+
|
|
118
|
+
print("=" * 50)
|
|
119
|
+
print(" GemmaSQLSeed Quick Start")
|
|
120
|
+
print("=" * 50)
|
|
121
|
+
print()
|
|
122
|
+
|
|
123
|
+
# Determine which python to use
|
|
124
|
+
if args.skip_install:
|
|
125
|
+
# Use current Python (already has sqlseed installed)
|
|
126
|
+
python = sys.executable
|
|
127
|
+
print("[1/5] Using current Python environment (skip-install)")
|
|
128
|
+
print("[2/5] Skipping installation (--skip-install)")
|
|
129
|
+
else:
|
|
130
|
+
# Create venv and install
|
|
131
|
+
venv_path = PROJECT_ROOT / ".venv"
|
|
132
|
+
if not venv_path.exists():
|
|
133
|
+
print("[1/5] Creating virtual environment...")
|
|
134
|
+
run([sys.executable, "-m", "venv", str(venv_path)])
|
|
135
|
+
else:
|
|
136
|
+
print("[1/5] Virtual environment exists, skipping")
|
|
137
|
+
|
|
138
|
+
if sys.platform == "win32":
|
|
139
|
+
python = str(venv_path / "Scripts" / "python.exe")
|
|
140
|
+
else:
|
|
141
|
+
python = str(venv_path / "bin" / "python")
|
|
142
|
+
|
|
143
|
+
print("[2/5] Installing dependencies (may take a few minutes on first run)...")
|
|
144
|
+
run([python, "-m", "pip", "install", "-q", "-e", f"{PROJECT_ROOT}[dev,all]"])
|
|
145
|
+
run([python, "-m", "pip", "install", "-q", "-e", str(PROJECT_ROOT / "plugins" / "sqlseed-ai")])
|
|
146
|
+
run([python, "-m", "pip", "install", "-q", "-e", str(PROJECT_ROOT / "plugins" / "mcp-server-sqlseed")])
|
|
147
|
+
|
|
148
|
+
# ── Step 3: Create test database ─────────────────────────────────
|
|
149
|
+
print("[3/5] Creating test database...")
|
|
150
|
+
if DB_PATH.exists():
|
|
151
|
+
DB_PATH.unlink()
|
|
152
|
+
|
|
153
|
+
create_db_script = Path(__file__).parent / "_create_demo_db.py"
|
|
154
|
+
run([python, str(create_db_script), str(DB_PATH)])
|
|
155
|
+
|
|
156
|
+
# ── Step 4: Fill data ────────────────────────────────────────────
|
|
157
|
+
print("[4/5] Filling data (zero-config)...")
|
|
158
|
+
_fill_data(python)
|
|
159
|
+
|
|
160
|
+
# ── Step 5: Gemma 4 AI analysis ──────────────────────────────────
|
|
161
|
+
_run_ai_analysis_step(args, python)
|
|
162
|
+
|
|
163
|
+
# ── Done ─────────────────────────────────────────────────────────
|
|
164
|
+
print()
|
|
165
|
+
print("=" * 50)
|
|
166
|
+
print(" Setup Complete!")
|
|
167
|
+
print("=" * 50)
|
|
168
|
+
print()
|
|
169
|
+
print(f" Database: {DB_PATH}")
|
|
170
|
+
cli_call = 'python -c "from sqlseed.cli.main import cli; cli()" --'
|
|
171
|
+
print(f" Preview: {cli_call} preview {DB_PATH} -t users -n 5")
|
|
172
|
+
print(f" Inspect: {cli_call} inspect {DB_PATH} --show-mapping")
|
|
173
|
+
print(f" AI Suggest: {cli_call} ai-suggest {DB_PATH} -t users -o config.yaml")
|
|
174
|
+
print(" MCP Server: mcp-server-sqlseed")
|
|
175
|
+
print()
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
if __name__ == "__main__":
|
|
179
|
+
main()
|
|
@@ -475,15 +475,19 @@ def ai_suggest(
|
|
|
475
475
|
ai_config = AIConfig.from_env().apply_overrides(api_key=api_key, base_url=base_url, model=model)
|
|
476
476
|
ai_config.timeout = timeout
|
|
477
477
|
|
|
478
|
-
if not ai_config.
|
|
478
|
+
if not ai_config.resolve_api_key():
|
|
479
479
|
click.echo(
|
|
480
|
-
"Error: AI API key not configured.
|
|
480
|
+
"Error: AI API key not configured. "
|
|
481
|
+
"Set SQLSEED_AI_API_KEY or OPENAI_API_KEY. "
|
|
482
|
+
"For Google AI Studio, set GOOGLE_API_KEY. "
|
|
483
|
+
"For LM Studio/Ollama, set SQLSEED_AI_BACKEND=lm_studio or ollama.",
|
|
481
484
|
err=True,
|
|
482
485
|
)
|
|
483
486
|
raise SystemExit(1)
|
|
484
487
|
|
|
485
488
|
resolved_model = ai_config.resolve_model()
|
|
486
|
-
|
|
489
|
+
backend_name = ai_config.backend.value.replace("_", " ").title()
|
|
490
|
+
click.echo(f"Using AI model: {resolved_model} (via {backend_name})")
|
|
487
491
|
|
|
488
492
|
analyzer = SchemaAnalyzer(config=ai_config)
|
|
489
493
|
total_timeout = timeout * 2
|
|
@@ -491,13 +495,15 @@ def ai_suggest(
|
|
|
491
495
|
old_handler: Any = None
|
|
492
496
|
if hasattr(signal, "SIGALRM"):
|
|
493
497
|
old_handler = signal.signal(signal.SIGALRM, lambda _s, _f: _sigalrm_handler(total_timeout))
|
|
494
|
-
signal
|
|
498
|
+
_alarm_fn = vars(signal)["alarm"]
|
|
499
|
+
_alarm_fn(int(total_timeout))
|
|
495
500
|
|
|
496
501
|
try:
|
|
497
502
|
result = _run_ai_analysis(analyzer, db_path, table, verify, max_retries, no_cache)
|
|
498
503
|
finally:
|
|
499
504
|
if hasattr(signal, "SIGALRM"):
|
|
500
|
-
signal
|
|
505
|
+
_alarm_fn = vars(signal)["alarm"]
|
|
506
|
+
_alarm_fn(0)
|
|
501
507
|
if old_handler is not None:
|
|
502
508
|
signal.signal(signal.SIGALRM, old_handler)
|
|
503
509
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|