onemix-bot 1.0.0__tar.gz
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.
- onemix_bot-1.0.0/PKG-INFO +130 -0
- onemix_bot-1.0.0/README.md +95 -0
- onemix_bot-1.0.0/onemix_bot/__init__.py +20 -0
- onemix_bot-1.0.0/onemix_bot/bot.py +303 -0
- onemix_bot-1.0.0/onemix_bot.egg-info/PKG-INFO +130 -0
- onemix_bot-1.0.0/onemix_bot.egg-info/SOURCES.txt +9 -0
- onemix_bot-1.0.0/onemix_bot.egg-info/dependency_links.txt +1 -0
- onemix_bot-1.0.0/onemix_bot.egg-info/requires.txt +4 -0
- onemix_bot-1.0.0/onemix_bot.egg-info/top_level.txt +1 -0
- onemix_bot-1.0.0/setup.cfg +4 -0
- onemix_bot-1.0.0/setup.py +33 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: onemix-bot
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Python SDK for building bots on the ONEMIX messenger platform
|
|
5
|
+
Home-page: https://github.com/onemix/bot-sdk-python
|
|
6
|
+
Author: ONEMIX Team
|
|
7
|
+
Author-email: support@itpaxlive.ru
|
|
8
|
+
Keywords: onemix bot messenger api sdk
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Communications :: Chat
|
|
19
|
+
Requires-Python: >=3.8
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
Requires-Dist: requests>=2.25.0
|
|
22
|
+
Provides-Extra: webhook
|
|
23
|
+
Requires-Dist: flask>=2.0.0; extra == "webhook"
|
|
24
|
+
Dynamic: author
|
|
25
|
+
Dynamic: author-email
|
|
26
|
+
Dynamic: classifier
|
|
27
|
+
Dynamic: description
|
|
28
|
+
Dynamic: description-content-type
|
|
29
|
+
Dynamic: home-page
|
|
30
|
+
Dynamic: keywords
|
|
31
|
+
Dynamic: provides-extra
|
|
32
|
+
Dynamic: requires-dist
|
|
33
|
+
Dynamic: requires-python
|
|
34
|
+
Dynamic: summary
|
|
35
|
+
|
|
36
|
+
# onemix-bot — Python SDK для ботов ONEMIX
|
|
37
|
+
|
|
38
|
+
Библиотека для создания ботов на платформе ONEMIX мессенджера.
|
|
39
|
+
|
|
40
|
+
## Установка
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install onemix-bot
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Или из исходников:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
git clone <repo>
|
|
50
|
+
cd onemix-bot-sdk
|
|
51
|
+
pip install -e .
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Быстрый старт
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
from onemix_bot import OnemixBot
|
|
58
|
+
|
|
59
|
+
bot = OnemixBot(
|
|
60
|
+
token="YOUR_BOT_TOKEN", # Получите у @botfather
|
|
61
|
+
api_url="https://your-server.com" # URL вашего ONEMIX сервера
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
@bot.command("start")
|
|
65
|
+
def on_start(msg):
|
|
66
|
+
bot.reply(msg, "Привет! Я бот ONEMIX")
|
|
67
|
+
|
|
68
|
+
@bot.on_message()
|
|
69
|
+
def echo(msg):
|
|
70
|
+
bot.reply(msg, f"Вы написали: {msg['content']}")
|
|
71
|
+
|
|
72
|
+
bot.run()
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## API
|
|
76
|
+
|
|
77
|
+
### OnemixBot(token, api_url, poll_interval=2.0)
|
|
78
|
+
|
|
79
|
+
Создаёт экземпляр бота.
|
|
80
|
+
|
|
81
|
+
### Методы
|
|
82
|
+
|
|
83
|
+
| Метод | Описание |
|
|
84
|
+
|-------|----------|
|
|
85
|
+
| `bot.get_me()` | Информация о боте |
|
|
86
|
+
| `bot.send_message(chat_id, text)` | Отправить сообщение |
|
|
87
|
+
| `bot.reply(msg, text)` | Ответить на сообщение |
|
|
88
|
+
| `bot.get_updates(limit=100)` | Получить обновления |
|
|
89
|
+
| `bot.set_webhook(url, secret=None)` | Установить вебхук |
|
|
90
|
+
| `bot.delete_webhook()` | Удалить вебхук |
|
|
91
|
+
| `bot.set_commands(commands)` | Установить команды |
|
|
92
|
+
| `bot.run()` | Запустить polling loop |
|
|
93
|
+
| `bot.run_threaded()` | Запустить в фоновом потоке |
|
|
94
|
+
| `bot.stop()` | Остановить polling |
|
|
95
|
+
| `bot.process_update(update)` | Обработать обновление (для вебхуков) |
|
|
96
|
+
|
|
97
|
+
### Декораторы
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
@bot.command("start") # Обработка команды /start
|
|
101
|
+
@bot.on_message() # Обработка всех текстовых сообщений
|
|
102
|
+
@bot.on_message(pattern=r"") # Обработка по regex-шаблону
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Webhook-режим
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
from flask import Flask, request
|
|
109
|
+
from onemix_bot import OnemixBot
|
|
110
|
+
|
|
111
|
+
app = Flask(__name__)
|
|
112
|
+
bot = OnemixBot(token="TOKEN", api_url="https://server.com")
|
|
113
|
+
|
|
114
|
+
@bot.command("start")
|
|
115
|
+
def start(msg):
|
|
116
|
+
bot.reply(msg, "Привет!")
|
|
117
|
+
|
|
118
|
+
@app.route("/webhook", methods=["POST"])
|
|
119
|
+
def webhook():
|
|
120
|
+
bot.process_update(request.json)
|
|
121
|
+
return "ok"
|
|
122
|
+
|
|
123
|
+
if __name__ == "__main__":
|
|
124
|
+
bot.set_webhook("https://your-server.com/webhook")
|
|
125
|
+
app.run(port=5000)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Лицензия
|
|
129
|
+
|
|
130
|
+
MIT
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# onemix-bot — Python SDK для ботов ONEMIX
|
|
2
|
+
|
|
3
|
+
Библиотека для создания ботов на платформе ONEMIX мессенджера.
|
|
4
|
+
|
|
5
|
+
## Установка
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install onemix-bot
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Или из исходников:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
git clone <repo>
|
|
15
|
+
cd onemix-bot-sdk
|
|
16
|
+
pip install -e .
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Быстрый старт
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
from onemix_bot import OnemixBot
|
|
23
|
+
|
|
24
|
+
bot = OnemixBot(
|
|
25
|
+
token="YOUR_BOT_TOKEN", # Получите у @botfather
|
|
26
|
+
api_url="https://your-server.com" # URL вашего ONEMIX сервера
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
@bot.command("start")
|
|
30
|
+
def on_start(msg):
|
|
31
|
+
bot.reply(msg, "Привет! Я бот ONEMIX")
|
|
32
|
+
|
|
33
|
+
@bot.on_message()
|
|
34
|
+
def echo(msg):
|
|
35
|
+
bot.reply(msg, f"Вы написали: {msg['content']}")
|
|
36
|
+
|
|
37
|
+
bot.run()
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## API
|
|
41
|
+
|
|
42
|
+
### OnemixBot(token, api_url, poll_interval=2.0)
|
|
43
|
+
|
|
44
|
+
Создаёт экземпляр бота.
|
|
45
|
+
|
|
46
|
+
### Методы
|
|
47
|
+
|
|
48
|
+
| Метод | Описание |
|
|
49
|
+
|-------|----------|
|
|
50
|
+
| `bot.get_me()` | Информация о боте |
|
|
51
|
+
| `bot.send_message(chat_id, text)` | Отправить сообщение |
|
|
52
|
+
| `bot.reply(msg, text)` | Ответить на сообщение |
|
|
53
|
+
| `bot.get_updates(limit=100)` | Получить обновления |
|
|
54
|
+
| `bot.set_webhook(url, secret=None)` | Установить вебхук |
|
|
55
|
+
| `bot.delete_webhook()` | Удалить вебхук |
|
|
56
|
+
| `bot.set_commands(commands)` | Установить команды |
|
|
57
|
+
| `bot.run()` | Запустить polling loop |
|
|
58
|
+
| `bot.run_threaded()` | Запустить в фоновом потоке |
|
|
59
|
+
| `bot.stop()` | Остановить polling |
|
|
60
|
+
| `bot.process_update(update)` | Обработать обновление (для вебхуков) |
|
|
61
|
+
|
|
62
|
+
### Декораторы
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
@bot.command("start") # Обработка команды /start
|
|
66
|
+
@bot.on_message() # Обработка всех текстовых сообщений
|
|
67
|
+
@bot.on_message(pattern=r"") # Обработка по regex-шаблону
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Webhook-режим
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
from flask import Flask, request
|
|
74
|
+
from onemix_bot import OnemixBot
|
|
75
|
+
|
|
76
|
+
app = Flask(__name__)
|
|
77
|
+
bot = OnemixBot(token="TOKEN", api_url="https://server.com")
|
|
78
|
+
|
|
79
|
+
@bot.command("start")
|
|
80
|
+
def start(msg):
|
|
81
|
+
bot.reply(msg, "Привет!")
|
|
82
|
+
|
|
83
|
+
@app.route("/webhook", methods=["POST"])
|
|
84
|
+
def webhook():
|
|
85
|
+
bot.process_update(request.json)
|
|
86
|
+
return "ok"
|
|
87
|
+
|
|
88
|
+
if __name__ == "__main__":
|
|
89
|
+
bot.set_webhook("https://your-server.com/webhook")
|
|
90
|
+
app.run(port=5000)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Лицензия
|
|
94
|
+
|
|
95
|
+
MIT
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ONEMIX Bot SDK
|
|
3
|
+
Python library for building bots on the ONEMIX messenger platform.
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
from onemix_bot import OnemixBot
|
|
7
|
+
|
|
8
|
+
bot = OnemixBot(token="YOUR_TOKEN", api_url="https://your-server.com")
|
|
9
|
+
|
|
10
|
+
@bot.command("start")
|
|
11
|
+
def on_start(msg):
|
|
12
|
+
bot.reply(msg, "Hello!")
|
|
13
|
+
|
|
14
|
+
bot.run()
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from .bot import OnemixBot
|
|
18
|
+
|
|
19
|
+
__version__ = "1.0.0"
|
|
20
|
+
__all__ = ["OnemixBot"]
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ONEMIX Bot SDK — Core Bot class
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
import time
|
|
7
|
+
import json
|
|
8
|
+
import logging
|
|
9
|
+
import threading
|
|
10
|
+
from typing import Optional, List, Dict, Callable, Any
|
|
11
|
+
|
|
12
|
+
import requests
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger("onemix_bot")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class OnemixBot:
|
|
18
|
+
"""
|
|
19
|
+
Main class for interacting with the ONEMIX Bot API.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
token: Bot API token (from BotFather)
|
|
23
|
+
api_url: Base URL of the ONEMIX server (e.g., "https://your-server.com")
|
|
24
|
+
poll_interval: Seconds between polling requests (default: 2)
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(self, token: str, api_url: str = "", poll_interval: float = 2.0):
|
|
28
|
+
self.token = token
|
|
29
|
+
self.api_url = api_url.rstrip("/")
|
|
30
|
+
self.poll_interval = poll_interval
|
|
31
|
+
|
|
32
|
+
self._command_handlers: Dict[str, Callable] = {}
|
|
33
|
+
self._message_handlers: List[Dict[str, Any]] = []
|
|
34
|
+
self._running = False
|
|
35
|
+
self._seen_ids: set = set()
|
|
36
|
+
self._session = requests.Session()
|
|
37
|
+
self._session.headers.update({
|
|
38
|
+
"Authorization": f"Bot {self.token}",
|
|
39
|
+
"Content-Type": "application/json",
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
# ── API Methods ──────────────────────────────────────────────
|
|
43
|
+
|
|
44
|
+
def _request(self, method: str, path: str, **kwargs) -> Any:
|
|
45
|
+
"""Make an HTTP request to the ONEMIX Bot API."""
|
|
46
|
+
url = f"{self.api_url}{path}"
|
|
47
|
+
try:
|
|
48
|
+
resp = self._session.request(method, url, **kwargs)
|
|
49
|
+
resp.raise_for_status()
|
|
50
|
+
return resp.json()
|
|
51
|
+
except requests.exceptions.HTTPError as e:
|
|
52
|
+
logger.error("API error %s %s: %s — %s", method, path, e, resp.text)
|
|
53
|
+
raise
|
|
54
|
+
except requests.exceptions.RequestException as e:
|
|
55
|
+
logger.error("Request failed %s %s: %s", method, path, e)
|
|
56
|
+
raise
|
|
57
|
+
|
|
58
|
+
def get_me(self) -> dict:
|
|
59
|
+
"""Get information about this bot."""
|
|
60
|
+
data = self._request("GET", "/bot-api/getMe")
|
|
61
|
+
return data.get("result", data)
|
|
62
|
+
|
|
63
|
+
def send_message(self, chat_id: str, text: str) -> dict:
|
|
64
|
+
"""
|
|
65
|
+
Send a text message to a bot chat.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
chat_id: The bot_chat_id to send to
|
|
69
|
+
text: Message text
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
dict with ok and message_id
|
|
73
|
+
"""
|
|
74
|
+
return self._request("POST", "/bot-api/sendMessage", json={
|
|
75
|
+
"chat_id": chat_id,
|
|
76
|
+
"text": text,
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
def reply(self, message: dict, text: str) -> dict:
|
|
80
|
+
"""
|
|
81
|
+
Convenience method to reply to a received message.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
message: The incoming message dict (must have bot_chat_id)
|
|
85
|
+
text: Reply text
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
dict with ok and message_id
|
|
89
|
+
"""
|
|
90
|
+
chat_id = message.get("bot_chat_id")
|
|
91
|
+
if not chat_id:
|
|
92
|
+
raise ValueError("Message has no bot_chat_id")
|
|
93
|
+
return self.send_message(chat_id, text)
|
|
94
|
+
|
|
95
|
+
def get_updates(self, limit: int = 100) -> List[dict]:
|
|
96
|
+
"""
|
|
97
|
+
Get recent messages sent to this bot.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
limit: Maximum number of updates to fetch
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
List of message dicts
|
|
104
|
+
"""
|
|
105
|
+
data = self._request("GET", f"/bot-api/getUpdates?limit={limit}")
|
|
106
|
+
return data.get("result", [])
|
|
107
|
+
|
|
108
|
+
def set_webhook(self, url: str, secret: Optional[str] = None) -> dict:
|
|
109
|
+
"""
|
|
110
|
+
Set a webhook URL for receiving updates.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
url: Your webhook endpoint (must be HTTPS in production)
|
|
114
|
+
secret: Optional secret for verifying webhook calls
|
|
115
|
+
"""
|
|
116
|
+
me = self.get_me()
|
|
117
|
+
bot_id = me.get("id")
|
|
118
|
+
if not bot_id:
|
|
119
|
+
raise ValueError("Could not get bot ID")
|
|
120
|
+
payload = {"url": url}
|
|
121
|
+
if secret:
|
|
122
|
+
payload["secret"] = secret
|
|
123
|
+
return self._request("POST", f"/botfather/{bot_id}/webhook", json=payload)
|
|
124
|
+
|
|
125
|
+
def delete_webhook(self) -> dict:
|
|
126
|
+
"""Remove the webhook."""
|
|
127
|
+
me = self.get_me()
|
|
128
|
+
bot_id = me.get("id")
|
|
129
|
+
if not bot_id:
|
|
130
|
+
raise ValueError("Could not get bot ID")
|
|
131
|
+
return self._request("DELETE", f"/botfather/{bot_id}/webhook")
|
|
132
|
+
|
|
133
|
+
def set_commands(self, commands: List[Dict[str, str]]) -> dict:
|
|
134
|
+
"""
|
|
135
|
+
Set bot commands visible to users.
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
commands: List of {"command": "...", "description": "..."}
|
|
139
|
+
"""
|
|
140
|
+
me = self.get_me()
|
|
141
|
+
bot_id = me.get("id")
|
|
142
|
+
if not bot_id:
|
|
143
|
+
raise ValueError("Could not get bot ID")
|
|
144
|
+
return self._request("POST", f"/botfather/{bot_id}/commands", json={
|
|
145
|
+
"commands": commands,
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
# ── Decorators ───────────────────────────────────────────────
|
|
149
|
+
|
|
150
|
+
def command(self, cmd: str):
|
|
151
|
+
"""
|
|
152
|
+
Decorator to register a command handler.
|
|
153
|
+
|
|
154
|
+
Usage:
|
|
155
|
+
@bot.command("start")
|
|
156
|
+
def on_start(msg):
|
|
157
|
+
bot.reply(msg, "Hello!")
|
|
158
|
+
"""
|
|
159
|
+
def decorator(func: Callable):
|
|
160
|
+
clean_cmd = cmd.lstrip("/").lower()
|
|
161
|
+
self._command_handlers[clean_cmd] = func
|
|
162
|
+
return func
|
|
163
|
+
return decorator
|
|
164
|
+
|
|
165
|
+
def on_message(self, pattern: Optional[str] = None):
|
|
166
|
+
"""
|
|
167
|
+
Decorator to register a message handler.
|
|
168
|
+
|
|
169
|
+
Args:
|
|
170
|
+
pattern: Optional regex pattern to match against message content
|
|
171
|
+
|
|
172
|
+
Usage:
|
|
173
|
+
@bot.on_message()
|
|
174
|
+
def on_text(msg):
|
|
175
|
+
bot.reply(msg, "Got it!")
|
|
176
|
+
|
|
177
|
+
@bot.on_message(pattern=r"hello|hi")
|
|
178
|
+
def on_hello(msg):
|
|
179
|
+
bot.reply(msg, "Hey!")
|
|
180
|
+
"""
|
|
181
|
+
def decorator(func: Callable):
|
|
182
|
+
compiled = re.compile(pattern, re.IGNORECASE) if pattern else None
|
|
183
|
+
self._message_handlers.append({
|
|
184
|
+
"func": func,
|
|
185
|
+
"pattern": compiled,
|
|
186
|
+
})
|
|
187
|
+
return func
|
|
188
|
+
return decorator
|
|
189
|
+
|
|
190
|
+
# ── Update Processing ────────────────────────────────────────
|
|
191
|
+
|
|
192
|
+
def process_update(self, update: dict):
|
|
193
|
+
"""
|
|
194
|
+
Process a single update (message). Used for webhook mode.
|
|
195
|
+
|
|
196
|
+
Args:
|
|
197
|
+
update: The update dict from the webhook POST body
|
|
198
|
+
"""
|
|
199
|
+
msg = update.get("message", update)
|
|
200
|
+
content = msg.get("content", "")
|
|
201
|
+
|
|
202
|
+
# Try command handlers first
|
|
203
|
+
if content.startswith("/"):
|
|
204
|
+
parts = content.split(None, 1)
|
|
205
|
+
cmd_name = parts[0].lstrip("/").lower()
|
|
206
|
+
if cmd_name in self._command_handlers:
|
|
207
|
+
try:
|
|
208
|
+
self._command_handlers[cmd_name](msg)
|
|
209
|
+
except Exception as e:
|
|
210
|
+
logger.error("Command handler error /%s: %s", cmd_name, e)
|
|
211
|
+
return
|
|
212
|
+
|
|
213
|
+
# Try message handlers
|
|
214
|
+
for handler in self._message_handlers:
|
|
215
|
+
if handler["pattern"]:
|
|
216
|
+
if handler["pattern"].search(content):
|
|
217
|
+
try:
|
|
218
|
+
handler["func"](msg)
|
|
219
|
+
except Exception as e:
|
|
220
|
+
logger.error("Message handler error: %s", e)
|
|
221
|
+
return
|
|
222
|
+
else:
|
|
223
|
+
try:
|
|
224
|
+
handler["func"](msg)
|
|
225
|
+
except Exception as e:
|
|
226
|
+
logger.error("Message handler error: %s", e)
|
|
227
|
+
return
|
|
228
|
+
|
|
229
|
+
def _poll_once(self):
|
|
230
|
+
"""Fetch and process new updates once."""
|
|
231
|
+
try:
|
|
232
|
+
updates = self.get_updates(limit=100)
|
|
233
|
+
for update in updates:
|
|
234
|
+
msg_id = update.get("id")
|
|
235
|
+
if msg_id and msg_id not in self._seen_ids:
|
|
236
|
+
self._seen_ids.add(msg_id)
|
|
237
|
+
self.process_update(update)
|
|
238
|
+
|
|
239
|
+
# Keep seen_ids from growing infinitely
|
|
240
|
+
if len(self._seen_ids) > 10000:
|
|
241
|
+
self._seen_ids = set(list(self._seen_ids)[-5000:])
|
|
242
|
+
|
|
243
|
+
except Exception as e:
|
|
244
|
+
logger.error("Poll error: %s", e)
|
|
245
|
+
|
|
246
|
+
# ── Main Loop ────────────────────────────────────────────────
|
|
247
|
+
|
|
248
|
+
def run(self, api_url: Optional[str] = None):
|
|
249
|
+
"""
|
|
250
|
+
Start the long-polling loop. Blocks the current thread.
|
|
251
|
+
|
|
252
|
+
Args:
|
|
253
|
+
api_url: Override the API URL (optional)
|
|
254
|
+
"""
|
|
255
|
+
if api_url:
|
|
256
|
+
self.api_url = api_url.rstrip("/")
|
|
257
|
+
|
|
258
|
+
if not self.api_url:
|
|
259
|
+
raise ValueError("api_url is required. Pass it to OnemixBot() or run().")
|
|
260
|
+
|
|
261
|
+
self._running = True
|
|
262
|
+
me = self.get_me()
|
|
263
|
+
bot_name = me.get("name", "Unknown")
|
|
264
|
+
bot_username = me.get("username", "unknown")
|
|
265
|
+
logger.info("Bot started: %s (@%s)", bot_name, bot_username)
|
|
266
|
+
print(f"[onemix-bot] Started: {bot_name} (@{bot_username})")
|
|
267
|
+
print(f"[onemix-bot] Polling {self.api_url} every {self.poll_interval}s")
|
|
268
|
+
print(f"[onemix-bot] Registered: {len(self._command_handlers)} commands, "
|
|
269
|
+
f"{len(self._message_handlers)} message handlers")
|
|
270
|
+
|
|
271
|
+
# Pre-fill seen IDs so we don't process old messages
|
|
272
|
+
try:
|
|
273
|
+
old = self.get_updates(limit=100)
|
|
274
|
+
for u in old:
|
|
275
|
+
mid = u.get("id")
|
|
276
|
+
if mid:
|
|
277
|
+
self._seen_ids.add(mid)
|
|
278
|
+
logger.info("Skipped %d existing messages", len(self._seen_ids))
|
|
279
|
+
except Exception:
|
|
280
|
+
pass
|
|
281
|
+
|
|
282
|
+
try:
|
|
283
|
+
while self._running:
|
|
284
|
+
self._poll_once()
|
|
285
|
+
time.sleep(self.poll_interval)
|
|
286
|
+
except KeyboardInterrupt:
|
|
287
|
+
print("\n[onemix-bot] Stopped")
|
|
288
|
+
self._running = False
|
|
289
|
+
|
|
290
|
+
def stop(self):
|
|
291
|
+
"""Stop the polling loop."""
|
|
292
|
+
self._running = False
|
|
293
|
+
|
|
294
|
+
def run_threaded(self, api_url: Optional[str] = None) -> threading.Thread:
|
|
295
|
+
"""
|
|
296
|
+
Start the polling loop in a background thread.
|
|
297
|
+
|
|
298
|
+
Returns:
|
|
299
|
+
The started Thread object
|
|
300
|
+
"""
|
|
301
|
+
t = threading.Thread(target=self.run, args=(api_url,), daemon=True)
|
|
302
|
+
t.start()
|
|
303
|
+
return t
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: onemix-bot
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Python SDK for building bots on the ONEMIX messenger platform
|
|
5
|
+
Home-page: https://github.com/onemix/bot-sdk-python
|
|
6
|
+
Author: ONEMIX Team
|
|
7
|
+
Author-email: support@itpaxlive.ru
|
|
8
|
+
Keywords: onemix bot messenger api sdk
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Communications :: Chat
|
|
19
|
+
Requires-Python: >=3.8
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
Requires-Dist: requests>=2.25.0
|
|
22
|
+
Provides-Extra: webhook
|
|
23
|
+
Requires-Dist: flask>=2.0.0; extra == "webhook"
|
|
24
|
+
Dynamic: author
|
|
25
|
+
Dynamic: author-email
|
|
26
|
+
Dynamic: classifier
|
|
27
|
+
Dynamic: description
|
|
28
|
+
Dynamic: description-content-type
|
|
29
|
+
Dynamic: home-page
|
|
30
|
+
Dynamic: keywords
|
|
31
|
+
Dynamic: provides-extra
|
|
32
|
+
Dynamic: requires-dist
|
|
33
|
+
Dynamic: requires-python
|
|
34
|
+
Dynamic: summary
|
|
35
|
+
|
|
36
|
+
# onemix-bot — Python SDK для ботов ONEMIX
|
|
37
|
+
|
|
38
|
+
Библиотека для создания ботов на платформе ONEMIX мессенджера.
|
|
39
|
+
|
|
40
|
+
## Установка
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install onemix-bot
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Или из исходников:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
git clone <repo>
|
|
50
|
+
cd onemix-bot-sdk
|
|
51
|
+
pip install -e .
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Быстрый старт
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
from onemix_bot import OnemixBot
|
|
58
|
+
|
|
59
|
+
bot = OnemixBot(
|
|
60
|
+
token="YOUR_BOT_TOKEN", # Получите у @botfather
|
|
61
|
+
api_url="https://your-server.com" # URL вашего ONEMIX сервера
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
@bot.command("start")
|
|
65
|
+
def on_start(msg):
|
|
66
|
+
bot.reply(msg, "Привет! Я бот ONEMIX")
|
|
67
|
+
|
|
68
|
+
@bot.on_message()
|
|
69
|
+
def echo(msg):
|
|
70
|
+
bot.reply(msg, f"Вы написали: {msg['content']}")
|
|
71
|
+
|
|
72
|
+
bot.run()
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## API
|
|
76
|
+
|
|
77
|
+
### OnemixBot(token, api_url, poll_interval=2.0)
|
|
78
|
+
|
|
79
|
+
Создаёт экземпляр бота.
|
|
80
|
+
|
|
81
|
+
### Методы
|
|
82
|
+
|
|
83
|
+
| Метод | Описание |
|
|
84
|
+
|-------|----------|
|
|
85
|
+
| `bot.get_me()` | Информация о боте |
|
|
86
|
+
| `bot.send_message(chat_id, text)` | Отправить сообщение |
|
|
87
|
+
| `bot.reply(msg, text)` | Ответить на сообщение |
|
|
88
|
+
| `bot.get_updates(limit=100)` | Получить обновления |
|
|
89
|
+
| `bot.set_webhook(url, secret=None)` | Установить вебхук |
|
|
90
|
+
| `bot.delete_webhook()` | Удалить вебхук |
|
|
91
|
+
| `bot.set_commands(commands)` | Установить команды |
|
|
92
|
+
| `bot.run()` | Запустить polling loop |
|
|
93
|
+
| `bot.run_threaded()` | Запустить в фоновом потоке |
|
|
94
|
+
| `bot.stop()` | Остановить polling |
|
|
95
|
+
| `bot.process_update(update)` | Обработать обновление (для вебхуков) |
|
|
96
|
+
|
|
97
|
+
### Декораторы
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
@bot.command("start") # Обработка команды /start
|
|
101
|
+
@bot.on_message() # Обработка всех текстовых сообщений
|
|
102
|
+
@bot.on_message(pattern=r"") # Обработка по regex-шаблону
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Webhook-режим
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
from flask import Flask, request
|
|
109
|
+
from onemix_bot import OnemixBot
|
|
110
|
+
|
|
111
|
+
app = Flask(__name__)
|
|
112
|
+
bot = OnemixBot(token="TOKEN", api_url="https://server.com")
|
|
113
|
+
|
|
114
|
+
@bot.command("start")
|
|
115
|
+
def start(msg):
|
|
116
|
+
bot.reply(msg, "Привет!")
|
|
117
|
+
|
|
118
|
+
@app.route("/webhook", methods=["POST"])
|
|
119
|
+
def webhook():
|
|
120
|
+
bot.process_update(request.json)
|
|
121
|
+
return "ok"
|
|
122
|
+
|
|
123
|
+
if __name__ == "__main__":
|
|
124
|
+
bot.set_webhook("https://your-server.com/webhook")
|
|
125
|
+
app.run(port=5000)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Лицензия
|
|
129
|
+
|
|
130
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
onemix_bot
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
setup(
|
|
4
|
+
name="onemix-bot",
|
|
5
|
+
version="1.0.0",
|
|
6
|
+
description="Python SDK for building bots on the ONEMIX messenger platform",
|
|
7
|
+
long_description=open("README.md").read(),
|
|
8
|
+
long_description_content_type="text/markdown",
|
|
9
|
+
author="ONEMIX Team",
|
|
10
|
+
author_email="support@itpaxlive.ru",
|
|
11
|
+
url="https://github.com/onemix/bot-sdk-python",
|
|
12
|
+
packages=find_packages(),
|
|
13
|
+
python_requires=">=3.8",
|
|
14
|
+
install_requires=[
|
|
15
|
+
"requests>=2.25.0",
|
|
16
|
+
],
|
|
17
|
+
extras_require={
|
|
18
|
+
"webhook": ["flask>=2.0.0"],
|
|
19
|
+
},
|
|
20
|
+
classifiers=[
|
|
21
|
+
"Development Status :: 4 - Beta",
|
|
22
|
+
"Intended Audience :: Developers",
|
|
23
|
+
"License :: OSI Approved :: MIT License",
|
|
24
|
+
"Programming Language :: Python :: 3",
|
|
25
|
+
"Programming Language :: Python :: 3.8",
|
|
26
|
+
"Programming Language :: Python :: 3.9",
|
|
27
|
+
"Programming Language :: Python :: 3.10",
|
|
28
|
+
"Programming Language :: Python :: 3.11",
|
|
29
|
+
"Programming Language :: Python :: 3.12",
|
|
30
|
+
"Topic :: Communications :: Chat",
|
|
31
|
+
],
|
|
32
|
+
keywords="onemix bot messenger api sdk",
|
|
33
|
+
)
|