vantuz 3.2.7 → 3.3.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.
@@ -0,0 +1,76 @@
1
+ // core/scrapers/TrendyolScraper.js
2
+ import { Scraper } from './Scraper.js';
3
+
4
+ export class TrendyolScraper extends Scraper {
5
+ constructor() {
6
+ super();
7
+ this.baseUrl = 'https://www.trendyol.com';
8
+ }
9
+
10
+ async getProductPrice(productUrl) {
11
+ await this.init();
12
+ await this.goTo(productUrl);
13
+
14
+ // Example: Extract price. This selector might need adjustment based on actual Trendyol HTML.
15
+ const priceSelector = '.pr-new-price'; // Or similar selector for price
16
+ const priceText = await this.extractText(priceSelector);
17
+
18
+ await this.close();
19
+ return priceText ? parseFloat(priceText.replace(/[^\d,]/g, '').replace(',', '.')) : null;
20
+ }
21
+
22
+ async searchProducts(query) {
23
+ await this.init();
24
+ await this.goTo(`${this.baseUrl}/sr?q=${encodeURIComponent(query)}`);
25
+
26
+ // Example: Extract product titles and URLs from search results
27
+ const productTitles = await this.extractAllText('.p-card-wrppr .prdct-desc-v2 a span');
28
+ const productLinks = await this.page.locator('.p-card-wrppr .prdct-desc-v2 a').evaluateAll((links) => links.map(link => link.href));
29
+
30
+ const products = productTitles.map((title, index) => ({
31
+ title,
32
+ url: productLinks[index]
33
+ }));
34
+
35
+ await this.close();
36
+ return products;
37
+ }
38
+
39
+ async getPriceChanges(productUrl) {
40
+ await this.init();
41
+ await this.goTo(productUrl);
42
+ // Placeholder for logic to detect price changes over time
43
+ // This would involve comparing current price with a stored baseline
44
+ const currentPrice = await this.getProductPrice(productUrl); // Re-use existing method
45
+ await this.close();
46
+ return { productUrl, currentPrice, status: 'Price change detection not fully implemented yet' };
47
+ }
48
+
49
+ async getBuyboxStatus(productUrl) {
50
+ await this.init();
51
+ await this.goTo(productUrl);
52
+ // Placeholder for logic to determine buybox status (won/lost)
53
+ // This might involve checking specific elements or seller names on the product page
54
+ await this.close();
55
+ return { productUrl, status: 'Buybox status detection not fully implemented yet', won: false };
56
+ }
57
+
58
+ async getStockMovements(productUrl) {
59
+ await this.init();
60
+ await this.goTo(productUrl);
61
+ // Placeholder for logic to track stock changes
62
+ // This might involve monitoring "out of stock" indicators or specific stock counts if available
63
+ await this.close();
64
+ return { productUrl, status: 'Stock movement detection not fully implemented yet', inStock: true };
65
+ }
66
+
67
+ async getProductReviewsAndRatings(productUrl) {
68
+ await this.init();
69
+ await this.goTo(productUrl);
70
+ // Placeholder for logic to scrape reviews and ratings
71
+ // This often involves navigating to review sections or pagination
72
+ const reviews = ['Placeholder review 1', 'Placeholder review 2'];
73
+ const rating = 4.5; // Placeholder rating
74
+ await this.close();
75
+ return { productUrl, reviews, rating, status: 'Review and rating scraping not fully implemented yet' };
76
+ }
@@ -0,0 +1,97 @@
1
+ // core/vector-db.js
2
+ import { log } from './ai-provider.js';
3
+
4
+ class VectorDB {
5
+ constructor() {
6
+ this.collections = new Map(); // collectionName -> { vectors: [], metadatas: [] }
7
+ log('INFO', 'In-memory VectorDB initialized');
8
+ }
9
+
10
+ /**
11
+ * Kosinüs benzerliğini hesaplar.
12
+ * @param {number[]} vec1
13
+ * @param {number[]} vec2
14
+ * @returns {number} Kosinüs benzerliği.
15
+ */
16
+ _cosineSimilarity(vec1, vec2) {
17
+ if (vec1.length !== vec2.length) {
18
+ throw new Error('Vectors must be of the same dimension');
19
+ }
20
+ let dotProduct = 0;
21
+ let magnitude1 = 0;
22
+ let magnitude2 = 0;
23
+ for (let i = 0; i < vec1.length; i++) {
24
+ dotProduct += vec1[i] * vec2[i];
25
+ magnitude1 += vec1[i] * vec1[i];
26
+ magnitude2 += vec2[i] * vec2[i];
27
+ }
28
+ magnitude1 = Math.sqrt(magnitude1);
29
+ magnitude2 = Math.sqrt(magnitude2);
30
+
31
+ if (magnitude1 === 0 || magnitude2 === 0) {
32
+ return 0; // Avoid division by zero
33
+ }
34
+ return dotProduct / (magnitude1 * magnitude2);
35
+ }
36
+
37
+ /**
38
+ * Vektör koleksiyonu oluşturur veya alır.
39
+ * @param {string} collectionName
40
+ * @returns {{vectors: Array<number[]>, metadatas: Array<Object>}}
41
+ */
42
+ getCollection(collectionName) {
43
+ if (!this.collections.has(collectionName)) {
44
+ this.collections.set(collectionName, { vectors: [], metadatas: [] });
45
+ log('INFO', `Vector collection "${collectionName}" created.`);
46
+ }
47
+ return this.collections.get(collectionName);
48
+ }
49
+
50
+ /**
51
+ * Koleksiyona vektör ve metadata ekler.
52
+ * @param {string} collectionName
53
+ * @param {number[]} vector
54
+ * @param {Object} metadata
55
+ */
56
+ add(collectionName, vector, metadata) {
57
+ const collection = this.getCollection(collectionName);
58
+ collection.vectors.push(vector);
59
+ collection.metadatas.push(metadata);
60
+ log('INFO', `Vector added to collection "${collectionName}"`);
61
+ }
62
+
63
+ /**
64
+ * Bir sorgu vektörüne en benzer vektörleri bulur.
65
+ * @param {string} collectionName
66
+ * @param {number[]} queryVector
67
+ * @param {number} topK En çok kaç sonuç döndürülecek.
68
+ * @returns {Array<{metadata: Object, similarity: number}>} Sıralanmış sonuçlar.
69
+ */
70
+ search(collectionName, queryVector, topK = 5) {
71
+ const collection = this.collections.get(collectionName);
72
+ if (!collection || collection.vectors.length === 0) {
73
+ return [];
74
+ }
75
+
76
+ const results = collection.vectors.map((vector, index) => {
77
+ const similarity = this._cosineSimilarity(queryVector, vector);
78
+ return {
79
+ metadata: collection.metadatas[index],
80
+ similarity: similarity
81
+ };
82
+ });
83
+
84
+ results.sort((a, b) => b.similarity - a.similarity); // Yüksek benzerlik önde
85
+ log('INFO', `Search performed on collection "${collectionName}", found ${results.length} results.`);
86
+ return results.slice(0, topK);
87
+ }
88
+ }
89
+
90
+ let vectorDbInstance = null;
91
+
92
+ export function getVectorDB() {
93
+ if (!vectorDbInstance) {
94
+ vectorDbInstance = new VectorDB();
95
+ }
96
+ return vectorDbInstance;
97
+ }
package/onboard.js CHANGED
@@ -50,7 +50,32 @@ class OnboardingWizard {
50
50
  constructor() {
51
51
  this.envVars = {};
52
52
  this.step = 0;
53
- this.totalSteps = 5;
53
+ this.totalSteps = 6; // Updated total steps
54
+ }
55
+
56
+ async step_EIAConfig() {
57
+ this.step = 5; // Adjust step number
58
+ this.printHeader('E-TICARET YÖNETİM AJANSI (EIA) YAPILANDIRMASI');
59
+
60
+ console.log('EIA\'nın operasyonlarını optimize etmek için bazı bilgiler sağlayın.\n');
61
+
62
+ const competitorUrls = await this.prompt('Rakip Ürün URL\'leri (virgülle ayırarak): ');
63
+ if (competitorUrls) {
64
+ this.envVars.EIA_COMPETITOR_URLS = competitorUrls.trim();
65
+ console.log(c('green', '[OK] Rakip URL\'leri kaydedildi.\n'));
66
+ } else {
67
+ console.log(c('yellow', '[BİLGİ] Rakip URL\'leri girilmedi.\n'));
68
+ }
69
+
70
+ const profitMargin = await this.prompt('Hedef Kar Marjı (%) [15]: ');
71
+ if (profitMargin && !isNaN(parseFloat(profitMargin))) {
72
+ this.envVars.EIA_TARGET_PROFIT_MARGIN = parseFloat(profitMargin);
73
+ console.log(c('green', '[OK] Hedef Kar Marjı kaydedildi.\n'));
74
+ } else {
75
+ this.envVars.EIA_TARGET_PROFIT_MARGIN = 15; // Default if invalid
76
+ console.log(c('yellow', '[BİLGİ] Geçersiz kar marjı, varsayılan %15 kullanılıyor.\n'));
77
+ }
78
+ await sleep(1000);
54
79
  }
55
80
 
56
81
  clear() { console.clear(); }
@@ -70,6 +95,7 @@ class OnboardingWizard {
70
95
  await this.step2_Platforms();
71
96
  await this.step3_Channels();
72
97
  await this.step4_Gateway();
98
+ await this.step_EIAConfig(); // New step
73
99
  await this.step5_Save();
74
100
  await this.showSuccess();
75
101
  } catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vantuz",
3
- "version": "3.2.7",
3
+ "version": "3.3.0",
4
4
  "description": "Yapay Zeka Destekli E-Ticaret Yönetim Platformu - 7 Pazaryeri + WhatsApp/Telegram",
5
5
  "type": "module",
6
6
  "main": "cli.js",
@@ -55,16 +55,18 @@
55
55
  "url": "https://github.com/nuricanavsar/vantuz/issues"
56
56
  },
57
57
  "dependencies": {
58
- "axios": "^1.6.0",
59
- "body-parser": "^2.2.2",
58
+ "axios": "^1.13.5",
60
59
  "cors": "^2.8.6",
60
+ "cron": "^4.4.0",
61
61
  "dotenv": "^16.0.0",
62
62
  "express": "^5.2.1",
63
63
  "openclaw": "^2026.2.9",
64
+ "sqlite3": "^5.1.7",
64
65
  "xml2js": "^0.6.2"
65
66
  },
66
67
  "devDependencies": {
67
- "eslint": "^8.0.0"
68
+ "eslint": "^8.0.0",
69
+ "playwright": "^1.58.2"
68
70
  },
69
71
  "os": [
70
72
  "darwin",
@@ -86,4 +88,4 @@
86
88
  "README.md",
87
89
  "DOCS_TR.md"
88
90
  ]
89
- }
91
+ }
@@ -173,20 +173,24 @@ export const platformHub = {
173
173
  const connected = this.getConnected();
174
174
  const allOrders = [];
175
175
 
176
- for (const platform of connected) {
176
+ const orderPromises = connected.map(async (platform) => {
177
177
  const api = platforms[platform];
178
178
  const result = await api.getOrders(params);
179
179
  if (result.success) {
180
180
  const orders = result.data.content || result.data.orders || result.data || [];
181
- orders.forEach(order => {
182
- allOrders.push({
183
- ...order,
184
- _platform: platform,
185
- _icon: this.getIcon(platform)
186
- });
187
- });
181
+ return orders.map(order => ({
182
+ ...order,
183
+ _platform: platform,
184
+ _icon: this.getIcon(platform)
185
+ }));
188
186
  }
189
- }
187
+ return [];
188
+ });
189
+
190
+ const results = await Promise.all(orderPromises);
191
+ results.forEach(platformOrders => {
192
+ allOrders.push(...platformOrders);
193
+ });
190
194
 
191
195
  // Tarihe göre sırala
192
196
  allOrders.sort((a, b) => new Date(b.createdDate || b.orderDate) - new Date(a.createdDate || a.orderDate));
package/server/app.js CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  import express from 'express';
3
3
  import cors from 'cors';
4
- import bodyParser from 'body-parser';
4
+
5
5
  import path from 'path';
6
6
  import { fileURLToPath } from 'url';
7
7
  import { getEngine } from '../core/engine.js';
@@ -16,7 +16,7 @@ const PORT = process.env.PORT || 3001;
16
16
 
17
17
  // Middleware
18
18
  app.use(cors());
19
- app.use(bodyParser.json());
19
+ app.use(express.json());
20
20
  app.use(express.static(path.join(__dirname, 'public')));
21
21
 
22
22
  // Engine Singleton