-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathbot.py
273 lines (228 loc) · 12.7 KB
/
bot.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
import telebot
from telebot import types
import logging
from db import UserDB
import config
import preproc_text
from keyboards import Keyboard
from initialization import BotInitializer
import time
# Настройка логирования
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# Словари для хранения пользовательских вопросов и выбранных тем
user_questions = {}
selected_topic = {}
# Инициализация бота
bot = telebot.TeleBot(config.TG_BOT_TOKEN)
initializer = BotInitializer()
documentation_structure = initializer.documentation_structure
questions_answers = initializer.questions_answers
prompt_gener = initializer.prompt_generator
model = initializer.model
# Обработка активных вопросов
activity_question = False
# Удаление предыдущего сообщения
def delete_previous_message(telegram_id, message_id):
try:
bot.delete_message(telegram_id, message_id)
except Exception as e:
logger.error(f"Error deleting message: {e}")
# Команда /start — Приветственное сообщение
@bot.message_handler(commands=['start'])
def send_welcome(message):
telegram_id = message.chat.id
delete_previous_message(telegram_id, message.message_id)
logger.info(f"User {telegram_id} started the bot.")
commands = [
telebot.types.BotCommand("start", "Начать работу с ботом"),
]
bot.set_my_commands(commands)
bot.send_message(
telegram_id,
"🎉 Добро пожаловать в QA бот компании СИЛА! 🎉\n\n"
"Нажмите на кнопку ниже и ознакомьтесь с документацией приложения: ",
reply_markup=Keyboard.create_main_menu()
)
@bot.message_handler(func=lambda message: message.chat.id not in selected_topic)
def handle_random_message(message):
telegram_id = message.chat.id
response_text = (
"🤖 Привет! Я — QA бот компании СИЛА. Вот что я умею:\n\n"
"1. 📚 **Документация**: Нажмите на кнопку 'Документация' в меню, чтобы ознакомиться с основными разделами.\n"
"2. ❓ **Часто задаваемые вопросы**: Нажмите 'Частые вопросы', чтобы просмотреть наиболее популярные вопросы.\n"
"3. ✉️ **Задать вопрос**: Вы можете задать любой вопрос, выбрав соответствующий раздел, и я помогу вам найти ответ.\n\n"
"Просто воспользуйтесь кнопками в меню или напишите /start для начала! 😊"
)
bot.send_message(telegram_id, response_text, reply_markup=Keyboard.create_main_menu())
# Кнопка "Документация" — отправка документации и кнопок навигации
@bot.callback_query_handler(func=lambda call: call.data == 'doc')
def handle_documentation(call):
telegram_id = call.message.chat.id
delete_previous_message(telegram_id, call.message.message_id)
markup = Keyboard.documentation_markup()
with open("documentation/data.docx", "rb") as file:
bot.send_document(
telegram_id, file, caption="📄 Ознакомьтесь с документацией.", reply_markup=markup
)
# Кнопка «Назад» — возврат в главное меню
@bot.callback_query_handler(func=lambda call: call.data == 'start')
def go_back(call):
telegram_id = call.message.chat.id
delete_previous_message(telegram_id, call.message.message_id)
bot.send_message(
telegram_id,
"🎉 Добро пожаловать в QA бот компании СИЛА! 🎉\n\n"
"Нажмите на кнопку ниже и ознакомьтесь с документацией приложения:",
reply_markup=Keyboard.create_main_menu()
)
# Часто задаваемые вопросы — отображение часто задаваемых вопросов
@bot.callback_query_handler(func=lambda call: call.data == 'often_questions')
def handle_often_questions(call):
telegram_id = call.message.chat.id
delete_previous_message(telegram_id, call.message.message_id)
markup = Keyboard.create_initial_questions_markup(questions_answers=questions_answers)
bot.send_message(telegram_id, "🔍 Список частых вопросов:", reply_markup=markup)
# Показ всех вопросов из часто задаваемых
@bot.callback_query_handler(func=lambda call: call.data == "show_all_questions")
def show_all_questions(call):
markup = Keyboard.create_all_questions_markup(questions_answers=questions_answers)
bot.edit_message_reply_markup(
chat_id=call.message.chat.id,
message_id=call.message.message_id,
reply_markup=markup
)
# Возврат к начальному списку вопросов
@bot.callback_query_handler(func=lambda call: call.data == "show_initial_questions")
def show_initial_questions(call):
markup = Keyboard.create_initial_questions_markup(questions_answers=questions_answers)
bot.edit_message_reply_markup(
chat_id=call.message.chat.id,
message_id=call.message.message_id,
reply_markup=markup
)
# Выбор вопроса из часто задаваемых и отображение ответа
@bot.callback_query_handler(func=lambda call: call.data.startswith("get_often_question_"))
def handle_question(call):
try:
question_index = int(call.data.split("get_often_question_")[1])
answer = questions_answers[question_index][1]
markup = types.InlineKeyboardMarkup()
markup.add(types.InlineKeyboardButton(text="🔙 Назад", callback_data="show_initial_questions"))
if '[img_data/imgs' in answer:
image_paths, cleaned_text = preproc_text.extract_and_remove_image_paths(answer)
bot.send_message(call.message.chat.id, cleaned_text)
# Отправляем группу медиа
media = [telebot.types.InputMediaPhoto(open(photo[1:-1], 'rb')) for photo in image_paths]
bot.send_media_group(call.message.chat.id, media)
else:
bot.send_message(call.message.chat.id, answer, reply_markup=markup)
except (ValueError, IndexError) as e:
logger.error(f"Error processing question: {e}")
bot.send_message(call.message.chat.id,
"⚠️ Произошла ошибка при обработке вашего запроса. Пожалуйста, попробуйте снова.")
# Запрос на выбор темы вопроса
@bot.callback_query_handler(func=lambda call: call.data == 'ask_question')
def ask_question(call):
telegram_id = call.message.chat.id
delete_previous_message(telegram_id, call.message.message_id)
markup = types.InlineKeyboardMarkup()
for topic in documentation_structure.keys():
markup.add(types.InlineKeyboardButton(text=topic, callback_data=f"topic_{topic}"))
bot.send_message(
telegram_id,
"❓ В какой части документации у вас возник вопрос?",
reply_markup=Keyboard.ask_question(markup)
)
# Выбор темы вопроса и ожидание текста от пользователя
@bot.callback_query_handler(func=lambda call: call.data.startswith("topic_"))
def choose_topic(call):
telegram_id = call.message.chat.id
delete_previous_message(telegram_id, call.message.message_id)
topic = call.data.split("_", 1)[1]
selected_topic[telegram_id] = topic if topic else "Другое"
if topic:
bot.send_message(
telegram_id,
f"📝 Вы выбрали вопрос с темой \"{topic}\".\nПожалуйста, введите ваш вопрос:"
)
else:
bot.send_message(
telegram_id,
"📝 Пожалуйста, введите ваш вопрос:"
)
# Обработка вопроса пользователя и генерация ответа
@bot.message_handler(func=lambda message: message.chat.id in selected_topic)
def handle_user_question(message):
global model, prompt_gener
telegram_id = message.chat.id
question = message.text
topic = selected_topic[telegram_id]
logger.info(f"User {telegram_id} asked a question on topic '{topic}': {question}")
while True:
try:
if len(topic) > 0:
answer = model.question(f'вопрос на тему {topic}. ' + question, prompt_gener)
else:
answer = model.question(question, prompt_gener)
break # Если успешно получили ответ, выходим из цикла
except Exception as e:
logger.warning(f"Model is busy. Retrying in 5 seconds... Error: {e}")
time.sleep(5) # Задержка 5 секунд, если модель занята
user_questions[telegram_id] = {'question': question, 'topic': topic, 'answer': answer}
if '[img_data/imgs' in answer:
image_paths, cleaned_text = preproc_text.extract_and_remove_image_paths(answer)
bot.send_message(message.chat.id, cleaned_text)
# Отправляем группу медиа
media = [telebot.types.InputMediaPhoto(open(photo[1:-1], 'rb')) for photo in image_paths]
bot.send_media_group(message.chat.id, media)
else:
bot.send_message(telegram_id, answer)
bot.send_message(
telegram_id,
"✅ Вы можете нажать кнопку ниже, чтобы подтвердить, что ваш вопрос решён:",
reply_markup=Keyboard.received_answer_markup()
)
# Кнопка "Вопрос решён" — подтверждение от пользователя
@bot.callback_query_handler(func=lambda call_data: call_data.data == "question_resolved")
def question_resolved(call_data):
telegram_id = call_data.message.chat.id
delete_previous_message(telegram_id, call_data.message.message_id)
bot.send_message(
telegram_id,
"Пожалуйста, оцените качество ответа на ваш вопрос:",
reply_markup=Keyboard.get_quality_markup()
)
# Оценка качества ответа и запись в базу данных
@bot.callback_query_handler(func=lambda call_data: call_data.data.startswith("quality_"))
def handle_quality_rating(call_data):
global prompt_gener, model
telegram_id = call_data.message.chat.id
quality_rating = int(call_data.data.split("_")[1])
delete_previous_message(telegram_id, call_data.message.message_id)
question = user_questions[telegram_id]['question']
topic = user_questions[telegram_id]['topic']
answer = user_questions[telegram_id]['answer']
with UserDB('user_database.db') as db:
db.add_question(telegram_id, question, answer, topic, quality_rating)
if quality_rating >= 4:
prompt_gener.record_qna(question=question, answer=answer)
logger.info(f"User {telegram_id} rated the answer quality: {quality_rating}")
if quality_rating == 1:
bot.send_message(
telegram_id,
"😞 Нам очень жаль, что ответ вас не удовлетворил. Пожалуйста, свяжитесь с нашей технической поддержкой, чтобы мы могли помочь вам лучше:\n\n"
"📞 Телефон: +7 (495) 258-06-36\n"
"✉️ Email: [email protected]\n"
"🌐 Сайт: lense.ru\n\n"
"Мы ценим ваше мнение и хотим улучшить качество нашей поддержки! 🙏",
reply_markup=Keyboard.markup_back()
)
else:
bot.send_message(
telegram_id,
f"Спасибо за вашу оценку! Вы поставили оценку: {quality_rating}. Если у вас есть еще вопросы, не стесняйтесь задавать их! 😊",
reply_markup=Keyboard.markup_back()
)
if __name__ == '__main__':
bot.polling(none_stop=True)