Pikilap commited on
Commit
cd182cf
·
1 Parent(s): 43e4c76

feat(命令): 重构机器人消息处理并添加静音/解除静音命令,包括更新忽略文件、优化消息格式和错误处理、实现静音和解除静音命令以及增强命令处理逻辑

Browse files
Files changed (5) hide show
  1. .gitignore +1 -1
  2. APP/bot_utils.py +12 -19
  3. APP/commands.py +153 -1
  4. APP/handlers.py +1 -1
  5. APP/webhook.py +12 -7
.gitignore CHANGED
@@ -1,4 +1,4 @@
1
- test.py
2
  __pycache__
3
  .env
4
  .venv
 
1
+ *test*
2
  __pycache__
3
  .env
4
  .venv
APP/bot_utils.py CHANGED
@@ -32,30 +32,23 @@ def call_ai_stream_api(api_url, model, messages, api_key):
32
  logging.error(f"AI API 请求失败: {e}")
33
  raise
34
 
35
- def send_bot_message(bot, chat_id, text, reply_to_message_id=None, parse_mode='MarkdownV2', reply_markup=None):
36
  try:
37
- sent_message = bot.send_message(
38
- chat_id,
39
- text,
40
- reply_to_message_id=reply_to_message_id,
41
- parse_mode=parse_mode,
42
- reply_markup=reply_markup
43
- )
44
- if sent_message and hasattr(sent_message, 'message_id'):
45
- add_message_to_delete_queue(chat_id, sent_message.message_id)
46
- logging.info(f"消息已发送到聊天 {chat_id}")
47
- return sent_message
48
  else:
49
- logging.error(f"发送消息到聊天 {chat_id} 失败: 无效的响应格式")
50
- return None
51
  except ApiTelegramException as e:
52
- if e.error_code == 400 and "chat not found" in e.description:
53
- logging.warning(f"聊天 {chat_id} 未找到")
54
- else:
55
- logging.error(f"发送消息到聊天 {chat_id} 失败: {e}")
56
  except Exception as e:
57
  logging.error(f"发送消息到聊天 {chat_id} 失败: {e}")
58
- return None
59
 
60
  def edit_bot_message(bot, chat_id, message_id, text, parse_mode='MarkdownV2'):
61
  try:
 
32
  logging.error(f"AI API 请求失败: {e}")
33
  raise
34
 
35
+ def send_bot_message(bot, chat_id, message, parse_mode='MarkdownV2', disable_web_page_preview=None):
36
  try:
37
+ if parse_mode == "HTML":
38
+ sent_message = bot.send_message(chat_id, message, parse_mode="HTML", disable_web_page_preview=disable_web_page_preview)
39
+ elif parse_mode == "MarkdownV2":
40
+ escaped_message = telegramify_markdown.markdownify(message)
41
+ sent_message = bot.send_message(chat_id, escaped_message, parse_mode='MarkdownV2', disable_web_page_preview=disable_web_page_preview)
 
 
 
 
 
 
42
  else:
43
+ sent_message = bot.send_message(chat_id, message, disable_web_page_preview=disable_web_page_preview)
44
+ return sent_message
45
  except ApiTelegramException as e:
46
+ error_message = str(e)
47
+ logging.error(f"发送消息到聊天 {chat_id} 失败: {error_message}")
48
+ bot.send_message(chat_id, f"错误: {error_message}", parse_mode='MarkdownV2')
 
49
  except Exception as e:
50
  logging.error(f"发送消息到聊天 {chat_id} 失败: {e}")
51
+ bot.send_message(chat_id, f"错误: {e}", parse_mode='MarkdownV2')
52
 
53
  def edit_bot_message(bot, chat_id, message_id, text, parse_mode='MarkdownV2'):
54
  try:
APP/commands.py CHANGED
@@ -2,6 +2,7 @@ import logging
2
  import datetime
3
  import json
4
  import random
 
5
  import time
6
  import telegramify_markdown
7
  from telebot import types
@@ -154,4 +155,155 @@ def handle_reset_db_command(message: types.Message, bot, thread_local):
154
 
155
  sent_message = bot.send_message(chat_id, f"请点击下方正确的验证码以确认操作:\n**正确验证码:{correct_code}**", reply_markup=markup, parse_mode="MarkdownV2")
