neogram 9.3.1 → 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 +149 -13
- 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
package/README.md
CHANGED
|
@@ -2,12 +2,35 @@
|
|
|
2
2
|
|
|
3
3
|
**Neogram** is a lightweight JavaScript module for working with the Telegram Bot API and AI. This is a port of the original Python library by SiriLV. It combines simple Telegram workflows with powerful features like text and image generation, translation, and more.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## ✨ Features
|
|
6
|
+
|
|
7
|
+
- **Full Telegram Bot API Coverage** - All 281+ Telegram API types and methods
|
|
8
|
+
- **AI Integration** - Built-in support for OnlySQ, ChatGPT, and Deef AI services
|
|
9
|
+
- **TypeScript Ready** - Complete type definitions for all Telegram objects
|
|
10
|
+
- **ES Modules** - Native ES module support (modern JavaScript)
|
|
11
|
+
- **Lightweight** - Minimal dependencies (axios, cheerio, form-data)
|
|
12
|
+
- **Flexible** - Support for both polling and webhook modes
|
|
13
|
+
- **File Uploads** - Easy handling of photos, documents, videos, and other media
|
|
14
|
+
- **Error Handling** - Comprehensive error handling with Telegram API error codes
|
|
15
|
+
- **Customizable** - Configurable API keys and endpoints for AI services
|
|
16
|
+
|
|
17
|
+
## 📦 Installation
|
|
6
18
|
|
|
7
19
|
```bash
|
|
8
20
|
npm install neogram
|
|
9
21
|
```
|
|
10
22
|
|
|
23
|
+
### Getting a Bot Token
|
|
24
|
+
|
|
25
|
+
1. Open Telegram and search for [@BotFather](https://t.me/botfather)
|
|
26
|
+
2. Send `/newbot` and follow the instructions
|
|
27
|
+
3. Copy the token provided by BotFather
|
|
28
|
+
4. Set it as environment variable or use directly in your code:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
export BOT_TOKEN="your_token_here"
|
|
32
|
+
```
|
|
33
|
+
|
|
11
34
|
## Dependencies
|
|
12
35
|
|
|
13
36
|
- `axios` (^1.7.7) - HTTP client for API requests
|
|
@@ -38,6 +61,51 @@ const me = await bot.getMe();
|
|
|
38
61
|
console.log(`Bot username: @${me.username}`);
|
|
39
62
|
```
|
|
40
63
|
|
|
64
|
+
## Quick Start
|
|
65
|
+
|
|
66
|
+
Here's a complete example of a bot that responds to messages and uses AI:
|
|
67
|
+
|
|
68
|
+
```javascript
|
|
69
|
+
import { Bot, OnlySQ } from 'neogram';
|
|
70
|
+
|
|
71
|
+
const bot = new Bot('YOUR_BOT_TOKEN');
|
|
72
|
+
const ai = new OnlySQ(); // Uses default 'openai' key
|
|
73
|
+
|
|
74
|
+
// Simple polling loop
|
|
75
|
+
let offset = 0;
|
|
76
|
+
while (true) {
|
|
77
|
+
const updates = await bot.getUpdates({ offset, timeout: 30 });
|
|
78
|
+
|
|
79
|
+
for (const update of updates) {
|
|
80
|
+
offset = update.update_id + 1;
|
|
81
|
+
|
|
82
|
+
if (update.message?.text) {
|
|
83
|
+
const { chat, text } = update.message;
|
|
84
|
+
|
|
85
|
+
// Echo with AI enhancement
|
|
86
|
+
if (text.startsWith('/ask ')) {
|
|
87
|
+
const question = text.substring(5);
|
|
88
|
+
const answer = await ai.generateAnswer('gpt-5.2-chat', [
|
|
89
|
+
{ role: 'user', content: question }
|
|
90
|
+
]);
|
|
91
|
+
|
|
92
|
+
await bot.sendMessage({
|
|
93
|
+
chat_id: chat.id,
|
|
94
|
+
text: `🤖 AI says: ${answer}`
|
|
95
|
+
});
|
|
96
|
+
} else {
|
|
97
|
+
await bot.sendMessage({
|
|
98
|
+
chat_id: chat.id,
|
|
99
|
+
text: `You said: ${text}`
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
For more examples, see the `examples/` directory.
|
|
108
|
+
|
|
41
109
|
## Core API Methods
|
|
42
110
|
|
|
43
111
|
The `Bot` class provides comprehensive access to the Telegram Bot API. Here are the main categories of methods:
|
|
@@ -104,10 +172,7 @@ The `Bot` class provides comprehensive access to the Telegram Bot API. Here are
|
|
|
104
172
|
|
|
105
173
|
### Updates and Polling
|
|
106
174
|
|
|
107
|
-
- `getUpdates(options)` - Get bot updates
|
|
108
|
-
- `setWebhook(options)` - Set webhook
|
|
109
|
-
- `deleteWebhook(options)` - Delete webhook
|
|
110
|
-
- `getWebhookInfo()` - Get webhook info
|
|
175
|
+
- `getUpdates(options)` - Get bot updates (polling mode)
|
|
111
176
|
|
|
112
177
|
### User and File Management
|
|
113
178
|
|
|
@@ -238,11 +303,15 @@ const translation = await chatgpt.generateTranslation(file, 'whisper-1');
|
|
|
238
303
|
|
|
239
304
|
### OnlySQ Class
|
|
240
305
|
|
|
241
|
-
Provides access to OnlySQ AI services:
|
|
306
|
+
Provides access to OnlySQ AI services with customizable API key support:
|
|
242
307
|
|
|
243
308
|
```javascript
|
|
309
|
+
// Default constructor uses 'openai' key (backward compatible)
|
|
244
310
|
const onlysq = new OnlySQ();
|
|
245
311
|
|
|
312
|
+
// Or provide your own API key
|
|
313
|
+
const onlysqWithKey = new OnlySQ({ apiKey: 'your-onlysq-api-key' });
|
|
314
|
+
|
|
246
315
|
// Get available models
|
|
247
316
|
const models = await onlysq.getModels({
|
|
248
317
|
modality: 'text', // Filter by modality
|
|
@@ -263,6 +332,7 @@ await onlysq.generateImage('flux', 'A futuristic city', '16:9', 'output.png');
|
|
|
263
332
|
```
|
|
264
333
|
|
|
265
334
|
**Methods:**
|
|
335
|
+
- `constructor(options?)` - Create instance with optional `{ apiKey }` (defaults to 'openai')
|
|
266
336
|
- `getModels(options)` - Get filtered list of available models
|
|
267
337
|
- `generateAnswer(model, messages)` - Generate text responses
|
|
268
338
|
- `generateImage(model, prompt, ratio, filename)` - Generate and save images
|
|
@@ -319,13 +389,77 @@ import {
|
|
|
319
389
|
} from 'neogram';
|
|
320
390
|
```
|
|
321
391
|
|
|
392
|
+
### TelegramObject Base Class
|
|
393
|
+
|
|
394
|
+
All Telegram API types extend the `TelegramObject` base class, which provides:
|
|
395
|
+
|
|
396
|
+
- **Automatic field mapping**: `from` ↔ `from_user`, `type` ↔ `type_val`, `filter` ↔ `filter_val`
|
|
397
|
+
- **Serialization**: `toJSON()` method for converting to plain objects
|
|
398
|
+
- **Deserialization**: Static `fromJSON(data)` method for creating instances
|
|
399
|
+
- **Constructor**: Accepts plain objects and automatically maps properties
|
|
400
|
+
|
|
401
|
+
Example:
|
|
402
|
+
```javascript
|
|
403
|
+
import { User } from 'neogram';
|
|
404
|
+
|
|
405
|
+
// Create User instance from Telegram API response
|
|
406
|
+
const userData = { id: 123, is_bot: false, first_name: 'John' };
|
|
407
|
+
const user = new User(userData);
|
|
408
|
+
|
|
409
|
+
// Convert back to plain object
|
|
410
|
+
const json = user.toJSON();
|
|
411
|
+
```
|
|
412
|
+
|
|
322
413
|
## Examples
|
|
323
414
|
|
|
324
|
-
See the `examples/` directory for complete
|
|
415
|
+
See the `examples/` directory for complete, runnable examples:
|
|
416
|
+
|
|
417
|
+
| File | Description | Key Features |
|
|
418
|
+
|------|-------------|--------------|
|
|
419
|
+
| `simple-bot.js` | Minimal bot with polling | `getUpdates`, `sendMessage`, error handling |
|
|
420
|
+
| `test-bot.js` | Feature-rich test bot | Commands, photos, polls, dice, locations, keyboards |
|
|
421
|
+
| `test-bot-full.js` | Complete bot with inline buttons | Callback query handling, answerCallbackQuery |
|
|
422
|
+
| `test-bot-debug.js` | Debug and connectivity test | Error inspection, token validation |
|
|
423
|
+
| `ai-bot.js` | AI-powered bot with OnlySQ | GPT-4o-mini integration, conversation history |
|
|
325
424
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
425
|
+
Run any example:
|
|
426
|
+
```bash
|
|
427
|
+
BOT_TOKEN="your_token_here" node examples/simple-bot.js
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### Webhook Example
|
|
431
|
+
|
|
432
|
+
```javascript
|
|
433
|
+
import { Bot } from 'neogram';
|
|
434
|
+
import express from 'express';
|
|
435
|
+
|
|
436
|
+
const bot = new Bot('YOUR_BOT_TOKEN');
|
|
437
|
+
const app = express();
|
|
438
|
+
|
|
439
|
+
app.use(express.json());
|
|
440
|
+
|
|
441
|
+
// Set webhook (run once)
|
|
442
|
+
await bot.setWebhook({
|
|
443
|
+
url: 'https://yourdomain.com/webhook',
|
|
444
|
+
secret_token: 'your_secret_token'
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
// Handle incoming updates
|
|
448
|
+
app.post('/webhook', async (req, res) => {
|
|
449
|
+
const update = req.body;
|
|
450
|
+
|
|
451
|
+
if (update.message?.text === '/start') {
|
|
452
|
+
await bot.sendMessage({
|
|
453
|
+
chat_id: update.message.chat.id,
|
|
454
|
+
text: 'Hello from webhook!'
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
res.sendStatus(200);
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
app.listen(3000, () => console.log('Webhook server running on port 3000'));
|
|
462
|
+
```
|
|
329
463
|
|
|
330
464
|
### Function Examples
|
|
331
465
|
|
|
@@ -713,7 +847,9 @@ src/
|
|
|
713
847
|
|
|
714
848
|
## Contributing
|
|
715
849
|
|
|
716
|
-
|
|
850
|
+
Join our Telegram channel: https://t.me/neogram_js
|
|
851
|
+
|
|
852
|
+
|
|
717
853
|
|
|
718
854
|
## License
|
|
719
855
|
|
|
@@ -721,5 +857,5 @@ MIT License - see LICENSE file for details.
|
|
|
721
857
|
|
|
722
858
|
## Credits
|
|
723
859
|
|
|
724
|
-
- Original Python library by
|
|
725
|
-
- JavaScript port by
|
|
860
|
+
- Original Python library by SiriLV
|
|
861
|
+
- JavaScript port by AndrewImm-OP
|
|
@@ -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
|
+
});
|
package/package.json
CHANGED
|
@@ -8,15 +8,11 @@
|
|
|
8
8
|
"contributors": [
|
|
9
9
|
{
|
|
10
10
|
"name": "AndrewImm-OP",
|
|
11
|
-
"email": "bessmertnyja89@gmail.com"
|
|
12
|
-
"url": "https://github.com/AndrewImm-OP"
|
|
11
|
+
"email": "bessmertnyja89@gmail.com"
|
|
13
12
|
}
|
|
14
13
|
],
|
|
15
14
|
"license": "MIT",
|
|
16
|
-
|
|
17
|
-
"type": "git",
|
|
18
|
-
"url": "git+https://github.com/AndrewImm-OP/neogram.git"
|
|
19
|
-
},
|
|
15
|
+
|
|
20
16
|
"keywords": [
|
|
21
17
|
"telegram",
|
|
22
18
|
"bot",
|
|
@@ -30,6 +26,7 @@
|
|
|
30
26
|
"files": [
|
|
31
27
|
"src",
|
|
32
28
|
"types",
|
|
29
|
+
"examples",
|
|
33
30
|
"README.md",
|
|
34
31
|
"LICENSE"
|
|
35
32
|
],
|
|
@@ -48,9 +45,7 @@
|
|
|
48
45
|
"cheerio": "^1.0.0",
|
|
49
46
|
"form-data": "^4.0.0"
|
|
50
47
|
},
|
|
51
|
-
"version": "9.3.
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
},
|
|
55
|
-
"homepage": "https://github.com/AndrewImm-OP/neogram#readme"
|
|
48
|
+
"version": "9.3.2"
|
|
49
|
+
|
|
50
|
+
|
|
56
51
|
}
|
package/src/ai/OnlySQ.js
CHANGED
|
@@ -2,6 +2,10 @@ import axios from 'axios';
|
|
|
2
2
|
import fs from 'fs';
|
|
3
3
|
|
|
4
4
|
export class OnlySQ {
|
|
5
|
+
constructor(options = {}) {
|
|
6
|
+
this.apiKey = options.apiKey || 'openai';
|
|
7
|
+
}
|
|
8
|
+
|
|
5
9
|
async getModels({
|
|
6
10
|
modality = null,
|
|
7
11
|
can_tools = null,
|
|
@@ -70,7 +74,7 @@ export class OnlySQ {
|
|
|
70
74
|
const { data } = await axios.post('https://api.onlysq.ru/ai/v2', payload, {
|
|
71
75
|
timeout: 30000,
|
|
72
76
|
headers: {
|
|
73
|
-
'Authorization':
|
|
77
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
74
78
|
'Content-Type': 'application/json',
|
|
75
79
|
'User-Agent': 'Mozilla/5.0 (compatible; OnlySQ/1.0)',
|
|
76
80
|
},
|
|
@@ -103,7 +107,7 @@ export class OnlySQ {
|
|
|
103
107
|
{
|
|
104
108
|
timeout: 60000, // Image generation can take longer
|
|
105
109
|
headers: {
|
|
106
|
-
'Authorization':
|
|
110
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
107
111
|
'Content-Type': 'application/json',
|
|
108
112
|
'User-Agent': 'Mozilla/5.0 (compatible; OnlySQ/1.0)',
|
|
109
113
|
},
|
package/types/index.d.ts
CHANGED