Файл: Разработка информационной системы персонализации новостной ленты на базе платформы Telegram.pdf

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 27.03.2024

Просмотров: 22

Скачиваний: 0

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

48
«-». Тогда пользователю будет предложено внести ключевые слова через запятую отметив каждое слово соответствующим знаком, например:
+осенний фестиваль, +акции, -реклама
Интерфейс реализации описанного выше сценария представлена на рисунке 5.
Рисунок 5 – Интерфейс редактирования фильтров

49
2.4.3. Редактирование каналов
После подписки на список каналов у пользователя возникает необходимость просмотреть список каналов, удалить каналы. Каналы выдаются пользователю в виде списка, а возможность удаления канала реализуется через команду напротив канала.
Интерфейс реализации описанного выше сценария представлена на
Рисунке 6.
Рисунок 6 – Интерфейс редактирования каналов

50
3. Практическая часть
3.1. Формирование фокус-группы
Для оценки результатов работы системы, выявления ошибок, учета пользовательского опыта и определения путей развития системы принято решение провести пробное использование системы группой не менее чем из 20 пользователей в течении одной рабочей недели. По результатам пробного использования у пользователей проведен опрос.
Для проведения опроса использовалась облачная площадка Google Forms.
Google Forms позволяет создавать произвольные опросные листы и предоставляет инструментарий по аналитике результатов опроса.
Для достижения поставленных перед опросом задач были определены следующие вопросы.
1) Понравилось ли вам использование данного бота?
2) Считаете ли вы его полезным для себя?
3) На сколько хорошо бот справлялся с поставленными задачами?
4) Легко ли вы разобрались в интерфейсе бота?
5) Встречали ли вы ошибки в работе бота?
3.2. Опрос фокус-группы
Результаты опроса представлены на рисунках 7 – 11.

51
Рисунок 7 – Результаты опроса. Вопрос 1
Большая часть участников опроса в фокус-группе оценили впечатление от использования бота на высший бал, при этом средняя оценка составила 8,77 баллов.
Рисунок 8 – Результаты опроса. Вопрос 2
Полезность бота была оценена участниками в среднем на 7,81. Оценка полезности оказалась ниже, чем впечатления от использования. Для работы над этим параметром могут быть разработаны предварительно настроенные

52 подборки каналов и фильтры для того, чтобы пользователь не тратил время и силы на настройку, а сразу приступал к использованию.
Рисунок 9 –
Результаты опроса. Вопрос 3
Участники дали высокую оценку качеству работы бота, она составила в среднем 8,86. Высокие показатели качества работы, помимо качества разработки могут быть связаны так же с понятными для пользованью задачами, поставленными перед ботом.
Рисунок 10 –
Результаты опроса. Вопрос 4


53
Оценка удобства интерфейса бота составила в среднем 7,54.
Рисунок 11 – Результаты опроса. Вопрос 5
Достаточно высокое число участников столкнулась с ошибками при работе бота, а именно 6 из 22. Основной ошибкой была ошибка в интерфейсе бота, когда не пользователь не мог вызвать основное меню из некоторых сценарных веток.
Данная ошибка была устранена.
3.3. Примеры работы модуля анализа схожести новостей
Пример работы модуля анализа новостей представлен на рисунке 12. В начале поста выделен заголовок новости на основании четырех схожих новостей из следующих каналов.
1. RT на русском.
2. The Bill.
3. Mash.

54 4. IZ.RU.
Далее перечисляются все ссылки на новости из вышеперечисленных каналов. Их модуль схожести новостей определил, как одинаковые. На рисунках
13-16 приведены оригинальные тексты новостей из источников, упомянутых на рисунке 12.
Рисунок 12 – Объединенная из 4 источников новость

55
Рисунок 13 – Новость в источнике 1

56
Рисунок 14 – Новость в сточнике 2

57
Рисунок 15 – Новость в источнике 3
Рисунок 16 – Новость в источнике 4