156
 
157
- thread_local.verification_codes = {user_id: {"code": correct_code, "timestamp": time.time()}}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  import datetime
3
  import json
4
  import random
5
+ import re
6
  import time
7
  import telegramify_markdown
8
  from telebot import types
 
155
 
156
  sent_message = bot.send_message(chat_id, f"请点击下方正确的验证码以确认操作:\n**正确验证码:{correct_code}**", reply_markup=markup, parse_mode="MarkdownV2")
157
 
158
+ thread_local.verification_codes = {user_id: {"code": correct_code, "timestamp": time.time()}}
159
+
160
+ def handle_mute_command(message: types.Message, bot, thread_local):
161
+ chat_id = message.chat.id
162
+ user_id = message.from_user.id
163
+
164
+ if chat_id < 0 and not is_group_admin(chat_id, user_id, message, bot):
165
+ send_bot_message(bot, chat_id, "你并非管理员,故无权限", parse_mode="MarkdownV2")
166
+ logging.warning(f"用户 {user_id} 尝试禁言用户,但无权限")
167
+ return
168
+
169
+ args = message.text.split()[1:]
170
+ target_user = None
171
+ time_str = None
172
+ reason = None
173
+
174
+ if message.reply_to_message:
175
+ target_user = message.reply_to_message.from_user
176
+ if args:
177
+ time_str = args[0]
178
+ reason = " ".join(args[1:])
179
+ elif len(args) >= 2:
180
+ user_str, time_str, *reason_parts = args
181
+ reason = " ".join(reason_parts)
182
+ try:
183
+ target_user = bot.get_chat_member(chat_id, user_str.lstrip('@')).user
184
+ except Exception:
185
+ send_bot_message(bot, chat_id, "无法找到用户", parse_mode="MarkdownV2")
186
+ logging.warning(f"禁言用户时发生错误: 无法找到用户")
187
+ return
188
+ else:
189
+ send_bot_message(bot, chat_id, "请使用正确的格式: `.mute [user] [time] [reason]` 或引用消息", parse_mode="MarkdownV2")
190
+ return
191
+
192
+ if not target_user:
193
+ send_bot_message(bot, chat_id, "请使用正确的格式: `.mute [user] [time] [reason]` 或引用消息", parse_mode="MarkdownV2")
194
+ return
195
+
196
+ try:
197
+ mute_duration = parse_duration(time_str)
198
+ except ValueError:
199
+ send_bot_message(bot, chat_id, "时间格式不正确", parse_mode="MarkdownV2")
200
+ return
201
+ except Exception as e:
202
+ send_bot_message(bot, chat_id, f"解析时间失败: {e}", parse_mode="MarkdownV2")
203
+ logging.warning(f"解析时间失败: {e}")
204
+ return
205
+
206
+ until_date = datetime.datetime.now() + datetime.timedelta(seconds=mute_duration) if mute_duration >= 30 else None
207
+
208
+ try:
209
+ bot.restrict_chat_member(chat_id, target_user.id, permissions=types.ChatPermissions(can_send_messages=False), until_date=until_date)
210
+ except Exception as e:
211
+ send_bot_message(bot, chat_id, f"禁言用户失败: {e}", parse_mode="MarkdownV2")
212
+ logging.warning(f"禁言用户失败: {e}")
213
+ return
214
+
215
+ formatted_time = str(datetime.timedelta(seconds=mute_duration)) if mute_duration else "永久"
216
+ admin_username = message.from_user.username or message.from_user.first_name
217
+
218
+ mute_message = (
219
+ "<b>禁言通知</b>\n\n"
220
+ f"被禁言用户: @{target_user.username or target_user.first_name}\n"
221
+ f"操作管理员: @{admin_username}\n"
222
+ f"禁言时长: <code>{formatted_time}</code>\n"
223
+ )
224
+ if reason:
225
+ mute_message += f"理由: <code>{reason}</code>\n"
226
+ if until_date:
227
+ mute_message += f"解除时间: <code>{until_date.strftime('%Y-%m-%d %H:%M:%S')}</code>"
228
+
229
+ send_bot_message(bot, chat_id, mute_message, parse_mode="HTML")
230
+ logging.info(f"用户 {user_id} 禁言用户 {target_user.id},时长 {time_str},原因: {reason}")
231
+
232
+
233
+ def handle_unmute_command(message: types.Message, bot, thread_local):
234
+ chat_id = message.chat.id
235
+ user_id = message.from_user.id
236
+
237
+ if chat_id < 0 and not is_group_admin(chat_id, user_id, message, bot):
238
+ send_bot_message(bot, chat_id, "你并非管理员,故无权限", parse_mode="MarkdownV2")
239
+ logging.warning(f"用户 {user_id} 尝试解禁用户,但无权限")
240
+ return
241
+
242
+ args = message.text.split()[1:]
243
+ target_user = None
244
+ reason = None
245
+
246
+ if message.reply_to_message:
247
+ target_user = message.reply_to_message.from_user
248
+ reason = " ".join(args)
249
+ elif args:
250
+ user_str, *reason_parts = args
251
+ reason = " ".join(reason_parts)
252
+ try:
253
+ target_user = bot.get_chat_member(chat_id, user_str.lstrip('@')).user
254
+ except Exception:
255
+ send_bot_message(bot, chat_id, "无法找到用户", parse_mode="MarkdownV2")
256
+ logging.warning(f"解禁用户时发生错误: 无法找到用户")
257
+ return
258
+ else:
259
+ send_bot_message(bot, chat_id, "请使用正确的格式: `.unmute [user] [reason]` 或引用消息", parse_mode="MarkdownV2")
260
+ return
261
+
262
+ if not target_user:
263
+ send_bot_message(bot, chat_id, "请使用正确的���式: `.unmute [user] [reason]` 或引用消息", parse_mode="MarkdownV2")
264
+ return
265
+
266
+ try:
267
+ bot.restrict_chat_member(chat_id, target_user.id, permissions=types.ChatPermissions(can_send_messages=True))
268
+ except Exception as e:
269
+ send_bot_message(bot, chat_id, f"解禁用户失败: {e}", parse_mode="MarkdownV2")
270
+ logging.warning(f"解禁用户失败: {e}")
271
+ return
272
+
273
+ admin_username = message.from_user.username or message.from_user.first_name
274
+ unmute_message = (
275
+ "<b>解除禁言通知</b>\n\n"
276
+ f"被解禁用户: @{target_user.username or target_user.first_name}\n"
277
+ f"操作管理员: @{admin_username}\n"
278
+ )
279
+ if reason:
280
+ unmute_message += f"理由: <code>{reason}</code>"
281
+ send_bot_message(bot, chat_id, unmute_message, parse_mode="HTML")
282
+ logging.info(f"用户 {user_id} 解禁用户 {target_user.id},原因: {reason}")
283
+
284
+ def parse_duration(duration_str):
285
+ if not duration_str:
286
+ return None
287
+
288
+ duration_str = duration_str.lower()
289
+ total_seconds = 0
290
+
291
+ pattern = re.compile(r'(\d+)([smhd])')
292
+
293
+ for match in pattern.finditer(duration_str):
294
+ value, unit = match.groups()
295
+ value = int(value)
296
+
297
+ if unit == 's':
298
+ total_seconds += value
299
+ elif unit == 'm':
300
+ total_seconds += value * 60
301
+ elif unit == 'h':
302
+ total_seconds += value * 3600
303
+ elif unit == 'd':
304
+ total_seconds += value * 86400
305
+
306
+ if not total_seconds and duration_str:
307
+ raise ValueError("无效的时间单位")
308
+
309
+ return total_seconds
APP/handlers.py CHANGED
@@ -71,7 +71,7 @@ def handle_model_selection(call: types.CallbackQuery, bot, thread_local):
71
  def handle_reset_db_verification(call: types.CallbackQuery, bot, thread_local):
