vantuz 3.0.0
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/LICENSE +45 -0
- package/README.md +44 -0
- package/cli.js +420 -0
- package/core/ai-analyst.js +46 -0
- package/core/database.js +74 -0
- package/core/license-manager.js +50 -0
- package/core/product-manager.js +134 -0
- package/package.json +72 -0
- package/plugins/vantuz/index.js +480 -0
- package/plugins/vantuz/memory/hippocampus.js +464 -0
- package/plugins/vantuz/package.json +21 -0
- package/plugins/vantuz/platforms/amazon.js +239 -0
- package/plugins/vantuz/platforms/ciceksepeti.js +175 -0
- package/plugins/vantuz/platforms/hepsiburada.js +189 -0
- package/plugins/vantuz/platforms/index.js +215 -0
- package/plugins/vantuz/platforms/n11.js +263 -0
- package/plugins/vantuz/platforms/pazarama.js +171 -0
- package/plugins/vantuz/platforms/pttavm.js +136 -0
- package/plugins/vantuz/platforms/trendyol.js +307 -0
- package/plugins/vantuz/services/alerts.js +253 -0
- package/plugins/vantuz/services/license.js +237 -0
- package/plugins/vantuz/services/scheduler.js +232 -0
- package/plugins/vantuz/tools/analytics.js +152 -0
- package/plugins/vantuz/tools/crossborder.js +187 -0
- package/plugins/vantuz/tools/nl-parser.js +211 -0
- package/plugins/vantuz/tools/product.js +110 -0
- package/plugins/vantuz/tools/quick-report.js +175 -0
- package/plugins/vantuz/tools/repricer.js +314 -0
- package/plugins/vantuz/tools/sentiment.js +115 -0
- package/plugins/vantuz/tools/vision.js +257 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
VANTUZ AI SOFTWARE LICENSE AGREEMENT
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nuri Can Avşar. All rights reserved.
|
|
4
|
+
|
|
5
|
+
This software and associated documentation files (the "Software") are licensed,
|
|
6
|
+
not sold. By installing, copying, or otherwise using the Software, you agree to
|
|
7
|
+
be bound by the terms of this agreement.
|
|
8
|
+
|
|
9
|
+
1. LICENSE GRANT
|
|
10
|
+
Subject to the terms of this agreement and payment of applicable license fees,
|
|
11
|
+
Licensor grants you a limited, non-exclusive, non-transferable license to use
|
|
12
|
+
the Software for your internal business purposes.
|
|
13
|
+
|
|
14
|
+
2. LICENSE KEY
|
|
15
|
+
A valid license key is required to use the Software. Each license key:
|
|
16
|
+
- Is valid for ONE (1) installation only
|
|
17
|
+
- Activates upon first use
|
|
18
|
+
- Expires 365 days after activation
|
|
19
|
+
- Cannot be shared, transferred, or resold
|
|
20
|
+
|
|
21
|
+
3. RESTRICTIONS
|
|
22
|
+
You may NOT:
|
|
23
|
+
- Copy, modify, or distribute the Software
|
|
24
|
+
- Reverse engineer, decompile, or disassemble the Software
|
|
25
|
+
- Remove or alter any proprietary notices
|
|
26
|
+
- Share your license key with others
|
|
27
|
+
- Use the Software for illegal purposes
|
|
28
|
+
|
|
29
|
+
4. INTELLECTUAL PROPERTY
|
|
30
|
+
The Software and all copies thereof are proprietary to Licensor and title
|
|
31
|
+
thereto remains exclusively with Licensor.
|
|
32
|
+
|
|
33
|
+
5. TERMINATION
|
|
34
|
+
This license is effective until terminated. It will terminate automatically
|
|
35
|
+
if you fail to comply with any term of this agreement.
|
|
36
|
+
|
|
37
|
+
6. WARRANTY DISCLAIMER
|
|
38
|
+
THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.
|
|
39
|
+
|
|
40
|
+
7. LIMITATION OF LIABILITY
|
|
41
|
+
IN NO EVENT SHALL LICENSOR BE LIABLE FOR ANY DAMAGES ARISING FROM USE
|
|
42
|
+
OF THE SOFTWARE.
|
|
43
|
+
|
|
44
|
+
For licensing inquiries: nuricanavsar2000@gmail.com
|
|
45
|
+
Website: https://nuricanavsar.com
|
package/README.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# 🐙 Vantuz AI
|
|
2
|
+
|
|
3
|
+
**Yapay Zeka Destekli E-Ticaret Yönetim Platformu**
|
|
4
|
+
|
|
5
|
+
7 Türk pazaryerini tek platformdan yönetin: Trendyol, Hepsiburada, N11, Amazon, Çiçeksepeti, PTTavm, Pazarama
|
|
6
|
+
|
|
7
|
+
## Kurulum
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install vantuz
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Hızlı Başlangıç
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Yapılandırma
|
|
17
|
+
npx vantuz config
|
|
18
|
+
|
|
19
|
+
# Başlat
|
|
20
|
+
npx vantuz tui
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Özellikler
|
|
24
|
+
|
|
25
|
+
- 🏪 **7 Pazaryeri** - Tek komutla tüm platformları yönet
|
|
26
|
+
- 🤖 **Akıllı Fiyatlama** - Rakip takibi ve otomatik fiyat optimizasyonu
|
|
27
|
+
- 📊 **Hızlı Raporlar** - Anlık satış ve stok özeti
|
|
28
|
+
- ⏰ **Otomasyon** - Zamanlanmış görevler ve uyarılar
|
|
29
|
+
- 🧠 **Türkçe NL** - Doğal dil komut desteği
|
|
30
|
+
|
|
31
|
+
## Komutlar
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npx vantuz tui # Sohbet modu
|
|
35
|
+
npx vantuz config # Ayarlar
|
|
36
|
+
npx vantuz status # Durum kontrolü
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Lisans
|
|
40
|
+
|
|
41
|
+
Ticari yazılım. Kullanım için lisans anahtarı gereklidir.
|
|
42
|
+
|
|
43
|
+
📧 nuricanavsar2000@gmail.com
|
|
44
|
+
🌐 https://nuricanavsar.com
|
package/cli.js
ADDED
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* 🐙 VANTUZ CLI
|
|
4
|
+
* Terminal üzerinden Vantuz AI ile etkileşim
|
|
5
|
+
*
|
|
6
|
+
* Kullanım:
|
|
7
|
+
* vantuz tui → Sohbet modu
|
|
8
|
+
* vantuz config → Ayarları yapılandır
|
|
9
|
+
* vantuz status → Durum kontrolü
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import fs from 'fs';
|
|
13
|
+
import path from 'path';
|
|
14
|
+
import { fileURLToPath } from 'url';
|
|
15
|
+
import readline from 'readline';
|
|
16
|
+
|
|
17
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
18
|
+
const CONFIG_PATH = path.join(__dirname, '.env');
|
|
19
|
+
const CONFIG_JSON = path.join(__dirname, 'vantuz.config.json');
|
|
20
|
+
|
|
21
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
22
|
+
// RENK KODLARI
|
|
23
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
24
|
+
|
|
25
|
+
const colors = {
|
|
26
|
+
reset: '\x1b[0m',
|
|
27
|
+
bold: '\x1b[1m',
|
|
28
|
+
dim: '\x1b[2m',
|
|
29
|
+
red: '\x1b[31m',
|
|
30
|
+
green: '\x1b[32m',
|
|
31
|
+
yellow: '\x1b[33m',
|
|
32
|
+
blue: '\x1b[34m',
|
|
33
|
+
magenta: '\x1b[35m',
|
|
34
|
+
cyan: '\x1b[36m',
|
|
35
|
+
white: '\x1b[37m',
|
|
36
|
+
bgBlue: '\x1b[44m',
|
|
37
|
+
bgMagenta: '\x1b[45m'
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const c = (color, text) => `${colors[color]}${text}${colors.reset}`;
|
|
41
|
+
|
|
42
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
43
|
+
// YARDIMCI FONKSİYONLAR
|
|
44
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
45
|
+
|
|
46
|
+
function clearScreen() {
|
|
47
|
+
console.clear();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function printHeader() {
|
|
51
|
+
console.log(c('cyan', `
|
|
52
|
+
╔═══════════════════════════════════════════════════════════╗
|
|
53
|
+
║ 🐙 ${c('bold', 'VANTUZ AI')} - E-Ticaretin Yapay Zeka Beyni ║
|
|
54
|
+
╚═══════════════════════════════════════════════════════════╝
|
|
55
|
+
`));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function loadConfig() {
|
|
59
|
+
try {
|
|
60
|
+
if (fs.existsSync(CONFIG_JSON)) {
|
|
61
|
+
return JSON.parse(fs.readFileSync(CONFIG_JSON, 'utf-8'));
|
|
62
|
+
}
|
|
63
|
+
} catch (e) { }
|
|
64
|
+
return {};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function saveConfig(config) {
|
|
68
|
+
fs.writeFileSync(CONFIG_JSON, JSON.stringify(config, null, 2));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function loadEnv() {
|
|
72
|
+
const env = {};
|
|
73
|
+
try {
|
|
74
|
+
if (fs.existsSync(CONFIG_PATH)) {
|
|
75
|
+
const content = fs.readFileSync(CONFIG_PATH, 'utf-8');
|
|
76
|
+
content.split('\n').forEach(line => {
|
|
77
|
+
const match = line.match(/^([^=]+)=(.*)$/);
|
|
78
|
+
if (match) {
|
|
79
|
+
env[match[1].trim()] = match[2].trim();
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
} catch (e) { }
|
|
84
|
+
return env;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function saveEnv(env) {
|
|
88
|
+
const lines = Object.entries(env).map(([k, v]) => `${k}=${v}`);
|
|
89
|
+
fs.writeFileSync(CONFIG_PATH, lines.join('\n'));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
93
|
+
// READLINE HELPER
|
|
94
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
95
|
+
|
|
96
|
+
function createRL() {
|
|
97
|
+
return readline.createInterface({
|
|
98
|
+
input: process.stdin,
|
|
99
|
+
output: process.stdout
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function ask(rl, question, defaultValue = '') {
|
|
104
|
+
return new Promise(resolve => {
|
|
105
|
+
const prompt = defaultValue
|
|
106
|
+
? `${question} ${c('dim', `[${defaultValue}]`)}: `
|
|
107
|
+
: `${question}: `;
|
|
108
|
+
rl.question(prompt, answer => {
|
|
109
|
+
resolve(answer.trim() || defaultValue);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async function askYesNo(rl, question, defaultYes = true) {
|
|
115
|
+
const hint = defaultYes ? '[E/h]' : '[e/H]';
|
|
116
|
+
const answer = await ask(rl, `${question} ${c('dim', hint)}`);
|
|
117
|
+
if (!answer) return defaultYes;
|
|
118
|
+
return answer.toLowerCase().startsWith('e') || answer.toLowerCase().startsWith('y');
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
122
|
+
// CONFIG KOMUTU
|
|
123
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
124
|
+
|
|
125
|
+
async function runConfig() {
|
|
126
|
+
clearScreen();
|
|
127
|
+
printHeader();
|
|
128
|
+
|
|
129
|
+
const rl = createRL();
|
|
130
|
+
const config = loadConfig();
|
|
131
|
+
const env = loadEnv();
|
|
132
|
+
|
|
133
|
+
console.log(c('yellow', ' ⚙️ Yapılandırma Sihirbazı'));
|
|
134
|
+
console.log(c('dim', ' Her adımda Enter = varsayılan, "skip" = atla\n'));
|
|
135
|
+
|
|
136
|
+
// AI Provider
|
|
137
|
+
console.log(c('cyan', '\n ═══ AI Sağlayıcı ═══'));
|
|
138
|
+
console.log(' 1) OpenAI (GPT-4)');
|
|
139
|
+
console.log(' 2) Anthropic (Claude)');
|
|
140
|
+
console.log(' 3) DeepSeek');
|
|
141
|
+
console.log(' 4) Groq');
|
|
142
|
+
console.log(' 5) Gemini');
|
|
143
|
+
console.log(' 6) Atla (skip)');
|
|
144
|
+
|
|
145
|
+
const aiChoice = await ask(rl, '\n Seçim', '1');
|
|
146
|
+
if (aiChoice !== '6' && aiChoice.toLowerCase() !== 'skip') {
|
|
147
|
+
const providers = ['openai', 'anthropic', 'deepseek', 'groq', 'gemini'];
|
|
148
|
+
config.aiProvider = providers[parseInt(aiChoice) - 1] || 'openai';
|
|
149
|
+
|
|
150
|
+
const keyMap = {
|
|
151
|
+
openai: 'OPENAI_API_KEY',
|
|
152
|
+
anthropic: 'ANTHROPIC_API_KEY',
|
|
153
|
+
deepseek: 'DEEPSEEK_API_KEY',
|
|
154
|
+
groq: 'GROQ_API_KEY',
|
|
155
|
+
gemini: 'GEMINI_API_KEY'
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const envKey = keyMap[config.aiProvider];
|
|
159
|
+
const apiKey = await ask(rl, ` ${envKey}`, env[envKey] || '');
|
|
160
|
+
if (apiKey && apiKey !== 'skip') {
|
|
161
|
+
env[envKey] = apiKey;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Platforms
|
|
166
|
+
console.log(c('cyan', '\n ═══ Pazaryeri Bağlantıları ═══'));
|
|
167
|
+
console.log(c('dim', ' Her platform için API bilgilerini girin veya "skip" yazın\n'));
|
|
168
|
+
|
|
169
|
+
const platforms = [
|
|
170
|
+
{ name: 'Trendyol', keys: ['TRENDYOL_SUPPLIER_ID', 'TRENDYOL_API_KEY', 'TRENDYOL_API_SECRET'] },
|
|
171
|
+
{ name: 'Hepsiburada', keys: ['HEPSIBURADA_MERCHANT_ID', 'HEPSIBURADA_USERNAME', 'HEPSIBURADA_PASSWORD'] },
|
|
172
|
+
{ name: 'N11', keys: ['N11_API_KEY', 'N11_API_SECRET'] },
|
|
173
|
+
{ name: 'Amazon', keys: ['AMAZON_SELLER_ID', 'AMAZON_CLIENT_ID', 'AMAZON_REFRESH_TOKEN'] },
|
|
174
|
+
{ name: 'Çiçeksepeti', keys: ['CICEKSEPETI_API_KEY'] },
|
|
175
|
+
{ name: 'PTTavm', keys: ['PTTAVM_API_KEY', 'PTTAVM_TOKEN'] },
|
|
176
|
+
{ name: 'Pazarama', keys: ['PAZARAMA_CLIENT_ID', 'PAZARAMA_CLIENT_SECRET'] }
|
|
177
|
+
];
|
|
178
|
+
|
|
179
|
+
for (const platform of platforms) {
|
|
180
|
+
const setup = await askYesNo(rl, ` ${platform.name} ayarla?`, false);
|
|
181
|
+
if (setup) {
|
|
182
|
+
for (const key of platform.keys) {
|
|
183
|
+
const value = await ask(rl, ` ${key}`, env[key] || '');
|
|
184
|
+
if (value && value !== 'skip') {
|
|
185
|
+
env[key] = value;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
console.log(c('green', ` ✓ ${platform.name} ayarlandı\n`));
|
|
189
|
+
} else {
|
|
190
|
+
console.log(c('dim', ` → ${platform.name} atlandı\n`));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Save
|
|
195
|
+
saveConfig(config);
|
|
196
|
+
saveEnv(env);
|
|
197
|
+
|
|
198
|
+
console.log(c('green', '\n ✅ Yapılandırma kaydedildi!'));
|
|
199
|
+
console.log(c('dim', ` → ${CONFIG_JSON}`));
|
|
200
|
+
console.log(c('dim', ` → ${CONFIG_PATH}`));
|
|
201
|
+
console.log(c('cyan', '\n Başlatmak için: vantuz tui\n'));
|
|
202
|
+
|
|
203
|
+
rl.close();
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
207
|
+
// TUI (SOHBET MODU)
|
|
208
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
209
|
+
|
|
210
|
+
async function runTUI() {
|
|
211
|
+
clearScreen();
|
|
212
|
+
printHeader();
|
|
213
|
+
|
|
214
|
+
const rl = createRL();
|
|
215
|
+
const config = loadConfig();
|
|
216
|
+
const env = loadEnv();
|
|
217
|
+
|
|
218
|
+
console.log(c('green', ' 💬 Sohbet Modu'));
|
|
219
|
+
console.log(c('dim', ' Komutlar: /help, /stok, /fiyat, /rapor, /cikis\n'));
|
|
220
|
+
|
|
221
|
+
// Check AI config
|
|
222
|
+
const hasAI = env.OPENAI_API_KEY || env.ANTHROPIC_API_KEY || env.DEEPSEEK_API_KEY;
|
|
223
|
+
if (!hasAI) {
|
|
224
|
+
console.log(c('yellow', ' ⚠️ AI sağlayıcı yapılandırılmamış.'));
|
|
225
|
+
console.log(c('dim', ' → vantuz config komutunu çalıştırın\n'));
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Chat loop
|
|
229
|
+
const prompt = () => {
|
|
230
|
+
rl.question(c('cyan', '\n Sen: '), async (input) => {
|
|
231
|
+
input = input.trim();
|
|
232
|
+
|
|
233
|
+
if (!input) {
|
|
234
|
+
prompt();
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Commands
|
|
239
|
+
if (input.startsWith('/')) {
|
|
240
|
+
await handleCommand(input, config, env);
|
|
241
|
+
prompt();
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// AI Chat
|
|
246
|
+
console.log(c('magenta', '\n Vantuz: ') + await processChat(input, config, env));
|
|
247
|
+
prompt();
|
|
248
|
+
});
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
prompt();
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
async function handleCommand(input, config, env) {
|
|
255
|
+
const [cmd, ...args] = input.slice(1).split(' ');
|
|
256
|
+
|
|
257
|
+
switch (cmd.toLowerCase()) {
|
|
258
|
+
case 'help':
|
|
259
|
+
case 'yardim':
|
|
260
|
+
console.log(`
|
|
261
|
+
${c('cyan', 'Komutlar:')}
|
|
262
|
+
/stok [platform] → Stok durumu
|
|
263
|
+
/fiyat <ürün> <tl> → Fiyat güncelle
|
|
264
|
+
/rapor [dönem] → Satış raporu
|
|
265
|
+
/platformlar → Bağlı platformlar
|
|
266
|
+
/config → Ayarları aç
|
|
267
|
+
/cikis → Çıkış
|
|
268
|
+
`);
|
|
269
|
+
break;
|
|
270
|
+
|
|
271
|
+
case 'stok':
|
|
272
|
+
console.log(c('yellow', '\n 📦 Stok kontrolü yapılıyor...'));
|
|
273
|
+
console.log(c('dim', ' (Bu özellik API bağlantısı gerektirir)'));
|
|
274
|
+
break;
|
|
275
|
+
|
|
276
|
+
case 'fiyat':
|
|
277
|
+
console.log(c('yellow', '\n 💰 Fiyat güncelleme...'));
|
|
278
|
+
console.log(c('dim', ` Hedef: ${args.join(' ')}`));
|
|
279
|
+
break;
|
|
280
|
+
|
|
281
|
+
case 'rapor':
|
|
282
|
+
console.log(c('yellow', '\n 📊 Rapor oluşturuluyor...'));
|
|
283
|
+
const period = args[0] || '7d';
|
|
284
|
+
console.log(c('dim', ` Dönem: ${period}`));
|
|
285
|
+
break;
|
|
286
|
+
|
|
287
|
+
case 'platformlar':
|
|
288
|
+
console.log(`
|
|
289
|
+
${c('cyan', 'Platform Durumu:')}
|
|
290
|
+
🟠 Trendyol: ${env.TRENDYOL_API_KEY ? c('green', '✓ Bağlı') : c('dim', '○ Ayarlanmamış')}
|
|
291
|
+
🟣 Hepsiburada: ${env.HEPSIBURADA_MERCHANT_ID ? c('green', '✓ Bağlı') : c('dim', '○ Ayarlanmamış')}
|
|
292
|
+
🔵 N11: ${env.N11_API_KEY ? c('green', '✓ Bağlı') : c('dim', '○ Ayarlanmamış')}
|
|
293
|
+
🟡 Amazon: ${env.AMAZON_SELLER_ID ? c('green', '✓ Bağlı') : c('dim', '○ Ayarlanmamış')}
|
|
294
|
+
🌸 Çiçeksepeti: ${env.CICEKSEPETI_API_KEY ? c('green', '✓ Bağlı') : c('dim', '○ Ayarlanmamış')}
|
|
295
|
+
📮 PTTavm: ${env.PTTAVM_API_KEY ? c('green', '✓ Bağlı') : c('dim', '○ Ayarlanmamış')}
|
|
296
|
+
🛒 Pazarama: ${env.PAZARAMA_CLIENT_ID ? c('green', '✓ Bağlı') : c('dim', '○ Ayarlanmamış')}
|
|
297
|
+
`);
|
|
298
|
+
break;
|
|
299
|
+
|
|
300
|
+
case 'config':
|
|
301
|
+
console.log(c('dim', '\n → Terminalde "vantuz config" yazın'));
|
|
302
|
+
break;
|
|
303
|
+
|
|
304
|
+
case 'cikis':
|
|
305
|
+
case 'exit':
|
|
306
|
+
case 'quit':
|
|
307
|
+
console.log(c('cyan', '\n 👋 Görüşmek üzere!\n'));
|
|
308
|
+
process.exit(0);
|
|
309
|
+
|
|
310
|
+
default:
|
|
311
|
+
console.log(c('red', ` ❌ Bilinmeyen komut: /${cmd}`));
|
|
312
|
+
console.log(c('dim', ' /help yazarak komutları görebilirsiniz'));
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
async function processChat(input, config, env) {
|
|
317
|
+
// Simple NL parsing
|
|
318
|
+
const lower = input.toLowerCase();
|
|
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) {
|
|
338
|
+
return 'AI yanıtı için API anahtarı gerekli. "vantuz config" ile ayarlayın.';
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
return 'Anladım! Bu işlem için pazaryeri API bağlantısı gerekiyor.';
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
345
|
+
// STATUS KOMUTU
|
|
346
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
347
|
+
|
|
348
|
+
async function runStatus() {
|
|
349
|
+
printHeader();
|
|
350
|
+
|
|
351
|
+
const config = loadConfig();
|
|
352
|
+
const env = loadEnv();
|
|
353
|
+
|
|
354
|
+
console.log(c('cyan', ' 📊 Sistem Durumu\n'));
|
|
355
|
+
|
|
356
|
+
// AI
|
|
357
|
+
const aiProvider = config.aiProvider || 'Ayarlanmamış';
|
|
358
|
+
const hasAIKey = env.OPENAI_API_KEY || env.ANTHROPIC_API_KEY;
|
|
359
|
+
console.log(` AI Sağlayıcı: ${aiProvider} ${hasAIKey ? c('green', '✓') : c('red', '✗')}`);
|
|
360
|
+
|
|
361
|
+
// Platforms
|
|
362
|
+
console.log('\n Platformlar:');
|
|
363
|
+
const platforms = [
|
|
364
|
+
['Trendyol', 'TRENDYOL_API_KEY'],
|
|
365
|
+
['Hepsiburada', 'HEPSIBURADA_MERCHANT_ID'],
|
|
366
|
+
['N11', 'N11_API_KEY'],
|
|
367
|
+
['Amazon', 'AMAZON_SELLER_ID'],
|
|
368
|
+
['Çiçeksepeti', 'CICEKSEPETI_API_KEY'],
|
|
369
|
+
['PTTavm', 'PTTAVM_API_KEY'],
|
|
370
|
+
['Pazarama', 'PAZARAMA_CLIENT_ID']
|
|
371
|
+
];
|
|
372
|
+
|
|
373
|
+
let connected = 0;
|
|
374
|
+
for (const [name, key] of platforms) {
|
|
375
|
+
const status = env[key] ? c('green', '✓ Bağlı') : c('dim', '○');
|
|
376
|
+
if (env[key]) connected++;
|
|
377
|
+
console.log(` ${name}: ${status}`);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
console.log(`\n Toplam: ${connected}/${platforms.length} platform bağlı`);
|
|
381
|
+
console.log();
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
385
|
+
// MAIN
|
|
386
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
387
|
+
|
|
388
|
+
const args = process.argv.slice(2);
|
|
389
|
+
const command = args[0]?.toLowerCase();
|
|
390
|
+
|
|
391
|
+
switch (command) {
|
|
392
|
+
case 'tui':
|
|
393
|
+
case 'chat':
|
|
394
|
+
case 'sohbet':
|
|
395
|
+
runTUI();
|
|
396
|
+
break;
|
|
397
|
+
|
|
398
|
+
case 'config':
|
|
399
|
+
case 'ayar':
|
|
400
|
+
case 'setup':
|
|
401
|
+
runConfig();
|
|
402
|
+
break;
|
|
403
|
+
|
|
404
|
+
case 'status':
|
|
405
|
+
case 'durum':
|
|
406
|
+
runStatus();
|
|
407
|
+
break;
|
|
408
|
+
|
|
409
|
+
default:
|
|
410
|
+
printHeader();
|
|
411
|
+
console.log(`
|
|
412
|
+
${c('yellow', 'Kullanım:')}
|
|
413
|
+
|
|
414
|
+
vantuz tui Sohbet modunu başlat
|
|
415
|
+
vantuz config Ayarları yapılandır
|
|
416
|
+
vantuz status Sistem durumunu göster
|
|
417
|
+
|
|
418
|
+
${c('dim', 'İlk kullanımda: vantuz config')}
|
|
419
|
+
`);
|
|
420
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
async analyze(data, config) {
|
|
5
|
+
if (!config.ai || !config.ai.apiKey) {
|
|
6
|
+
throw new Error('AI yapılandırması eksik. Ayarlardan API anahtarınızı girin.');
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const prompt = `
|
|
10
|
+
Senin adın Vantuz. uzman e-ticaret analistisin.
|
|
11
|
+
Aşağıdaki e-ticaret verilerini analiz et ve mağaza sahibine 3 adet kritik, eyleme dönüştürülebilir öneri sun.
|
|
12
|
+
Yanıtın kısa, net ve profesyonel olsun. Türkçe yanıt ver.
|
|
13
|
+
|
|
14
|
+
Veriler:
|
|
15
|
+
${JSON.stringify(data, null, 2)}
|
|
16
|
+
`;
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const baseURL = config.ai.baseUrl || 'https://api.openai.com/v1';
|
|
20
|
+
const model = config.ai.model || 'gpt-4-turbo';
|
|
21
|
+
|
|
22
|
+
// Generic OpenAI Compatible Endpoint Support (Works with DeepSeek, OpenAI, LocalAI)
|
|
23
|
+
const response = await axios.post(`${baseURL}/chat/completions`, {
|
|
24
|
+
model: model,
|
|
25
|
+
messages: [
|
|
26
|
+
{ role: 'system', content: 'Sen uzman bir e-ticaret danışmanısın.' },
|
|
27
|
+
{ role: 'user', content: prompt }
|
|
28
|
+
],
|
|
29
|
+
temperature: 0.7
|
|
30
|
+
}, {
|
|
31
|
+
headers: {
|
|
32
|
+
'Authorization': `Bearer ${config.ai.apiKey}`,
|
|
33
|
+
'Content-Type': 'application/json'
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
return response.data.choices[0].message.content;
|
|
38
|
+
|
|
39
|
+
} catch (error) {
|
|
40
|
+
if (error.response) {
|
|
41
|
+
throw new Error(`AI API Hatası: ${error.response.status} - ${JSON.stringify(error.response.data)}`);
|
|
42
|
+
}
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
};
|
package/core/database.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
const { Sequelize, DataTypes } = require('sequelize');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
|
|
5
|
+
// Veritabanı dosyasının yolu (Kullanıcının home dizininde veya proje klasöründe)
|
|
6
|
+
const dbPath = path.join(process.cwd(), 'vantuz.sqlite');
|
|
7
|
+
|
|
8
|
+
const sequelize = new Sequelize({
|
|
9
|
+
dialect: 'sqlite',
|
|
10
|
+
storage: dbPath,
|
|
11
|
+
logging: false // Konsolu kirletmesin
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
// --- MODELLER ---
|
|
15
|
+
|
|
16
|
+
// Mağaza Ayarları (API Keyler vb.)
|
|
17
|
+
const Store = sequelize.define('Store', {
|
|
18
|
+
name: { type: DataTypes.STRING, allowNull: false },
|
|
19
|
+
platform: { type: DataTypes.STRING, allowNull: false }, // trendyol, amazon, etc.
|
|
20
|
+
credentials: { type: DataTypes.JSON, allowNull: false }, // { apiKey: '...', apiSecret: '...' }
|
|
21
|
+
isActive: { type: DataTypes.BOOLEAN, defaultValue: true }
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// Ürünler
|
|
25
|
+
const Product = sequelize.define('Product', {
|
|
26
|
+
name: { type: DataTypes.STRING, allowNull: false },
|
|
27
|
+
barcode: { type: DataTypes.STRING, unique: true },
|
|
28
|
+
sku: { type: DataTypes.STRING },
|
|
29
|
+
description: { type: DataTypes.TEXT },
|
|
30
|
+
brand: { type: DataTypes.STRING },
|
|
31
|
+
images: { type: DataTypes.JSON }, // Resim URL'leri listesi
|
|
32
|
+
marketData: { type: DataTypes.JSON }, // { trendyol: { price: 100, stock: 10 }, amazon: { ... } }
|
|
33
|
+
aiAnalysis: { type: DataTypes.TEXT } // AI tarafından üretilen satış önerileri
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// Siparişler
|
|
37
|
+
const Order = sequelize.define('Order', {
|
|
38
|
+
platform: { type: DataTypes.STRING, allowNull: false },
|
|
39
|
+
orderNumber: { type: DataTypes.STRING, unique: true },
|
|
40
|
+
customerName: { type: DataTypes.STRING },
|
|
41
|
+
totalAmount: { type: DataTypes.FLOAT },
|
|
42
|
+
currency: { type: DataTypes.STRING, defaultValue: 'TRY' },
|
|
43
|
+
status: { type: DataTypes.STRING },
|
|
44
|
+
orderDate: { type: DataTypes.DATE },
|
|
45
|
+
items: { type: DataTypes.JSON } // Sipariş içeriği
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Loglar ve AI Önerileri
|
|
49
|
+
const Insight = sequelize.define('Insight', {
|
|
50
|
+
type: { type: DataTypes.STRING }, // 'pricing', 'stock', 'trend'
|
|
51
|
+
message: { type: DataTypes.TEXT },
|
|
52
|
+
priority: { type: DataTypes.INTEGER }, // 1: Düşük, 5: Kritik
|
|
53
|
+
isRead: { type: DataTypes.BOOLEAN, defaultValue: false }
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// Veritabanını Başlat
|
|
57
|
+
async function initDB() {
|
|
58
|
+
try {
|
|
59
|
+
await sequelize.sync({ alter: true }); // Tabloları güncelle
|
|
60
|
+
return true;
|
|
61
|
+
} catch (error) {
|
|
62
|
+
console.error('Veritabanı hatası:', error);
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
module.exports = {
|
|
68
|
+
sequelize,
|
|
69
|
+
Store,
|
|
70
|
+
Product,
|
|
71
|
+
Order,
|
|
72
|
+
Insight,
|
|
73
|
+
initDB
|
|
74
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const crypto = require('crypto');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
// Müşteriye Gidecek Olan PUBLIC KEY (Sadece doğrulama yapar)
|
|
6
|
+
const PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
|
|
7
|
+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy... (Buraya gerçek key gelecek)
|
|
8
|
+
-----END PUBLIC KEY-----`;
|
|
9
|
+
|
|
10
|
+
// NOT: Bu dosya artık lisans ÜRETEMEZ. Sadece doğrular.
|
|
11
|
+
// Lisans üretmek için 'admin-keygen.js' dosyasını kullanın (Müşteriye vermeyin).
|
|
12
|
+
|
|
13
|
+
module.exports = {
|
|
14
|
+
verifyLicense(licenseKey) {
|
|
15
|
+
try {
|
|
16
|
+
// Lisans formatı: BASE64_DATA.BASE64_SIGNATURE
|
|
17
|
+
const parts = licenseKey.split('.');
|
|
18
|
+
if (parts.length !== 2) return { valid: false, reason: 'Geçersiz Format' };
|
|
19
|
+
|
|
20
|
+
const data = parts[0];
|
|
21
|
+
const signature = parts[1];
|
|
22
|
+
|
|
23
|
+
// İmzayı doğrula
|
|
24
|
+
const verify = crypto.createVerify('SHA256');
|
|
25
|
+
verify.update(data);
|
|
26
|
+
verify.end();
|
|
27
|
+
|
|
28
|
+
// Gerçek Public Key'i okuyalım (Normalde hardcoded olur ama demo için dosyadan okuyorum)
|
|
29
|
+
const pubKey = fs.readFileSync(path.join(__dirname, '../public.pem'), 'utf8');
|
|
30
|
+
|
|
31
|
+
const isValid = verify.verify(pubKey, signature, 'base64');
|
|
32
|
+
|
|
33
|
+
if (!isValid) {
|
|
34
|
+
return { valid: false, reason: 'Sahte Lisans (İmza Geçersiz)' };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const payload = JSON.parse(Buffer.from(data, 'base64').toString('utf8'));
|
|
38
|
+
const today = new Date().toISOString().split('T')[0];
|
|
39
|
+
|
|
40
|
+
if (payload.expiry < today) {
|
|
41
|
+
return { valid: false, reason: 'Süresi Dolmuş Lisans' };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return { valid: true, data: payload };
|
|
45
|
+
|
|
46
|
+
} catch (e) {
|
|
47
|
+
return { valid: false, reason: 'Lisans Okunamadı' };
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|