Skip to content

Commit 9e95f5f

Browse files
committed
added teacher info getting support
1 parent d3dbc7d commit 9e95f5f

File tree

11 files changed

+154
-75
lines changed

11 files changed

+154
-75
lines changed

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ ignore = [
8888
'ANN003',
8989
'PLC0206',
9090
'PERF403',
91+
'TRY002',
9192
# Temporary
9293
'EXE005',
9394
'EXE003',

src/telegram_assistant/bot/__main__.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,19 @@
22

33
from aiogram import Bot
44
from aiogram.client.default import DefaultBotProperties
5-
from dotenv import load_dotenv
65

76
from telegram_assistant.bot.discpatcher import dp
87
from telegram_assistant.config import cfg
9-
from telegram_assistant.llm.context_manager import ContextManager
108
from telegram_assistant.llm.llm_repo import LLMRepository
9+
from telegram_assistant.parser.repository.parser_repo import ParserRepository
1110

1211

1312
def on_startup() -> None:
1413
print("Бот запущен")
1514

1615

1716
async def main() -> None:
17+
parse_repo = ParserRepository()
1818
llm_repo = LLMRepository()
1919
llm_repo.context_manager.create_base_context()
2020
bot = Bot(
@@ -23,7 +23,11 @@ async def main() -> None:
2323
)
2424
dp.startup.register(on_startup)
2525
await bot.delete_webhook(drop_pending_updates=True)
26-
await dp.start_polling(bot, llm_repo=llm_repo)
26+
await dp.start_polling(
27+
bot,
28+
llm_repo=llm_repo,
29+
parse_repo=parse_repo,
30+
)
2731

2832

2933
if __name__ == "__main__":

src/telegram_assistant/bot/logic/callbackdata/main_menu_cb_data.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@ class MainMenuCBData(CallbackData, prefix="main_menu"):
66

77

88
class QuestionCBData(CallbackData, prefix="question"):
9-
action: str = "Question"
9+
action: str
10+
question_id: str
11+
12+
13+
class ParseCBData(CallbackData, prefix="parse"):
14+
action: str
15+
16+
17+
class DynamicQuestionCBData(CallbackData, prefix="dynamic_question"):
18+
action: str
1019
question_id: str
11-
Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
from aiogram import F, Router
22
from aiogram.types import CallbackQuery
3+
from aiogram.utils.deep_linking import create_start_link
34

45
from telegram_assistant.bot.logic.callbackdata import MainMenuCBData
5-
from telegram_assistant.bot.logic.callbackdata.main_menu_cb_data import QuestionCBData
6+
from telegram_assistant.bot.logic.callbackdata.main_menu_cb_data import ParseCBData, QuestionCBData
67
from telegram_assistant.bot.logic.keyboards.inline import main_menu_kb
78
from telegram_assistant.llm.llm_repo import LLMRepository
8-
from telegram_assistant.llm.yandex_gpt import YandexGPT
9+
from telegram_assistant.parser.repository.parser_repo import ParserRepository
10+
911

1012
router = Router()
1113

14+
MAX_MESSAGE_LEN = 4000
15+
1216

1317
@router.callback_query(MainMenuCBData.filter(F.action == "BackToMainMenu"))
1418
async def back_to_main_menu_handler(query: CallbackQuery) -> None:
@@ -18,22 +22,44 @@ async def back_to_main_menu_handler(query: CallbackQuery) -> None:
1822
text=message_text,
1923
reply_markup=main_menu_kb(),
2024
)
21-
25+
26+
2227
@router.callback_query(QuestionCBData.filter(F.action == "Question"))
2328
async def ask_question_handler(query: CallbackQuery, callback_data: QuestionCBData, llm_repo: LLMRepository) -> None:
24-
question = llm_repo.context_manager.questions_ids[callback_data.question_id]
25-
message_text = llm_repo.get_question_info(question)
26-
29+
await query.message.answer(
30+
text="Генерация ответа может занять некоторое время...",
31+
parse_mode="HTML",
32+
)
33+
message_text = llm_repo.get_question_info(callback_data.question_id)
2734
await query.message.answer(
2835
text=message_text,
36+
parse_mode="HTML",
2937
)
3038