72
  user_id = call.from_user.id
73
  chat_id = call.message.chat.id
74
- selected_code = call.data.replace("resetdb_verify_", "") # 确保解析逻辑与 callback_data 格式一致
75
  user_code_data = getattr(thread_local, 'verification_codes', {}).get(user_id)
76
 
77
  if not user_code_data:
 
71
  def handle_reset_db_verification(call: types.CallbackQuery, bot, thread_local):
72
  user_id = call.from_user.id
73
  chat_id = call.message.chat.id
74
+ selected_code = call.data.replace("resetdb_verify_", "")
75
  user_code_data = getattr(thread_local, 'verification_codes', {}).get(user_id)
76
 
77
  if not user_code_data:
APP/webhook.py CHANGED
@@ -5,8 +5,8 @@ from handlers import (
5
  handle_model_page_navigation, handle_reset_db_verification,
6
  )
7
  from commands import (
8
- handle_set_command, handle_clear_command, handle_reset_db_command,
9
- handle_json_command, handle_id_command
10
  )
11
  import logging
12
 
@@ -21,7 +21,9 @@ async def telegram_webhook(request: Request, token: str, bot, thread_local):
21
  try:
22
  body = await request.json()
23
  update = telebot.types.Update.de_json(body)
24
-
 
 
25
  if update.callback_query:
