Skip to content

Commit 6e95790

Browse files
committed
feat: add Yandex Cloud GPT AI provider support
- Add YandexProvider implementation with support for Yandex Cloud GPT API - Support YANDEX_CLOUD_FOLDER, YANDEX_CLOUD_API_KEY, YANDEX_CLOUD_MODEL env vars - Integrate Yandex provider into AiAnalysisService and AiConfig - Add Yandex configuration to pdodb init wizard - Update documentation with Yandex provider information - Support both 'summary' and 'content' response formats for different models
1 parent efbb1fe commit 6e95790

File tree

6 files changed

+80
-10
lines changed

6 files changed

+80
-10
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ Built on top of PDO with **zero external dependencies**, it offers:
3636
- **ActiveRecord Pattern** - Optional lightweight ORM for object-based database operations with relationships (hasOne, hasMany, belongsTo, hasManyThrough), eager/lazy loading, and query scopes
3737

3838
**Developer Experience:**
39-
- **🤖 AI-Powered Analysis** - Get intelligent database optimization recommendations using OpenAI, Anthropic, Google, Microsoft, or Ollama. Analyze queries, optimize schema, and get AI-powered suggestions through `explainAiAdvice()` method or CLI commands. Includes MCP server for IDE/agent integration.
39+
- **🤖 AI-Powered Analysis** - Get intelligent database optimization recommendations using OpenAI, Anthropic, Google, Microsoft, DeepSeek, Yandex, or Ollama. Analyze queries, optimize schema, and get AI-powered suggestions through `explainAiAdvice()` method or CLI commands. Includes MCP server for IDE/agent integration.
4040
- **🖥️ Interactive TUI Dashboard** - Real-time database monitoring with full-screen terminal interface. 8 panes across 2 screens: Active Queries, Connection Pool, Cache Statistics, Server Metrics, Schema Browser, Migration Manager, Server Variables, and SQL Scratchpad. Features include global search filter, query inspection, performance tracking, query management, and keyboard navigation. Launch with `pdodb ui`
4141
- **CLI Tools** - Database management, user management, dump/restore, migration generator, seed generator, model generator, schema inspector, interactive query tester (REPL), AI analysis commands
4242
- **Enhanced EXPLAIN** - Automatic detection of full table scans, missing indexes, and optimization recommendations
@@ -498,7 +498,7 @@ pdodb ai analyze "SELECT * FROM users WHERE email = '[email protected]'" \
498498
--table=users
499499
```
500500

501-
**Supported Providers:** OpenAI, Anthropic, Google, Microsoft, DeepSeek, Ollama (local, no API key)
501+
**Supported Providers:** OpenAI, Anthropic, Google, Microsoft, DeepSeek, Yandex, Ollama (local, no API key)
502502

503503
**Model Selection:** Configure models via environment variables (`PDODB_AI_<PROVIDER>_MODEL`) or config array (`ai.providers.<provider>.model`)
504504

@@ -727,7 +727,7 @@ Perfect for debugging, monitoring production databases, understanding query patt
727727
### Available Commands
728728

729729
- **`ui`** ⭐ - **Interactive TUI Dashboard** - Real-time database monitoring (full-screen terminal interface)
730-
- **`ai`** 🤖 - **AI-Powered Analysis** - Get intelligent database optimization recommendations using OpenAI, Anthropic, Google, Microsoft, or Ollama
730+
- **`ai`** 🤖 - **AI-Powered Analysis** - Get intelligent database optimization recommendations using OpenAI, Anthropic, Google, Microsoft, DeepSeek, Yandex, or Ollama
731731
- **`db`** - Manage databases (create, drop, list, check existence)
732732
- **`user`** - Manage database users (create, drop, grant/revoke privileges)
733733
- **`dump`** - Dump and restore database (with compression, auto-naming, rotation)

documentation/05-advanced-features/23-ai-analysis.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ PDOdb supports multiple AI providers, each with their own strengths:
3333
| **Google** | gemini-2.5-flash, gemini-2.5-pro, gemini-2.0-flash-001, gemini-flash-latest, gemini-pro-latest | Multimodal analysis, large context | Yes |
3434
| **Microsoft** | Azure OpenAI models | Enterprise environments | Yes |
3535
| **DeepSeek** | deepseek-chat, deepseek-reasoner | Cost-effective, OpenAI-compatible | Yes |
36+
| **Yandex** | gpt-oss-120b/latest | Russian market, Yandex Cloud | Yes (API key + folder ID) |
3637
| **Ollama** | Any local model (llama2, deepseek-coder, etc.) | Privacy, offline use, no API costs | No |
3738

3839
## Configuration
@@ -64,6 +65,11 @@ export PDODB_AI_MICROSOFT_MODEL=gpt-4 # Optional: model name
6465
export PDODB_AI_DEEPSEEK_KEY=...
6566
export PDODB_AI_DEEPSEEK_MODEL=deepseek-chat # Optional: deepseek-reasoner (thinking mode)
6667

68+
# Yandex Cloud
69+
export PDODB_AI_YANDEX_KEY=...
70+
export PDODB_AI_YANDEX_FOLDER_ID=b1ge9k4rdlck8g72slht # Required: Yandex Cloud folder ID
71+
export PDODB_AI_YANDEX_MODEL=gpt-oss-120b/latest # Optional: model name
72+
6773
# Ollama (local, no API key needed)
6874
export PDODB_AI_OLLAMA_URL=http://localhost:11434
6975
export PDODB_AI_OLLAMA_MODEL=llama3.2 # Optional: model name
@@ -92,6 +98,8 @@ $db = new PdoDb('mysql', [
9298
'google_key' => '...',
9399
'microsoft_key' => '...',
94100
'deepseek_key' => '...',
101+
'yandex_key' => '...',
102+
'yandex_folder_id' => 'b1ge9k4rdlck8g72slht', # Optional: can also be in providers.yandex.folder_id
95103
'ollama_url' => 'http://localhost:11434',
96104
'providers' => [
97105
'openai' => [
@@ -117,6 +125,12 @@ $db = new PdoDb('mysql', [
117125
'temperature' => 0.7,
118126
'max_tokens' => 2000,
119127
],
128+
'yandex' => [
129+
'folder_id' => 'b1ge9k4rdlck8g72slht', # Required: Yandex Cloud folder ID
130+
'model' => 'gpt-oss-120b/latest', # Optional: model name
131+
'temperature' => 0.7,
132+
'max_tokens' => 2000,
133+
],
120134
'ollama' => [
121135
'model' => 'llama3.2', # or any local model name
122136
],

src/ai/AiAnalysisService.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use tommyknocker\pdodb\ai\providers\MicrosoftProvider;
1111
use tommyknocker\pdodb\ai\providers\OllamaProvider;
1212
use tommyknocker\pdodb\ai\providers\OpenAiProvider;
13+
use tommyknocker\pdodb\ai\providers\YandexProvider;
1314
use tommyknocker\pdodb\exceptions\QueryException;
1415
use tommyknocker\pdodb\PdoDb;
1516

@@ -84,8 +85,9 @@ protected function createProvider(string $providerName): AiProviderInterface
8485
'microsoft' => new MicrosoftProvider($this->config),
8586
'ollama' => new OllamaProvider($this->config),
8687
'deepseek' => new DeepSeekProvider($this->config),
88+
'yandex' => new YandexProvider($this->config),
8789
default => throw new QueryException(
88-
"Unsupported AI provider: {$providerName}. Supported: openai, anthropic, google, microsoft, ollama, deepseek",
90+
"Unsupported AI provider: {$providerName}. Supported: openai, anthropic, google, microsoft, ollama, deepseek, yandex",
8991
0
9092
),
9193
};

src/ai/AiConfig.php

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ protected function loadFromConfig(?array $config): void
6262
$this->apiKeys['deepseek'] = (string)$aiConfig['deepseek_key'];
6363
}
6464

65+
if (isset($aiConfig['yandex_key'])) {
66+
$this->apiKeys['yandex'] = (string)$aiConfig['yandex_key'];
67+
}
68+
6569
if (isset($aiConfig['ollama_url'])) {
6670
$this->ollamaUrl = (string)$aiConfig['ollama_url'];
6771
}
@@ -113,6 +117,21 @@ protected function loadFromEnvironment(): void
113117
$this->apiKeys['deepseek'] = $deepseekKey;
114118
}
115119

120+
$yandexKey = getenv('PDODB_AI_YANDEX_KEY');
121+
if ($yandexKey !== false && $yandexKey !== '') {
122+
$this->apiKeys['yandex'] = $yandexKey;
123+
}
124+
125+
$yandexFolderId = getenv('PDODB_AI_YANDEX_FOLDER_ID');
126+
if ($yandexFolderId !== false && $yandexFolderId !== '') {
127+
$this->setProviderSetting('yandex', 'folder_id', $yandexFolderId);
128+
}
129+
130+
$yandexModel = getenv('PDODB_AI_YANDEX_MODEL');
131+
if ($yandexModel !== false && $yandexModel !== '') {
132+
$this->setProviderSetting('yandex', 'model', $yandexModel);
133+
}
134+
116135
$ollamaUrl = getenv('PDODB_AI_OLLAMA_URL');
117136
if ($ollamaUrl !== false && $ollamaUrl !== '') {
118137
$this->ollamaUrl = $ollamaUrl;
@@ -129,7 +148,7 @@ protected function loadFromEnvironment(): void
129148
*/
130149
protected function loadProviderModelsFromEnvironment(): void
131150
{
132-
$providers = ['openai', 'anthropic', 'google', 'microsoft', 'ollama', 'deepseek'];
151+
$providers = ['openai', 'anthropic', 'google', 'microsoft', 'ollama', 'deepseek', 'yandex'];
133152
foreach ($providers as $provider) {
134153
$envVar = 'PDODB_AI_' . strtoupper($provider) . '_MODEL';
135154
$model = getenv($envVar);

src/cli/InitConfigGenerator.php

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,23 +87,30 @@ public static function generateEnv(array $config, array $structure, string $path
8787
$lines[] = 'PDODB_AI_PROVIDER=' . $config['ai']['provider'];
8888
}
8989

90-
$providers = ['openai', 'anthropic', 'google', 'microsoft', 'deepseek', 'ollama'];
90+
$providers = ['openai', 'anthropic', 'google', 'microsoft', 'deepseek', 'yandex', 'ollama'];
9191
foreach ($providers as $provider) {
9292
$keyName = $provider . '_key';
9393
if (isset($config['ai'][$keyName])) {
9494
$lines[] = 'PDODB_AI_' . strtoupper($provider) . '_KEY=' . $config['ai'][$keyName];
9595
}
9696
}
9797

98+
// Yandex folder ID
99+
if (isset($config['ai']['providers']['yandex']['folder_id'])) {
100+
$lines[] = 'PDODB_AI_YANDEX_FOLDER_ID=' . $config['ai']['providers']['yandex']['folder_id'];
101+
}
102+
98103
if (isset($config['ai']['ollama_url'])) {
99104
$lines[] = 'PDODB_AI_OLLAMA_URL=' . $config['ai']['ollama_url'];
100105
}
101106

102107
// Provider-specific settings
103108
if (isset($config['ai']['providers']) && is_array($config['ai']['providers'])) {
104109
foreach ($config['ai']['providers'] as $provider => $settings) {
105-
if (is_array($settings) && isset($settings['model'])) {
106-
$lines[] = 'PDODB_AI_' . strtoupper($provider) . '_MODEL=' . $settings['model'];
110+
if (is_array($settings)) {
111+
if (isset($settings['model'])) {
112+
$lines[] = 'PDODB_AI_' . strtoupper($provider) . '_MODEL=' . $settings['model'];
113+
}
107114
}
108115
}
109116
}

src/cli/InitWizard.php

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ protected function loadAiConfigFromEnv(): void
201201
$this->config['ai'] = [];
202202
}
203203

204-
$providers = ['openai', 'anthropic', 'google', 'microsoft', 'deepseek', 'ollama'];
204+
$providers = ['openai', 'anthropic', 'google', 'microsoft', 'deepseek', 'yandex', 'ollama'];
205205
foreach ($providers as $provider) {
206206
$envVar = 'PDODB_AI_' . strtoupper($provider) . '_KEY';
207207
$key = getenv($envVar);
@@ -210,6 +210,18 @@ protected function loadAiConfigFromEnv(): void
210210
}
211211
}
212212

213+
// Yandex folder ID
214+
$yandexFolderId = getenv('PDODB_AI_YANDEX_FOLDER_ID');
215+
if ($yandexFolderId !== false && $yandexFolderId !== '') {
216+
if (!isset($this->config['ai']['providers'])) {
217+
$this->config['ai']['providers'] = [];
218+
}
219+
if (!isset($this->config['ai']['providers']['yandex'])) {
220+
$this->config['ai']['providers']['yandex'] = [];
221+
}
222+
$this->config['ai']['providers']['yandex']['folder_id'] = $yandexFolderId;
223+
}
224+
213225
$ollamaUrl = getenv('PDODB_AI_OLLAMA_URL');
214226
if ($ollamaUrl !== false && $ollamaUrl !== '') {
215227
$this->config['ai']['ollama_url'] = $ollamaUrl;
@@ -686,7 +698,7 @@ protected function askAiConfiguration(): void
686698
$this->config['ai'] = [];
687699
}
688700

689-
$providers = ['openai', 'anthropic', 'google', 'microsoft', 'ollama', 'deepseek'];
701+
$providers = ['openai', 'anthropic', 'google', 'microsoft', 'ollama', 'deepseek', 'yandex'];
690702
echo " Available providers: " . implode(', ', $providers) . "\n";
691703
$provider = static::readInput(' Default AI provider', 'openai');
692704
$provider = mb_strtolower(trim($provider), 'UTF-8');
@@ -704,6 +716,22 @@ protected function askAiConfiguration(): void
704716
if ($url !== '') {
705717
$this->config['ai']['ollama_url'] = $url;
706718
}
719+
} elseif ($p === 'yandex') {
720+
// Yandex needs API key and folder ID
721+
$key = static::readPassword(" {$p} API key (optional, press Enter to skip)");
722+
if ($key !== '') {
723+
$this->config['ai'][$p . '_key'] = $key;
724+
$folderId = static::readInput(" {$p} folder ID (optional, press Enter to skip)");
725+
if ($folderId !== '') {
726+
if (!isset($this->config['ai']['providers'])) {
727+
$this->config['ai']['providers'] = [];
728+
}
729+
if (!isset($this->config['ai']['providers'][$p])) {
730+
$this->config['ai']['providers'][$p] = [];
731+
}
732+
$this->config['ai']['providers'][$p]['folder_id'] = $folderId;
733+
}
734+
}
707735
} else {
708736
$key = static::readPassword(" {$p} API key (optional, press Enter to skip)");
709737
if ($key !== '') {

0 commit comments

Comments
 (0)