vantuz 3.0.1 โ 3.1.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/cli.js +197 -109
- package/core/ai-provider.js +252 -0
- package/core/channels.js +334 -0
- package/core/engine.js +373 -0
- package/package.json +6 -3
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ๐ค AI Provider Integration v3.1
|
|
3
|
+
* Gerรงek AI API รงaฤrฤฑlarฤฑ + Context desteฤi
|
|
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
|
+
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
14
|
+
// LOGGING
|
|
15
|
+
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
16
|
+
|
|
17
|
+
export function log(level, message, data = null) {
|
|
18
|
+
const timestamp = new Date().toISOString();
|
|
19
|
+
const logLine = `[${timestamp}] [${level}] ${message}${data ? ' | ' + JSON.stringify(data) : ''}\n`;
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
fs.appendFileSync(LOG_FILE, logLine);
|
|
23
|
+
} catch (e) { }
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function getLogs(lines = 50) {
|
|
27
|
+
try {
|
|
28
|
+
if (!fs.existsSync(LOG_FILE)) {
|
|
29
|
+
return 'Log dosyasฤฑ bulunamadฤฑ.';
|
|
30
|
+
}
|
|
31
|
+
const content = fs.readFileSync(LOG_FILE, 'utf-8');
|
|
32
|
+
const allLines = content.split('\n').filter(l => l.trim());
|
|
33
|
+
return allLines.slice(-lines).join('\n');
|
|
34
|
+
} catch (e) {
|
|
35
|
+
return `Log okuma hatasฤฑ: ${e.message}`;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function clearLogs() {
|
|
40
|
+
try {
|
|
41
|
+
fs.writeFileSync(LOG_FILE, '');
|
|
42
|
+
return true;
|
|
43
|
+
} catch (e) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
49
|
+
// SYSTEM PROMPT
|
|
50
|
+
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
51
|
+
|
|
52
|
+
const VANTUZ_SYSTEM_PROMPT = `Sen Vantuz AI, e-ticaret operasyonlarฤฑnฤฑ yรถneten yapay zeka asistanฤฑsฤฑn.
|
|
53
|
+
|
|
54
|
+
## Kimliฤin
|
|
55
|
+
- ฤฐsim: Vantuz AI
|
|
56
|
+
- Uzmanlฤฑk: E-ticaret yรถnetimi, pazaryeri entegrasyonlarฤฑ, fiyatlandฤฑrma stratejileri
|
|
57
|
+
- Dil: Tรผrkรงe
|
|
58
|
+
- Kiลilik: Profesyonel, รงรถzรผm odaklฤฑ, verimli
|
|
59
|
+
|
|
60
|
+
## Desteklenen Pazaryerleri
|
|
61
|
+
1. ๐ Trendyol - Tam entegrasyon
|
|
62
|
+
2. ๐ฃ Hepsiburada - Tam entegrasyon
|
|
63
|
+
3. ๐ต N11 - Tam entegrasyon
|
|
64
|
+
4. ๐ก Amazon - FBA destekli
|
|
65
|
+
5. ๐ธ รiรงeksepeti - Entegre
|
|
66
|
+
6. ๐ฎ PTTavm - Entegre
|
|
67
|
+
7. ๐ Pazarama - Entegre
|
|
68
|
+
|
|
69
|
+
## Yeteneklerin
|
|
70
|
+
- Stok kontrolรผ ve gรผncelleme
|
|
71
|
+
- Fiyat analizi ve gรผncelleme
|
|
72
|
+
- Sipariล yรถnetimi
|
|
73
|
+
- Rakip analizi
|
|
74
|
+
- Satฤฑล raporlarฤฑ
|
|
75
|
+
|
|
76
|
+
## รnemli Kurallar
|
|
77
|
+
1. Kar marjฤฑnฤฑn altฤฑna fiyat dรผลรผrme รถnerme
|
|
78
|
+
2. Stokta olmayan รผrรผnรผ satฤฑลa aรงma
|
|
79
|
+
3. Kritik iลlemlerden รถnce onay iste
|
|
80
|
+
4. Kฤฑsa ve รถz yanฤฑt ver
|
|
81
|
+
5. Sayฤฑsal verileri dรผzgรผn formatla
|
|
82
|
+
|
|
83
|
+
## Yanฤฑt Formatฤฑ
|
|
84
|
+
- Kฤฑsa ve รถz ol
|
|
85
|
+
- Emoji kullan ama abartma
|
|
86
|
+
- Sayฤฑsal verileri tablo formatฤฑnda gรถster
|
|
87
|
+
- Hata durumunda รงรถzรผm รถner`;
|
|
88
|
+
|
|
89
|
+
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
90
|
+
// AI CHAT
|
|
91
|
+
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
92
|
+
|
|
93
|
+
export async function chat(message, config, env) {
|
|
94
|
+
const provider = config.aiProvider || 'gemini';
|
|
95
|
+
|
|
96
|
+
// Context bilgisi ekle
|
|
97
|
+
const contextInfo = config.systemContext || '';
|
|
98
|
+
const fullSystemPrompt = VANTUZ_SYSTEM_PROMPT + contextInfo;
|
|
99
|
+
|
|
100
|
+
log('INFO', `AI isteฤi: ${provider}`, { message: message.slice(0, 100) });
|
|
101
|
+
|
|
102
|
+
try {
|
|
103
|
+
switch (provider) {
|
|
104
|
+
case 'gemini':
|
|
105
|
+
return await chatGemini(message, env.GEMINI_API_KEY, fullSystemPrompt);
|
|
106
|
+
case 'groq':
|
|
107
|
+
return await chatGroq(message, env.GROQ_API_KEY, fullSystemPrompt);
|
|
108
|
+
case 'openai':
|
|
109
|
+
return await chatOpenAI(message, env.OPENAI_API_KEY, fullSystemPrompt);
|
|
110
|
+
case 'anthropic':
|
|
111
|
+
return await chatAnthropic(message, env.ANTHROPIC_API_KEY, fullSystemPrompt);
|
|
112
|
+
case 'deepseek':
|
|
113
|
+
return await chatDeepSeek(message, env.DEEPSEEK_API_KEY, fullSystemPrompt);
|
|
114
|
+
default:
|
|
115
|
+
return 'Desteklenmeyen AI saฤlayฤฑcฤฑ: ' + provider;
|
|
116
|
+
}
|
|
117
|
+
} catch (error) {
|
|
118
|
+
log('ERROR', `AI hatasฤฑ: ${error.message}`, { provider });
|
|
119
|
+
return `AI hatasฤฑ: ${error.message}. /logs komutu ile detay gรถrรผn.`;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
124
|
+
// PROVIDER IMPLEMENTATIONS
|
|
125
|
+
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
126
|
+
|
|
127
|
+
async function chatGemini(message, apiKey, systemPrompt) {
|
|
128
|
+
if (!apiKey) throw new Error('GEMINI_API_KEY ayarlanmamฤฑล');
|
|
129
|
+
|
|
130
|
+
const url = `https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key=${apiKey}`;
|
|
131
|
+
|
|
132
|
+
const response = await axios.post(url, {
|
|
133
|
+
contents: [{
|
|
134
|
+
parts: [{
|
|
135
|
+
text: `${systemPrompt}\n\nKullanฤฑcฤฑ: ${message}`
|
|
136
|
+
}]
|
|
137
|
+
}]
|
|
138
|
+
}, {
|
|
139
|
+
headers: { 'Content-Type': 'application/json' },
|
|
140
|
+
timeout: 30000
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
const text = response.data?.candidates?.[0]?.content?.parts?.[0]?.text;
|
|
144
|
+
if (!text) throw new Error('Gemini yanฤฑt vermedi');
|
|
145
|
+
|
|
146
|
+
log('INFO', 'Gemini yanฤฑtฤฑ alฤฑndฤฑ', { chars: text.length });
|
|
147
|
+
return text;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
async function chatGroq(message, apiKey, systemPrompt) {
|
|
151
|
+
if (!apiKey) throw new Error('GROQ_API_KEY ayarlanmamฤฑล');
|
|
152
|
+
|
|
153
|
+
const response = await axios.post('https://api.groq.com/openai/v1/chat/completions', {
|
|
154
|
+
model: 'llama-3.3-70b-versatile',
|
|
155
|
+
messages: [
|
|
156
|
+
{ role: 'system', content: systemPrompt },
|
|
157
|
+
{ role: 'user', content: message }
|
|
158
|
+
],
|
|
159
|
+
max_tokens: 1000,
|
|
160
|
+
temperature: 0.7
|
|
161
|
+
}, {
|
|
162
|
+
headers: {
|
|
163
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
164
|
+
'Content-Type': 'application/json'
|
|
165
|
+
},
|
|
166
|
+
timeout: 30000
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
const text = response.data?.choices?.[0]?.message?.content;
|
|
170
|
+
if (!text) throw new Error('Groq yanฤฑt vermedi');
|
|
171
|
+
|
|
172
|
+
log('INFO', 'Groq yanฤฑtฤฑ alฤฑndฤฑ', { chars: text.length });
|
|
173
|
+
return text;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
async function chatOpenAI(message, apiKey, systemPrompt) {
|
|
177
|
+
if (!apiKey) throw new Error('OPENAI_API_KEY ayarlanmamฤฑล');
|
|
178
|
+
|
|
179
|
+
const response = await axios.post('https://api.openai.com/v1/chat/completions', {
|
|
180
|
+
model: 'gpt-4o-mini',
|
|
181
|
+
messages: [
|
|
182
|
+
{ role: 'system', content: systemPrompt },
|
|
183
|
+
{ role: 'user', content: message }
|
|
184
|
+
],
|
|
185
|
+
max_tokens: 1000
|
|
186
|
+
}, {
|
|
187
|
+
headers: {
|
|
188
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
189
|
+
'Content-Type': 'application/json'
|
|
190
|
+
},
|
|
191
|
+
timeout: 30000
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
const text = response.data?.choices?.[0]?.message?.content;
|
|
195
|
+
if (!text) throw new Error('OpenAI yanฤฑt vermedi');
|
|
196
|
+
|
|
197
|
+
log('INFO', 'OpenAI yanฤฑtฤฑ alฤฑndฤฑ', { chars: text.length });
|
|
198
|
+
return text;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
async function chatAnthropic(message, apiKey, systemPrompt) {
|
|
202
|
+
if (!apiKey) throw new Error('ANTHROPIC_API_KEY ayarlanmamฤฑล');
|
|
203
|
+
|
|
204
|
+
const response = await axios.post('https://api.anthropic.com/v1/messages', {
|
|
205
|
+
model: 'claude-3-haiku-20240307',
|
|
206
|
+
max_tokens: 1000,
|
|
207
|
+
messages: [
|
|
208
|
+
{ role: 'user', content: message }
|
|
209
|
+
],
|
|
210
|
+
system: systemPrompt
|
|
211
|
+
}, {
|
|
212
|
+
headers: {
|
|
213
|
+
'x-api-key': apiKey,
|
|
214
|
+
'anthropic-version': '2023-06-01',
|
|
215
|
+
'Content-Type': 'application/json'
|
|
216
|
+
},
|
|
217
|
+
timeout: 30000
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
const text = response.data?.content?.[0]?.text;
|
|
221
|
+
if (!text) throw new Error('Anthropic yanฤฑt vermedi');
|
|
222
|
+
|
|
223
|
+
log('INFO', 'Anthropic yanฤฑtฤฑ alฤฑndฤฑ', { chars: text.length });
|
|
224
|
+
return text;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
async function chatDeepSeek(message, apiKey, systemPrompt) {
|
|
228
|
+
if (!apiKey) throw new Error('DEEPSEEK_API_KEY ayarlanmamฤฑล');
|
|
229
|
+
|
|
230
|
+
const response = await axios.post('https://api.deepseek.com/v1/chat/completions', {
|
|
231
|
+
model: 'deepseek-chat',
|
|
232
|
+
messages: [
|
|
233
|
+
{ role: 'system', content: systemPrompt },
|
|
234
|
+
{ role: 'user', content: message }
|
|
235
|
+
],
|
|
236
|
+
max_tokens: 1000
|
|
237
|
+
}, {
|
|
238
|
+
headers: {
|
|
239
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
240
|
+
'Content-Type': 'application/json'
|
|
241
|
+
},
|
|
242
|
+
timeout: 30000
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
const text = response.data?.choices?.[0]?.message?.content;
|
|
246
|
+
if (!text) throw new Error('DeepSeek yanฤฑt vermedi');
|
|
247
|
+
|
|
248
|
+
log('INFO', 'DeepSeek yanฤฑtฤฑ alฤฑndฤฑ', { chars: text.length });
|
|
249
|
+
return text;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export default { chat, log, getLogs, clearLogs };
|
package/core/channels.js
ADDED
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ๐ฑ CHANNEL MANAGER
|
|
3
|
+
* WhatsApp ve Telegram entegrasyonu
|
|
4
|
+
*
|
|
5
|
+
* OpenClaw altyapฤฑsฤฑ รผzerine kurulu
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import os from 'os';
|
|
11
|
+
import axios from 'axios';
|
|
12
|
+
import { log } from './ai-provider.js';
|
|
13
|
+
|
|
14
|
+
const VANTUZ_HOME = path.join(os.homedir(), '.vantuz');
|
|
15
|
+
const CONFIG_PATH = path.join(VANTUZ_HOME, '.env');
|
|
16
|
+
|
|
17
|
+
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
18
|
+
// CHANNEL BASE CLASS
|
|
19
|
+
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
20
|
+
|
|
21
|
+
class Channel {
|
|
22
|
+
constructor(name, config) {
|
|
23
|
+
this.name = name;
|
|
24
|
+
this.config = config;
|
|
25
|
+
this.connected = false;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async connect() {
|
|
29
|
+
throw new Error('connect() must be implemented');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async send(to, message) {
|
|
33
|
+
throw new Error('send() must be implemented');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async startListening(onMessage) {
|
|
37
|
+
throw new Error('startListening() must be implemented');
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
42
|
+
// WHATSAPP (via WhatsApp Business API / Twilio / Meta Cloud API)
|
|
43
|
+
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
44
|
+
|
|
45
|
+
export class WhatsAppChannel extends Channel {
|
|
46
|
+
constructor(config) {
|
|
47
|
+
super('whatsapp', config);
|
|
48
|
+
this.apiUrl = config.apiUrl || 'https://graph.facebook.com/v17.0';
|
|
49
|
+
this.phoneNumberId = config.phoneNumberId;
|
|
50
|
+
this.accessToken = config.accessToken;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async connect() {
|
|
54
|
+
if (!this.phoneNumberId || !this.accessToken) {
|
|
55
|
+
log('ERROR', 'WhatsApp: phoneNumberId veya accessToken eksik');
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
// Verify connection
|
|
61
|
+
const response = await axios.get(
|
|
62
|
+
`${this.apiUrl}/${this.phoneNumberId}`,
|
|
63
|
+
{
|
|
64
|
+
headers: { 'Authorization': `Bearer ${this.accessToken}` }
|
|
65
|
+
}
|
|
66
|
+
);
|
|
67
|
+
this.connected = response.status === 200;
|
|
68
|
+
log('INFO', 'WhatsApp baฤlantฤฑsฤฑ kuruldu', { phoneNumberId: this.phoneNumberId });
|
|
69
|
+
return true;
|
|
70
|
+
} catch (e) {
|
|
71
|
+
log('ERROR', 'WhatsApp baฤlantฤฑ hatasฤฑ', { error: e.message });
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async send(to, message) {
|
|
77
|
+
if (!this.connected) {
|
|
78
|
+
await this.connect();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
const response = await axios.post(
|
|
83
|
+
`${this.apiUrl}/${this.phoneNumberId}/messages`,
|
|
84
|
+
{
|
|
85
|
+
messaging_product: 'whatsapp',
|
|
86
|
+
recipient_type: 'individual',
|
|
87
|
+
to: to,
|
|
88
|
+
type: 'text',
|
|
89
|
+
text: { body: message }
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
headers: {
|
|
93
|
+
'Authorization': `Bearer ${this.accessToken}`,
|
|
94
|
+
'Content-Type': 'application/json'
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
log('INFO', 'WhatsApp mesaj gรถnderildi', { to, messageId: response.data?.messages?.[0]?.id });
|
|
100
|
+
return { success: true, messageId: response.data?.messages?.[0]?.id };
|
|
101
|
+
} catch (e) {
|
|
102
|
+
log('ERROR', 'WhatsApp gรถnderme hatasฤฑ', { error: e.message });
|
|
103
|
+
return { success: false, error: e.message };
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Webhook handler iรงin
|
|
108
|
+
handleWebhook(body) {
|
|
109
|
+
const entry = body.entry?.[0];
|
|
110
|
+
const changes = entry?.changes?.[0];
|
|
111
|
+
const value = changes?.value;
|
|
112
|
+
const message = value?.messages?.[0];
|
|
113
|
+
|
|
114
|
+
if (message) {
|
|
115
|
+
return {
|
|
116
|
+
from: message.from,
|
|
117
|
+
text: message.text?.body || '',
|
|
118
|
+
timestamp: message.timestamp,
|
|
119
|
+
messageId: message.id
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
127
|
+
// TELEGRAM (via Telegram Bot API)
|
|
128
|
+
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
129
|
+
|
|
130
|
+
export class TelegramChannel extends Channel {
|
|
131
|
+
constructor(config) {
|
|
132
|
+
super('telegram', config);
|
|
133
|
+
this.botToken = config.botToken;
|
|
134
|
+
this.apiUrl = `https://api.telegram.org/bot${this.botToken}`;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async connect() {
|
|
138
|
+
if (!this.botToken) {
|
|
139
|
+
log('ERROR', 'Telegram: botToken eksik');
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
try {
|
|
144
|
+
const response = await axios.get(`${this.apiUrl}/getMe`);
|
|
145
|
+
if (response.data.ok) {
|
|
146
|
+
this.botInfo = response.data.result;
|
|
147
|
+
this.connected = true;
|
|
148
|
+
log('INFO', 'Telegram baฤlantฤฑsฤฑ kuruldu', { username: this.botInfo.username });
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
return false;
|
|
152
|
+
} catch (e) {
|
|
153
|
+
log('ERROR', 'Telegram baฤlantฤฑ hatasฤฑ', { error: e.message });
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
async send(chatId, message, options = {}) {
|
|
159
|
+
if (!this.connected) {
|
|
160
|
+
await this.connect();
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
try {
|
|
164
|
+
const response = await axios.post(`${this.apiUrl}/sendMessage`, {
|
|
165
|
+
chat_id: chatId,
|
|
166
|
+
text: message,
|
|
167
|
+
parse_mode: options.parseMode || 'HTML',
|
|
168
|
+
...options
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
log('INFO', 'Telegram mesaj gรถnderildi', { chatId, messageId: response.data?.result?.message_id });
|
|
172
|
+
return { success: true, messageId: response.data?.result?.message_id };
|
|
173
|
+
} catch (e) {
|
|
174
|
+
log('ERROR', 'Telegram gรถnderme hatasฤฑ', { error: e.message });
|
|
175
|
+
return { success: false, error: e.message };
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async setWebhook(url) {
|
|
180
|
+
try {
|
|
181
|
+
const response = await axios.post(`${this.apiUrl}/setWebhook`, {
|
|
182
|
+
url: url,
|
|
183
|
+
allowed_updates: ['message', 'callback_query']
|
|
184
|
+
});
|
|
185
|
+
log('INFO', 'Telegram webhook ayarlandฤฑ', { url });
|
|
186
|
+
return response.data.ok;
|
|
187
|
+
} catch (e) {
|
|
188
|
+
log('ERROR', 'Telegram webhook hatasฤฑ', { error: e.message });
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async getUpdates(offset = 0) {
|
|
194
|
+
try {
|
|
195
|
+
const response = await axios.post(`${this.apiUrl}/getUpdates`, {
|
|
196
|
+
offset,
|
|
197
|
+
timeout: 30
|
|
198
|
+
});
|
|
199
|
+
return response.data.result || [];
|
|
200
|
+
} catch (e) {
|
|
201
|
+
log('ERROR', 'Telegram getUpdates hatasฤฑ', { error: e.message });
|
|
202
|
+
return [];
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Long polling mode
|
|
207
|
+
async startPolling(onMessage) {
|
|
208
|
+
let offset = 0;
|
|
209
|
+
log('INFO', 'Telegram polling baลlatฤฑldฤฑ');
|
|
210
|
+
|
|
211
|
+
while (true) {
|
|
212
|
+
try {
|
|
213
|
+
const updates = await this.getUpdates(offset);
|
|
214
|
+
|
|
215
|
+
for (const update of updates) {
|
|
216
|
+
offset = update.update_id + 1;
|
|
217
|
+
|
|
218
|
+
if (update.message?.text) {
|
|
219
|
+
const msg = {
|
|
220
|
+
chatId: update.message.chat.id,
|
|
221
|
+
from: update.message.from,
|
|
222
|
+
text: update.message.text,
|
|
223
|
+
messageId: update.message.message_id
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
// Callback
|
|
227
|
+
if (onMessage) {
|
|
228
|
+
const response = await onMessage(msg);
|
|
229
|
+
if (response) {
|
|
230
|
+
await this.send(msg.chatId, response);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
} catch (e) {
|
|
236
|
+
log('ERROR', 'Polling hatasฤฑ', { error: e.message });
|
|
237
|
+
await new Promise(r => setTimeout(r, 5000));
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
244
|
+
// CHANNEL MANAGER
|
|
245
|
+
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
246
|
+
|
|
247
|
+
export class ChannelManager {
|
|
248
|
+
constructor() {
|
|
249
|
+
this.channels = {};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
loadEnv() {
|
|
253
|
+
const env = {};
|
|
254
|
+
try {
|
|
255
|
+
if (fs.existsSync(CONFIG_PATH)) {
|
|
256
|
+
const content = fs.readFileSync(CONFIG_PATH, 'utf-8');
|
|
257
|
+
content.split('\n').forEach(line => {
|
|
258
|
+
const match = line.match(/^([^=]+)=(.*)$/);
|
|
259
|
+
if (match) {
|
|
260
|
+
env[match[1].trim()] = match[2].trim();
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
} catch (e) { }
|
|
265
|
+
return env;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
async initAll() {
|
|
269
|
+
const env = this.loadEnv();
|
|
270
|
+
const results = {};
|
|
271
|
+
|
|
272
|
+
// WhatsApp
|
|
273
|
+
if (env.WHATSAPP_PHONE_NUMBER_ID && env.WHATSAPP_ACCESS_TOKEN) {
|
|
274
|
+
const wa = new WhatsAppChannel({
|
|
275
|
+
phoneNumberId: env.WHATSAPP_PHONE_NUMBER_ID,
|
|
276
|
+
accessToken: env.WHATSAPP_ACCESS_TOKEN
|
|
277
|
+
});
|
|
278
|
+
if (await wa.connect()) {
|
|
279
|
+
this.channels.whatsapp = wa;
|
|
280
|
+
results.whatsapp = true;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Telegram
|
|
285
|
+
if (env.TELEGRAM_BOT_TOKEN) {
|
|
286
|
+
const tg = new TelegramChannel({
|
|
287
|
+
botToken: env.TELEGRAM_BOT_TOKEN
|
|
288
|
+
});
|
|
289
|
+
if (await tg.connect()) {
|
|
290
|
+
this.channels.telegram = tg;
|
|
291
|
+
results.telegram = true;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return results;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
getChannel(name) {
|
|
299
|
+
return this.channels[name];
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
getConnected() {
|
|
303
|
+
return Object.keys(this.channels);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
async broadcast(message, channels = 'all') {
|
|
307
|
+
const targets = channels === 'all'
|
|
308
|
+
? Object.keys(this.channels)
|
|
309
|
+
: channels.split(',');
|
|
310
|
+
|
|
311
|
+
const results = {};
|
|
312
|
+
for (const ch of targets) {
|
|
313
|
+
if (this.channels[ch]) {
|
|
314
|
+
// Not: WhatsApp ve Telegram iรงin farklฤฑ recipient gerekir
|
|
315
|
+
// Bu รถrnek bir demonstration, gerรงek kullanฤฑmda recipient listesi lazฤฑm
|
|
316
|
+
results[ch] = 'Channel ready';
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return results;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Singleton
|
|
324
|
+
let managerInstance = null;
|
|
325
|
+
|
|
326
|
+
export async function getChannelManager() {
|
|
327
|
+
if (!managerInstance) {
|
|
328
|
+
managerInstance = new ChannelManager();
|
|
329
|
+
await managerInstance.initAll();
|
|
330
|
+
}
|
|
331
|
+
return managerInstance;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
export default ChannelManager;
|