58
ЗАКЛЮЧЕНИЕ
В рамках выпускной квалификационной работы была выполнена разработка системы персонализации новостной ленты на базе платформы
Telegram.
В ходе выполнения работы проведен анализ предметной области, обзор современных технологий реализации информационных систем, обзор возможностей платформы Telegram и обзор методов анализа схожести текстов.
Выбрано технологическое и решение для реализации системы.
Разработаны архитектура системы с учетом архитектуры Telegram, структура базы данных, сценарии работы системы, интерфейс системы и реализованы алгоритмы серверной части системы.
Разработана и обучена нейронная сеть для обнаружения одинаковых новостей и произведена интеграция нейронной сети в информационную систему.
Для оценки результатов работы системы проведено пробное использование системы среди фокус-группы, с последующем проведением опроса. По результатам опроса установлено, что система интересна и полезна пользователем.
Таким образом, работа выполнена в полном объёме. Система удовлетворяет всем поставленным требованиям технического задания и пригодна для дальнейшей эксплуатации.


59
СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ
1. Сенаторов А. А. Telegram. Как запустить канал, привлечь подписчиков и заработать на контенте. – М.: Альпина Паблишер, 2018. –156 с.
2. Статья BBC [Электронный ресурс] – Режим доступа: URL: https://www.bbc.com/russian/vert-fut-52774764 (Дата обращения 20.03.2022)
3. Официальная документация Telegram MTProto [Электронный ресурс]
– Режим доступа: URL: https://core.telegram.org/mtproto (Дата обращения
25.04.2022)
4. Официальная документация Telegram API. [Электронный ресурс] –
Режим доступа: URL: https://core.telegram.org/methods (Дата обращения
01.05.2022)
5. Осипов Д. Л. Технологии проектирования баз данных. – М.: ДМК,
2019. – 497c.
6. Кристофер Д. Маннинг, Прабхакар Рагхаван, Хинрич Шютце.
Введение в информационный поиск. – Пер. с англ. – М.: Вильяме, 2011. – 428c.
7. Статья Medium [Электронный ресурс] – Режим доступа: URL: https://medium.com/@bigdataschool/как-работает-word2vec-нейросети-для-nlp-
1609812f80e5 (Дата обращения 15.05.2022)
8. Лен Басс. Архитектура программного обеспечения на практике, 2-е издание. – Пер. с англ. – СПб.: Питер, 2006.
– 574 с.
9. С. В. Назаров. Архитектура и проектирование программных систем. –
М.: ИНФРА-М, 2013. – 413c.
10. Майкл Нильсен. Neural Networks and Deep Learning. – NY.: Chapter,
2019. – 653c.
11. Ян Гудфеллоу, Иошуа Бенджио, Аарон Курвилль. Глубокое обучение.
2-е издание. – Пер. с англ. – М.: ДМК, 2018. – 652 с.

60
ПРИЛОЖЕНИЕ А. Графическая часть
В графическую часть выпускной квалификационной работы входят следующие материалы.
1) Архитектурная схема разрабатываемой системы.
2) Иллюстрация работы системы 1. Объединение новостей из четырех источников в один пост.
3) Иллюстрация работы системы 2. Первый источник.
4) Иллюстрация работы системы 3. Второй источник.
5) Иллюстрация работы системы 4. Третий источник.

61
ПРИЛОЖЕНИЕ Б. Исходный код telegram-bot
server
main.py
from aiogram.utils import executor from create_bot import dp, ids, bot from db import user as us from antiflood import ThrottlingMiddleware async def on_startup(_): global ids ids+=(us.get_all_users_ids()) print(‘Бот запущен’) async def on_shutdown(_): await dp.storage.close() await dp.storage.wait_closed() from handlers import add_channels, manage_channels, ui, cancel, registration cancel.register_handlers_cancel(dp) add_channels.register_handlers_add_channels(dp) manage_channels.register_handlers_manage_channels(dp) registration.register_handlers_reg(dp) ui.register_handlers_ui(dp) dp.middleware.setup(ThrottlingMiddleware()) executor.start_polling(dp, skip_updates=True, on_startup=on_startup, on_shutdown=on_shutdown)
add_channels.py
from aiogram import types, Dispatcher, filters from attr import validate from create_bot import dp, bot, ids, r from db import user as us from antiflood import rate_limit from keyboards import user_kb from aiogram.dispatcher import FSMContext