3139

32-
@router.callback_query(MainMenuCBData.filter(F.action == "BackToMainMenu"))
33-
async def back_to_main_menu_handler(query: CallbackQuery) -> None:
34-
message_text = f"<b>Приветствую, {query.from_user.first_name}</b>\n\n"
40+
@router.callback_query(ParseCBData.filter(F.action == "TeachersParse"))
41+
async def teachers_parse_handler(query: CallbackQuery, parse_repo: ParserRepository) -> None:
42+
message_texts: list[str] = [""]
43+
teachers_dict = parse_repo.url_parser.parse_teachers()
44+
45+
for teacher_name, teacher_url in teachers_dict.items():
46+
cutted_teacher_url = "teacher_" + teacher_url.split("/")[-1]
47+
try:
48+
deep_link = await create_start_link(query.bot, cutted_teacher_url, encode=True)
49+
except:
50+
continue
51+
teacher_info = f'<a href="{deep_link}">{teacher_name}</a>\n'
52+
if len(message_texts[-1] + teacher_info) > MAX_MESSAGE_LEN:
53+
message_texts.append(teacher_info)
54+
else:
55+
message_texts[-1] += teacher_info
3556

36-
await query.message.edit_text(
37-
text=message_text,
38-
reply_markup=main_menu_kb(),
57+
for text in message_texts:
58+
await query.message.answer(
59+
text=text,
60+
parse_mode="HTML",
61+
)
62+
63+
await query.message.answer(
64+
text="Нажмите на ФИО любого учителя, чтобы получить краткий рассказ о нем"
3965
)

src/telegram_assistant/bot/logic/commands/start_commands.py

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,42 @@
11
from aiogram import Router
2-
from aiogram.filters import CommandStart
2+
from aiogram.filters import CommandStart, CommandObject
33
from aiogram.types import Message
4+
from aiogram.utils.deep_linking import decode_payload
45

5-
from telegram_assistant.bot.logic.keyboards.inline import (
6-
main_menu_kb,
7-
)
6+
from telegram_assistant.bot.logic.keyboards.inline import main_menu_kb
7+
8+
from telegram_assistant.llm.llm_repo import LLMRepository
9+
from telegram_assistant.parser.repository.parser_repo import ParserRepository
810

911
router = Router()
1012

13+
@router.message(CommandStart(deep_link=True))
14+
async def start_with_deep_link(
15+
message: Message,
16+
command: CommandObject,
17+
parse_repo: ParserRepository,
18+
llm_repo: LLMRepository,
19+
):
20+
try:
21+
if args := decode_payload(command.args):
22+
if args.startswith("teacher_"):
23+
url_start = "https://sfedu.ru/s7/person/ru/"
24+
teacher_id = args.lstrip("teacher_")
25+
context = parse_repo.base_parser.parse_teacher_info(url_start + teacher_id)
26+
teacher_info = llm_repo.get_dynamic_question_info(
27+
question=f"Расскажи об этом учителе вкратце, ID={teacher_id}",
28+
context=context + "Максимальная длина твоего ответа - 3000 символов. На айди вопроса не обращай внимание!"
29+
)
30+
31+
await message.answer(
32+
text=teacher_info
33+
)
34+
35+
36+
37+
except:
38+
await message.answer("Возникла ошибка")
39+
1140

1241
@router.message(CommandStart())
1342
async def start(message: Message) -> None:

src/telegram_assistant/bot/logic/keyboards/inline/main_menu.py

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from aiogram.utils.keyboard import InlineKeyboardBuilder
33

44
from telegram_assistant.bot.logic.callbackdata import MainMenuCBData
5-
from telegram_assistant.bot.logic.callbackdata.main_menu_cb_data import QuestionCBData
5+
from telegram_assistant.bot.logic.callbackdata.main_menu_cb_data import ParseCBData, QuestionCBData
66

77

88
def main_menu_kb() -> InlineKeyboardMarkup:
@@ -13,35 +13,39 @@ def main_menu_kb() -> InlineKeyboardMarkup:
1313
callback_data=QuestionCBData(
1414
action="Question",
1515
question_id="1",
16-
).pack(),
16+
).pack(),
1717
),
1818
InlineKeyboardButton(
19-
text="Кафедры", # Расскажи о кафедрах ЮФУ
20-
callback_data=MainMenuCBData(action="BackToMainMenu").pack(),
19+
text="Кафедры", # Расскажи о кафедрах ЮФУ
20+
callback_data=ParseCBData(
21+
action="DepartmentsParse",
22+
).pack(),
2123
),
2224
InlineKeyboardButton(
23-
text="Преподаватели", # Расскажи о преподавателе <ФИО> из ЮФУ
24-
callback_data=MainMenuCBData(action="BackToMainMenu").pack(),
25+
text="Преподаватели", # Расскажи о кафедрах ЮФУ
26+
callback_data=ParseCBData(
27+
action="TeachersParse",
28+
).pack(),
2529
),
2630
)
2731
builder.row(
2832
InlineKeyboardButton(
29-
text="Поступление", # Расскажи о поступлении в ЮФУ
33+
text="Поступление",
3034
callback_data=QuestionCBData(
3135
action="Question",
3236
question_id="2",
33-
).pack(),
37+
).pack(),
3438
),
3539
InlineKeyboardButton(
36-
text="Расписание", # дадим ссылку
40+
text="Расписание", # дадим ссылку
3741
callback_data=MainMenuCBData(action="BackToMainMenu").pack(),
3842
),
3943
InlineKeyboardButton(
40-
text="Мероприятия", # Расскажи о последних мероприятих ЮФУ + опционально(, основываясь на постах)
44+
text="Мероприятия", # Расскажи о последних мероприятих ЮФУ + опционально(, основываясь на постах)
4145
callback_data=QuestionCBData(
4246
action="Question",
4347
question_id="3",
44-
).pack(),
48+
).pack(),
4549
),
4650
)
4751

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,52 @@
1-
from telegram_assistant.parser.repository.parser_repo import ParserRepo
1+
from telegram_assistant.parser.repository.parser_repo import ParserRepository
22

