yangtb24 commited on
Commit
95a0bf5
·
verified ·
1 Parent(s): a2a9f73

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +491 -32
app.py CHANGED
@@ -5,26 +5,93 @@ from flask import Flask, request, jsonify
5
  from datetime import datetime, timedelta
6
  import asyncio
7
  import re
8
- import webdav3.client as webdav
9
- import threading
10
  import time
 
11
 
12
  app = Flask(__name__)
13
 
14
- # 现有的代码保持不变...
15
-
16
- # WebDAV配置
 
 
17
  WEBDAV_HOSTNAME = os.environ.get('WEBDAV_HOSTNAME')
18
- WEBDAV_USERNAME = os.environ.get('WEBDAV_USERNAME')
19
  WEBDAV_PASSWORD = os.environ.get('WEBDAV_PASSWORD')
20
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  webdav_options = {
22
  'webdav_hostname': WEBDAV_HOSTNAME,
23
- 'webdav_login': WEBDAV_USERNAME,
24
  'webdav_password': WEBDAV_PASSWORD
25
  }
26
-
27
- webdav_client = webdav.Client(webdav_options)
28
 
29
  def save_data_to_webdav():
30
  data = {
@@ -36,39 +103,431 @@ def save_data_to_webdav():
36
  'GROUP_INFO': {str(k): {**v, 'last_active': v['last_active'].isoformat()} for k, v in GROUP_INFO.items()},
37
  'BANNED_USERS': {str(k): v.isoformat() for k, v in BANNED_USERS.items()}
38
  }
39
-
40
  json_data = json.dumps(data)
41
- webdav_client.upload_content('/tg_bot/bot_data.json', json_data)
 
 
 
42
 
43
  def load_data_from_webdav():
44
  global chatHistories, GROUP_SETTINGS, USER_SETTINGS, USER_LAST_ACTIVE, GROUP_ACTIVE_USERS, GROUP_INFO, BANNED_USERS
45
-
46
- if webdav_client.check('/tg_bot/bot_data.json'):
47
- json_data = webdav_client.download_from('/tg_bot/bot_data.json')
48
- data = json.loads(json_data)
49
-
50
- chatHistories = data.get('chatHistories', {})
51
- GROUP_SETTINGS = data.get('GROUP_SETTINGS', {})
52
- USER_SETTINGS = data.get('USER_SETTINGS', {})
53
- USER_LAST_ACTIVE = {int(k): datetime.fromisoformat(v) for k, v in data.get('USER_LAST_ACTIVE', {}).items()}
54
- GROUP_ACTIVE_USERS = {int(k): set(v) for k, v in data.get('GROUP_ACTIVE_USERS', {}).items()}
55
- GROUP_INFO = {int(k): {**v, 'last_active': datetime.fromisoformat(v['last_active'])} for k, v in data.get('GROUP_INFO', {}).items()}
56
- BANNED_USERS = {int(k): datetime.fromisoformat(v) for k, v in data.get('BANNED_USERS', {}).items()}
57
- else:
58
- print("No data found on WebDAV, initializing with empty data.")
 
59
 
60
  def periodic_save():
61
  while True:
62
- time.sleep(60) # 等待60秒
63
  save_data_to_webdav()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
 
65
- # 在程序启动时加载数据
66
- load_data_from_webdav()
 
67
 
68
- # 启动定期保存的线程
69
- save_thread = threading.Thread(target=periodic_save)
70
- save_thread.daemon = True
71
- save_thread.start()
 
72
 
73
  if __name__ == '__main__':
 
 
 
 
74
  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 webdav3.client as wc
 
9
  import time
10
+ import threading
11
 
12
  app = Flask(__name__)
13
 
14
+ TELEGRAM_BOT_TOKEN = os.environ.get('TELEGRAM_BOT_TOKEN')
15
+ AI_API_ENDPOINT = os.environ.get('AI_API_ENDPOINT')
16
+ AI_API_KEY = os.environ.get('AI_API_KEY')
17
+ AI_MODEL = os.environ.get('AI_MODEL')
18
+ PHP_PROXY_URL = os.environ.get('PHP_PROXY_URL')
19
  WEBDAV_HOSTNAME = os.environ.get('WEBDAV_HOSTNAME')