62 from aiogram.dispatcher.filters.state import State,
StatesGroup from aiogram.utils.markdown import escape_md class AddChannel(StatesGroup): subject = State() filter_one = State() class MultiAddChannel(StatesGroup): channels = State() confirm = State() async def add(msg):
# Добавление канала if type(msg)
== types.callback_query.CallbackQuery: await msg.answer() msg = msg.message await AddChannel.subject.set() await msg.answer(“Для добавления канала отправьте пригласительную ссылку в формате https://t.me/123”, reply_markup=user_kb.kb_cancel_inl) async def process_subject(msg: types.Message, state:
FSMContext):
# Ввод имени канала await state.update_data(subject=msg.text) await AddChannel.next() await msg.answer(‘Введите фильтры через запятую в формате +осенний фестиваль, +акции, -реклама. \
Вы ни при каких обстоятельствах не будете получать новостей со словами после «-«, \ а если укажете что-либо после «+», то будете получать только те новости где есть эти слова. \
Можно использовать только «-« или только «+». Если хотите убрать фильтрацию, то нажмите на кнопку ниже', reply_markup=user_kb.remove_filters) async def process_subject_finish(msg: types.Message, state: FSMContext):
# Добавление канала в БД subject = (await state.get_data())[‘subject’] uid = msg.from_user.id if type(msg)
== types.callback_query.CallbackQuery:


63 await msg.answer() msg = msg.message fltrs = ‘’ else: for I in msg.text.split(‘,’):
I = i.strip() if I == ‘’: await msg.reply(f'Не ставьте запятые по краям сообщения и по несколько запятых подряд, введите фильтры еще раз или нажмите «Отмена»', reply_markup=user_kb.kb_cancel_inl) return if len(i) <= 2: await msg.reply(f'Фильтр состоит минимум из знака и двух символов, введите фильтры еще раз или нажмите «Отмена»', reply_markup=user_kb.kb_cancel_inl) return if i[0]!=’+’ and i[0]!=’-‘: await msg.reply(f'Вы забыли указать + или – перед фразой «{i}», введите фильтры еще раз или нажмите «Отмена»', reply_markup=user_kb.kb_cancel_inl) return fltrs = msg.text if us.if_has_link(uid, subject): await msg.answer(«Уже имеется такой канал») await state.finish() else: us.add_news(user_id=int(uid), channel_link=subject, filters=fltrs) await msg.answer(“Канал внесён в список”, reply_markup=user_kb.menu) r.set(str(uid) + “ “ + subject, ‘добавить’) await state.finish() async def add_multi(msg: types.Message):
# Добавление нескольких каналов await MultiAddChannel.channels.set() await message.reply(«Вводите названия каналов или ссылки через запятую») async def check_text(msg: types.Message, state=FSMContext): await state.update_data(text=msg.text)

64 await msg.reply(‘Всё правильно?’, reply_markup=user_kb.check_text) await MultiAddChannel.next() async def multi_finish(cb: types.CallbackQuery, state:
FSMContext):
# Непосредственно добавление if cb.data == 'ok': text:str = (await state.get_data())[‘text’] channels = [] for I in text.split(‘,’):
I = i.strip() if us.if_has_link(cb.from_user.id, i): await cb.message.answer(«Уже имеется канал «+i) else: us.add_news(user_id=cb.from_user.id, channel_link=i) r.set(str(cb.from_user.id) + “ “ + I,
‘добавить’) await cb.answer(«Новые каналы были внесены в список. Отредактировать фильтры вы можете через главное меню», show_alert=True) else: await cb.answer(«Добавление отменено», user_kb.menu) await state.finish() def register_handlers_add_channels(dp: Dispatcher): dp.register_message_handler(add, commands=[‘add_channel’], state=’*’) dp.register_callback_query_handler(add, text=”add_channel”) dp.register_message_handler(process_subject, state=AddChannel.subject) dp.register_message_handler(check_text, state=MultiAddChannel.channels) dp.register_callback_query_handler(multi_finish, state=MultiAddChannel.confirm) dp.register_message_handler(process_subject_finish, state=AddChannel.filter_one)

65 dp.register_callback_query_handler(process_subject_finish
, text=’remove_filters’, state=AddChannel.filter_one)
sender.py
import telebot # Синхронный аналог aiogram
from telebot.types
import
InputMediaPhoto,
InputMediaVideo
from settings import token #
�”обавляем токен из файла настроек bot = telebot.TeleBot(token)
def send(id, url, text, media=None): text = text+’\n
�сточники:’+url
if media[‘video’] == [] and media[‘photo’] == []: msg = bot.send_message(id, text)
elif media[‘video’] == [] and len(media[‘photo’])
== 1: msg
= bot.send_photo(id, str(media[‘photo’][0]), caption=text)
elif media[‘photo’] == [] and len(media[‘video’])
== 1: msg
= bot.send_video(id, str(media[‘video’][0]), caption=text)
else: medias = []
for I in media[‘photo’]: medias.append(InputMediaPhoto(i))
for I in media[‘video’]: medias.append(InputMediaVideo(i)) bot.send_media_group(id, medias) msg = bot.send_message(id, text)
return msg.message_id, text
def edit(phrase, id, mid): bot.edit_message_text(phrase, id, mid)
return mid, phrase