33

44
class ContextManager:
5-
def __init__(self):
6-
self.parser_repo = ParserRepo()
5+
def __init__(self) -> None:
6+
self.parser_repo = ParserRepository()
77
self.questions_ids: dict[int, str] = {
88
"1": "Расскажи о ЮФУ",
99
"2": "Расскажи о поступлении в ЮФУ",
10-
"3": "Расскажи о последних мероприятих ЮФУ",
11-
}
10+
"3": "Расскажи о последних мероприятиях ЮФУ\
11+
(Основываясь на данных, которые тебе предоставлены)\
12+
(Расскажи о них, но без таких строк 'В сообщении содержится информация о след мероприятиях ЮФУ')",
13+
}
1214
self.context_dictionary = {
13-
"Расскажи о поступлении в ЮФУ": "context_admission.txt",
14-
"Расскажи о последних мероприятих ЮФУ": "context_events.txt",
15-
"Расскажи о ЮФУ": "context_SFU_description.txt",
15+
"1": "context_SFU_description.txt",
16+
"2": "context_admission.txt",
17+
"3": "context_events.txt",
1618
}
17-
19+
1820
def create_base_context(self) -> None:
19-
admission = self.parser_repo.base_parser.parse_admission_rules()
21+
university_info = self.parser_repo.base_parser.parse_university_info()
2022
self.save_context(
21-
"Расскажи о поступлении в ЮФУ",
22-
admission
23+
"1",
24+
university_info,
2325
)
24-
vk_events = self.parser_repo.vk_parser.parse_vk_wall_posts()
26+
admission = self.parser_repo.base_parser.parse_admission_rules()
2527
self.save_context(
26-
"Расскажи о последних мероприятих ЮФУ",
27-
vk_events
28+
"2",
29+
admission,
2830
)
29-
university_info = self.parser_repo.base_parser.parse_university_info()
31+
vk_events = self.parser_repo.vk_parser.parse_vk_wall_posts()
3032
self.save_context(
31-
"Расскажи о ЮФУ",
32-
university_info
33+
"3",
34+
vk_events,
3335
)
34-
35-
def save_context(self, question: str, context: str) -> None:
36-
path = f"src/telegram_assistant/llm/context/{self.context_dictionary[question]}"
36+
37+
def save_context(self, question_id: str, context: str) -> None:
38+
path = f"src/telegram_assistant/llm/context/{self.context_dictionary[question_id]}"
3739
with open(path, "w", encoding="utf-8") as file:
3840
file.write(context)
3941

