neogram 9.3.0 → 9.3.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/README.md +623 -1001
- package/examples/README.md +47 -0
- package/examples/ai-bot.js +155 -0
- package/examples/simple-bot.js +30 -0
- package/examples/test-bot-debug.js +26 -0
- package/examples/test-bot-full.js +221 -0
- package/examples/test-bot.js +196 -0
- package/package.json +6 -11
- package/src/ai/OnlySQ.js +6 -2
- package/types/index.d.ts +2 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Примеры использования neogram-js
|
|
2
|
+
|
|
3
|
+
## Запуск тестового бота
|
|
4
|
+
|
|
5
|
+
1. Создай бота через [@BotFather](https://t.me/botfather)
|
|
6
|
+
2. Получи токен
|
|
7
|
+
3. Экспортируй токен:
|
|
8
|
+
|
|
9
|
+
\`\`\`bash
|
|
10
|
+
export BOT_TOKEN="your_bot_token_here"
|
|
11
|
+
\`\`\`
|
|
12
|
+
|
|
13
|
+
4. Запусти бота:
|
|
14
|
+
|
|
15
|
+
\`\`\`bash
|
|
16
|
+
node examples/test-bot.js
|
|
17
|
+
\`\`\`
|
|
18
|
+
|
|
19
|
+
## Простой эхо-бот
|
|
20
|
+
|
|
21
|
+
\`\`\`bash
|
|
22
|
+
export BOT_TOKEN="your_token"
|
|
23
|
+
node examples/simple-bot.js
|
|
24
|
+
\`\`\`
|
|
25
|
+
|
|
26
|
+
## Доступные команды в test-bot
|
|
27
|
+
|
|
28
|
+
- \`/start\` - Приветствие и список команд
|
|
29
|
+
- \`/test\` - Тест основных функций
|
|
30
|
+
- \`/photo\` - Отправка фото
|
|
31
|
+
- \`/poll\` - Создание опроса
|
|
32
|
+
- \`/dice\` - Бросить кубик
|
|
33
|
+
- \`/location\` - Отправить локацию
|
|
34
|
+
- \`/keyboard\` - Показать клавиатуру
|
|
35
|
+
- \`/inline\` - Inline кнопки
|
|
36
|
+
- \`/help\` - Помощь
|
|
37
|
+
|
|
38
|
+
## Что тестируется
|
|
39
|
+
|
|
40
|
+
- ✅ Long polling (getUpdates)
|
|
41
|
+
- ✅ Отправка сообщений
|
|
42
|
+
- ✅ Отправка медиа (фото)
|
|
43
|
+
- ✅ Опросы
|
|
44
|
+
- ✅ Действия (typing, dice)
|
|
45
|
+
- ✅ Локации
|
|
46
|
+
- ✅ Клавиатуры (reply & inline)
|
|
47
|
+
- ✅ Обработка команд
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { Bot } from '../src/Bot.js';
|
|
2
|
+
import axios from 'axios';
|
|
3
|
+
|
|
4
|
+
const BOT_TOKEN = process.env.BOT_TOKEN;
|
|
5
|
+
const ONLYSQ_API_KEY = process.env.ONLYSQ_API_KEY || 'openai';
|
|
6
|
+
const ONLYSQ_API_URL = 'https://api.onlysq.ru/ai/openai/chat/completions';
|
|
7
|
+
|
|
8
|
+
if (!BOT_TOKEN) {
|
|
9
|
+
console.error('❌ Установи BOT_TOKEN');
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const bot = new Bot(BOT_TOKEN);
|
|
14
|
+
const conversations = new Map();
|
|
15
|
+
|
|
16
|
+
console.log('🤖 AI Бот запускается...');
|
|
17
|
+
|
|
18
|
+
async function callOnlySQ(messages) {
|
|
19
|
+
try {
|
|
20
|
+
const response = await axios.post(ONLYSQ_API_URL, {
|
|
21
|
+
model: 'gpt-4o-mini',
|
|
22
|
+
messages: messages,
|
|
23
|
+
temperature: 0.7,
|
|
24
|
+
max_tokens: 1000
|
|
25
|
+
}, {
|
|
26
|
+
headers: {
|
|
27
|
+
'Authorization': `Bearer ${ONLYSQ_API_KEY}`,
|
|
28
|
+
'Content-Type': 'application/json'
|
|
29
|
+
},
|
|
30
|
+
proxy: false
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
return response.data.choices[0].message.content;
|
|
34
|
+
} catch (error) {
|
|
35
|
+
console.error('❌ Ошибка OnlySQ:', error.message);
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function start() {
|
|
41
|
+
try {
|
|
42
|
+
const me = await bot.getMe();
|
|
43
|
+
console.log('✅ Бот запущен:', '@' + me.username);
|
|
44
|
+
console.log('🧠 OnlySQ API: GPT-4o-mini');
|
|
45
|
+
console.log('🔄 Ожидаю сообщения...\n');
|
|
46
|
+
|
|
47
|
+
let offset = 0;
|
|
48
|
+
|
|
49
|
+
while (true) {
|
|
50
|
+
try {
|
|
51
|
+
const updates = await bot.getUpdates({ offset, timeout: 30 });
|
|
52
|
+
|
|
53
|
+
for (const update of updates) {
|
|
54
|
+
offset = update.update_id + 1;
|
|
55
|
+
|
|
56
|
+
if (update.message) {
|
|
57
|
+
await handleMessage(update.message);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
} catch (error) {
|
|
61
|
+
console.error('❌ Ошибка получения обновлений:', error.message);
|
|
62
|
+
await new Promise(r => setTimeout(r, 3000));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error('❌ Ошибка запуска:', error.message);
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async function handleMessage(message) {
|
|
72
|
+
const chatId = message.chat.id;
|
|
73
|
+
const text = message.text;
|
|
74
|
+
const username = message.from.username || message.from.first_name;
|
|
75
|
+
|
|
76
|
+
if (!text) return;
|
|
77
|
+
|
|
78
|
+
console.log(`📨 @${username}: ${text}`);
|
|
79
|
+
|
|
80
|
+
if (text === '/start') {
|
|
81
|
+
await bot.sendMessage({
|
|
82
|
+
chat_id: chatId,
|
|
83
|
+
text: '👋 Привет! Я AI бот на базе OnlySQ!\n\n' +
|
|
84
|
+
'🧠 Модель: GPT-4o-mini\n' +
|
|
85
|
+
'📚 Построен на neogram-js\n\n' +
|
|
86
|
+
'Просто напиши мне что-нибудь!\n\n' +
|
|
87
|
+
'/clear - очистить историю\n' +
|
|
88
|
+
'/help - помощь'
|
|
89
|
+
});
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (text === '/clear') {
|
|
94
|
+
conversations.delete(chatId);
|
|
95
|
+
await bot.sendMessage({
|
|
96
|
+
chat_id: chatId,
|
|
97
|
+
text: '🗑️ История диалога очищена!'
|
|
98
|
+
});
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (text === '/help') {
|
|
103
|
+
await bot.sendMessage({
|
|
104
|
+
chat_id: chatId,
|
|
105
|
+
text: '📚 AI Бот на neogram-js\n\n' +
|
|
106
|
+
'🧠 Модель: GPT-4o-mini (OnlySQ)\n' +
|
|
107
|
+
'🔥 Framework: neogram-js\n' +
|
|
108
|
+
'💬 Long Polling\n\n' +
|
|
109
|
+
'Задавай любые вопросы!'
|
|
110
|
+
});
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
await bot.sendChatAction({ chat_id: chatId, action: 'typing' });
|
|
115
|
+
|
|
116
|
+
try {
|
|
117
|
+
if (!conversations.has(chatId)) {
|
|
118
|
+
conversations.set(chatId, [
|
|
119
|
+
{ role: 'system', content: 'Ты полезный AI ассистент. Отвечай кратко и по делу на русском языке.' }
|
|
120
|
+
]);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const history = conversations.get(chatId);
|
|
124
|
+
history.push({ role: 'user', content: text });
|
|
125
|
+
|
|
126
|
+
// Ограничиваем историю (последние 10 пар сообщений)
|
|
127
|
+
if (history.length > 21) {
|
|
128
|
+
history.splice(1, 2);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const aiResponse = await callOnlySQ(history);
|
|
132
|
+
history.push({ role: 'assistant', content: aiResponse });
|
|
133
|
+
|
|
134
|
+
console.log(`🤖 AI: ${aiResponse.substring(0, 80)}${aiResponse.length > 80 ? '...' : ''}`);
|
|
135
|
+
|
|
136
|
+
await bot.sendMessage({
|
|
137
|
+
chat_id: chatId,
|
|
138
|
+
text: aiResponse
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
} catch (error) {
|
|
142
|
+
console.error('❌ Ошибка AI:', error.message);
|
|
143
|
+
await bot.sendMessage({
|
|
144
|
+
chat_id: chatId,
|
|
145
|
+
text: '❌ Ошибка при обработке запроса. Попробуй позже или напиши /clear'
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
start().catch(console.error);
|
|
151
|
+
|
|
152
|
+
process.on('SIGINT', () => {
|
|
153
|
+
console.log('\n👋 Бот остановлен');
|
|
154
|
+
process.exit(0);
|
|
155
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Bot } from '../src/Bot.js';
|
|
2
|
+
|
|
3
|
+
const bot = new Bot(process.env.BOT_TOKEN);
|
|
4
|
+
|
|
5
|
+
async function main() {
|
|
6
|
+
const me = await bot.getMe();
|
|
7
|
+
console.log('Бот запущен:', me.username);
|
|
8
|
+
|
|
9
|
+
let offset = 0;
|
|
10
|
+
|
|
11
|
+
while (true) {
|
|
12
|
+
const updates = await bot.getUpdates({ offset, timeout: 30 });
|
|
13
|
+
|
|
14
|
+
for (const update of updates) {
|
|
15
|
+
offset = update.update_id + 1;
|
|
16
|
+
|
|
17
|
+
if (update.message) {
|
|
18
|
+
const { chat, text } = update.message;
|
|
19
|
+
console.log('Получено:', text);
|
|
20
|
+
|
|
21
|
+
await bot.sendMessage({
|
|
22
|
+
chat_id: chat.id,
|
|
23
|
+
text: 'Ты написал: ' + text
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Bot } from '../src/Bot.js';
|
|
2
|
+
|
|
3
|
+
const TOKEN = process.env.BOT_TOKEN;
|
|
4
|
+
const bot = new Bot(TOKEN);
|
|
5
|
+
|
|
6
|
+
console.log('🤖 Тестирую бота...');
|
|
7
|
+
console.log('🔑 Токен:', TOKEN.substring(0, 10) + '...');
|
|
8
|
+
console.log('🌐 Base URL:', bot.http.defaults.baseURL);
|
|
9
|
+
|
|
10
|
+
async function start() {
|
|
11
|
+
try {
|
|
12
|
+
console.log('📡 Отправляю getMe...');
|
|
13
|
+
const me = await bot.getMe();
|
|
14
|
+
console.log('✅ Успех!');
|
|
15
|
+
console.log('👤 @' + me.username);
|
|
16
|
+
console.log('🆔 ID:', me.id);
|
|
17
|
+
console.log('📝 Имя:', me.first_name);
|
|
18
|
+
} catch (error) {
|
|
19
|
+
console.error('❌ Ошибка:', error.message);
|
|
20
|
+
console.error('📊 Код:', error.code);
|
|
21
|
+
console.error('🔧 Config:', error.config?.url);
|
|
22
|
+
console.error('📄 Response:', error.response?.data);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
start();
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { Bot } from '../src/Bot.js';
|
|
2
|
+
|
|
3
|
+
const TOKEN = process.env.BOT_TOKEN;
|
|
4
|
+
if (!TOKEN) {
|
|
5
|
+
console.error('❌ Ошибка: установи переменную BOT_TOKEN');
|
|
6
|
+
process.exit(1);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const bot = new Bot(TOKEN);
|
|
10
|
+
|
|
11
|
+
console.log('🤖 Бот запускается...');
|
|
12
|
+
|
|
13
|
+
async function start() {
|
|
14
|
+
try {
|
|
15
|
+
const me = await bot.getMe();
|
|
16
|
+
console.log('✅ Бот успешно запущен!');
|
|
17
|
+
console.log('👤 Username:', '@' + me.username);
|
|
18
|
+
console.log('🆔 Bot ID:', me.id);
|
|
19
|
+
console.log('📝 Name:', me.first_name);
|
|
20
|
+
console.log('');
|
|
21
|
+
console.log('🔄 Ожидаю сообщения...');
|
|
22
|
+
|
|
23
|
+
let offset = 0;
|
|
24
|
+
|
|
25
|
+
while (true) {
|
|
26
|
+
try {
|
|
27
|
+
const updates = await bot.getUpdates({
|
|
28
|
+
offset,
|
|
29
|
+
timeout: 30,
|
|
30
|
+
limit: 100
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
for (const update of updates) {
|
|
34
|
+
offset = update.update_id + 1;
|
|
35
|
+
|
|
36
|
+
// Обрабатываем сообщения
|
|
37
|
+
if (update.message) {
|
|
38
|
+
await handleMessage(update.message);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Обрабатываем нажатия на inline кнопки
|
|
42
|
+
if (update.callback_query) {
|
|
43
|
+
await handleCallback(update.callback_query);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
} catch (error) {
|
|
47
|
+
console.error('❌ Ошибка при получении обновлений:', error.message);
|
|
48
|
+
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
} catch (error) {
|
|
52
|
+
console.error('❌ Ошибка при запуске:', error.message);
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function handleMessage(message) {
|
|
58
|
+
const chatId = message.chat.id;
|
|
59
|
+
const text = message.text;
|
|
60
|
+
const username = message.from.username || message.from.first_name;
|
|
61
|
+
|
|
62
|
+
console.log('📨 Сообщение от @' + username + ':', text);
|
|
63
|
+
|
|
64
|
+
if (text === '/start') {
|
|
65
|
+
await bot.sendMessage({
|
|
66
|
+
chat_id: chatId,
|
|
67
|
+
text: '👋 Привет! Я тестовый бот для neogram-js!\n\n' +
|
|
68
|
+
'Доступные команды:\n' +
|
|
69
|
+
'/test - Тест основных функций\n' +
|
|
70
|
+
'/photo - Отправить фото\n' +
|
|
71
|
+
'/poll - Создать опрос\n' +
|
|
72
|
+
'/dice - Бросить кубик\n' +
|
|
73
|
+
'/location - Отправить локацию\n' +
|
|
74
|
+
'/keyboard - Показать клавиатуру\n' +
|
|
75
|
+
'/inline - Inline кнопки\n' +
|
|
76
|
+
'/help - Помощь'
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
else if (text === '/test') {
|
|
81
|
+
await bot.sendChatAction({ chat_id: chatId, action: 'typing' });
|
|
82
|
+
|
|
83
|
+
await bot.sendMessage({
|
|
84
|
+
chat_id: chatId,
|
|
85
|
+
text: '✅ Тест основных функций:\n\n' +
|
|
86
|
+
'✓ sendMessage работает\n' +
|
|
87
|
+
'✓ getUpdates работает\n' +
|
|
88
|
+
'✓ sendChatAction работает\n\n' +
|
|
89
|
+
'🎉 Всё отлично!'
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
else if (text === '/photo') {
|
|
94
|
+
await bot.sendPhoto({
|
|
95
|
+
chat_id: chatId,
|
|
96
|
+
photo: 'https://picsum.photos/800/600',
|
|
97
|
+
caption: '📸 Случайное фото с picsum.photos'
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
else if (text === '/poll') {
|
|
102
|
+
await bot.sendPoll({
|
|
103
|
+
chat_id: chatId,
|
|
104
|
+
question: 'Как тебе neogram-js?',
|
|
105
|
+
pollOptions: ['🔥 Отлично!', '👍 Хорошо', '👌 Норм', '🤔 Так себе']
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
else if (text === '/dice') {
|
|
110
|
+
await bot.sendDice({ chat_id: chatId, emoji: '🎲' });
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
else if (text === '/location') {
|
|
114
|
+
await bot.sendLocation({
|
|
115
|
+
chat_id: chatId,
|
|
116
|
+
latitude: 55.7558,
|
|
117
|
+
longitude: 37.6173
|
|
118
|
+
});
|
|
119
|
+
await bot.sendMessage({
|
|
120
|
+
chat_id: chatId,
|
|
121
|
+
text: '📍 Красная площадь, Москва'
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
else if (text === '/keyboard') {
|
|
126
|
+
await bot.sendMessage({
|
|
127
|
+
chat_id: chatId,
|
|
128
|
+
text: '⌨️ Клавиатура:',
|
|
129
|
+
reply_markup: {
|
|
130
|
+
keyboard: [
|
|
131
|
+
[{ text: '🔥 Кнопка 1' }, { text: '⚡ Кнопка 2' }],
|
|
132
|
+
[{ text: '💎 Кнопка 3' }],
|
|
133
|
+
[{ text: '❌ Убрать клавиатуру' }]
|
|
134
|
+
],
|
|
135
|
+
resize_keyboard: true
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
else if (text === '/inline') {
|
|
141
|
+
await bot.sendMessage({
|
|
142
|
+
chat_id: chatId,
|
|
143
|
+
text: '🔘 Inline кнопки (нажми на них!):',
|
|
144
|
+
reply_markup: {
|
|
145
|
+
inline_keyboard: [
|
|
146
|
+
[
|
|
147
|
+
{ text: '✅ Кнопка 1', callback_data: 'btn1' },
|
|
148
|
+
{ text: '❌ Кнопка 2', callback_data: 'btn2' }
|
|
149
|
+
],
|
|
150
|
+
[
|
|
151
|
+
{ text: '🔥 Кнопка 3', callback_data: 'btn3' }
|
|
152
|
+
],
|
|
153
|
+
[
|
|
154
|
+
{ text: '🌐 Google', url: 'https://google.com' }
|
|
155
|
+
]
|
|
156
|
+
]
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
else if (text === '❌ Убрать клавиатуру') {
|
|
162
|
+
await bot.sendMessage({
|
|
163
|
+
chat_id: chatId,
|
|
164
|
+
text: '✅ Клавиатура убрана',
|
|
165
|
+
reply_markup: { remove_keyboard: true }
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
else if (text === '/help') {
|
|
170
|
+
await bot.sendMessage({
|
|
171
|
+
chat_id: chatId,
|
|
172
|
+
text: '📚 Помощь:\n\n' +
|
|
173
|
+
'Этот бот тестирует функциональность neogram-js\n' +
|
|
174
|
+
'Используй /start чтобы увидеть все команды'
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
else {
|
|
179
|
+
await bot.sendMessage({
|
|
180
|
+
chat_id: chatId,
|
|
181
|
+
text: '🤔 Неизвестная команда. Используй /help'
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Обработка callback_query (нажатия на inline кнопки)
|
|
187
|
+
async function handleCallback(callbackQuery) {
|
|
188
|
+
const chatId = callbackQuery.message.chat.id;
|
|
189
|
+
const messageId = callbackQuery.message.message_id;
|
|
190
|
+
const data = callbackQuery.data;
|
|
191
|
+
const username = callbackQuery.from.username || callbackQuery.from.first_name;
|
|
192
|
+
|
|
193
|
+
console.log('🔘 Callback от @' + username + ':', data);
|
|
194
|
+
|
|
195
|
+
// Отвечаем на callback (убирает "часики" у пользователя)
|
|
196
|
+
await bot.answerCallbackQuery({ callback_query_id: callbackQuery.id });
|
|
197
|
+
|
|
198
|
+
if (data === 'btn1') {
|
|
199
|
+
await bot.sendMessage({
|
|
200
|
+
chat_id: chatId,
|
|
201
|
+
text: '✅ Ты нажал на Кнопку 1!'
|
|
202
|
+
});
|
|
203
|
+
} else if (data === 'btn2') {
|
|
204
|
+
await bot.sendMessage({
|
|
205
|
+
chat_id: chatId,
|
|
206
|
+
text: '❌ Ты нажал на Кнопку 2!'
|
|
207
|
+
});
|
|
208
|
+
} else if (data === 'btn3') {
|
|
209
|
+
await bot.sendMessage({
|
|
210
|
+
chat_id: chatId,
|
|
211
|
+
text: '🔥 Ты нажал на Кнопку 3!'
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
start().catch(console.error);
|
|
217
|
+
|
|
218
|
+
process.on('SIGINT', () => {
|
|
219
|
+
console.log('\n👋 Бот остановлен');
|
|
220
|
+
process.exit(0);
|
|
221
|
+
});
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { Bot } from '../src/Bot.js';
|
|
2
|
+
|
|
3
|
+
// Получаем токен из переменной окружения
|
|
4
|
+
const TOKEN = process.env.BOT_TOKEN;
|
|
5
|
+
|
|
6
|
+
if (!TOKEN) {
|
|
7
|
+
console.error('❌ Ошибка: установи переменную BOT_TOKEN');
|
|
8
|
+
console.error('Пример: export BOT_TOKEN="your_token_here"');
|
|
9
|
+
process.exit(1);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const bot = new Bot(TOKEN);
|
|
13
|
+
|
|
14
|
+
console.log('🤖 Бот запускается...');
|
|
15
|
+
|
|
16
|
+
// Получаем информацию о боте
|
|
17
|
+
async function start() {
|
|
18
|
+
try {
|
|
19
|
+
const me = await bot.getMe();
|
|
20
|
+
console.log('✅ Бот успешно запущен!');
|
|
21
|
+
console.log('👤 Username:', '@' + me.username);
|
|
22
|
+
console.log('🆔 Bot ID:', me.id);
|
|
23
|
+
console.log('📝 Name:', me.first_name);
|
|
24
|
+
console.log('');
|
|
25
|
+
console.log('🔄 Ожидаю сообщения...');
|
|
26
|
+
|
|
27
|
+
let offset = 0;
|
|
28
|
+
|
|
29
|
+
// Polling loop
|
|
30
|
+
while (true) {
|
|
31
|
+
try {
|
|
32
|
+
const updates = await bot.getUpdates({
|
|
33
|
+
offset,
|
|
34
|
+
timeout: 30,
|
|
35
|
+
limit: 100
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
for (const update of updates) {
|
|
39
|
+
offset = update.update_id + 1;
|
|
40
|
+
await handleUpdate(update);
|
|
41
|
+
}
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.error('❌ Ошибка при получении обновлений:', error.message);
|
|
44
|
+
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
} catch (error) {
|
|
48
|
+
console.error('❌ Ошибка при запуске:', error.message);
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Обработка обновлений
|
|
54
|
+
async function handleUpdate(update) {
|
|
55
|
+
const message = update.message;
|
|
56
|
+
if (!message) return;
|
|
57
|
+
|
|
58
|
+
const chatId = message.chat.id;
|
|
59
|
+
const text = message.text;
|
|
60
|
+
const username = message.from.username || message.from.first_name;
|
|
61
|
+
|
|
62
|
+
console.log('📨 Сообщение от @' + username + ':', text);
|
|
63
|
+
|
|
64
|
+
// Команды
|
|
65
|
+
if (text === '/start') {
|
|
66
|
+
await bot.sendMessage({
|
|
67
|
+
chat_id: chatId,
|
|
68
|
+
text: '👋 Привет! Я тестовый бот для neogram-js!\n\n' +
|
|
69
|
+
'Доступные команды:\n' +
|
|
70
|
+
'/test - Тест основных функций\n' +
|
|
71
|
+
'/photo - Отправить фото\n' +
|
|
72
|
+
'/poll - Создать опрос\n' +
|
|
73
|
+
'/dice - Бросить кубик\n' +
|
|
74
|
+
'/location - Отправить локацию\n' +
|
|
75
|
+
'/keyboard - Показать клавиатуру\n' +
|
|
76
|
+
'/inline - Inline кнопки\n' +
|
|
77
|
+
'/help - Помощь'
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
else if (text === '/test') {
|
|
82
|
+
await bot.sendChatAction({ chat_id: chatId, action: 'typing' });
|
|
83
|
+
|
|
84
|
+
await bot.sendMessage({
|
|
85
|
+
chat_id: chatId,
|
|
86
|
+
text: '✅ Тест основных функций:\n\n' +
|
|
87
|
+
'✓ sendMessage работает\n' +
|
|
88
|
+
'✓ getUpdates работает\n' +
|
|
89
|
+
'✓ sendChatAction работает\n\n' +
|
|
90
|
+
'🎉 Всё отлично!'
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
else if (text === '/photo') {
|
|
95
|
+
await bot.sendPhoto({
|
|
96
|
+
chat_id: chatId,
|
|
97
|
+
photo: 'https://picsum.photos/800/600',
|
|
98
|
+
caption: '📸 Случайное фото с picsum.photos'
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
else if (text === '/poll') {
|
|
103
|
+
await bot.sendPoll({
|
|
104
|
+
chat_id: chatId,
|
|
105
|
+
question: 'Как тебе neogram-js?',
|
|
106
|
+
pollOptions: ['🔥 Отлично!', '👍 Хорошо', '👌 Норм', '🤔 Так себе']
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
else if (text === '/dice') {
|
|
111
|
+
await bot.sendDice({ chat_id: chatId, emoji: '🎲' });
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
else if (text === '/location') {
|
|
115
|
+
await bot.sendLocation({
|
|
116
|
+
chat_id: chatId,
|
|
117
|
+
latitude: 55.7558,
|
|
118
|
+
longitude: 37.6173
|
|
119
|
+
});
|
|
120
|
+
await bot.sendMessage({
|
|
121
|
+
chat_id: chatId,
|
|
122
|
+
text: '📍 Красная площадь, Москва'
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
else if (text === '/keyboard') {
|
|
127
|
+
await bot.sendMessage({
|
|
128
|
+
chat_id: chatId,
|
|
129
|
+
text: '⌨️ Клавиатура:',
|
|
130
|
+
reply_markup: {
|
|
131
|
+
keyboard: [
|
|
132
|
+
[{ text: '🔥 Кнопка 1' }, { text: '⚡ Кнопка 2' }],
|
|
133
|
+
[{ text: '💎 Кнопка 3' }],
|
|
134
|
+
[{ text: '❌ Убрать клавиатуру' }]
|
|
135
|
+
],
|
|
136
|
+
resize_keyboard: true
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
else if (text === '/inline') {
|
|
142
|
+
await bot.sendMessage({
|
|
143
|
+
chat_id: chatId,
|
|
144
|
+
text: '🔘 Inline кнопки:',
|
|
145
|
+
reply_markup: {
|
|
146
|
+
inline_keyboard: [
|
|
147
|
+
[
|
|
148
|
+
{ text: '✅ Кнопка 1', callback_data: 'btn1' },
|
|
149
|
+
{ text: '❌ Кнопка 2', callback_data: 'btn2' }
|
|
150
|
+
],
|
|
151
|
+
[
|
|
152
|
+
{ text: '🌐 Google', url: 'https://google.com' }
|
|
153
|
+
]
|
|
154
|
+
]
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
else if (text === '❌ Убрать клавиатуру') {
|
|
160
|
+
await bot.sendMessage({
|
|
161
|
+
chat_id: chatId,
|
|
162
|
+
text: '✅ Клавиатура убрана',
|
|
163
|
+
reply_markup: { remove_keyboard: true }
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
else if (text === '/help') {
|
|
168
|
+
await bot.sendMessage({
|
|
169
|
+
chat_id: chatId,
|
|
170
|
+
text: '📚 Помощь:\n\n' +
|
|
171
|
+
'Этот бот тестирует функциональность neogram-js\n' +
|
|
172
|
+
'Используй /start чтобы увидеть все команды'
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
else {
|
|
177
|
+
await bot.sendMessage({
|
|
178
|
+
chat_id: chatId,
|
|
179
|
+
text: '🤔 Неизвестная команда. Используй /help'
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Обработка callback запросов (inline кнопки)
|
|
185
|
+
bot.on = (event, handler) => {
|
|
186
|
+
// TODO: implement event system
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
// Запуск
|
|
190
|
+
start().catch(console.error);
|
|
191
|
+
|
|
192
|
+
// Graceful shutdown
|
|
193
|
+
process.on('SIGINT', () => {
|
|
194
|
+
console.log('\n👋 Бот остановлен');
|
|
195
|
+
process.exit(0);
|
|
196
|
+
});
|