66
ПРИЛОЖЕНИЕ В. Исходный код telegram-bot
server
import asyncio
from telethon import TelegramClient, events
from telethon.tl.functions.channels
import
JoinChannelRequest
from telethon.tl.custom.message import Message
from telethon.tl.types import MessageMediaDocument,
MessageMediaPhoto
from telethon.events import StopPropagation
import os
import sys
from settings import api_id, api_hash, host_redis, port_redis, charset, decode_responses, queue_db_redis
import redis
import compare_news as ai
from db import user as us
from sender import send, edit
import datetime client = TelegramClient('grab', api_id, api_hash) channels_to_join = us.get_all_channels() # Получаем каналы для парсинга lst = [] # Сюда тоже скоро поступят каналы r = redis.StrictRedis( # Подключаем бд host=host_redis, port=port_redis, charset=charset, decode_responses=decode_responses, db=queue_db_redis
) async def news_processing(msg: Message, text, name, media): lm_text = ai.preprocess_text(text) #Леммы из текста date = msg.date #
�"ата поста users = us.get_users_of_channel(name) # Получаем всех подписчиков

67 interest = []
for i in users:
if us.check_text(lm_text, us.get_user_filters(i)): interest.append(us.User.get(us.User.id==i)) # Отбираем кому подходит по фильтрам
if not interest: # Если никому, то новость не нужна
return channels_to_search = [] channels = {}
for i in interest: #Каждый пользователь
for ii in us.get_channels_of_user(i.id): #
Каждый канал Пользователя
if ii.channel_name != name: channels[i.id]=(ii.channel_name)
#
�-аписываем под него, если не источник новости
if ii.channel_name
not
in channels_to_search: channels_to_search.append(ii.channel_name) #
� добавляем в общий список если не повторялся to_check
= us.get_news_for_check(channels_to_search, channels.keys()) # Получаем список пользователей и новостей к проверке repeat = []
if to_check == {}: us.register(send(users[0], f"\n{(date+datetime.timedelta(hours=3)).strftime('%H:%M')
} {name} - https://t.me/{msg.chat.username}/{msg.id}", text, media),text, lm_text, media, name, users[0], date)
for i in to_check.keys():
for ii in to_check[i]:
if
(ii.id
in repeat
or ai.are_news_same(text, ii.text)): repeat.append(ii.id) us.register(edit(f"{ii.edit_text}\n{(date+datetime.timede lta(hours=3)).strftime('%H:%M')}
{name}
- https://t.me/{msg.chat.username}/{msg.id}", i,
(us.switch_np(ii.sent))[i]),text, lm_text, media, name, i, date)# Ссылка на источник

68
else: us.register(send(i, f"\n{(date+datetime.timedelta(hours=3)).strftime('%H:%M')
} {name} - https://t.me/{msg.chat.username}/{msg.id}", text, media),text, lm_text, media, name, i, date)
# await client.forward_messages(entity=channel_to_send_news, messages=event.message)
@client.on(events.Album(lst)) async def my_event_handler(event):
"""Обнаруживает сообщения с несколькими вложениями""" media = {'video':[], 'photo':[]} name = await event.get_chat().title text = ''
for i in event: i:Message
if i.text != '': text = i.text
if
False:# type(i.media)
==
MessageMediaDocument: media['video'].append(i.media.document.access_hash)
if False:# type(i.media) == MessageMediaPhoto: media['photo'].append(i.media.photo.access_hash) await news_processing(event[0].message, text, name, media) #Отправка в фильтр await event.delete()
@client.on(events.NewMessage(lst)) async def my_event_handler(event): msg:Message = event.message
if msg.grouped_id != None: # Пропускает уже обработанные
return name = (await event.get_chat()).title text = msg.text media = {'video':[], 'photo':[]}
if
False:# type(msg.media)
==
MessageMediaDocument: