vantuz 3.0.1 → 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 +25 -21
- package/core/ai-provider.js +205 -0
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -13,6 +13,7 @@ import fs from 'fs';
|
|
|
13
13
|
import path from 'path';
|
|
14
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
|
// Config dosyaları kullanıcının home dizininde saklanır
|
|
18
19
|
const VANTUZ_HOME = path.join(os.homedir(), '.vantuz');
|
|
@@ -274,6 +275,8 @@ async function handleCommand(input, config, env) {
|
|
|
274
275
|
/fiyat <ürün> <tl> → Fiyat güncelle
|
|
275
276
|
/rapor [dönem] → Satış raporu
|
|
276
277
|
/platformlar → Bağlı platformlar
|
|
278
|
+
/logs [n] → Son n log satırı
|
|
279
|
+
/logs clear → Logları temizle
|
|
277
280
|
/config → Ayarları aç
|
|
278
281
|
/cikis → Çıkış
|
|
279
282
|
`);
|
|
@@ -318,6 +321,18 @@ async function handleCommand(input, config, env) {
|
|
|
318
321
|
console.log(c('cyan', '\n 👋 Görüşmek üzere!\n'));
|
|
319
322
|
process.exit(0);
|
|
320
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
|
+
|
|
321
336
|
default:
|
|
322
337
|
console.log(c('red', ` ❌ Bilinmeyen komut: /${cmd}`));
|
|
323
338
|
console.log(c('dim', ' /help yazarak komutları görebilirsiniz'));
|
|
@@ -325,31 +340,20 @@ async function handleCommand(input, config, env) {
|
|
|
325
340
|
}
|
|
326
341
|
|
|
327
342
|
async function processChat(input, config, env) {
|
|
328
|
-
//
|
|
329
|
-
const lower = input.toLowerCase();
|
|
330
|
-
|
|
331
|
-
if (lower.includes('stok') && (lower.includes('düşük') || lower.includes('az'))) {
|
|
332
|
-
return 'Düşük stoklu ürünleri kontrol ediyorum... (API bağlantısı gerekli)';
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
if (lower.includes('fiyat') && lower.includes('güncelle')) {
|
|
336
|
-
return 'Fiyat güncellemesi için /fiyat <ürün> <tl> komutunu kullanın.';
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
if (lower.includes('sipariş') || lower.includes('order')) {
|
|
340
|
-
return 'Siparişleri kontrol ediyorum... (API bağlantısı gerekli)';
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
if (lower.includes('rapor')) {
|
|
344
|
-
return 'Rapor için /rapor 7d yazabilirsiniz.';
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
// Default response
|
|
343
|
+
// AI API anahtarı kontrolü
|
|
348
344
|
if (!hasAnyAIKey(env)) {
|
|
349
345
|
return 'AI yanıtı için API anahtarı gerekli. "vantuz config" ile ayarlayın.';
|
|
350
346
|
}
|
|
351
347
|
|
|
352
|
-
|
|
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
|
+
}
|
|
353
357
|
}
|
|
354
358
|
|
|
355
359
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -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 };
|