Резюмировать мой текст?

Привет, удивительные люди интернета, у вас все в порядке? Сегодня я предлагаю вашему вниманию очередную статью, исследующую мир искусственного интеллекта, в которой мы узнаем, как резюмировать тексты с помощью NLP (Natural Language Processing).
Для начала мы должны понять, что резюмирование — это, по сути, создание резюме, когда из текста создается другой текст, в котором сжато излагается смысл исходного текста, концентрируясь только на основных моментах.

В настоящее время мы используем обобщенные тексты, чтобы облегчить анализ полученных данных, например, крупная организация использует этот процесс, чтобы собрать важные части отзывов для создания инсайтов, другой пример — когда нам нужно обобщить важные части определенного текста, чтобы представить в виде ссылок на статьи, блоги.

Хотя это кажется тривиальным, это очень распространенная деятельность, которая обычно выполняется вручную, что делает процесс более утомительным и медленным, так как же решить эту проблему? Благодаря технологическому прогрессу сегодня мы можем делать это автоматически с помощью машинного обучения, в частности, используя обработку естественного языка.

Существует два подхода, которые используются для обобщения: абстрактное обобщение, которое заключается в генерации новых предложений из оригинального текста, и экстрактивное обобщение, когда мы определяем важные предложения в тексте и извлекаем их, создавая резюме.

Мы создадим API, используя FastAPI, где в качестве входных данных будет текст и url, мы начнем с разделения статьи на части. В первой части мы будем обрабатывать полученные данные, во второй — заниматься обобщением.

Прикладываем руки к работе

Работа с данными

  • Давайте начнем с установки фреймворка fastAPI
pip install fastapi

Войдите в полноэкранный режим Выход из полноэкранного режима
  • Нам также понадобится ASGI-сервер
pip install uvicorn

Войдите в полноэкранный режим Выход из полноэкранного режима

Наш проект будет иметь следующую структуру:

text_summarizer_api/ # raiz
┣ api/
┃ ┣ routers/
┃ ┃ ┗ summarization.py # rotas da API (POST/GET)
┃ ┣ schemas/
┃ ┃ ┗ summarization_schema.py # Formato da entrada de dados
┃ ┣ services/
┃ ┃ ┗ summarization_service.py # Sumarização de texto
┣ main.py # Inicial
┗ requirements.txt

Войдите в полноэкранный режим Выход из полноэкранного режима

Мы начнем с создания нашего сервиса суммирования, помня, что в этой части мы будем работать с данными:

Учитывая следующую полезную нагрузку, мы понимаем, что можем получить как текст, так и url, кроме того, язык является обязательным, чтобы обобщение было выполнено правильно.

Давайте начнем с метода get_summarization, чтобы определить, какой тип данных мы получаем:

async def get_summarization(summarization):
    formatted_text = summarization.text if summarization.url is None else scraping_text(summarization.url)

Войдите в полноэкранный режим Выход из полноэкранного режима

Если мы передаем URL, нам нужно будет провести веб-скреппинг для извлечения нужной нам текстовой информации, и для этого мы используем модуль BeautifulSoup.

pip install beautifulsoup4 requests
Войдите в полноэкранный режим Выход из полноэкранного режима

Мы не будем углубляться в то, как делается этот скрейпинг, возможно, в другой статье, но для удовлетворения нашего запроса мы сделаем следующее:

  • Мы отправим запрос по полученному url
  • Мы получим содержимое HTML в виде текста
  • Мы рассмотрим структуру, полученную в супе, и поищем конкретный элемент
  • Наконец, мы извлечем текст и выполним очистку, удалив все специальные символы, подчеркивания и неиспользуемые пробелы.
from bs4 import BeautifulSoup as bs

def scraping_text(url):
    response = requests.get(url)
    soup = bs(response.content, 'lxml')
    paragraph = soup.find_all(name='p', attrs= {"class": "pw-post-body-paragraph"}, limit=40)
    joined_text = ''.join([p.text.strip().lower() for p in paragraph])
    joined_text = format_text(joined_text)
    return joined_text