26
  callback_query = update.callback_query
27
  if callback_query.data.startswith('resetdb_verify_'):
@@ -33,7 +35,7 @@ async def telegram_webhook(request: Request, token: str, bot, thread_local):
33
 
34
  elif update.message:
35
  message = update.message
36
- if should_process_message(message, bot):
37
  if message.text and message.text.startswith('.set'):
38
  handle_set_command(message, bot, thread_local)
39
  elif message.text and message.text.startswith('.clear'):
@@ -44,6 +46,10 @@ async def telegram_webhook(request: Request, token: str, bot, thread_local):
44
  handle_json_command(message, bot)
45
  elif message.text and message.text.startswith('.id'):
46
  handle_id_command(message, bot)
 
 
 
 
47
  else:
48
  handle_message(message, bot, thread_local)
49
 
@@ -54,13 +60,12 @@ async def telegram_webhook(request: Request, token: str, bot, thread_local):
54
  logging.error(f"Webhook 处理失败: {e}", exc_info=True)
55
  return Response(status_code=500)
56
 
57
- def should_process_message(message: telebot.types.Message, bot):
58
- direct_commands = [".set", ".clear", ".resetdb", ".json", ".id"]
59
 
60
  if message.chat.type == 'private':
61
  return True
62
  elif message.chat.type in ['group', 'supergroup']:
63
- bot_username = bot.get_me().username
64
  if message.reply_to_message and message.reply_to_message.from_user.id == bot.get_me().id:
65
  return True
66
  elif message.text:
 
5
  handle_model_page_navigation, handle_reset_db_verification,
6
  )
7
  from commands import (
8
+ handle_mute_command, handle_set_command, handle_clear_command, handle_reset_db_command,
9
+ handle_json_command, handle_id_command, handle_unmute_command
10
  )
11
  import logging
12
 
 
21
  try:
22
  body = await request.json()
23
  update = telebot.types.Update.de_json(body)
24
+
25
+ bot_username = bot.get_me().username
26
+
27
  if update.callback_query:
28
  callback_query = update.callback_query
29
  if callback_query.data.startswith('resetdb_verify_'):
 
35
 
36
  elif update.message:
37
  message = update.message
38
+ if should_process_message(message, bot, bot_username):
39
  if message.text and message.text.startswith('.set'):
40
  handle_set_command(message, bot, thread_local)
41
  elif message.text and message.text.startswith('.clear'):
 
46
  handle_json_command(message, bot)
47
  elif message.text and message.text.startswith('.id'):
48
  handle_id_command(message, bot)
49
+ elif message.text and message.text.startswith('.mute'):
50
+ handle_mute_command(message, bot, thread_local)
51
+ elif message.text and message.text.startswith('.unmute'):
52
+ handle_unmute_command(message, bot, thread_local)
53
  else:
54
  handle_message(message, bot, thread_local)
55
 
 
60
  logging.error(f"Webhook 处理失败: {e}", exc_info=True)
61
  return Response(status_code=500)
62
 
63
+ def should_process_message(message: telebot.types.Message, bot, bot_username):
64
+ direct_commands = [".set", ".clear", ".resetdb", ".json", ".id", ".mute", ".unmute"]
65
 
66
  if message.chat.type == 'private':
67
  return True
68
  elif message.chat.type in ['group', 'supergroup']:
 
69
  if message.reply_to_message and message.reply_to_message.from_user.id == bot.get_me().id:
70
  return True
71
  elif message.text: