Skip to content

Commit 14ac332

Browse files
committed
fix: restore OpenRouter as free option, fix lint/mypy errors
- Restore OpenRouter documentation as openai_compat backend example - Fix ruff import sorting in analyzer.py - Fix ruff format in 4 plugin files - Fix mypy no-any-return in analyzer.py - Fix mypy attr-defined for signal.alarm on Windows
1 parent c5cac66 commit 14ac332

9 files changed

Lines changed: 49 additions & 38 deletions

File tree

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -681,7 +681,9 @@ sqlseed-ai supports Gemma 4 model family (2B/4B/26B/31B) with Native Function Ca
681681
| **Google AI Studio** | Official API, recommended for Gemma 4 26B/31B | `--backend google_ai_studio` or `SQLSEED_AI_BACKEND=google_ai_studio` |
682682
| **LM Studio** | Local inference, suitable for Gemma 4 2B/4B | `--backend lm_studio` or `SQLSEED_AI_BACKEND=lm_studio` |
683683
| **Ollama** | Local inference, suitable for Gemma 4 2B/4B/26B | `--backend ollama` or `SQLSEED_AI_BACKEND=ollama` |
684-
| **OpenAI-compatible** | Generic OpenAI-compatible endpoint | `--backend openai_compat` or `SQLSEED_AI_BACKEND=openai_compat` |
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>`.
685687

686688
```bash
687689
# Skip cache

README.zh-CN.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -574,10 +574,12 @@ sqlseed-ai 支持 Gemma 4 系列模型(2B/4B/26B/31B)通过 GEMMA_TOOLS 协
574574

575575
| 后端 | 说明 | 配置方式 |
576576
| :--- | :--- | :--- |
577-
| **Google AI Studio** | 官方 API,推荐 Gemma 4 26B/31B | `--backend google` 或 `SQLSEED_AI_BACKEND=google` |
578-
| **LM Studio** | 本地推理,适合 Gemma 4 2B/4B | `--backend lm-studio` 或 `SQLSEED_AI_BACKEND=lm-studio` |
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` |
579579
| **Ollama** | 本地推理,适合 Gemma 4 2B/4B/26B | `--backend ollama` 或 `SQLSEED_AI_BACKEND=ollama` |
580-
| **OpenAI-compatible** | 通用 OpenAI 兼容端点 | `--backend openai_compat` 或 `SQLSEED_AI_BACKEND=openai_compat` |
580+
| **OpenAI-compatible** | 通用 OpenAI 兼容端点(如 OpenRouter、DeepSeek) | `--backend openai_compat` 或 `SQLSEED_AI_BACKEND=openai_compat` |
581+
582+
> **💡 OpenRouter(免费方案)**:没有付费 API Key 的用户,可以使用 OpenRouter 的免费模型。设置 `SQLSEED_AI_BACKEND=openai_compat`、`SQLSEED_AI_BASE_URL=https://openrouter.ai/api/v1`、`SQLSEED_AI_MODEL=<免费模型名>`。
581583

582584
> **💡 环境变量**:支持 `SQLSEED_AI_API_KEY`、`SQLSEED_AI_BASE_URL`、`SQLSEED_AI_MODEL`、`SQLSEED_AI_BACKEND`。也支持 `OPENAI_API_KEY` / `OPENAI_BASE_URL` 作为回退。
583585

