vantuz 3.4.2 → 3.5.1

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.
Files changed (92) hide show
  1. package/.env.example +21 -0
  2. package/.openclaw/completions/openclaw.bash +227 -0
  3. package/.openclaw/completions/openclaw.fish +1552 -0
  4. package/.openclaw/completions/openclaw.ps1 +1966 -0
  5. package/.openclaw/completions/openclaw.zsh +3571 -0
  6. package/.openclaw/gateway.cmd +10 -0
  7. package/.openclaw/identity/device.json +7 -0
  8. package/.openclaw/openclaw.json +40 -0
  9. package/.windsurf/workflows/vantuz-dev.md +31 -0
  10. package/DOCS_TR.md +80 -0
  11. package/LICENSE +45 -45
  12. package/README.md +52 -21
  13. package/cli.js +685 -585
  14. package/config.js +733 -733
  15. package/core/agent-loop.js +190 -190
  16. package/core/ai-provider.js +298 -261
  17. package/core/automation.js +523 -523
  18. package/core/brand-analyst.js +101 -0
  19. package/core/channels.js +167 -167
  20. package/core/dashboard.js +230 -230
  21. package/core/database.js +135 -37
  22. package/core/eia-monitor.js +3 -1
  23. package/core/engine.js +648 -636
  24. package/core/gateway.js +447 -447
  25. package/core/learning.js +214 -214
  26. package/core/license.js +113 -0
  27. package/core/marketplace-adapter.js +168 -168
  28. package/core/memory.js +190 -190
  29. package/core/migrations/001-initial-schema.sql +1 -1
  30. package/core/queue.js +120 -120
  31. package/core/self-healer.js +314 -314
  32. package/core/unified-product.js +214 -214
  33. package/core/vision-service.js +113 -113
  34. package/index.js +217 -174
  35. package/modules/crm/sentiment-crm.js +231 -231
  36. package/modules/healer/listing-healer.js +201 -201
  37. package/modules/oracle/predictor.js +214 -214
  38. package/modules/researcher/agent.js +169 -169
  39. package/modules/team/agents/base.js +92 -92
  40. package/modules/team/agents/dev.js +33 -33
  41. package/modules/team/agents/josh.js +40 -40
  42. package/modules/team/agents/marketing.js +33 -33
  43. package/modules/team/agents/milo.js +36 -36
  44. package/modules/team/index.js +78 -78
  45. package/modules/team/shared-memory.js +87 -87
  46. package/modules/war-room/competitor-tracker.js +250 -250
  47. package/modules/war-room/pricing-engine.js +308 -308
  48. package/n11docs.md +1680 -0
  49. package/nodes/warehouse.js +238 -238
  50. package/onboard.js +1 -1
  51. package/openclawdocs.md +3 -0
  52. package/package.json +7 -5
  53. package/platforms/pttavm.js +14 -14
  54. package/plugins/vantuz/index.js +528 -528
  55. package/plugins/vantuz/memory/hippocampus.js +465 -465
  56. package/plugins/vantuz/package.json +20 -20
  57. package/plugins/vantuz/platforms/_template.js +118 -118
  58. package/plugins/vantuz/platforms/amazon.js +236 -236
  59. package/plugins/vantuz/platforms/ciceksepeti.js +166 -166
  60. package/plugins/vantuz/platforms/hepsiburada.js +180 -180
  61. package/plugins/vantuz/platforms/index.js +165 -165
  62. package/plugins/vantuz/platforms/n11.js +229 -229
  63. package/plugins/vantuz/platforms/pazarama.js +154 -154
  64. package/plugins/vantuz/platforms/pttavm.js +127 -127
  65. package/plugins/vantuz/platforms/trendyol.js +326 -326
  66. package/plugins/vantuz/services/alerts.js +253 -253
  67. package/plugins/vantuz/services/license.js +34 -34
  68. package/plugins/vantuz/services/scheduler.js +232 -232
  69. package/plugins/vantuz/tools/analytics.js +152 -152
  70. package/plugins/vantuz/tools/crossborder.js +187 -187
  71. package/plugins/vantuz/tools/nl-parser.js +211 -211
  72. package/plugins/vantuz/tools/product.js +110 -110
  73. package/plugins/vantuz/tools/quick-report.js +175 -175
  74. package/plugins/vantuz/tools/repricer.js +314 -314
  75. package/plugins/vantuz/tools/sentiment.js +115 -115
  76. package/plugins/vantuz/tools/vision.js +257 -257
  77. package/public.pem +9 -0
  78. package/server/app.js +260 -260
  79. package/server/public/index.html +514 -514
  80. package/start.bat +33 -33
  81. package/vantuz.sqlite +0 -0
  82. package/workspace/AGENTS.md +73 -0
  83. package/workspace/BRAND.md +29 -0
  84. package/workspace/SOUL.md +72 -0
  85. package/workspace/team/DECISIONS.md +3 -0
  86. package/workspace/team/GOALS.md +3 -0
  87. package/workspace/team/PROJECT_STATUS.md +3 -0
  88. package/workspace/team/agents/dev/SOUL.md +12 -0
  89. package/workspace/team/agents/josh/SOUL.md +12 -0
  90. package/workspace/team/agents/marketing/SOUL.md +12 -0
  91. package/workspace/team/agents/milo/SOUL.md +12 -0
  92. package/vantuz-3.3.4.tgz +0 -0