40-
def get_context(self, question: str) -> str:
41-
if not (question in self.context_dictionary.keys()):
42+
def get_context(self, question_id: str) -> str:
43+
if question_id not in self.context_dictionary.keys():
4244
raise Exception("Контекст вопроса не найден")
43-
44-
path = f"src/telegram_assistant/llm/context/{self.context_dictionary[question]}"
45-
with open(path, "r", encoding="utf-8") as file:
45+
46+
path = f"src/telegram_assistant/llm/context/{self.context_dictionary[question_id]}"
47+
with open(path, encoding="utf-8") as file:
4648
context = file.read()
47-
49+
4850
return context
4951

50-
def get_dynamic_context(self) -> str:
51-
...
52+
def get_dynamic_context(self) -> str: ...

src/telegram_assistant/llm/llm_repo.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,15 @@ class LLMRepository:
66
def __init__(self) -> None:
77
self.context_manager = ContextManager()
88
self.llm = YandexGPT()
9-
9+
1010
self.already_answered_questions: dict[str, str] = {}
11-
12-
def get_question_info(self, question: str) -> str:
13-
context = self.context_manager.get_context(question)
14-
11+
12+
def get_question_info(self, questio_id: str) -> str:
13+
question = self.context_manager.questions_ids[questio_id]
14+
context = (
15+
self.context_manager.get_context(questio_id) + " В ОТВЕТЕ НЕЛЬЗЯ ИСПОЛЬЗОВАТЬ СИМВОЛЫ ** НИ В КОЕМ СЛУЧАЕ"
16+
"Постарайся дать относительно краткий и информативный ответ, не привышающий по длине 3500 символов"
17+
)
1518
if question not in self.already_answered_questions.keys():
1619
llm_answer = self.llm.run(
1720
user_text=question,
@@ -22,18 +25,17 @@ def get_question_info(self, question: str) -> str:
2225
llm_answer = self.already_answered_questions[question]
2326

2427
return llm_answer
25-
28+
2629
def get_dynamic_question_info(self, question: str, context: str) -> str:
27-
editted_context = context +\
28-
"Основываясь только на этой информации дай ответ на следующий вопрос."
29-
30+
editted_context = context + "Основываясь только на этой информации дай ответ на следующий вопрос."
31+
3032
if question not in self.already_answered_questions.keys():
3133
llm_answer = self.llm.run(
3234
user_text=question,
33-
context=context,
35+
context=editted_context,
3436
)
3537
self.already_answered_questions[question] = llm_answer
3638
else:
3739
llm_answer = self.already_answered_questions[question]
3840

39-
return llm_answer
41+
return llm_answer

src/telegram_assistant/llm/yandex_gpt.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,5 @@ def run(
2828
headers={"Accept": "application/json", "Authorization": f"Api-Key {self.api_key}"},
2929
json=data,
3030
).json()
31-
31+
3232
return response["result"]["alternatives"][0]["message"]["text"]

src/telegram_assistant/parser/repository/parser_repo.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from telegram_assistant.parser.vk_parser import VKParser
77

88

9-
class ParserRepo:
9+
class ParserRepository:
1010
def __init__(self) -> None:
1111
self.vk_parser = VKParser()
1212
self.url_parser = URLParser()

0 commit comments

Comments
 (0)