File size: 6,530 Bytes
7ac661d
 
 
 
 
 
 
 
 
 
 
 
56da2e5
7ac661d
 
56da2e5
 
 
 
 
 
7ac661d
 
56da2e5
7ac661d
 
 
 
 
 
 
 
 
56da2e5
 
7ac661d
 
 
 
56da2e5
 
 
7ac661d
 
56da2e5
7ac661d
 
 
 
 
 
 
 
 
56da2e5
 
 
 
 
7ac661d
 
 
 
56da2e5
 
 
7ac661d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56da2e5
 
 
 
 
 
ad706f3
 
7ac661d
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
# abstractive.py

"""
Módulo de resúmenes 'abstractive.py'

Contiene implementaciones de diferentes técnicas de resumen de texto:
- TF-IDF Summarizer
- TextRank Summarizer
- Combined Summarizer (que combina TF-IDF y TextRank para extraer palabras clave)
- BERT Summarizer (extractivo basado en un modelo BERT preentrenado)
"""

import numpy as np
import networkx as nx
from typing import List
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
from summarizer import Summarizer


class TFIDFSummarizer:
    """Genera resúmenes usando el modelo TF-IDF."""

    @staticmethod
    def summarize(sentences: List[str], preprocessed_sentences: List[str], num_sentences: int = 1) -> str:
        """
        Genera un resumen basado en TF-IDF seleccionando las oraciones mejor puntuadas.

        :param sentences: Lista de oraciones originales (sin procesar).
        :param preprocessed_sentences: Lista de oraciones preprocesadas (por ejemplo, tokenizadas o normalizadas).
        :param num_sentences: Número de oraciones a devolver en el resumen.
        :return: Un string que contiene el resumen formado por las oraciones más relevantes.
        """
        vectorizer = TfidfVectorizer()
        tfidf_matrix = vectorizer.fit_transform(preprocessed_sentences)
        sentence_scores = np.sum(tfidf_matrix.toarray(), axis=1)
        ranked_indices = np.argsort(sentence_scores)[::-1]
        selected = [sentences[i] for i in ranked_indices[:num_sentences]]
        return ' '.join(selected)


class TextRankSummarizer:
    """Genera resúmenes usando el algoritmo TextRank."""

    @staticmethod
    def summarize(sentences: List[str], preprocessed_sentences: List[str], num_sentences: int = 1) -> str:
        """
        Genera un resumen usando el algoritmo de grafos TextRank.

        :param sentences: Lista de oraciones originales.
        :param preprocessed_sentences: Lista de oraciones preprocesadas.
        :param num_sentences: Número de oraciones a devolver en el resumen.
        :return: Un string que contiene el resumen.
        """
        vectorizer = TfidfVectorizer()
        tfidf_matrix = vectorizer.fit_transform(preprocessed_sentences)
        similarity_matrix = cosine_similarity(tfidf_matrix)
        nx_graph = nx.from_numpy_array(similarity_matrix)
        scores = nx.pagerank(nx_graph)
        # Ordena los nodos (oraciones) por puntaje descendente
        ranked_indices = sorted(((scores[node], node) for node in nx_graph.nodes), reverse=True)
        selected = [sentences[i] for _, i in ranked_indices[:num_sentences]]
        return ' '.join(selected)


class CombinedSummarizer:
    """Genera resúmenes combinando palabras clave TF-IDF y TextRank."""

    def __init__(self, top_n_keywords: int = 10):
        """
        :param top_n_keywords: Número de palabras clave a extraer de cada método (TF-IDF y TextRank).
        """
        self.top_n_keywords = top_n_keywords

    def extract_keywords_tfidf(self, preprocessed_sentences: List[str]) -> List[str]:
        """
        Extrae palabras clave basadas en TF-IDF.

        :param preprocessed_sentences: Lista de oraciones preprocesadas.
        :return: Lista con las palabras clave más relevantes según TF-IDF.
        """
        vectorizer = TfidfVectorizer()
        tfidf_matrix = vectorizer.fit_transform(preprocessed_sentences)
        tfidf_scores = zip(vectorizer.get_feature_names_out(), tfidf_matrix.toarray().sum(axis=0))
        sorted_scores = sorted(tfidf_scores, key=lambda x: x[1], reverse=True)
        return [word for word, _ in sorted_scores[:self.top_n_keywords]]

    def extract_keywords_textrank(self, preprocessed_sentences: List[str]) -> List[str]:
        """
        Extrae palabras clave basadas en TextRank (a través de la co-ocurrencia de palabras).

        :param preprocessed_sentences: Lista de oraciones preprocesadas.
        :return: Lista con las palabras clave más relevantes según TextRank.
        """
        words = ' '.join(preprocessed_sentences).split()
        co_occurrence_graph = nx.Graph()
        for i in range(len(words) - 1):
            word_pair = (words[i], words[i + 1])
            if co_occurrence_graph.has_edge(*word_pair):
                co_occurrence_graph[word_pair[0]][word_pair[1]]['weight'] += 1
            else:
                co_occurrence_graph.add_edge(word_pair[0], word_pair[1], weight=1)

        ranks = nx.pagerank(co_occurrence_graph, weight='weight')
        sorted_ranks = sorted(ranks.items(), key=lambda x: x[1], reverse=True)
        return [word for word, _ in sorted_ranks[:self.top_n_keywords]]

    def combined_keywords(self, preprocessed_sentences: List[str]) -> List[str]:
        """
        Combina las palabras clave obtenidas tanto por TF-IDF como por TextRank
        y devuelve la intersección de ambas listas.

        :param preprocessed_sentences: Lista de oraciones preprocesadas.
        :return: Lista con las palabras clave en común (intersección).
        """
        tfidf_keywords = self.extract_keywords_tfidf(preprocessed_sentences)
        textrank_keywords = self.extract_keywords_textrank(preprocessed_sentences)
        return list(set(tfidf_keywords) & set(textrank_keywords))

    def summarize(self, sentences: List[str], preprocessed_sentences: List[str], num_sentences: int = 1) -> str:
        """
        Genera un resumen basado en la frecuencia de palabras clave combinadas (TF-IDF & TextRank).

        :param sentences: Lista de oraciones originales.
        :param preprocessed_sentences: Lista de oraciones preprocesadas.
        :param num_sentences: Número de oraciones a devolver en el resumen.
        :return: Un string con las oraciones más relevantes.
        """
        keywords = self.combined_keywords(preprocessed_sentences)
        sentence_scores = []
        for i, sentence in enumerate(preprocessed_sentences):
            score = sum(1 for word in sentence.split() if word in keywords)
            sentence_scores.append((score, i))
        # Ordena las oraciones por la cantidad de palabras clave presentes
        ranked_sentences = sorted(sentence_scores, key=lambda x: x[0], reverse=True)
        selected = [sentences[i] for _, i in ranked_sentences[:num_sentences]]
        return ' '.join(selected)


class BERTSummarizer:
    def __init__(self):
        self.model = Summarizer()

    def summarize(self, text, num_sentences):
        return self.model(text, num_sentences=num_sentences)