@@ -1,465 +1,465 @@
1
- /**
2
- * 🧠 HIPPOCAMPUS - Gelişmiş Hafıza Sistemi
3
- *
4
- * Beyin'in hippocampus bölgesinden ilham alınarak tasarlanmış,
5
- * uzun süreli hafıza yönetimi ve bağlamsal hatırlama sistemi.
6
- *
7
- * Özellikler:
8
- * - Episodik hafıza (olaylar, kararlar)
9
- * - Semantik hafıza (ürün bilgileri, kurallar)
10
- * - Vektör tabanlı benzerlik araması
11
- * - Otomatik hafıza konsolidasyonu
12
- * - Önem bazlı unutma mekanizması
13
- */
14
-
15
- import { Sequelize, DataTypes, Op } from 'sequelize';
16
- import path from 'path';
17
- import crypto from 'crypto';
18
-
19
- export class Hippocampus {
20
- constructor(api) {
21
- this.api = api;
22
- this.logger = api.logger;
23
- this.db = null;
24
- this.models = {};
25
- this.initialized = false;
26
- }
27
-
28
- async initialize() {
29
- const dbPath = path.join(process.cwd(), '.vantuz', 'hippocampus.sqlite');
30
-
31
- this.db = new Sequelize({
32
- dialect: 'sqlite',
33
- storage: dbPath,
34
- dialectModule: require('better-sqlite3'),
35
- logging: false
36
- });
37
-
38
- // Hafıza Modelleri
39
- this.models.Memory = this.db.define('Memory', {
40
- id: {
41
- type: DataTypes.UUID,
42
- defaultValue: DataTypes.UUIDV4,
43
- primaryKey: true
44
- },
45
- type: {
46
- type: DataTypes.STRING,
47
- allowNull: false,
48
- // decision, price_change, product, conversation, insight, rule
49
- },
50
- content: {
51
- type: DataTypes.TEXT,
52
- allowNull: false
53
- },
54
- context: {
55
- type: DataTypes.JSON,
56
- // İlişkili veriler: productId, platform, userId, etc.
57
- },
58
- embedding: {
59
- type: DataTypes.TEXT,
60
- // Vektör gömme (JSON olarak saklanır)
61
- },
62
- importance: {
63
- type: DataTypes.FLOAT,
64
- defaultValue: 0.5,
65
- // 0-1 arası önem skoru
66
- },
67
- accessCount: {
68
- type: DataTypes.INTEGER,
69
- defaultValue: 0
70
- },
71
- lastAccessed: {
72
- type: DataTypes.DATE
73
- },
74
- expiresAt: {
75
- type: DataTypes.DATE,
76
- // null = kalıcı hafıza
77
- },
78
- tags: {
79
- type: DataTypes.JSON,
80
- defaultValue: []
81
- }
82
- });
83
-
84
- // Fiyat Karar Geçmişi
85
- this.models.PricingDecision = this.db.define('PricingDecision', {
86
- id: {
87
- type: DataTypes.UUID,
88
- defaultValue: DataTypes.UUIDV4,
89
- primaryKey: true
90
- },
91
- productId: DataTypes.STRING,
92
- barcode: DataTypes.STRING,
93
- platform: DataTypes.STRING,
94
- previousPrice: DataTypes.FLOAT,
95
- newPrice: DataTypes.FLOAT,
96
- reason: DataTypes.TEXT,
97
- factors: {
98
- type: DataTypes.JSON,
99
- // { competitorPrice, competitorStock, ourStock, margin, velocity }
100
- },
101
- outcome: {
102
- type: DataTypes.STRING,
103
- // applied, rejected, pending
104
- },
105
- profitImpact: DataTypes.FLOAT
106
- });
107
-
108
- // Ürün Bağlamı
109
- this.models.ProductContext = this.db.define('ProductContext', {
110
- id: {
111
- type: DataTypes.UUID,
112
- defaultValue: DataTypes.UUIDV4,
113
- primaryKey: true
114
- },
115
- barcode: {
116
- type: DataTypes.STRING,
117
- unique: true
118
- },
119
- name: DataTypes.STRING,
120
- category: DataTypes.STRING,
121
- avgSalePrice: DataTypes.FLOAT,
122
- avgCost: DataTypes.FLOAT,
123
- seasonality: DataTypes.JSON,
124
- competitorHistory: DataTypes.JSON,
125
- customerSentiment: {
126
- type: DataTypes.JSON,
127
- // { positive: 0.8, negative: 0.2, topComplaints: [] }
128
- },
129
- priceElasticity: DataTypes.FLOAT,
130
- optimalPriceRange: DataTypes.JSON
131
- });
132
-
133
- // Konuşma Geçmişi (Session bazlı)
134
- this.models.ConversationMemory = this.db.define('ConversationMemory', {
135
- id: {
136
- type: DataTypes.UUID,
137
- defaultValue: DataTypes.UUIDV4,
138
- primaryKey: true
139
- },
140
- sessionKey: DataTypes.STRING,
141
- userId: DataTypes.STRING,
142
- channel: DataTypes.STRING,
143
- role: {
144
- type: DataTypes.STRING,
145
- // user, assistant
146
- },
147
- content: DataTypes.TEXT,
148
- intent: DataTypes.STRING,
149
- entities: DataTypes.JSON,
150
- actionTaken: DataTypes.STRING
151
- });
152
-
153
- // Öğrenilen Kurallar
154
- this.models.LearnedRule = this.db.define('LearnedRule', {
155
- id: {
156
- type: DataTypes.UUID,
157
- defaultValue: DataTypes.UUIDV4,
158
- primaryKey: true
159
- },
160
- trigger: DataTypes.TEXT,
161
- condition: DataTypes.JSON,
162
- action: DataTypes.TEXT,
163
- confidence: {
164
- type: DataTypes.FLOAT,
165
- defaultValue: 0.5
166
- },
167
- usageCount: {
168
- type: DataTypes.INTEGER,
169
- defaultValue: 0
170
- },
171
- successRate: {
172
- type: DataTypes.FLOAT,
173
- defaultValue: 0.5
174
- }
175
- });
176
-
177
- await this.db.sync({ alter: true });
178
- this.initialized = true;
179
- this.logger.info('🧠 Hippocampus veritabanı hazır.');
180
-
181
- // Hafıza konsolidasyonu zamanlayıcısı (her gece)
182
- this._startConsolidation();
183
- }
184
-
185
- // ═══════════════════════════════════════════════════════════════════════════
186
- // HAFIZA KAYDETME
187
- // ═══════════════════════════════════════════════════════════════════════════
188
-
189
- async remember(type, content, context = {}, options = {}) {
190
- const memory = await this.models.Memory.create({
191
- type,
192
- content: typeof content === 'string' ? content : JSON.stringify(content),
193
- context,
194
- importance: options.importance || this._calculateImportance(type, content),
195
- tags: options.tags || [],
196
- expiresAt: options.temporary ? new Date(Date.now() + 24 * 60 * 60 * 1000) : null
197
- });
198
-
199
- this.logger.debug(`💾 Hafıza kaydedildi: ${type} - ${memory.id}`);
200
- return memory;
201
- }
202
-
203
- async recordPricingDecision(decision) {
204
- return await this.models.PricingDecision.create(decision);
205
- }
206
-
207
- async updateProductContext(barcode, updates) {
208
- const [context, created] = await this.models.ProductContext.findOrCreate({
209
- where: { barcode },
210
- defaults: { barcode, ...updates }
211
- });
212
-
213
- if (!created) {
214
- await context.update(updates);
215
- }
216
-
217
- return context;
218
- }
219
-
220
- async recordConversation(sessionKey, userId, channel, role, content, metadata = {}) {
221
- return await this.models.ConversationMemory.create({
222
- sessionKey,
223
- userId,
224
- channel,
225
- role,
226
- content,
227
- intent: metadata.intent,
228
- entities: metadata.entities,
229
- actionTaken: metadata.action
230
- });
231
- }
232
-
233
- // ═══════════════════════════════════════════════════════════════════════════
234
- // HAFIZA ARAMA
235
- // ═══════════════════════════════════════════════════════════════════════════
236
-
237
- async search({ query, type, limit = 10, minImportance = 0 }) {
238
- const where = {};
239
-
240
- if (type && type !== 'all') {
241
- where.type = type;
242
- }
243
-
244
- if (minImportance > 0) {
245
- where.importance = { [Op.gte]: minImportance };
246
- }
247
-
248
- // Basit metin araması (ileride vektör araması eklenebilir)
249
- if (query) {
250
- where.content = { [Op.like]: `%${query}%` };
251
- }
252
-
253
- const memories = await this.models.Memory.findAll({
254
- where,
255
- order: [['importance', 'DESC'], ['createdAt', 'DESC']],
256
- limit
257
- });
258
-
259
- // Erişim sayacını güncelle
260
- for (const mem of memories) {
261
- await mem.update({
262
- accessCount: mem.accessCount + 1,
263
- lastAccessed: new Date()
264
- });
265
- }
266
-
267
- return memories.map(m => ({
268
- id: m.id,
269
- type: m.type,
270
- content: m.content,
271
- context: m.context,
272
- importance: m.importance,
273
- createdAt: m.createdAt
274
- }));
275
- }
276
-
277
- async getProductContext(barcode) {
278
- return await this.models.ProductContext.findOne({ where: { barcode } });
279
- }
280
-
281
- async getPricingHistory(barcode, limit = 10) {
282
- return await this.models.PricingDecision.findAll({
283
- where: { barcode },
284
- order: [['createdAt', 'DESC']],
285
- limit
286
- });
287
- }
288
-
289
- async getRecentConversations(sessionKey, limit = 20) {
290
- return await this.models.ConversationMemory.findAll({
291
- where: { sessionKey },
292
- order: [['createdAt', 'DESC']],
293
- limit
294
- });
295
- }
296
-
297
- async getLearnedRules(trigger) {
298
- return await this.models.LearnedRule.findAll({
299
- where: {
300
- trigger: { [Op.like]: `%${trigger}%` },
301
- confidence: { [Op.gte]: 0.6 }
302
- },
303
- order: [['confidence', 'DESC'], ['usageCount', 'DESC']]
304
- });
305
- }
306
-
307
- // ═══════════════════════════════════════════════════════════════════════════
308
- // BAĞLAMSAL HATIRLATMA
309
- // ═══════════════════════════════════════════════════════════════════════════
310
-
311
- async getRelevantContext(input, options = {}) {
312
- const context = {
313
- recentDecisions: [],
314
- productHistory: null,
315
- relatedMemories: [],
316
- applicableRules: []
317
- };
318
-
319
- // Ürün barkodu varsa ürün bağlamını al
320
- if (options.barcode) {
321
- context.productHistory = await this.getProductContext(options.barcode);
322
- context.recentDecisions = await this.getPricingHistory(options.barcode, 5);
323
- }
324
-
325
- // İlgili hafızaları ara
326
- context.relatedMemories = await this.search({
327
- query: input,
328
- type: options.type || 'all',
329
- limit: 5,
330
- minImportance: 0.3
331
- });
332
-
333
- // Uygulanabilir kuralları bul
334
- context.applicableRules = await this.getLearnedRules(input);
335
-
336
- return context;
337
- }
338
-
339
- // ═══════════════════════════════════════════════════════════════════════════
340
- // ÖĞRENME & KONSOLİDASYON
341
- // ═══════════════════════════════════════════════════════════════════════════
342
-
343
- async learnRule(trigger, condition, action) {
344
- const existing = await this.models.LearnedRule.findOne({
345
- where: { trigger, action }
346
- });
347
-
348
- if (existing) {
349
- await existing.update({
350
- usageCount: existing.usageCount + 1,
351
- confidence: Math.min(1, existing.confidence + 0.05)
352
- });
353
- return existing;
354
- }
355
-
356
- return await this.models.LearnedRule.create({
357
- trigger,
358
- condition,
359
- action,
360
- confidence: 0.5
361
- });
362
- }
363
-
364
- async recordRuleOutcome(ruleId, success) {
365
- const rule = await this.models.LearnedRule.findByPk(ruleId);
366
- if (!rule) return;
367
-
368
- const newSuccessRate = (rule.successRate * rule.usageCount + (success ? 1 : 0)) / (rule.usageCount + 1);
369
- const newConfidence = success
370
- ? Math.min(1, rule.confidence + 0.1)
371
- : Math.max(0, rule.confidence - 0.1);
372
-
373
- await rule.update({
374
- usageCount: rule.usageCount + 1,
375
- successRate: newSuccessRate,
376
- confidence: newConfidence
377
- });
378
- }
379
-
380
- _startConsolidation() {
381
- // Her gece saat 3'te çalış
382
- const now = new Date();
383
- const night = new Date(now);
384
- night.setHours(3, 0, 0, 0);
385
- if (night <= now) night.setDate(night.getDate() + 1);
386
-
387
- const delay = night - now;
388
-
389
- setTimeout(() => {
390
- this._consolidate();
391
- // Sonra her 24 saatte bir
392
- setInterval(() => this._consolidate(), 24 * 60 * 60 * 1000);
393
- }, delay);
394
- }
395
-
396
- async _consolidate() {
397
- this.logger.info('🧠 Hafıza konsolidasyonu başlıyor...');
398
-
399
- // 1. Süresi dolmuş hafızaları sil
400
- await this.models.Memory.destroy({
401
- where: {
402
- expiresAt: { [Op.lt]: new Date() }
403
- }
404
- });
405
-
406
- // 2. Düşük önemli ve erişilmeyen hafızaları "unut"
407
- const oldDate = new Date(Date.now() - 90 * 24 * 60 * 60 * 1000); // 90 gün
408
- await this.models.Memory.destroy({
409
- where: {
410
- importance: { [Op.lt]: 0.3 },
411
- accessCount: { [Op.lt]: 3 },
412
- lastAccessed: { [Op.lt]: oldDate }
413
- }
414
- });
415
-
416
- // 3. Düşük güvenilirlikli kuralları sil
417
- await this.models.LearnedRule.destroy({
418
- where: {
419
- confidence: { [Op.lt]: 0.2 },
420
- usageCount: { [Op.gt]: 10 }
421
- }
422
- });
423
-
424
- this.logger.info('🧠 Hafıza konsolidasyonu tamamlandı.');
425
- }
426
-
427
- _calculateImportance(type, content) {
428
- // Tip bazlı temel önem
429
- const baseImportance = {
430
- decision: 0.8,
431
- price_change: 0.7,
432
- insight: 0.6,
433
- rule: 0.9,
434
- product: 0.5,
435
- conversation: 0.3
436
- };
437
-
438
- return baseImportance[type] || 0.5;
439
- }
440
-
441
- // ═══════════════════════════════════════════════════════════════════════════
442
- // İSTATİSTİKLER
443
- // ═══════════════════════════════════════════════════════════════════════════
444
-
445
- async getStats() {
446
- const memoryCount = await this.models.Memory.count();
447
- const decisionCount = await this.models.PricingDecision.count();
448
- const productCount = await this.models.ProductContext.count();
449
- const ruleCount = await this.models.LearnedRule.count();
450
-
451
- return {
452
- memories: memoryCount,
453
- decisions: decisionCount,
454
- products: productCount,
455
- rules: ruleCount,
456
- initialized: this.initialized
457
- };
458
- }
459
-
460
- async close() {
461
- if (this.db) {
462
- await this.db.close();
463
- }
464
- }
465
- }
1
+ /**
2
+ * 🧠 HIPPOCAMPUS - Gelişmiş Hafıza Sistemi
3
+ *
4
+ * Beyin'in hippocampus bölgesinden ilham alınarak tasarlanmış,
5
+ * uzun süreli hafıza yönetimi ve bağlamsal hatırlama sistemi.
6
+ *
7
+ * Özellikler:
8
+ * - Episodik hafıza (olaylar, kararlar)
9
+ * - Semantik hafıza (ürün bilgileri, kurallar)
10
+ * - Vektör tabanlı benzerlik araması
11
+ * - Otomatik hafıza konsolidasyonu
12
+ * - Önem bazlı unutma mekanizması
13
+ */
14
+
15
+ import { Sequelize, DataTypes, Op } from 'sequelize';
16
+ import path from 'path';
17
+ import crypto from 'crypto';
18
+
19
+ export class Hippocampus {
20
+ constructor(api) {
21
+ this.api = api;
22
+ this.logger = api.logger;
23
+ this.db = null;
24
+ this.models = {};
25
+ this.initialized = false;
26
+ }
27
+
28
+ async initialize() {
29
+ const dbPath = path.join(process.cwd(), '.vantuz', 'hippocampus.sqlite');
30
+
31
+ this.db = new Sequelize({
32
+ dialect: 'sqlite',
33
+ storage: dbPath,
34
+ dialectModule: require('better-sqlite3'),
35
+ logging: false
36
+ });
37
+
38
+ // Hafıza Modelleri
39
+ this.models.Memory = this.db.define('Memory', {
40
+ id: {
41
+ type: DataTypes.UUID,
42
+ defaultValue: DataTypes.UUIDV4,
43
+ primaryKey: true
44
+ },
45
+ type: {
46
+ type: DataTypes.STRING,
47
+ allowNull: false,
48
+ // decision, price_change, product, conversation, insight, rule
49
+ },
50
+ content: {
51
+ type: DataTypes.TEXT,
52
+ allowNull: false
53
+ },
54
+ context: {
55
+ type: DataTypes.JSON,
56
+ // İlişkili veriler: productId, platform, userId, etc.
57
+ },
58
+ embedding: {
59
+ type: DataTypes.TEXT,
60
+ // Vektör gömme (JSON olarak saklanır)
61
+ },
62
+ importance: {
63
+ type: DataTypes.FLOAT,
64
+ defaultValue: 0.5,
65
+ // 0-1 arası önem skoru
66
+ },
67
+ accessCount: {
68
+ type: DataTypes.INTEGER,
69
+ defaultValue: 0
70
+ },
71
+ lastAccessed: {
72
+ type: DataTypes.DATE
73
+ },
74
+ expiresAt: {
75
+ type: DataTypes.DATE,
76
+ // null = kalıcı hafıza
77
+ },
78
+ tags: {
79
+ type: DataTypes.JSON,
80
+ defaultValue: []
81
+ }
82
+ });
83
+
84
+ // Fiyat Karar Geçmişi
85
+ this.models.PricingDecision = this.db.define('PricingDecision', {
86
+ id: {
87
+ type: DataTypes.UUID,
88
+ defaultValue: DataTypes.UUIDV4,
89
+ primaryKey: true
90
+ },
91
+ productId: DataTypes.STRING,
92
+ barcode: DataTypes.STRING,
93
+ platform: DataTypes.STRING,
94
+ previousPrice: DataTypes.FLOAT,
95
+ newPrice: DataTypes.FLOAT,
96
+ reason: DataTypes.TEXT,
97
+ factors: {
98
+ type: DataTypes.JSON,
99
+ // { competitorPrice, competitorStock, ourStock, margin, velocity }
100
+ },
101
+ outcome: {
102
+ type: DataTypes.STRING,
103
+ // applied, rejected, pending
104
+ },
105
+ profitImpact: DataTypes.FLOAT
106
+ });
107
+
108
+ // Ürün Bağlamı
109
+ this.models.ProductContext = this.db.define('ProductContext', {
110
+ id: {
111
+ type: DataTypes.UUID,
112
+ defaultValue: DataTypes.UUIDV4,
113
+ primaryKey: true
114
+ },
115
+ barcode: {
116
+ type: DataTypes.STRING,
117
+ unique: true
118
+ },
119
+ name: DataTypes.STRING,
120
+ category: DataTypes.STRING,
121
+ avgSalePrice: DataTypes.FLOAT,
122
+ avgCost: DataTypes.FLOAT,
123
+ seasonality: DataTypes.JSON,
124
+ competitorHistory: DataTypes.JSON,
125
+ customerSentiment: {
126
+ type: DataTypes.JSON,
127
+ // { positive: 0.8, negative: 0.2, topComplaints: [] }
128
+ },
129
+ priceElasticity: DataTypes.FLOAT,
130
+ optimalPriceRange: DataTypes.JSON
131
+ });
132
+
133
+ // Konuşma Geçmişi (Session bazlı)
134
+ this.models.ConversationMemory = this.db.define('ConversationMemory', {
135
+ id: {
136
+ type: DataTypes.UUID,
137
+ defaultValue: DataTypes.UUIDV4,
138
+ primaryKey: true
139
+ },
140
+ sessionKey: DataTypes.STRING,
141
+ userId: DataTypes.STRING,
142
+ channel: DataTypes.STRING,
143
+ role: {
144
+ type: DataTypes.STRING,
145
+ // user, assistant
146
+ },
147
+ content: DataTypes.TEXT,
148
+ intent: DataTypes.STRING,
149
+ entities: DataTypes.JSON,
150
+ actionTaken: DataTypes.STRING
151
+ });
152
+
153
+ // Öğrenilen Kurallar
154
+ this.models.LearnedRule = this.db.define('LearnedRule', {
155
+ id: {
156
+ type: DataTypes.UUID,
157
+ defaultValue: DataTypes.UUIDV4,
158
+ primaryKey: true
159
+ },
160
+ trigger: DataTypes.TEXT,
161
+ condition: DataTypes.JSON,
162
+ action: DataTypes.TEXT,
163
+ confidence: {
164
+ type: DataTypes.FLOAT,
165
+ defaultValue: 0.5
166
+ },
167
+ usageCount: {
168
+ type: DataTypes.INTEGER,
169
+ defaultValue: 0
170
+ },
171
+ successRate: {
172
+ type: DataTypes.FLOAT,
173
+ defaultValue: 0.5
174
+ }
175
+ });
176
+
177
+ await this.db.sync({ alter: true });
178
+ this.initialized = true;
179
+ this.logger.info('🧠 Hippocampus veritabanı hazır.');
180
+
181
+ // Hafıza konsolidasyonu zamanlayıcısı (her gece)
182
+ this._startConsolidation();
183
+ }
184
+
185
+ // ═══════════════════════════════════════════════════════════════════════════
186
+ // HAFIZA KAYDETME
187
+ // ═══════════════════════════════════════════════════════════════════════════
188
+
189
+ async remember(type, content, context = {}, options = {}) {
190
+ const memory = await this.models.Memory.create({
191
+ type,
192
+ content: typeof content === 'string' ? content : JSON.stringify(content),
193
+ context,
194
+ importance: options.importance || this._calculateImportance(type, content),
195
+ tags: options.tags || [],
196
+ expiresAt: options.temporary ? new Date(Date.now() + 24 * 60 * 60 * 1000) : null
197
+ });
198
+
199
+ this.logger.debug(`💾 Hafıza kaydedildi: ${type} - ${memory.id}`);
200
+ return memory;
201
+ }
202
+
203
+ async recordPricingDecision(decision) {
204
+ return await this.models.PricingDecision.create(decision);
205
+ }
206
+
207
+ async updateProductContext(barcode, updates) {
208
+ const [context, created] = await this.models.ProductContext.findOrCreate({
209
+ where: { barcode },
210
+ defaults: { barcode, ...updates }
211
+ });
212
+
213
+ if (!created) {
214
+ await context.update(updates);
215
+ }
216
+
217
+ return context;
218
+ }
219
+
220
+ async recordConversation(sessionKey, userId, channel, role, content, metadata = {}) {
221
+ return await this.models.ConversationMemory.create({
222
+ sessionKey,
223
+ userId,
224
+ channel,
225
+ role,
226
+ content,
227
+ intent: metadata.intent,
228
+ entities: metadata.entities,
229
+ actionTaken: metadata.action
230
+ });
231
+ }
232
+
233
+ // ═══════════════════════════════════════════════════════════════════════════
234
+ // HAFIZA ARAMA
235
+ // ═══════════════════════════════════════════════════════════════════════════
236
+
237
+ async search({ query, type, limit = 10, minImportance = 0 }) {
238
+ const where = {};
239
+
240
+ if (type && type !== 'all') {
241
+ where.type = type;
242
+ }
243
+
244
+ if (minImportance > 0) {
245
+ where.importance = { [Op.gte]: minImportance };
246
+ }
247
+
248
+ // Basit metin araması (ileride vektör araması eklenebilir)
249
+ if (query) {
250
+ where.content = { [Op.like]: `%${query}%` };
251
+ }
252
+
253
+ const memories = await this.models.Memory.findAll({
254
+ where,
255
+ order: [['importance', 'DESC'], ['createdAt', 'DESC']],
256
+ limit
257
+ });
258
+
259
+ // Erişim sayacını güncelle
260
+ for (const mem of memories) {
261
+ await mem.update({
262
+ accessCount: mem.accessCount + 1,
263
+ lastAccessed: new Date()
264
+ });
265
+ }
266
+
267
+ return memories.map(m => ({
268
+ id: m.id,
269
+ type: m.type,
270
+ content: m.content,
271
+ context: m.context,
272
+ importance: m.importance,
273
+ createdAt: m.createdAt
274
+ }));
275
+ }
276
+
277
+ async getProductContext(barcode) {
278
+ return await this.models.ProductContext.findOne({ where: { barcode } });
279
+ }
280
+
281
+ async getPricingHistory(barcode, limit = 10) {
282
+ return await this.models.PricingDecision.findAll({
283
+ where: { barcode },
284
+ order: [['createdAt', 'DESC']],
285
+ limit
286
+ });
287
+ }
288
+
289
+ async getRecentConversations(sessionKey, limit = 20) {
290
+ return await this.models.ConversationMemory.findAll({
291
+ where: { sessionKey },
292
+ order: [['createdAt', 'DESC']],
293
+ limit
294
+ });
295
+ }
296
+
297
+ async getLearnedRules(trigger) {
298
+ return await this.models.LearnedRule.findAll({
299
+ where: {
300
+ trigger: { [Op.like]: `%${trigger}%` },
301
+ confidence: { [Op.gte]: 0.6 }
302
+ },
303
+ order: [['confidence', 'DESC'], ['usageCount', 'DESC']]
304
+ });
305
+ }
306
+
307
+ // ═══════════════════════════════════════════════════════════════════════════
308
+ // BAĞLAMSAL HATIRLATMA
309
+ // ═══════════════════════════════════════════════════════════════════════════
310
+
311
+ async getRelevantContext(input, options = {}) {
312
+ const context = {
313
+ recentDecisions: [],
314
+ productHistory: null,
315
+ relatedMemories: [],
316
+ applicableRules: []
317
+ };
318
+
319
+ // Ürün barkodu varsa ürün bağlamını al
320
+ if (options.barcode) {
321
+ context.productHistory = await this.getProductContext(options.barcode);
322
+ context.recentDecisions = await this.getPricingHistory(options.barcode, 5);
323
+ }
324
+
325
+ // İlgili hafızaları ara
326
+ context.relatedMemories = await this.search({
327
+ query: input,
328
+ type: options.type || 'all',
329
+ limit: 5,
330
+ minImportance: 0.3
331
+ });
332
+
333
+ // Uygulanabilir kuralları bul
334
+ context.applicableRules = await this.getLearnedRules(input);
335
+
336
+ return context;
337
+ }
338
+
339
+ // ═══════════════════════════════════════════════════════════════════════════
340
+ // ÖĞRENME & KONSOLİDASYON
341
+ // ═══════════════════════════════════════════════════════════════════════════
342
+
343
+ async learnRule(trigger, condition, action) {
344
+ const existing = await this.models.LearnedRule.findOne({
345
+ where: { trigger, action }
346
+ });
347
+
348
+ if (existing) {
349
+ await existing.update({
350
+ usageCount: existing.usageCount + 1,
351
+ confidence: Math.min(1, existing.confidence + 0.05)
352
+ });
353
+ return existing;
354
+ }
355
+
356
+ return await this.models.LearnedRule.create({
357
+ trigger,
358
+ condition,
359
+ action,
360
+ confidence: 0.5
361
+ });
362
+ }
363
+
364
+ async recordRuleOutcome(ruleId, success) {
365
+ const rule = await this.models.LearnedRule.findByPk(ruleId);
366
+ if (!rule) return;
367
+
368
+ const newSuccessRate = (rule.successRate * rule.usageCount + (success ? 1 : 0)) / (rule.usageCount + 1);
369
+ const newConfidence = success
370
+ ? Math.min(1, rule.confidence + 0.1)
371
+ : Math.max(0, rule.confidence - 0.1);
372
+
373
+ await rule.update({
374
+ usageCount: rule.usageCount + 1,
375
+ successRate: newSuccessRate,
376
+ confidence: newConfidence
377
+ });
378
+ }
379
+
380
+ _startConsolidation() {
381
+ // Her gece saat 3'te çalış
382
+ const now = new Date();
383
+ const night = new Date(now);
384
+ night.setHours(3, 0, 0, 0);
385
+ if (night <= now) night.setDate(night.getDate() + 1);
386
+
387
+ const delay = night - now;
388
+
389
+ setTimeout(() => {
390
+ this._consolidate();
391
+ // Sonra her 24 saatte bir
392
+ setInterval(() => this._consolidate(), 24 * 60 * 60 * 1000);
393
+ }, delay);
394
+ }
395
+
396
+ async _consolidate() {
397
+ this.logger.info('🧠 Hafıza konsolidasyonu başlıyor...');
398
+
399
+ // 1. Süresi dolmuş hafızaları sil
400
+ await this.models.Memory.destroy({
401
+ where: {
402
+ expiresAt: { [Op.lt]: new Date() }
403
+ }
404
+ });
405
+
406
+ // 2. Düşük önemli ve erişilmeyen hafızaları "unut"
407
+ const oldDate = new Date(Date.now() - 90 * 24 * 60 * 60 * 1000); // 90 gün
408
+ await this.models.Memory.destroy({
409
+ where: {
410
+ importance: { [Op.lt]: 0.3 },
411
+ accessCount: { [Op.lt]: 3 },
412
+ lastAccessed: { [Op.lt]: oldDate }
413
+ }
414
+ });
415
+
416
+ // 3. Düşük güvenilirlikli kuralları sil
417
+ await this.models.LearnedRule.destroy({
418
+ where: {
419
+ confidence: { [Op.lt]: 0.2 },
420
+ usageCount: { [Op.gt]: 10 }
421
+ }
422
+ });
423
+
424
+ this.logger.info('🧠 Hafıza konsolidasyonu tamamlandı.');
425
+ }
426
+
427
+ _calculateImportance(type, content) {
428
+ // Tip bazlı temel önem
429
+ const baseImportance = {
430
+ decision: 0.8,
431
+ price_change: 0.7,
432
+ insight: 0.6,
433
+ rule: 0.9,
434
+ product: 0.5,
435
+ conversation: 0.3
436
+ };
437
+
438
+ return baseImportance[type] || 0.5;
439
+ }
440
+
441
+ // ═══════════════════════════════════════════════════════════════════════════
442
+ // İSTATİSTİKLER
443
+ // ═══════════════════════════════════════════════════════════════════════════
444
+
445
+ async getStats() {
446
+ const memoryCount = await this.models.Memory.count();
447
+ const decisionCount = await this.models.PricingDecision.count();
448
+ const productCount = await this.models.ProductContext.count();
449
+ const ruleCount = await this.models.LearnedRule.count();
450
+
451
+ return {
452
+ memories: memoryCount,
453
+ decisions: decisionCount,
454
+ products: productCount,
455
+ rules: ruleCount,
456
+ initialized: this.initialized
457
+ };
458
+ }
459
+
460
+ async close() {
461
+ if (this.db) {
462
+ await this.db.close();
463
+ }
464
+ }
465
+ }