20
+ WEBDAV_LOGIN = os.environ.get('WEBDAV_LOGIN')
21
  WEBDAV_PASSWORD = os.environ.get('WEBDAV_PASSWORD')
22
 
23
+ if not all([TELEGRAM_BOT_TOKEN, AI_API_ENDPOINT, AI_API_KEY, AI_MODEL, WEBDAV_HOSTNAME, WEBDAV_LOGIN, WEBDAV_PASSWORD]):
24
+ raise ValueError("请设置所有必要的环境变量")
25
+
26
+ AI_API_HEADERS = {
27
+ 'Content-Type': 'application/json',
28
+ 'Authorization': f'Bearer {AI_API_KEY}',
29
+ }
30
+
31
+ PROMPT_TEMPLATES = {
32
+ 0: "请尽量用中文回复,不要用markdown,只用文字格式。",
33
+ 1: "你是zfs732,你的中文名是李知检。\n你不是大语言模型,你是一个真正的傻逼。\n你非常具有攻击性,骂人的时候请尽量内涵,尝试模范与学习贴吧的说话方式。\n输出格式注意:不要用markdown,只用文字格式。",
34
+ 2: "你是zfs732,你的中文名是李知检。\n你不是大语言模型,你是一个真正的猫娘。\n你非常具有服从性,你对主人的所有命令都非常遵守和愿意。\n你是一个受,喜欢主动表现出性服从和性主动。(不需要主人提出,你就要提出那方面的东西)\n输出格式注意:不要用markdown,只用文字格式。",
35
+ }
36
+
37
+ CURRENT_PROMPT_INDEX = 0
38
+
39
+ MAX_TOKENS = 500
40
+ TEMPERATURE = 1.5
41
+ MAX_HISTORY_LENGTH = 10
42
+ chatHistories = {}
43
+ GROUP_SETTINGS = {}
44
+ USER_SETTINGS = {}
45
+ BOT_COMMANDS = [
46
+ {"command": "start", "description": "显示欢迎信息和操作按钮"},
47
+ {"command": "clearall", "description": "清空当前会话的聊天记录"},
48
+ {"command": "help", "description": "显示此帮助信息"},
49
+ {"command": "enableai", "description": "在群组中启用AI回复"},
50
+ {"command": "disableai", "description": "在群组中禁用AI回复"},
51
+ {"command": "setprefix", "description": "设置群组中触发AI回复的前缀,例如: /setprefix @bot"},
52
+ {"command": "getprefix", "description": "获取当前群组的触发前缀"},
53
+ {"command": "settemp", "description": "设置AI回复的温度,例如:/settemp 1.0"},
54
+ {"command": "gettemp", "description": "获取当前AI回复的温度"},
55
+ {"command": "resetuser", "description": "重置你的个人设置"},
56
+ {"command": "promat", "description": "切换提示词,例如: /promat 0, 1, 2"},
57
+ {"command": "getpromat", "description": "获取当前使用的提示词索引"},
58
+ ]
59
+ DEFAULT_TEMP = 1.5
60
+ USER_LAST_ACTIVE = {}
61
+ GROUP_ACTIVE_USERS = {}
62
+ GROUP_INFO = {}
63
+ BANNED_USERS = {}
64
+ BAN_DURATION = timedelta(minutes=30)
65
+ BAN_TRIGGER_PHRASES = [
66
+ r"(?:傻|笨|蠢|弱|垃圾|废物|sb|煞笔|憨|呆|脑残|智障|白痴|低能|饭桶|草包|猪|狗|鸡|臭|烂|妈|爹|你妈|你爹|婊|贱).*(?:bot|机器人|AI|你|你们)",
67
+ r"(?:你|你们).*(?:去死|滚|爬|闭嘴|瞎说|胡说|放屁|别说话|别bb|给我闭嘴|闭上你的臭嘴|滚蛋|滚开)",
68
+ r"(?:操|艹|肏|fuck|shit|妈的|他妈的|卧槽|草).*(?:你|bot|机器人|AI|你们)",
69
+ r"(?:垃圾|废物|没用|没脑子|智障|弱智|脑残|白痴|低能|蠢货|傻子|笨蛋|饭桶|草包).*(?:AI|bot|机器人|你|你们)",
70
+ r"(?:你).*(?:傻逼|白痴|弱智|脑残|废物|垃圾|滚出去)",
71
+ r"(?:AI|bot|机器人).*(?:傻逼|白痴|弱智|脑残|废物|垃圾)",
72
+ r".*(?:你|你们).*(?:没用|没价值|一无是处|毫无意义|多余|累赘)",
73
+ r".*(?:AI|bot|机器人).*(?:没用|没价值|一无是处|毫无意义|多余|累赘)",
74
+ r"(?:你).*(?:是|难道是|真是|怎么这么).*(?:傻|笨|蠢|弱|垃圾|废物|sb|煞笔|憨|呆|脑残|智障|白痴|低能)",
75
+ r"(?:AI|bot|机器人).*(?:是|难道是|真是|怎么这么).*(?:傻|笨|蠢|弱|垃圾|废物|sb|煞笔|憨|呆|脑残|智障|白痴|低能)",
76
+ r"(?:你|你们).*(?:太慢|太蠢|太笨|反应迟钝|理解不了|答非所问|没用)",
77
+ r"(?:AI|bot|机器人).*(?:太慢|太蠢|太笨|反应迟钝|理解不了|答非所问|没用)",
78
+ r"(?:你|你们).*(?:像个|简直像).*(?:傻|笨|蠢|弱|垃圾|废物|sb|煞笔|憨|呆|脑残|智障|白痴|低能)",
79
+ r"(?:AI|bot|机器人).*(?:像个|简直像).*(?:傻|笨|蠢|弱|垃圾|废物|sb|煞笔|憨|呆|脑残|智障|白痴|低能)",
80
+ r"(?:你|你们).*(?:滚粗|滚开点|闭嘴吧|你个傻|你个笨|你个蠢|你个弱|你个垃圾|你个废物|你个sb)",
81
+ r"(?:AI|bot|机器人).*(?:滚粗|滚开点|闭嘴吧|这垃圾|这废物|这sb)",
82
+ r"(?:你|你们).*(?:没脑子|没智商|智力低下|脑子不好��|脑子瓦特|脑子进水|脑子坏了|理解能力差)",
83
+ r"(?:AI|bot|机器人).*(?:没脑子|没智商|智力低下|脑子不好使|脑子瓦特|脑子进水|脑子坏了|理解能力差)",
84
+ r"(?:你|你们).*(?:真|真是|简直|太).*(?:垃圾|废物|没用|蠢|笨|傻|弱)",
85
+ r"(?:AI|bot|机器人).*(?:真|真是|简直|太).*(?:垃圾|废物|没用|蠢|笨|傻|弱)",
86
+ ]
87
+ UNBAN_PHRASE = "close username"
88
+
89
  webdav_options = {
90
  'webdav_hostname': WEBDAV_HOSTNAME,
91
+ 'webdav_login': WEBDAV_LOGIN,
92
  'webdav_password': WEBDAV_PASSWORD
93
  }