def format_text(text):
    formatted_text = unicodedata.normalize('NFD', text).encode('ascii', 'ignore').decode('utf-8')
    formatted_text = re.sub(r'[[0-9]*]', ' ', formatted_text)
    formatted_text = re.sub(r's+', ' ', formatted_text)
    return formatted_text

Войдите в полноэкранный режим Выход из полноэкранного режима

Хорошо, мы обработали данные и теперь переходим ко второй части статьи.

Обобщение

Чтобы начать процесс обобщения, нам нужно установить и импортировать необходимые библиотеки:

pip install nltk
Войдите в полноэкранный режим Выход из полноэкранного режима

NLTK, что расшифровывается как Natural Language Toolkit, представляет собой набор инструментов естественного языка, содержащий различные алгоритмы, реализованные для работы с естественным языком.

Мы будем использовать пакеты Corpus и Tokenizers, когда мы говорим о «токенизации», мы говорим о разделении текста на ряд лексем, уже корпус текста — это большой массив текста или коллекция текстов, которые могут быть наборами данных, такими как произведения автора, стихи или набор стоп-слов.

NLKT включает некоторые корпорации, которые представляют собой списки нерелевантных слов, т.е. высокочастотных слов, которые мы можем отфильтровать в документе перед началом обработки. В нашем случае мы отфильтруем эти стоп-слова, добавим их в словарь python, чтобы проверить, как часто они появляются в тексте, прежде чем их удалить.

Мы будем использовать этот словарь над каждой фразой, чтобы знать, какие из них имеют наиболее релевантное содержание в общем тексте.

import re
import requests
from bs4 import BeautifulSoup as bs
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize, sent_tokenize

async def get_summarization(summarization):
    formatted_text = summarization.text if summarization.url is None else scraping_text(summarization.url)
    stop_words = set(stopwords.words(str(summarization.language)))
    frequences_word = handle_frequence_word(stop_words, formatted_text)
    print('Dicionário de frequencia de palavras de parada', frequences_word)

def handle_frequence_word(stop_words, text):
    words = word_tokenize(text)
    frequences_word = dict()
    for word in words:
        if word in stop_words:
            continue
        if word in frequences_word:
            frequences_word[word] += 1
        else:
            frequences_word[word] = 1

    return frequences_word

def scraping_text(url):
    response = requests.get(url)
    soup = bs(response.content, 'lxml')
    paragraph = soup.find_all(name='p', attrs= {"class": "pw-post-body-paragraph"}, limit=40)
    joined_text = ''.join([p.text.strip().lower() for p in paragraph])
    joined_text = format_text(joined_text)
    return joined_text

def format_text(text):
    formatted_text = unicodedata.normalize('NFD', text).encode('ascii', 'ignore').decode('utf-8')
    formatted_text = re.sub(r'[[0-9]*]', ' ', formatted_text)
    formatted_text = re.sub(r's+', ' ', formatted_text)
    return formatted_text
Войдите в полноэкранный режим Выход из полноэкранного режима

Теперь мы займемся предложениями, т.е. лексемами предложений, позже мы будем использовать этот список в тексте резюме. В этой оценке мы будем рассматривать частоту встречаемости каждого термина, поэтому мы будем оценивать каждое предложение по его словам, то есть складывать частоту каждого важного слова, встречающегося в предложении.

async def get_summarization(summarization):
    formatted_text = summarization.text if summarization.url is None else scraping_text(summarization.url)
    stop_words = set(stopwords.words(str(summarization.language)))
    frequences_word = handle_frequence_word(stop_words, formatted_text)
    sentences = sent_tokenize(formatted_text)
    frequences_sentence = handle_sentences(frequences_word, sentences)

def handle_sentences(frequences_word, sentences):
    frequences_sentence = dict()
    for sentence in sentences:
        for word, freq in frequences_word.items():
            if word in sentence:
                if sentence in frequences_sentence:
                    frequences_sentence[sentence] += freq
                else:
                    frequences_sentence[sentence] = freq

    return frequences_sentence
