vantuz 3.0.0 → 3.0.2
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.
- package/cli.js +44 -28
- package/core/ai-provider.js +205 -0
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -11,12 +11,19 @@
|
|
|
11
11
|
|
|
12
12
|
import fs from 'fs';
|
|
13
13
|
import path from 'path';
|
|
14
|
-
import
|
|
14
|
+
import os from 'os';
|
|
15
15
|
import readline from 'readline';
|
|
16
|
+
import { chat as aiChat, log, getLogs, clearLogs } from './core/ai-provider.js';
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
const
|
|
18
|
+
// Config dosyaları kullanıcının home dizininde saklanır
|
|
19
|
+
const VANTUZ_HOME = path.join(os.homedir(), '.vantuz');
|
|
20
|
+
const CONFIG_PATH = path.join(VANTUZ_HOME, '.env');
|
|
21
|
+
const CONFIG_JSON = path.join(VANTUZ_HOME, 'config.json');
|
|
22
|
+
|
|
23
|
+
// Dizin yoksa oluştur
|
|
24
|
+
if (!fs.existsSync(VANTUZ_HOME)) {
|
|
25
|
+
fs.mkdirSync(VANTUZ_HOME, { recursive: true });
|
|
26
|
+
}
|
|
20
27
|
|
|
21
28
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
22
29
|
// RENK KODLARI
|
|
@@ -89,6 +96,11 @@ function saveEnv(env) {
|
|
|
89
96
|
fs.writeFileSync(CONFIG_PATH, lines.join('\n'));
|
|
90
97
|
}
|
|
91
98
|
|
|
99
|
+
function hasAnyAIKey(env) {
|
|
100
|
+
return env.OPENAI_API_KEY || env.ANTHROPIC_API_KEY ||
|
|
101
|
+
env.DEEPSEEK_API_KEY || env.GROQ_API_KEY || env.GEMINI_API_KEY;
|
|
102
|
+
}
|
|
103
|
+
|
|
92
104
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
93
105
|
// READLINE HELPER
|
|
94
106
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -219,7 +231,7 @@ async function runTUI() {
|
|
|
219
231
|
console.log(c('dim', ' Komutlar: /help, /stok, /fiyat, /rapor, /cikis\n'));
|
|
220
232
|
|
|
221
233
|
// Check AI config
|
|
222
|
-
const hasAI = env
|
|
234
|
+
const hasAI = hasAnyAIKey(env);
|
|
223
235
|
if (!hasAI) {
|
|
224
236
|
console.log(c('yellow', ' ⚠️ AI sağlayıcı yapılandırılmamış.'));
|
|
225
237
|
console.log(c('dim', ' → vantuz config komutunu çalıştırın\n'));
|
|
@@ -263,6 +275,8 @@ async function handleCommand(input, config, env) {
|
|
|
263
275
|
/fiyat <ürün> <tl> → Fiyat güncelle
|
|
264
276
|
/rapor [dönem] → Satış raporu
|
|
265
277
|
/platformlar → Bağlı platformlar
|
|
278
|
+
/logs [n] → Son n log satırı
|
|
279
|
+
/logs clear → Logları temizle
|
|
266
280
|
/config → Ayarları aç
|
|
267
281
|
/cikis → Çıkış
|
|
268
282
|
`);
|
|
@@ -307,6 +321,18 @@ async function handleCommand(input, config, env) {
|
|
|
307
321
|
console.log(c('cyan', '\n 👋 Görüşmek üzere!\n'));
|
|
308
322
|
process.exit(0);
|
|
309
323
|
|
|
324
|
+
case 'logs':
|
|
325
|
+
case 'log':
|
|
326
|
+
if (args[0] === 'clear') {
|
|
327
|
+
clearLogs();
|
|
328
|
+
console.log(c('green', '\n ✓ Loglar temizlendi'));
|
|
329
|
+
} else {
|
|
330
|
+
const lineCount = parseInt(args[0]) || 30;
|
|
331
|
+
console.log(c('cyan', `\n 📝 Son ${lineCount} log:`));
|
|
332
|
+
console.log(c('dim', getLogs(lineCount)));
|
|
333
|
+
}
|
|
334
|
+
break;
|
|
335
|
+
|
|
310
336
|
default:
|
|
311
337
|
console.log(c('red', ` ❌ Bilinmeyen komut: /${cmd}`));
|
|
312
338
|
console.log(c('dim', ' /help yazarak komutları görebilirsiniz'));
|
|
@@ -314,31 +340,20 @@ async function handleCommand(input, config, env) {
|
|
|
314
340
|
}
|
|
315
341
|
|
|
316
342
|
async function processChat(input, config, env) {
|
|
317
|
-
//
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
if (lower.includes('stok') && (lower.includes('düşük') || lower.includes('az'))) {
|
|
321
|
-
return 'Düşük stoklu ürünleri kontrol ediyorum... (API bağlantısı gerekli)';
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
if (lower.includes('fiyat') && lower.includes('güncelle')) {
|
|
325
|
-
return 'Fiyat güncellemesi için /fiyat <ürün> <tl> komutunu kullanın.';
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
if (lower.includes('sipariş') || lower.includes('order')) {
|
|
329
|
-
return 'Siparişleri kontrol ediyorum... (API bağlantısı gerekli)';
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
if (lower.includes('rapor')) {
|
|
333
|
-
return 'Rapor için /rapor 7d yazabilirsiniz.';
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
// Default response
|
|
337
|
-
if (!env.OPENAI_API_KEY && !env.ANTHROPIC_API_KEY) {
|
|
343
|
+
// AI API anahtarı kontrolü
|
|
344
|
+
if (!hasAnyAIKey(env)) {
|
|
338
345
|
return 'AI yanıtı için API anahtarı gerekli. "vantuz config" ile ayarlayın.';
|
|
339
346
|
}
|
|
340
347
|
|
|
341
|
-
|
|
348
|
+
try {
|
|
349
|
+
// Gerçek AI çağrısı
|
|
350
|
+
console.log(c('dim', '\n 🧠 Düşünüyorum...'));
|
|
351
|
+
const response = await aiChat(input, config, env);
|
|
352
|
+
return response;
|
|
353
|
+
} catch (error) {
|
|
354
|
+
log('ERROR', `Chat hatası: ${error.message}`);
|
|
355
|
+
return `Hata: ${error.message}. /logs komutu ile detay görün.`;
|
|
356
|
+
}
|
|
342
357
|
}
|
|
343
358
|
|
|
344
359
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -355,7 +370,7 @@ async function runStatus() {
|
|
|
355
370
|
|
|
356
371
|
// AI
|
|
357
372
|
const aiProvider = config.aiProvider || 'Ayarlanmamış';
|
|
358
|
-
const hasAIKey = env
|
|
373
|
+
const hasAIKey = hasAnyAIKey(env);
|
|
359
374
|
console.log(` AI Sağlayıcı: ${aiProvider} ${hasAIKey ? c('green', '✓') : c('red', '✗')}`);
|
|
360
375
|
|
|
361
376
|
// Platforms
|
|
@@ -378,6 +393,7 @@ async function runStatus() {
|
|
|
378
393
|
}
|
|
379
394
|
|
|
380
395
|
console.log(`\n Toplam: ${connected}/${platforms.length} platform bağlı`);
|
|
396
|
+
console.log(c('dim', `\n Config: ${CONFIG_PATH}`));
|
|
381
397
|
console.log();
|
|
382
398
|
}
|
|
383
399
|
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 🤖 AI Provider Integration
|
|
3
|
+
* Gerçek AI API çağrıları
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import axios from 'axios';
|
|
7
|
+
import fs from 'fs';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import os from 'os';
|
|
10
|
+
|
|
11
|
+
const LOG_FILE = path.join(os.homedir(), '.vantuz', 'vantuz.log');
|
|
12
|
+
|
|
13
|
+
// Log fonksiyonu
|
|
14
|
+
export function log(level, message, data = null) {
|
|
15
|
+
const timestamp = new Date().toISOString();
|
|
16
|
+
const logLine = `[${timestamp}] [${level}] ${message}${data ? ' | ' + JSON.stringify(data) : ''}\n`;
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
fs.appendFileSync(LOG_FILE, logLine);
|
|
20
|
+
} catch (e) { }
|
|
21
|
+
|
|
22
|
+
if (level === 'ERROR') {
|
|
23
|
+
console.error(`❌ ${message}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function getLogs(lines = 50) {
|
|
28
|
+
try {
|
|
29
|
+
if (!fs.existsSync(LOG_FILE)) {
|
|
30
|
+
return 'Log dosyası bulunamadı.';
|
|
31
|
+
}
|
|
32
|
+
const content = fs.readFileSync(LOG_FILE, 'utf-8');
|
|
33
|
+
const allLines = content.split('\n').filter(l => l.trim());
|
|
34
|
+
return allLines.slice(-lines).join('\n');
|
|
35
|
+
} catch (e) {
|
|
36
|
+
return `Log okuma hatası: ${e.message}`;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function clearLogs() {
|
|
41
|
+
try {
|
|
42
|
+
fs.writeFileSync(LOG_FILE, '');
|
|
43
|
+
return true;
|
|
44
|
+
} catch (e) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// AI Chat fonksiyonu
|
|
50
|
+
export async function chat(message, config, env) {
|
|
51
|
+
const provider = config.aiProvider || 'gemini';
|
|
52
|
+
|
|
53
|
+
log('INFO', `AI isteği: ${provider}`, { message: message.slice(0, 100) });
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
switch (provider) {
|
|
57
|
+
case 'gemini':
|
|
58
|
+
return await chatGemini(message, env.GEMINI_API_KEY);
|
|
59
|
+
case 'groq':
|
|
60
|
+
return await chatGroq(message, env.GROQ_API_KEY);
|
|
61
|
+
case 'openai':
|
|
62
|
+
return await chatOpenAI(message, env.OPENAI_API_KEY);
|
|
63
|
+
case 'anthropic':
|
|
64
|
+
return await chatAnthropic(message, env.ANTHROPIC_API_KEY);
|
|
65
|
+
case 'deepseek':
|
|
66
|
+
return await chatDeepSeek(message, env.DEEPSEEK_API_KEY);
|
|
67
|
+
default:
|
|
68
|
+
return 'Desteklenmeyen AI sağlayıcı: ' + provider;
|
|
69
|
+
}
|
|
70
|
+
} catch (error) {
|
|
71
|
+
log('ERROR', `AI hatası: ${error.message}`, { provider });
|
|
72
|
+
return `AI hatası: ${error.message}. /logs komutu ile detay görün.`;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Gemini API
|
|
77
|
+
async function chatGemini(message, apiKey) {
|
|
78
|
+
if (!apiKey) throw new Error('GEMINI_API_KEY ayarlanmamış');
|
|
79
|
+
|
|
80
|
+
const url = `https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key=${apiKey}`;
|
|
81
|
+
|
|
82
|
+
const response = await axios.post(url, {
|
|
83
|
+
contents: [{
|
|
84
|
+
parts: [{
|
|
85
|
+
text: `Sen Vantuz AI, bir e-ticaret asistanısın. Türkiye pazaryerleri (Trendyol, Hepsiburada, N11, Amazon, Çiçeksepeti, PTTavm, Pazarama) konusunda uzmansın. Kısa ve öz yanıt ver.\n\nKullanıcı: ${message}`
|
|
86
|
+
}]
|
|
87
|
+
}]
|
|
88
|
+
}, {
|
|
89
|
+
headers: { 'Content-Type': 'application/json' },
|
|
90
|
+
timeout: 30000
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const text = response.data?.candidates?.[0]?.content?.parts?.[0]?.text;
|
|
94
|
+
if (!text) throw new Error('Gemini yanıt vermedi');
|
|
95
|
+
|
|
96
|
+
log('INFO', 'Gemini yanıtı alındı', { chars: text.length });
|
|
97
|
+
return text;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Groq API
|
|
101
|
+
async function chatGroq(message, apiKey) {
|
|
102
|
+
if (!apiKey) throw new Error('GROQ_API_KEY ayarlanmamış');
|
|
103
|
+
|
|
104
|
+
const response = await axios.post('https://api.groq.com/openai/v1/chat/completions', {
|
|
105
|
+
model: 'llama-3.3-70b-versatile',
|
|
106
|
+
messages: [
|
|
107
|
+
{ role: 'system', content: 'Sen Vantuz AI, bir e-ticaret asistanısın. Türkiye pazaryerleri konusunda uzmansın. Kısa ve öz yanıt ver.' },
|
|
108
|
+
{ role: 'user', content: message }
|
|
109
|
+
],
|
|
110
|
+
max_tokens: 1000
|
|
111
|
+
}, {
|
|
112
|
+
headers: {
|
|
113
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
114
|
+
'Content-Type': 'application/json'
|
|
115
|
+
},
|
|
116
|
+
timeout: 30000
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
const text = response.data?.choices?.[0]?.message?.content;
|
|
120
|
+
if (!text) throw new Error('Groq yanıt vermedi');
|
|
121
|
+
|
|
122
|
+
log('INFO', 'Groq yanıtı alındı', { chars: text.length });
|
|
123
|
+
return text;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// OpenAI API
|
|
127
|
+
async function chatOpenAI(message, apiKey) {
|
|
128
|
+
if (!apiKey) throw new Error('OPENAI_API_KEY ayarlanmamış');
|
|
129
|
+
|
|
130
|
+
const response = await axios.post('https://api.openai.com/v1/chat/completions', {
|
|
131
|
+
model: 'gpt-4o-mini',
|
|
132
|
+
messages: [
|
|
133
|
+
{ role: 'system', content: 'Sen Vantuz AI, bir e-ticaret asistanısın. Türkiye pazaryerleri konusunda uzmansın. Kısa ve öz yanıt ver.' },
|
|
134
|
+
{ role: 'user', content: message }
|
|
135
|
+
],
|
|
136
|
+
max_tokens: 1000
|
|
137
|
+
}, {
|
|
138
|
+
headers: {
|
|
139
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
140
|
+
'Content-Type': 'application/json'
|
|
141
|
+
},
|
|
142
|
+
timeout: 30000
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
const text = response.data?.choices?.[0]?.message?.content;
|
|
146
|
+
if (!text) throw new Error('OpenAI yanıt vermedi');
|
|
147
|
+
|
|
148
|
+
log('INFO', 'OpenAI yanıtı alındı', { chars: text.length });
|
|
149
|
+
return text;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Anthropic API
|
|
153
|
+
async function chatAnthropic(message, apiKey) {
|
|
154
|
+
if (!apiKey) throw new Error('ANTHROPIC_API_KEY ayarlanmamış');
|
|
155
|
+
|
|
156
|
+
const response = await axios.post('https://api.anthropic.com/v1/messages', {
|
|
157
|
+
model: 'claude-3-haiku-20240307',
|
|
158
|
+
max_tokens: 1000,
|
|
159
|
+
messages: [
|
|
160
|
+
{ role: 'user', content: message }
|
|
161
|
+
],
|
|
162
|
+
system: 'Sen Vantuz AI, bir e-ticaret asistanısın. Türkiye pazaryerleri konusunda uzmansın. Kısa ve öz yanıt ver.'
|
|
163
|
+
}, {
|
|
164
|
+
headers: {
|
|
165
|
+
'x-api-key': apiKey,
|
|
166
|
+
'anthropic-version': '2023-06-01',
|
|
167
|
+
'Content-Type': 'application/json'
|
|
168
|
+
},
|
|
169
|
+
timeout: 30000
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
const text = response.data?.content?.[0]?.text;
|
|
173
|
+
if (!text) throw new Error('Anthropic yanıt vermedi');
|
|
174
|
+
|
|
175
|
+
log('INFO', 'Anthropic yanıtı alındı', { chars: text.length });
|
|
176
|
+
return text;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// DeepSeek API
|
|
180
|
+
async function chatDeepSeek(message, apiKey) {
|
|
181
|
+
if (!apiKey) throw new Error('DEEPSEEK_API_KEY ayarlanmamış');
|
|
182
|
+
|
|
183
|
+
const response = await axios.post('https://api.deepseek.com/v1/chat/completions', {
|
|
184
|
+
model: 'deepseek-chat',
|
|
185
|
+
messages: [
|
|
186
|
+
{ role: 'system', content: 'Sen Vantuz AI, bir e-ticaret asistanısın. Türkiye pazaryerleri konusunda uzmansın. Kısa ve öz yanıt ver.' },
|
|
187
|
+
{ role: 'user', content: message }
|
|
188
|
+
],
|
|
189
|
+
max_tokens: 1000
|
|
190
|
+
}, {
|
|
191
|
+
headers: {
|
|
192
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
193
|
+
'Content-Type': 'application/json'
|
|
194
|
+
},
|
|
195
|
+
timeout: 30000
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
const text = response.data?.choices?.[0]?.message?.content;
|
|
199
|
+
if (!text) throw new Error('DeepSeek yanıt vermedi');
|
|
200
|
+
|
|
201
|
+
log('INFO', 'DeepSeek yanıtı alındı', { chars: text.length });
|
|
202
|
+
return text;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export default { chat, log, getLogs, clearLogs };
|