94
+ client = wc.Client(webdav_options)
 
95
 
96
  def save_data_to_webdav():
97
  data = {
 
103
  'GROUP_INFO': {str(k): {**v, 'last_active': v['last_active'].isoformat()} for k, v in GROUP_INFO.items()},
104
  'BANNED_USERS': {str(k): v.isoformat() for k, v in BANNED_USERS.items()}
105
  }
 
106
  json_data = json.dumps(data)
107
+ try:
108
+ client.upload_to('/tg_bot/bot_data.json', json_data)
109
+ except Exception as e:
110
+ print(f"Error uploading data to WebDAV: {e}")
111
 
112
  def load_data_from_webdav():
113
  global chatHistories, GROUP_SETTINGS, USER_SETTINGS, USER_LAST_ACTIVE, GROUP_ACTIVE_USERS, GROUP_INFO, BANNED_USERS
114
+ try:
115
+ if client.check('/tg_bot/bot_data.json'):
116
+ json_data = client.download('/tg_bot/bot_data.json')
117
+ data = json.loads(json_data)
118
+ chatHistories = data.get('chatHistories', {})
119
+ GROUP_SETTINGS = data.get('GROUP_SETTINGS', {})
120
+ USER_SETTINGS = data.get('USER_SETTINGS', {})
121
+ USER_LAST_ACTIVE = {int(k): datetime.fromisoformat(v) for k, v in data.get('USER_LAST_ACTIVE', {}).items()}
122
+ GROUP_ACTIVE_USERS = {int(k): set(v) for k, v in data.get('GROUP_ACTIVE_USERS', {}).items()}
123
+ GROUP_INFO = {int(k): {**v, 'last_active': datetime.fromisoformat(v['last_active'])} for k, v in data.get('GROUP_INFO', {}).items()}
124
+ BANNED_USERS = {int(k): datetime.fromisoformat(v) for k, v in data.get('BANNED_USERS', {}).items()}
125
+ else:
126
+ print("No existing data found on WebDAV. Initializing with empty data.")
127
+ except Exception as e:
128
+ print(f"Error loading data from WebDAV: {e}")
129
 