Войдите в полноэкранный режим Выход из полноэкранного режима

В завершение части обобщения мы создадим резюме, выбрав 30% наиболее взвешенных предложений.

select_lenght = int(len(frequences_sentence) * 0.3) # peso 30%
Войдите в полноэкранный режим Выход из полноэкранного режима

С помощью функции nlargest модуля heapq мы вернем заданное количество наибольших элементов итерабельной таблицы, в нашем случае мы найдем наибольшее n элементов, здесь значение списка с предложениями с 30% весом на вершине итерабельной таблицы, которая является нашим словарем предложений.

summary = nlargest(select_lenght, frequences_sentence, key=frequences_sentence.get)
Войдите в полноэкранный режим Выход из полноэкранного режима

Наконец, мы проходим через созданную сводку, конкатенируя ее в строку, являющуюся результатом нашей сводки.

Полный код нашего сервиса выглядит следующим образом:

import re
import requests
import unicodedata
from bs4 import BeautifulSoup as bs
from heapq import nlargest
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize, sent_tokenize

async def get_summarization(summarization):
    formatted_text = summarization.text if summarization.url is None else scraping_text(summarization.url)
    stop_words = set(stopwords.words(str(summarization.language)))
    frequences_word = handle_frequence_word(stop_words, formatted_text)
    sentences = sent_tokenize(formatted_text)
    frequences_sentence = handle_sentences(frequences_word, sentences)
    return get_resume(frequences_sentence)

def scraping_text(url):
    response = requests.get(url)
    soup = bs(response.content, 'lxml')
    paragraph = soup.find_all(name='p', attrs= {"class": "pw-post-body-paragraph"}, limit=40)
    joined_text = ''.join([p.text.strip().lower() for p in paragraph])
    joined_text = format_text(joined_text)
    return joined_text

def format_text(text):
    formatted_text = unicodedata.normalize('NFD', text).encode('ascii', 'ignore').decode('utf-8')
    formatted_text = re.sub(r'[[0-9]*]', ' ', formatted_text)
    formatted_text = re.sub(r's+', ' ', formatted_text)
    return formatted_text

def handle_frequence_word(stop_words, text):
    words = word_tokenize(text)
    frequences_word = dict()
    for word in words:
        if word in stop_words:
            continue
        if word in frequences_word:
            frequences_word[word] += 1
        else:
            frequences_word[word] = 1

    return frequences_word

def handle_sentences(frequences_word, sentences):
    frequences_sentence = dict()
    for sentence in sentences:
        for word, freq in frequences_word.items():
            if word in sentence:
                if sentence in frequences_sentence:
                    frequences_sentence[sentence] += freq
                else:
                    frequences_sentence[sentence] = freq

    return frequences_sentence

def get_resume(frequences_sentence):
    select_lenght = int(len(frequences_sentence) * 0.3) # peso 30%
    summary = nlargest(select_lenght, frequences_sentence, key=frequences_sentence.get)
    final = [word for word in summary]
    summary = ''.join(final)
    return summary

Войдите в полноэкранный режим Выход из полноэкранного режима

Заканчивая…

Чтобы закончить наш API, теперь давайте потреблять сервисы на маршрутах и генерировать конечные точки входа, полный код находится на моем github.
Чтобы завершить работу над нашим API, теперь мы будем потреблять сервисы в маршрутах и генерировать конечные точки входа, полный код находится на моем github.

Запустим наш сервер: uvicorn main:app —reload и мы сможем получить доступ к API: http://127.0.0.1:8000/docs.

Получаем вывод, обобщенный и сохраняющий логику исходного текста

Что ж, ребята, мы не стали углубляться в создание API, потому что я хочу показать вам, как можно автоматизировать некоторые трудоемкие процессы с помощью машинного обучения. Надеюсь, вам понравился этот материал, и на сегодня мы закончили.

Оцените статью
devanswers.ru
Добавить комментарий