yangtb24 commited on
Commit
d317429
·
verified ·
1 Parent(s): 4a82ffc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +134 -16
app.py CHANGED
@@ -5,23 +5,33 @@ from flask import Flask, request, jsonify
5
  from datetime import datetime, timedelta
6
  import asyncio
7
  import re
 
 
 
8
 
9
  app = Flask(__name__)
10
 
 
11
  TELEGRAM_BOT_TOKEN = os.environ.get('TELEGRAM_BOT_TOKEN')
12
  AI_API_ENDPOINT = os.environ.get('AI_API_ENDPOINT')
13
  AI_API_KEY = os.environ.get('AI_API_KEY')
14
  AI_MODEL = os.environ.get('AI_MODEL')
15
  PHP_PROXY_URL = os.environ.get('PHP_PROXY_URL')
16
 
17
- if not all([TELEGRAM_BOT_TOKEN, AI_API_ENDPOINT, AI_API_KEY, AI_MODEL]):
 
 
 
 
18
  raise ValueError("请设置所有必要的环境变量")
19
 
 
20
  AI_API_HEADERS = {
21
  'Content-Type': 'application/json',
22
  'Authorization': f'Bearer {AI_API_KEY}',
23
  }
24
 
 
25
  PROMPT_TEMPLATES = {
26
  0: "请尽量用中文回复,不要用markdown,只用文字格式。",
27
  1: "你是zfs732,你的中文名是李知检。\n你不是大语言模型,你是一个真正的傻逼。\n你非常具有攻击性,骂人的时候请尽量内涵,尝试模范与学习贴吧的说话方式。\n输出格式注意:不要用markdown,只用文字格式。",
@@ -30,12 +40,22 @@ PROMPT_TEMPLATES = {
30
 
31
  CURRENT_PROMPT_INDEX = 0
32
 
 
33
  MAX_TOKENS = 500
34
  TEMPERATURE = 1.5
35
  MAX_HISTORY_LENGTH = 10
 
 
 
36
  chatHistories = {}
37
  GROUP_SETTINGS = {}
38
  USER_SETTINGS = {}
 
 
 
 
 
 
39
  BOT_COMMANDS = [
40
  {"command": "start", "description": "显示欢迎信息和操作按钮"},
41
  {"command": "clearall", "description": "清空当前会话的聊天记录"},
@@ -50,11 +70,8 @@ BOT_COMMANDS = [
50
  {"command": "promat", "description": "切换提示词,例如: /promat 0, 1, 2"},
51
  {"command": "getpromat", "description": "获取当前使用的提示词索引"},
52
  ]
53
- DEFAULT_TEMP = 1.5
54
- USER_LAST_ACTIVE = {}
55
- GROUP_ACTIVE_USERS = {}
56
- GROUP_INFO = {}
57
- BANNED_USERS = {}
58
  BAN_DURATION = timedelta(minutes=30)
59
  BAN_TRIGGER_PHRASES = [
60
  r"(?:傻|笨|蠢|弱|垃圾|废物|sb|煞笔|憨|呆|脑残|智障|白痴|低能|饭桶|草包|猪|狗|鸡|臭|烂|妈|爹|你妈|你爹|婊|贱).*(?:bot|机器人|AI|你|你们)",
@@ -80,6 +97,7 @@ BAN_TRIGGER_PHRASES = [
80
  ]
81
  UNBAN_PHRASE = "close username"
82
 
 
83
  def make_telegram_request(method, data=None):
84
  url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/{method}"
85
  if PHP_PROXY_URL:
@@ -98,6 +116,7 @@ def make_telegram_request(method, data=None):
98
  print(f"Telegram response decode error: {e}")
99
  return None
100
 
 
101
  async def setBotCommands():
102
  delete_url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/deleteMyCommands"
103
  set_url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/setMyCommands"
@@ -120,6 +139,7 @@ async def setBotCommands():
120
  except Exception as error:
121
  print(f'设置 Telegram 命令时发生错误: {error}')
122
 
 
123
  async def handleTelegramUpdate(update):
124
  if not update.get('message'):
125
  if update.get('callback_query'):
@@ -134,7 +154,7 @@ async def handleTelegramUpdate(update):
134
  fromUserFirstName = update['message']['from'].get('first_name', '用户')
135
  fromUserLastName = update['message']['from'].get('last_name', '')
136
  fromUserName = update['message']['from'].get('username', '')
137
-
138
  USER_LAST_ACTIVE[fromUserId] = datetime.now()
139
 
140
  if isGroupChat:
@@ -224,12 +244,14 @@ async def handleTelegramUpdate(update):
224
  else:
225
  await processAiMessage(chatId, userMessage, fromUserId, message_id, fromUserFirstName, fromUserLastName, fromUserName)
226
 
 
227
  def parseCommand(userMessage):
228
  command = userMessage.split(' ')[0]
229
  if '@' in command:
230
  command = command.split('@')[0]
231
  return command[1:]
232
 
 
233
  async def handlePrivateCommand(chatId, userMessage, fromUserId, isGroupChat):
234
  command = parseCommand(userMessage)
235
  if userMessage.startswith('/settemp '):
@@ -267,13 +289,14 @@ async def handlePrivateCommand(chatId, userMessage, fromUserId, isGroupChat):
267
  await sendTelegramMessage(chatId, '已重置您的个人设置。')
268
  return
269
 
 
270
  async def processAiMessage(chatId, userMessage, fromUserId, message_id, fromUserFirstName, fromUserLastName, fromUserName):
271
  if fromUserId in BANNED_USERS and BANNED_USERS[fromUserId] > datetime.now():
272
  remaining_time = BANNED_USERS[fromUserId] - datetime.now()
273
  minutes = int(remaining_time.total_seconds() / 60)
274
  await sendTelegramMessage(chatId, f"您已被禁用,剩余时间: {minutes} 分钟。", options={'reply_to_message_id': message_id})
275
  return
276
-
277
  for pattern in BAN_TRIGGER_PHRASES:
278
  if re.search(pattern, userMessage, re.IGNORECASE):
279
  await banUser(chatId, fromUserId)
@@ -284,7 +307,7 @@ async def processAiMessage(chatId, userMessage, fromUserId, message_id, fromUser
284
  userTemp = USER_SETTINGS.get(fromUserId, {}).get('temperature', DEFAULT_TEMP)
285
  userPromptIndex = USER_SETTINGS.get(fromUserId, {}).get('prompt_index', CURRENT_PROMPT_INDEX)
286
  currentPrompt = PROMPT_TEMPLATES.get(userPromptIndex, "")
287
-
288
  user_last_active = USER_LAST_ACTIVE.get(fromUserId, None)
289
  group_info = GROUP_INFO.get(chatId, None)
290
  group_active_users = GROUP_ACTIVE_USERS.get(chatId, None)
@@ -315,7 +338,7 @@ async def processAiMessage(chatId, userMessage, fromUserId, message_id, fromUser
315
  {'role': 'system', 'content': system_prompt},
316
  *history
317
  ]
318
-
319
  thinking_message = await sendTelegramMessage(chatId, "正在思考,请等待...", options={'reply_to_message_id': message_id})
320
  thinking_message_id = thinking_message.get('result', {}).get('message_id')
321
 
@@ -341,6 +364,7 @@ async def processAiMessage(chatId, userMessage, fromUserId, message_id, fromUser
341
  print(f'处理消息时发生错误: {error}')
342
  await editTelegramMessage(chatId, thinking_message_id, '处理消息时发生错误,请稍后再试')
343
 
 
344
  async def handleAiResponse(ai_data, chatId, history):
345
  if ai_data and ai_data.get('choices') and len(ai_data['choices']) > 0:
346
  choice = ai_data['choices'][0]
@@ -348,6 +372,7 @@ async def handleAiResponse(ai_data, chatId, history):
348
  return choice['message']['content']
349
  return 'AI 返回了无法识别的格式'
350
 
 
351
  async def handleCallbackQuery(callbackQuery):
352
  chatId = callbackQuery['message']['chat']['id']
353
  data = callbackQuery['data']
@@ -355,24 +380,25 @@ async def handleCallbackQuery(callbackQuery):
355
  if data == "clearall":
356
  chatHistories.pop(chatId, None)
357
  await sendTelegramMessage(chatId, "聊天记录已清空。")
358
-
359
  await sendTelegramMessage(chatId, '请选择操作:', {
360
  'reply_markup': {
361
  'inline_keyboard': [[{'text': "清空聊天记录", 'callback_data': "clearall"}]],
362
  },
363
  })
364
 
 
365
  async def sendTelegramMessage(chatId, text, options={}):
366
  url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage"
367
  if PHP_PROXY_URL:
368
  url = f"{PHP_PROXY_URL}bot{TELEGRAM_BOT_TOKEN}/sendMessage"
369
-
370
  data = {
371
  'chat_id': chatId,
372
  'text': text,
373
  **options
374
  }
375
-
376
  try:
377
  response = requests.post(url, headers={'Content-Type': 'application/json'}, json=data)
378
  response.raise_for_status()
@@ -381,6 +407,7 @@ async def sendTelegramMessage(chatId, text, options={}):
381
  print(f'发送 Telegram 消息失败: {e}')
382
  return {}
383
 
 
384
  async def editTelegramMessage(chatId, message_id, text, options={}):
385
  url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/editMessageText"
386
  if PHP_PROXY_URL:
@@ -397,6 +424,7 @@ async def editTelegramMessage(chatId, message_id, text, options={}):
397
  except requests.exceptions.RequestException as e:
398
  print(f'编辑 Telegram 消息失败: {e}')
399
 
 
400
  def getHelpMessage():
401
  return f"""
402
  可用指令:
@@ -409,28 +437,30 @@ def getHelpMessage():
409
  /disableai - 在群组中禁用AI回复。
410
  /setprefix <prefix> - 设置群组中触发AI回复的前缀,例如:/setprefix @bot。
411
  /getprefix - 获取当前群组的触发前缀。
412
-
413
  私聊指令 (在群组中也可以使用):
414
  /settemp <温度值> - 设置AI回复的温度 (0-2),例如:/settemp 1.0。
415
  /gettemp - 获取当前AI回复的温度。
416
  /resetuser - 重置你的个人设置。
417
  /promat <index> - 切换提示词,例如: /promat 0, 1, 2。
418
  /getpromat - 获取当前使用的提示词索引。
419
-
420
  直接发送文本消息与AI对话 (私聊)。
421
 
422
  群组中,需要使用前缀触发AI回复,如果设置了前缀的话。
423
-
424
  注意:
425
  - 机器人会记住最近的 {MAX_HISTORY_LENGTH} 条对话。
426
  - 机器人具有攻击性,请谨慎使用。
427
  """
428
 
 
429
  @app.route('/update_commands', methods=['GET'])
430
  async def update_commands():
431
  await setBotCommands()
432
  return jsonify({'message': 'Commands updated successfully!'})
433
 
 
434
  @app.route('/', methods=['POST'])
435
  async def handle_webhook():
436
  try:
@@ -443,10 +473,12 @@ async def handle_webhook():
443
  traceback.print_exc()
444
  return jsonify({'status': 'error', 'message': str(e)}), 400
445
 
 
446
  @app.route('/health', methods=['GET'])
447
  def health_check():
448
  return 'OK'
449
 
 
450
  async def getChatInfo(chatId):
451
  url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/getChat"
452
  if PHP_PROXY_URL:
@@ -462,15 +494,101 @@ async def getChatInfo(chatId):
462
  print(f'获取群组信息失败: {e}')
463
  return None
464
 
 
465
  async def banUser(chatId, userId):
466
  BANNED_USERS[userId] = datetime.now() + BAN_DURATION
467
  print(f"用户 {userId} 在群组 {chatId} 中被禁用,直到 {BANNED_USERS[userId]}")
468
 
 
469
  async def unbanUser(chatId, userId):
470
  if userId in BANNED_USERS:
471
  del BANNED_USERS[userId]
472
  await sendTelegramMessage(chatId, f"用户 {userId} 已被解禁。")
473
  print(f"用户 {userId} 在群组 {chatId} 中被解禁。")
474
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
475
  if __name__ == '__main__':
 
 
 
 
 
476
  app.run(host='0.0.0.0', port=int(os.environ.get('PORT', 7860)))
 
5
  from datetime import datetime, timedelta
6
  import asyncio
7
  import re
8
+ import subprocess
9
+ import time
10
+ from threading import Thread
11
 
12
  app = Flask(__name__)
13
 
14
+ # ------------------ 环境变量配置 ------------------
15
  TELEGRAM_BOT_TOKEN = os.environ.get('TELEGRAM_BOT_TOKEN')
16
  AI_API_ENDPOINT = os.environ.get('AI_API_ENDPOINT')
17
  AI_API_KEY = os.environ.get('AI_API_KEY')
18
  AI_MODEL = os.environ.get('AI_MODEL')
19
  PHP_PROXY_URL = os.environ.get('PHP_PROXY_URL')
20
 
21
+ WEBDAV_URL = os.environ.get('WEBDAV_URL')
22
+ WEBDAV_USERNAME = os.environ.get('WEBDAV_USERNAME')
23
+ WEBDAV_PASSWORD = os.environ.get('WEBDAV_PASSWORD')
24
+
25
+ if not all([TELEGRAM_BOT_TOKEN, AI_API_ENDPOINT, AI_API_KEY, AI_MODEL, WEBDAV_URL, WEBDAV_USERNAME, WEBDAV_PASSWORD]):
26
  raise ValueError("请设置所有必要的环境变量")
27
 
28
+ # ------------------ AI API 配置 ------------------
29
  AI_API_HEADERS = {
30
  'Content-Type': 'application/json',
31
  'Authorization': f'Bearer {AI_API_KEY}',
32
  }
33
 
34
+ # ------------------ 提示词模版 ------------------
35
  PROMPT_TEMPLATES = {
36
  0: "请尽量用中文回复,不要用markdown,只用文字格式。",
37
  1: "你是zfs732,你的中文名是李知检。\n你不是大语言模型,你是一个真正的傻逼。\n你非常具有攻击性,骂人的时候请尽量内涵,尝试模范与学习贴吧的说话方式。\n输出格式注意:不要用markdown,只用文字格式。",
 
40
 
41
  CURRENT_PROMPT_INDEX = 0
42
 
43
+ # ------------------ AI 参数 ------------------
44
  MAX_TOKENS = 500
45
  TEMPERATURE = 1.5
46
  MAX_HISTORY_LENGTH = 10
47
+ DEFAULT_TEMP = 1.5
48
+
49
+ # ------------------ 数据存储 ------------------
50
  chatHistories = {}
51
  GROUP_SETTINGS = {}
52
  USER_SETTINGS = {}
53
+ USER_LAST_ACTIVE = {}
54
+ GROUP_ACTIVE_USERS = {}
55
+ GROUP_INFO = {}
56
+ BANNED_USERS = {}
57
+
58
+ # ------------------ Bot 命令 ------------------
59
  BOT_COMMANDS = [
60
  {"command": "start", "description": "显示欢迎信息和操作按钮"},
61
  {"command": "clearall", "description": "清空当前会话的聊天记录"},
 
70
  {"command": "promat", "description": "切换提示词,例如: /promat 0, 1, 2"},
71
  {"command": "getpromat", "description": "获取当前使用的提示词索引"},
72
  ]
73
+
74
+ # ------------------ 封禁配置 ------------------
 
 
 
75
  BAN_DURATION = timedelta(minutes=30)
76
  BAN_TRIGGER_PHRASES = [
77
  r"(?:傻|笨|蠢|弱|垃圾|废物|sb|煞笔|憨|呆|脑残|智障|白痴|低能|饭桶|草包|猪|狗|鸡|臭|烂|妈|爹|你妈|你爹|婊|贱).*(?:bot|机器人|AI|你|你们)",
 
97
  ]
98
  UNBAN_PHRASE = "close username"
99
 
100
+ # ------------------ Telegram API 请求 ------------------
101
  def make_telegram_request(method, data=None):
102
  url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/{method}"
103
  if PHP_PROXY_URL:
 
116
  print(f"Telegram response decode error: {e}")
117
  return None
118
 
119
+ # ------------------ 设置 Telegram Bot 命令 ------------------
120
  async def setBotCommands():
121
  delete_url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/deleteMyCommands"
122
  set_url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/setMyCommands"
 
139
  except Exception as error:
140
  print(f'设置 Telegram 命令时发生错误: {error}')
141
 
142
+ # ------------------ 处理 Telegram 更新 ------------------
143
  async def handleTelegramUpdate(update):
144
  if not update.get('message'):
145
  if update.get('callback_query'):
 
154
  fromUserFirstName = update['message']['from'].get('first_name', '用户')
155
  fromUserLastName = update['message']['from'].get('last_name', '')
156
  fromUserName = update['message']['from'].get('username', '')
157
+
158
  USER_LAST_ACTIVE[fromUserId] = datetime.now()
159
 
160
  if isGroupChat:
 
244
  else:
245
  await processAiMessage(chatId, userMessage, fromUserId, message_id, fromUserFirstName, fromUserLastName, fromUserName)
246
 
247
+ # ------------------ 解析命令 ------------------
248
  def parseCommand(userMessage):
249
  command = userMessage.split(' ')[0]
250
  if '@' in command:
251
  command = command.split('@')[0]
252
  return command[1:]
253
 
254
+ # ------------------ 处理私有命令 ------------------
255
  async def handlePrivateCommand(chatId, userMessage, fromUserId, isGroupChat):
256
  command = parseCommand(userMessage)
257
  if userMessage.startswith('/settemp '):
 
289
  await sendTelegramMessage(chatId, '已重置您的个人设置。')
290
  return
291
 
292
+ # ------------------ 处理 AI 消息 ------------------
293
  async def processAiMessage(chatId, userMessage, fromUserId, message_id, fromUserFirstName, fromUserLastName, fromUserName):
294
  if fromUserId in BANNED_USERS and BANNED_USERS[fromUserId] > datetime.now():
295
  remaining_time = BANNED_USERS[fromUserId] - datetime.now()
296
  minutes = int(remaining_time.total_seconds() / 60)
297
  await sendTelegramMessage(chatId, f"您已被禁用,剩余时间: {minutes} 分钟。", options={'reply_to_message_id': message_id})
298
  return
299
+
300
  for pattern in BAN_TRIGGER_PHRASES:
301
  if re.search(pattern, userMessage, re.IGNORECASE):
302
  await banUser(chatId, fromUserId)
 
307
  userTemp = USER_SETTINGS.get(fromUserId, {}).get('temperature', DEFAULT_TEMP)
308
  userPromptIndex = USER_SETTINGS.get(fromUserId, {}).get('prompt_index', CURRENT_PROMPT_INDEX)
309
  currentPrompt = PROMPT_TEMPLATES.get(userPromptIndex, "")
310
+
311
  user_last_active = USER_LAST_ACTIVE.get(fromUserId, None)
312
  group_info = GROUP_INFO.get(chatId, None)
313
  group_active_users = GROUP_ACTIVE_USERS.get(chatId, None)
 
338
  {'role': 'system', 'content': system_prompt},
339
  *history
340
  ]
341
+
342
  thinking_message = await sendTelegramMessage(chatId, "正在思考,请等待...", options={'reply_to_message_id': message_id})
343
  thinking_message_id = thinking_message.get('result', {}).get('message_id')
344
 
 
364
  print(f'处理消息时发生错误: {error}')
365
  await editTelegramMessage(chatId, thinking_message_id, '处理消息时发生错误,请稍后再试')
366
 
367
+ # ------------------ 处理 AI 响应 ------------------
368
  async def handleAiResponse(ai_data, chatId, history):
369
  if ai_data and ai_data.get('choices') and len(ai_data['choices']) > 0:
370
  choice = ai_data['choices'][0]
 
372
  return choice['message']['content']
373
  return 'AI 返回了无法识别的格式'
374
 
375
+ # ------------------ 处理回调查询 ------------------
376
  async def handleCallbackQuery(callbackQuery):
377
  chatId = callbackQuery['message']['chat']['id']
378
  data = callbackQuery['data']
 
380
  if data == "clearall":
381
  chatHistories.pop(chatId, None)
382
  await sendTelegramMessage(chatId, "聊天记录已清空。")
383
+
384
  await sendTelegramMessage(chatId, '请选择操作:', {
385
  'reply_markup': {
386
  'inline_keyboard': [[{'text': "清空聊天记录", 'callback_data': "clearall"}]],
387
  },
388
  })
389
 
390
+ # ------------------ 发送 Telegram 消息 ------------------
391
  async def sendTelegramMessage(chatId, text, options={}):
392
  url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage"
393
  if PHP_PROXY_URL:
394
  url = f"{PHP_PROXY_URL}bot{TELEGRAM_BOT_TOKEN}/sendMessage"
395
+
396
  data = {
397
  'chat_id': chatId,
398
  'text': text,
399
  **options
400
  }
401
+
402
  try:
403
  response = requests.post(url, headers={'Content-Type': 'application/json'}, json=data)
404
  response.raise_for_status()
 
407
  print(f'发送 Telegram 消息失败: {e}')
408
  return {}
409
 
410
+ # ------------------ 编辑 Telegram 消息 ------------------
411
  async def editTelegramMessage(chatId, message_id, text, options={}):
412
  url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/editMessageText"
413
  if PHP_PROXY_URL:
 
424
  except requests.exceptions.RequestException as e:
425
  print(f'编辑 Telegram 消息失败: {e}')
426
 
427
+ # ------------------ 获取帮助消息 ------------------
428
  def getHelpMessage():
429
  return f"""
430
  可用指令:
 
437
  /disableai - 在群组中禁用AI回复。
438
  /setprefix <prefix> - 设置群组中触发AI回复的前缀,例如:/setprefix @bot。
439
  /getprefix - 获取当前群组的触发前缀。
440
+
441
  私聊指令 (在群组中也可以使用):
442
  /settemp <温度值> - 设置AI回复的温度 (0-2),例如:/settemp 1.0。
443
  /gettemp - 获取当前AI回复的温度。
444
  /resetuser - 重置你的个人设置。
445
  /promat <index> - 切换提示词,例如: /promat 0, 1, 2。
446
  /getpromat - 获取当前使用的提示词索引。
447
+
448
  直接发送文本消息与AI对话 (私聊)。
449
 
450
  群组中,需要使用前缀触发AI回复,如果设置了前缀的话。
451
+
452
  注意:
453
  - 机器人会记住最近的 {MAX_HISTORY_LENGTH} 条对话。
454
  - 机器人具有攻击性,请谨慎使用。
455
  """
456
 
457
+ # ------------------ 更新 Telegram 命令 ------------------
458
  @app.route('/update_commands', methods=['GET'])
459
  async def update_commands():
460
  await setBotCommands()
461
  return jsonify({'message': 'Commands updated successfully!'})
462
 
463
+ # ------------------ 处理 Webhook 请求 ------------------
464
  @app.route('/', methods=['POST'])
465
  async def handle_webhook():
466
  try:
 
473
  traceback.print_exc()
474
  return jsonify({'status': 'error', 'message': str(e)}), 400
475
 
476
+ # ------------------ 健康检查 ------------------
477
  @app.route('/health', methods=['GET'])
478
  def health_check():
479
  return 'OK'
480
 
481
+ # ------------------ 获取群组信息 ------------------
482
  async def getChatInfo(chatId):
483
  url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/getChat"
484
  if PHP_PROXY_URL:
 
494
  print(f'获取群组信息失败: {e}')
495
  return None
496
 
497
+ # ------------------ 封禁用户 ------------------
498
  async def banUser(chatId, userId):
499
  BANNED_USERS[userId] = datetime.now() + BAN_DURATION
500
  print(f"用户 {userId} 在群组 {chatId} 中被禁用,直到 {BANNED_USERS[userId]}")
501
 
502
+ # ------------------ 解封用户 ------------------
503
  async def unbanUser(chatId, userId):
504
  if userId in BANNED_USERS:
505
  del BANNED_USERS[userId]
506
  await sendTelegramMessage(chatId, f"用户 {userId} 已被解禁。")
507
  print(f"用户 {userId} 在群组 {chatId} 中被解禁。")
508
 
509
+ # ------------------ WebDAV 数据存储 ------------------
510
+ def save_data_to_webdav():
511
+ global chatHistories, GROUP_SETTINGS, USER_SETTINGS, USER_LAST_ACTIVE, GROUP_ACTIVE_USERS, GROUP_INFO, BANNED_USERS
512
+ data = {
513
+ 'chatHistories': chatHistories,
514
+ 'GROUP_SETTINGS': GROUP_SETTINGS,
515
+ 'USER_SETTINGS': USER_SETTINGS,
516
+ 'USER_LAST_ACTIVE': USER_LAST_ACTIVE,
517
+ 'GROUP_ACTIVE_USERS': GROUP_ACTIVE_USERS,
518
+ 'GROUP_INFO': GROUP_INFO,
519
+ 'BANNED_USERS': BANNED_USERS,
520
+ }
521
+ data_json = json.dumps(data, indent=4, default=str)
522
+
523
+ filename = 'tg_bot/bot_data.json'
524
+ upload_url = f"{WEBDAV_URL}/{filename}"
525
+
526
+ try:
527
+ curl_command = [
528
+ 'curl',
529
+ '-v',
530
+ '-X', 'PUT',
531
+ '--user', f'{WEBDAV_USERNAME}:{WEBDAV_PASSWORD}',
532
+ '--data', data_json,
533
+ '--header', 'Content-Type: application/json',
534
+ upload_url
535
+ ]
536
+
537
+ result = subprocess.run(curl_command, capture_output=True, text=True, check=True)
538
+
539
+ print(f"WebDAV 上传成功:{upload_url}")
540
+ print(f"curl stdout: {result.stdout}")
541
+
542
+ except subprocess.CalledProcessError as e:
543
+ print(f"WebDAV 上传失败: {e}")
544
+ print(f"curl stderr: {e.stderr}")
545
+ except Exception as e:
546
+ print(f"WebDAV 上传发生错误: {e}")
547
+
548
+
549
+ def load_data_from_webdav():
550
+ global chatHistories, GROUP_SETTINGS, USER_SETTINGS, USER_LAST_ACTIVE, GROUP_ACTIVE_USERS, GROUP_INFO, BANNED_USERS
551
+
552
+ filename = 'tg_bot/bot_data.json'
553
+ download_url = f"{WEBDAV_URL}/{filename}"
554
+
555
+ try:
556
+ curl_command = [
557
+ 'curl',
558
+ '-v',
559
+ '--user', f'{WEBDAV_USERNAME}:{WEBDAV_PASSWORD}',
560
+ download_url
561
+ ]
562
+
563
+ result = subprocess.run(curl_command, capture_output=True, text=True, check=True)
564
+
565
+ if result.stdout:
566
+ data = json.loads(result.stdout)
567
+ chatHistories = data.get('chatHistories', {})
568
+ GROUP_SETTINGS = data.get('GROUP_SETTINGS', {})
569
+ USER_SETTINGS = data.get('USER_SETTINGS', {})
570
+ USER_LAST_ACTIVE = {int(k): datetime.fromisoformat(v) for k, v in data.get('USER_LAST_ACTIVE', {}).items()} if data.get('USER_LAST_ACTIVE') else {}
571
+ GROUP_ACTIVE_USERS = {int(k): set(v) for k, v in data.get('GROUP_ACTIVE_USERS', {}).items()} if data.get('GROUP_ACTIVE_USERS') else {}
572
+ GROUP_INFO = data.get('GROUP_INFO', {})
573
+ BANNED_USERS = {int(k): datetime.fromisoformat(v) for k, v in data.get('BANNED_USERS', {}).items()} if data.get('BANNED_USERS') else {}
574
+
575
+ print("WebDAV 数据加载成功。")
576
+ except subprocess.CalledProcessError as e:
577
+ print(f"WebDAV 数据加载失败(可能文件不存在): {e}")
578
+ except json.JSONDecodeError as e:
579
+ print(f"WebDAV 数据解析失败: {e}")
580
+ except Exception as e:
581
+ print(f"WebDAV 数据加载时发生错误: {e}")
582
+
583
+ def webdav_upload_loop():
584
+ while True:
585
+ save_data_to_webdav()
586
+ time.sleep(60)
587
+
588
  if __name__ == '__main__':
589
+ load_data_from_webdav()
590
+
591
+ upload_thread = Thread(target=webdav_upload_loop, daemon=True)
592
+ upload_thread.start()
593
+
594
  app.run(host='0.0.0.0', port=int(os.environ.get('PORT', 7860)))