plugins/mcp-server-sqlseed/src/mcp_server_sqlseed/server.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -322,10 +322,12 @@ def sqlseed_list_gemma_models() -> dict[str, Any]:
322322
"""
323323
models = []
324324
for member in GemmaModel:
325-
models.append({
326-
"id": member.value,
327-
"display_name": member.display_name,
328-
})
325+
models.append(
326+
{
327+
"id": member.value,
328+
"display_name": member.display_name,
329+
}
330+
)
329331

330332
backends = [
331333
{"id": "google_ai_studio", "description": "Google AI Studio API (free tier available, recommended)"},

plugins/sqlseed-ai/README.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
AI-powered data generation plugin for [sqlseed](https://github.com/sunbos/sqlseed).
66

7-
LLM-driven schema analysis, self-correcting config generation, and template pool assistance. Supports multiple backends: Google AI Studio (Gemma 4 Native Function Calling), LM Studio, Ollama, and any OpenAI-compatible API.
7+
LLM-driven schema analysis, self-correcting config generation, and template pool assistance. Supports multiple backends: Google AI Studio (Gemma 4 Native Function Calling), LM Studio, Ollama, and any OpenAI-compatible API (OpenRouter, OpenAI, DeepSeek, etc.).
88

99
## Installation
1010

@@ -54,7 +54,14 @@ When using the `google_ai_studio` backend (default), the `GemmaModel` enum provi
5454

5555
1. **Google AI Studio**: Defaults to `gemma-4-26b-it` (recommended balance of quality and speed).
5656
2. **LM Studio / Ollama**: User must specify a loaded model via `--model` or `SQLSEED_AI_MODEL`.
57-
3. **OpenAI-compatible**: User must specify both `--model` and `--base-url`.
57+
3. **OpenAI-compatible** (OpenRouter, DeepSeek, etc.): User must specify both `--model` and `--base-url`.
58+
59+
For **OpenRouter free models**, set:
60+
```bash
61+
export SQLSEED_AI_BACKEND=openai_compat
62+
export SQLSEED_AI_BASE_URL=https://openrouter.ai/api/v1
63+
export SQLSEED_AI_MODEL=<free-model-name>
64+
```
5865

5966
Skip auto-selection by specifying `--model` or `SQLSEED_AI_MODEL`.
6067

plugins/sqlseed-ai/README.zh-CN.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
[sqlseed](https://github.com/sunbos/sqlseed) 的 AI 驱动数据生成插件。
66

7-
LLM 驱动的 Schema 分析、自纠正配置生成和模板池辅助。支持多种后端:Google AI Studio(Gemma 4 原生函数调用)、LM Studio、Ollama,以及任何 OpenAI 兼容 API。
7+
LLM 驱动的 Schema 分析、自纠正配置生成和模板池辅助。支持多种后端:Google AI Studio(Gemma 4 原生函数调用)、LM Studio、Ollama,以及任何 OpenAI 兼容 API(OpenRouter、OpenAI、DeepSeek 等)
88

99
## 安装
1010

@@ -54,7 +54,14 @@ sqlseed ai-suggest app.db --table users -o users.yaml --no-cache
5454

5555
1. **Google AI Studio**:默认使用 `gemma-4-26b-it`(推荐的质量与速度平衡)。
5656
2. **LM Studio / Ollama**:用户需通过 `--model``SQLSEED_AI_MODEL` 指定已加载的模型。
57-
3. **OpenAI-compatible**:用户需同时指定 `--model``--base-url`
57+
3. **OpenAI-compatible**(OpenRouter、DeepSeek 等):用户需同时指定 `--model``--base-url`
58+
59+
**OpenRouter 免费模型**设置:
60+
```bash
61+
export SQLSEED_AI_BACKEND=openai_compat
62+
export SQLSEED_AI_BASE_URL=https://openrouter.ai/api/v1
63+
export SQLSEED_AI_MODEL=<免费模型名>
64+
```
5865

5966
通过 `--model``SQLSEED_AI_MODEL` 跳过自动选择。
6067

plugins/sqlseed-ai/src/sqlseed_ai/_model_selector.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,16 +73,14 @@ def select_next_gemma_model(failed_model: str) -> str | None:
7373

7474
def get_available_gemma_models() -> list[dict[str, str]]:
7575
"""Return list of available Gemma 4 models with display info."""
76-
return [
77-
{"id": m.value, "display_name": m.display_name}
78-
for m in _GEMMA_MODEL_PRIORITY
79-
]
76+
return [{"id": m.value, "display_name": m.display_name} for m in _GEMMA_MODEL_PRIORITY]
8077

8178

8279
# ── Legacy compatibility ─────────────────────────────────────────────
8380
# These functions maintain backward compatibility with code that
8481
# referenced the old OpenRouter-based model selector.
8582

83+
8684
def select_best_free_model() -> str:
8785
"""Legacy compat: returns the default Gemma 4 model."""
8886
return select_gemma_model()

plugins/sqlseed-ai/src/sqlseed_ai/analyzer.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from sqlseed_ai._client import get_openai_client
88
from sqlseed_ai._json_utils import parse_json_response
99
from sqlseed_ai._model_selector import select_next_gemma_model
10-
from sqlseed_ai.config import AIConfig, AIBackend
10+
from sqlseed_ai.config import AIBackend, AIConfig
1111
from sqlseed_ai.examples import FEW_SHOT_EXAMPLES
1212

1313
from sqlseed._utils.logger import get_logger
@@ -343,9 +343,7 @@ def _call_llm_once(self, messages: list[dict[str, str]]) -> dict[str, Any]:
343343
return {}
344344
return self._parse_json_response(content)
345345

346-
def _try_tool_calling(
347-
self, client: Any, kwargs: dict[str, Any]
348-
) -> dict[str, Any] | None:
346+
def _try_tool_calling(self, client: Any, kwargs: dict[str, Any]) -> dict[str, Any] | None:
349347
"""Attempt Gemma 4 native function calling.
350348
351349
If the model supports tool use, it will invoke the `analyze_schema`
@@ -374,7 +372,7 @@ def _try_tool_calling(
374372
args_str = tool_call.function.arguments
375373
if args_str:
376374
try:
377-
result = json.loads(args_str)
375+
result: dict[str, Any] | None = json.loads(args_str)
378376
logger.info(
379377
"Gemma 4 native function calling succeeded",
380378
tool="analyze_schema",

plugins/sqlseed-ai/src/sqlseed_ai/config.py

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
logger = get_logger(__name__)
1212

13+
1314
# ── Gemma 4 model registry ──────────────────────────────────────────
1415
class GemmaModel(str, Enum):
1516
"""Supported Gemma 4 model variants."""
@@ -60,15 +61,9 @@ class AIConfig(BaseModel):
6061
@classmethod
6162
def from_env(cls) -> AIConfig:
6263
api_key = (
63-
os.environ.get("SQLSEED_AI_API_KEY")
64-
or os.environ.get("GOOGLE_API_KEY")
65-
or os.environ.get("OPENAI_API_KEY")
66-
)
67-
base_url = (
68-
os.environ.get("SQLSEED_AI_BASE_URL")
69-
or os.environ.get("OPENAI_BASE_URL")
70-
or None
64+
os.environ.get("SQLSEED_AI_API_KEY") or os.environ.get("GOOGLE_API_KEY") or os.environ.get("OPENAI_API_KEY")
7165
)
66+
base_url = os.environ.get("SQLSEED_AI_BASE_URL") or os.environ.get("OPENAI_BASE_URL") or None
7267
model = os.environ.get("SQLSEED_AI_MODEL") or None
7368
backend_str = os.environ.get("SQLSEED_AI_BACKEND", "").lower()
7469
timeout_str = os.environ.get("SQLSEED_AI_TIMEOUT")
@@ -82,9 +77,7 @@ def from_env(cls) -> AIConfig:
8277
backend = AIBackend.OLLAMA
8378
elif backend_str == "openai_compat":
8479
backend = AIBackend.OPENAI_COMPAT
85-
elif backend_str == "google_ai_studio" or (
86-
base_url and "generativelanguage.googleapis.com" in base_url
87-
):
80+
elif backend_str == "google_ai_studio" or (base_url and "generativelanguage.googleapis.com" in base_url):
8881
backend = AIBackend.GOOGLE_AI_STUDIO
8982
elif base_url and ("127.0.0.1:1234" in base_url or "localhost:1234" in base_url):
9083
backend = AIBackend.LM_STUDIO
@@ -130,13 +123,15 @@ def resolve_api_key(self) -> str | None:
130123

131124
# Try environment variables
132125
return (
133-
os.environ.get("SQLSEED_AI_API_KEY")
134-
or os.environ.get("GOOGLE_API_KEY")
135-
or os.environ.get("OPENAI_API_KEY")
126+
os.environ.get("SQLSEED_AI_API_KEY") or os.environ.get("GOOGLE_API_KEY") or os.environ.get("OPENAI_API_KEY")
136127
)
137128

138129
def apply_overrides(
139-
self, *, api_key: str | None = None, base_url: str | None = None, model: str | None = None,
130+
self,
131+
*,
132+
api_key: str | None = None,
133+
base_url: str | None = None,
134+
model: str | None = None,
140135
backend: AIBackend | None = None,
141136
) -> AIConfig:
142137
if api_key:

src/sqlseed/cli/main.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -495,13 +495,13 @@ def ai_suggest(
495495
old_handler: Any = None
496496
if hasattr(signal, "SIGALRM"):
497497
old_handler = signal.signal(signal.SIGALRM, lambda _s, _f: _sigalrm_handler(total_timeout))
498-
signal.alarm(int(total_timeout))
498+
signal.alarm(int(total_timeout)) # type: ignore[attr-defined]
499499

500500
try:
501501
result = _run_ai_analysis(analyzer, db_path, table, verify, max_retries, no_cache)
502502
finally:
503503
if hasattr(signal, "SIGALRM"):
504-
signal.alarm(0)
504+
signal.alarm(0) # type: ignore[attr-defined]
505505
if old_handler is not None:
506506
signal.signal(signal.SIGALRM, old_handler)
507507

0 commit comments

Comments
 (0)