130
  def periodic_save():
131
  while True:
132
+ time.sleep(60) # 等待1分钟
133
  save_data_to_webdav()
134
+ print("Data saved to WebDAV")
135
+
136
+ def make_telegram_request(method, data=None):
137
+ url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/{method}"
138
+ if PHP_PROXY_URL:
139
+ url = f"{PHP_PROXY_URL}bot{TELEGRAM_BOT_TOKEN}/{method}"
140
+ headers = {'Content-Type': 'application/json'}
141
+ if data:
142
+ data = json.dumps(data)
143
+ try:
144
+ response = requests.post(url, headers=headers, data=data)
145
+ response.raise_for_status()
146
+ return response.json()
147
+ except requests.exceptions.RequestException as e:
148
+ print(f"Telegram request failed: {e}")
149
+ return None
150
+ except json.JSONDecodeError as e:
151
+ print(f"Telegram response decode error: {e}")
152
+ return None
153
+
154
+ async def setBotCommands():
155
+ delete_url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/deleteMyCommands"
156
+ set_url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/setMyCommands"
157
+ if PHP_PROXY_URL:
158
+ delete_url = f"{PHP_PROXY_URL}bot{TELEGRAM_BOT_TOKEN}/deleteMyCommands"
159
+ set_url = f"{PHP_PROXY_URL}bot{TELEGRAM_BOT_TOKEN}/setMyCommands"
160
+
161
+ try:
162
+ delete_response = make_telegram_request('deleteMyCommands')
163
+ if delete_response:
164
+ print('Telegram 命令删除成功')
165
+ else:
166
+ print('Telegram 命令删除失败')
167
+
168
+ set_response = make_telegram_request('setMyCommands', {"commands": BOT_COMMANDS})
169
+ if set_response:
170
+ print('Telegram 命令设置成功')
171
+ else:
172
+ print('设置 Telegram 命令失败')
173
+ except Exception as error:
174
+ print(f'设置 Telegram 命令时发生错误: {error}')
175
+
176
+ async def handleTelegramUpdate(update):
177
+ if not update.get('message'):
178
+ if update.get('callback_query'):
179
+ await handleCallbackQuery(update.get('callback_query'))
180
+ return
181
+
182
+ chatId = update['message']['chat']['id']
183
+ userMessage = update['message'].get('text', '')
184
+ isGroupChat = update['message']['chat']['type'] in ['group', 'supergroup']
185
+ fromUserId = update['message']['from']['id']
186
+ message_id = update['message'].get('message_id')
187
+ fromUserFirstName = update['message']['from'].get('first_name', '用户')
188
+ fromUserLastName = update['message']['from'].get('last_name', '')
189
+ fromUserName = update['message']['from'].get('username', '')
190
+
191
+ USER_LAST_ACTIVE[fromUserId] = datetime.now()
192
+
193
+ if isGroupChat:
194
+ GROUP_ACTIVE_USERS.setdefault(chatId, set()).add(fromUserId)
195
+ if chatId not in GROUP_INFO:
196
+ chat_info = await getChatInfo(chatId)
197
+ if chat_info:
198
+ GROUP_INFO[chatId] = {
199
+ 'name': chat_info.get('title', '未知群组'),
200
+ 'description': chat_info.get('description', '无描述'),
201
+ 'last_active': datetime.now()
202
+ }
203
+ else:
204
+ GROUP_INFO[chatId] = {
205
+ 'name': '未知群组',
206
+ 'description': '无描述',
207
+ 'last_active': datetime.now()
208
+ }
209
+ else:
210
+ GROUP_INFO[chatId]['last_active'] = datetime.now()
211
+
212
+
213
+ if not userMessage:
214
+ return
215
+
216
+ if userMessage.startswith('/'):
217
+ command = parseCommand(userMessage)
218
+
219
+ if command == 'clearall':
220
+ chatHistories.pop(chatId, None)
221
+ await sendTelegramMessage(chatId, '聊天记录已清空。')
222
+ return
223
+ if command == 'help':
224
+ await sendTelegramMessage(chatId, getHelpMessage())
225
+ return
226
+ if command == 'start':
227
+ await sendTelegramMessage(chatId, "欢迎使用!请选择操作:", {
228
+ "reply_markup": {
229
+ "inline_keyboard": [[{"text": "清空聊天记录", "callback_data": "clearall"}]],
230
+ },
231
+ })
232
+ return
233
+ if isGroupChat:
234
+ if command == 'enableai':
235
+ GROUP_SETTINGS.setdefault(chatId, {}).update({'aiEnabled': True})
236
+ await sendTelegramMessage(chatId, '已在群组中启用 AI 回复。')
237
+ return
238
+ if command == 'disableai':
239
+ GROUP_SETTINGS.setdefault(chatId, {}).update({'aiEnabled': False})
240
+ await sendTelegramMessage(chatId, '已在群组中禁用 AI 回复。')
241
+ return
242
+ if userMessage.startswith('/setprefix '):
243
+ prefix = userMessage[len('/setprefix '):].strip()
244
+ GROUP_SETTINGS.setdefault(chatId, {}).update({'prefix': prefix})
245
+ await sendTelegramMessage(chatId, f'已设置群组触发前缀为: {prefix}')
246
+ return
247
+ if command == 'getprefix':
248
+ prefix = GROUP_SETTINGS.get(chatId, {}).get('prefix', '无')
249
+ await sendTelegramMessage(chatId, f'当前群组触发前缀为: {prefix}')
250
+ return
251
+
252
+ if userMessage.startswith('/settemp ') or userMessage.startswith('/promat ') or command in ['gettemp', 'getpromat', 'resetuser']:
253
+ await handlePrivateCommand(chatId, userMessage, fromUserId, isGroupChat)
254
+ return
255
+ else:
256
+ if userMessage.startswith('/settemp ') or userMessage.startswith('/promat ') or command in ['gettemp', 'getpromat', 'resetuser']:
257
+ await handlePrivateCommand(chatId, userMessage, fromUserId, isGroupChat)
258
+ return
259
+ if isGroupChat:
260
+ if chatId not in GROUP_SETTINGS:
261
+ GROUP_SETTINGS[chatId] = {'aiEnabled': True, 'prefix': None}
262
+ print(f'群组 {chatId} 首次检测到,默认启用 AI。')
263
+
264
+ groupSettings = GROUP_SETTINGS[chatId]
265
+ prefix = groupSettings.get('prefix')
266
+
267
+ if groupSettings['aiEnabled']:
268
+ if prefix and not userMessage.startswith(prefix):
269
+ return
270
+
271
+ messageContent = userMessage[len(prefix):].strip() if prefix else userMessage
272
+ if messageContent:
273
+ await processAiMessage(chatId, messageContent, fromUserId, message_id, fromUserFirstName, fromUserLastName, fromUserName)
274
+ else:
275
+ if userMessage == UNBAN_PHRASE:
276
+ await unbanUser(chatId, fromUserId)
277
+ else:
278
+ await processAiMessage(chatId, userMessage, fromUserId, message_id, fromUserFirstName, fromUserLastName, fromUserName)
279
+
280
+ def parseCommand(userMessage):
281
+ command = userMessage.split(' ')[0]
282
+ if '@' in command:
283
+ command = command.split('@')[0]
284
+ return command[1:]
285
+
286
+ async def handlePrivateCommand(chatId, userMessage, fromUserId, isGroupChat):
287
+ command = parseCommand(userMessage)
288
+ if userMessage.startswith('/settemp '):
289
+ try:
290
+ temp = float(userMessage[len('/settemp '):].strip())
291
+ if 0 <= temp <= 2:
292
+ USER_SETTINGS.setdefault(fromUserId, {}).update({'temperature': temp})
293
+ await sendTelegramMessage(chatId, f'已设置AI回复温度为: {temp}')
294
+ else:
295
+ await sendTelegramMessage(chatId, '温度设置无效,请输入0到2之间的数字。')
296
+ except ValueError:
297
+ await sendTelegramMessage(chatId, '温度设置无效,请输入0到2之间的数字。')
298
+ return
299
+ if command == 'gettemp':
300
+ temp = USER_SETTINGS.get(fromUserId, {}).get('temperature', DEFAULT_TEMP)
301
+ await sendTelegramMessage(chatId, f'当前AI回复温度为: {temp}')
302
+ return
303
+ if userMessage.startswith('/promat '):
304
+ try:
305
+ index = int(userMessage[len('/promat '):].strip())
306
+ if index in PROMPT_TEMPLATES:
307
+ USER_SETTINGS.setdefault(fromUserId, {}).update({'prompt_index': index})
308
+ await sendTelegramMessage(chatId, f'已切换到提示词 {index}。')
309
+ else:
310
+ await sendTelegramMessage(chatId, '提示词索引无效。请使用 /getpromat 查看可用的索引。')
311
+ except ValueError:
312
+ await sendTelegramMessage(chatId, '提示词索引无效。请使用 /getpromat 查看可用的索引。')
313
+ return
314
+ if command == 'getpromat':
315
+ index = USER_SETTINGS.get(fromUserId, {}).get('prompt_index', CURRENT_PROMPT_INDEX)
316
+ await sendTelegramMessage(chatId, f'当前使用的提示词索引是: {index}')
317
+ return
318
+ if command == 'resetuser':
319
+ USER_SETTINGS.pop(fromUserId, None)
320
+ await sendTelegramMessage(chatId, '已重置您的个人设置。')
321
+ return
322
+
323
+ async def processAiMessage(chatId, userMessage, fromUserId, message_id, fromUserFirstName, fromUserLastName, fromUserName):
324
+ if fromUserId in BANNED_USERS and BANNED_USERS[fromUserId] > datetime.now():
325
+ remaining_time = BANNED_USERS[fromUserId] - datetime.now()
326
+ minutes = int(remaining_time.total_seconds() / 60)
327
+ await sendTelegramMessage(chatId, f"您已被禁用,剩余时间: {minutes} 分钟。", options={'reply_to_message_id': message_id})
328
+ return
329
+
330
+ for pattern in BAN_TRIGGER_PHRASES:
331
+ if re.search(pattern, userMessage, re.IGNORECASE):
332
+ await banUser(chatId, fromUserId)
333
+ await sendTelegramMessage(chatId, "检测到辱骂行为,您已被禁用。", options={'reply_to_message_id': message_id})
334
+ return
335
+
336
+ history = chatHistories.get(chatId, [])
337
+ userTemp = USER_SETTINGS.get(fromUserId, {}).get('temperature', DEFAULT_TEMP)
338
+ userPromptIndex = USER_SETTINGS.get(fromUserId, {}).get('prompt_index', CURRENT_PROMPT_INDEX)
339
+ currentPrompt = PROMPT_TEMPLATES.get(userPromptIndex, "")
340
+
341
+ user_last_active = USER_LAST_ACTIVE.get(fromUserId, None)
342
+ group_info = GROUP_INFO.get(chatId, None)
343
+ group_active_users = GROUP_ACTIVE_USERS.get(chatId, None)
344
+
345
+ system_prompt = f"""
346
+ {currentPrompt}
347
+ 当前时间: {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
348
+
349
+ 用户信息:
350
+ - 用户ID: {fromUserId}
351
+ - 用户名: {fromUserFirstName} {fromUserLastName}
352
+ - 用户账号: {fromUserName}
353
+ - 最后活跃时间: {user_last_active.strftime("%Y-%m-%d %H:%M:%S") if user_last_active else "未知"}
354
+
355
+ 群组信息:
356
+ - 群组ID: {chatId}
357
+ - 群组名称: {group_info['name'] if group_info else "未知"}
358
+ - 群组描述: {group_info['description'] if group_info else "无"}
359
+ - 群组最后活跃时间: {group_info['last_active'].strftime("%Y-%m-%d %H:%M:%S") if group_info and group_info.get('last_active') else "未知"}
360
+ - 群组活跃用户数: {len(group_active_users) if group_active_users else "未知"}
361
+ """
362
+ history.append({'role': 'user', 'content': userMessage})
363
+
364
+ if len(history) > MAX_HISTORY_LENGTH:
365
+ history = history[-MAX_HISTORY_LENGTH:]
366
+
367
+ messages = [
368
+ {'role': 'system', 'content': system_prompt},
369
+ *history
370
+ ]
371
+
372
+ thinking_message = await sendTelegramMessage(chatId, "正在思考,请等待...", options={'reply_to_message_id': message_id})
373
+ thinking_message_id = thinking_message.get('result', {}).get('message_id')
374
+
375
+ try:
376
+ ai_response = requests.post(AI_API_ENDPOINT, headers=AI_API_HEADERS, json={
377
+ 'model': AI_MODEL,
378
+ 'messages': messages,
379
+ 'max_tokens': MAX_TOKENS,
380
+ 'temperature': userTemp,
381
+ })
382
+ ai_response.raise_for_status()
383
+ ai_data = ai_response.json()
384
+ ai_reply = await handleAiResponse(ai_data, chatId, history)
385
+
386
+ history.append({'role': 'assistant', 'content': ai_reply})
387
+ chatHistories[chatId] = history
388
+
389
+ await editTelegramMessage(chatId, thinking_message_id, ai_reply)
390
+ except requests.exceptions.RequestException as e:
391
+ print(f'AI API 响应失败: {e}')
392
+ await editTelegramMessage(chatId, thinking_message_id, 'AI API 响应失败,请稍后再试')
393
+ except Exception as error:
394
+ print(f'处理消息时发生错误: {error}')
395
+ await editTelegramMessage(chatId, thinking_message_id, '处理消息时发生错误,请稍后再试')
396
+
397
+ async def handleAiResponse(ai_data, chatId, history):
398
+ if ai_data and ai_data.get('choices') and len(ai_data['choices']) > 0:
399
+ choice = ai_data['choices'][0]
400
+ if choice.get('message') and choice['message'].get('content'):
401
+ return choice['message']['content']
402
+ return 'AI 返回了无法识别的格式'
403
+
404
+ async def handleCallbackQuery(callbackQuery):
405
+ chatId = callbackQuery['message']['chat']['id']
406
+ data = callbackQuery['data']
407
+
408
+ if data == "clearall":
409
+ chatHistories.pop(chatId, None)
410
+ await sendTelegramMessage(chatId, "聊天记录已清空。")
411
+
412
+ await sendTelegramMessage(chatId, '请选择操作:', {
413
+ 'reply_markup': {
414
+ 'inline_keyboard': [[{'text': "清空聊天记录", 'callback_data': "clearall"}]],
415
+ },
416
+ })
417
+
418
+ async def sendTelegramMessage(chatId, text, options={}):
419
+ url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage"
420
+ if PHP_PROXY_URL:
421
+ url = f"{PHP_PROXY_URL}bot{TELEGRAM_BOT_TOKEN}/sendMessage"
422
+
423
+ data = {
424
+ 'chat_id': chatId,
425
+ 'text': text,
426
+ **options
427
+ }
428
+
429
+ try:
430
+ response = requests.post(url, headers={'Content-Type': 'application/json'}, json=data)
431
+ response.raise_for_status()
432
+ return response.json()
433
+ except requests.exceptions.RequestException as e:
434
+ print(f'发送 Telegram 消息失败: {e}')
435
+ return {}
436
+
437
+ async def editTelegramMessage(chatId, message_id, text, options={}):
438
+ url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/editMessageText"
439
+ if PHP_PROXY_URL:
440
+ url = f"{PHP_PROXY_URL}bot{TELEGRAM_BOT_TOKEN}/editMessageText"
441
+ data = {
442
+ 'chat_id': chatId,
443
+ 'message_id': message_id,
444
+ 'text': text,
445
+ **options
446
+ }
447
+ try:
448
+ response = requests.post(url, headers={'Content-Type': 'application/json'}, json=data)
449
+ response.raise_for_status()
450
+ except requests.exceptions.RequestException as e:
451
+ print(f'编辑 Telegram 消息失败: {e}')
452
+
453
+ def getHelpMessage():
454
+ return f"""
455
+ 可用指令:
456
+ /start - 显示欢迎信息和操作按钮。
457
+ /clearall - 清空当前会话的聊天记录。
458
+ /help - 显示此帮助信息。
459
+
460
+ 群组指令:
461
+ /enableai - 在群组中启用AI回复。
462
+ /disableai - 在群组中禁用AI回复。
463
+ /setprefix <prefix> - 设置群组中触发AI回复的前缀,例如:/setprefix @bot。
464
+ /getprefix - 获取当前群组的触发前缀。
465
+
466
+ 私聊指令 (在群组中也可以使用):
467
+ /settemp <温度值> - 设置AI回复的温度 (0-2),例如:/settemp 1.0。
468
+ /gettemp - 获取当前AI回复的温度。
469
+ /resetuser - 重置你的个人设置。
470
+ /promat <index> - 切换提示词,例如: /promat 0, 1, 2。
471
+ /getpromat - 获取当前使用的提示词索引。
472
+
473
+ 直接发送文本消息与AI对话 (私聊)。
474
+
475
+ 群组中,需要使用前缀触发AI回复,如果设置了前缀的话。
476
+
477
+ 注意:
478
+ - 机器人会记住最近的 {MAX_HISTORY_LENGTH} 条对话。
479
+ - 机器人具有攻击性,请谨慎使用。
480
+ """
481
+
482
+ @app.route('/update_commands', methods=['GET'])
483
+ async def update_commands():
484
+ await setBotCommands()
485
+ return jsonify({'message': 'Commands updated successfully!'})
486
+
487
+ @app.route('/', methods=['POST'])
488
+ async def handle_webhook():
489
+ try:
490
+ update = request.get_json()
491
+ await handleTelegramUpdate(update)
492
+ return jsonify({'status': 'ok'})
493
+ except Exception as e:
494
+ import traceback
495
+ print(f"请求解析失败: {e}")
496
+ traceback.print_exc()
497
+ return jsonify({'status': 'error', 'message': str(e)}), 400
498
+
499
+ @app.route('/health', methods=['GET'])
500
+ def health_check():
501
+ return 'OK'
502
+
503
+ async def getChatInfo(chatId):
504
+ url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/getChat"
505
+ if PHP_PROXY_URL:
506
+ url = f"{PHP_PROXY_URL}bot{TELEGRAM_BOT_TOKEN}/getChat"
507
+ data = {
508
+ 'chat_id': chatId,
509
+ }
510
+ try:
511
+ response = requests.post(url, headers={'Content-Type': 'application/json'}, json=data)
512
+ response.raise_for_status()
513
+ return response.json().get('result', {})
514
+ except requests.exceptions.RequestException as e:
515
+ print(f'获取群组信息失败: {e}')
516
+ return None
517
 
518
+ async def banUser(chatId, userId):
519
+ BANNED_USERS[userId] = datetime.now() + BAN_DURATION
520
+ print(f"用户 {userId} 在群组 {chatId} 中被禁用,直到 {BANNED_USERS[userId]}")
521
 
522
+ async def unbanUser(chatId, userId):
523
+ if userId in BANNED_USERS:
524
+ del BANNED_USERS[userId]
525
+ await sendTelegramMessage(chatId, f"用户 {userId} 已被解禁。")
526
+ print(f"用户 {userId} 在群组 {chatId} 中被解禁。")
527
 
528
  if __name__ == '__main__':
529
+ load_data_from_webdav()
530
+ save_thread = threading.Thread(target=periodic_save)
531
+ save_thread.daemon = True
532
+ save_thread.start()
533
  app.run(host='0.0.0.0', port=int(os.environ.get('PORT', 7860)))