Misnik commited on
Commit
a2eb307
·
verified ·
1 Parent(s): 4b27036

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +74 -35
app.py CHANGED
@@ -5,6 +5,7 @@ from langdetect import detect
5
  import re
6
 
7
  # Инициализация мультиязычной модели
 
8
  model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')
9
  kw_model = KeyBERT(model)
10
 
@@ -19,27 +20,31 @@ STOP_WORDS = {
19
  # Добавьте другие языки, если необходимо
20
  }
21
 
22
- def detect_language(text):
23
  """
24
- Определение языка текста.
 
25
  """
26
  try:
27
  return detect(text)
28
  except:
29
- return "en" # По умолчанию английский
30
 
31
- def clean_text(text, lang):
32
  """
33
- Удаление стоп-слов из текста на основе языка.
34
  """
35
  stop_words = STOP_WORDS.get(lang, [])
36
  words = text.split()
37
  cleaned_text = " ".join([word for word in words if word.lower() not in stop_words])
38
  return cleaned_text
39
 
40
- def segment_text(text, max_segment_length=1000):
41
  """
42
- Разделение текста на сегменты по предложениям.
 
 
 
43
  """
44
  sentences = re.split(r'(?<=[.!?]) +', text)
45
  segments = []
@@ -51,52 +56,84 @@ def segment_text(text, max_segment_length=1000):
51
  else:
52
  segments.append(current_segment.strip())
53
  current_segment = sentence
54
-
55
  if current_segment:
56
  segments.append(current_segment.strip())
57
 
58
  return segments
59
 
60
- def postprocess_keywords(keywords, min_score=0.65):
61
  """
62
- Постобработка ключевых слов: удаление вложенных, коротких и низкорейтинговых фраз.
 
 
 
63
  """
64
  unique_keywords = []
65
  seen = set()
66
-
 
 
67
  for kw in sorted(keywords, key=lambda x: len(x[0]), reverse=True):
68
- if kw[0] not in seen and kw[1] >= min_score:
69
- if not any(kw[0] in u_kw["keyword"] for u_kw in unique_keywords):
70
- unique_keywords.append({"keyword": kw[0], "score": kw[1]})
71
- seen.add(kw[0])
72
-
73
- filtered_keywords = [
74
- kw for kw in unique_keywords if len(kw["keyword"].split()) > 1
75
- ]
 
 
 
 
 
76
  return filtered_keywords
77
 
78
- def evaluate_keywords(keywords, text_length):
79
  """
80
- Оценка качества ключевых слов.
 
 
81
  """
 
 
82
  avg_score = sum([kw["score"] for kw in keywords]) / len(keywords)
83
- coverage = len(keywords) / (text_length / 100) # Ключевые слова на 100 символов текста
84
  return {"average_score": avg_score, "coverage": coverage}
85
 
86
-
87
- def extract_keywords_interface(text, top_n=15, diversity=0.4, max_ngram=3):
 
 
88
  """
89
  Извлечение ключевых слов через Gradio интерфейс.
 
 
 
 
 
90
  """
91
  if not text or not text.strip():
92
- return []
93
-
94
- # Определение языка текста
 
 
 
 
 
 
95
  lang = detect_language(text)
 
 
96
  cleaned_text = clean_text(text, lang)
97
- segments = segment_text(cleaned_text)
98
- all_keywords = []
99
 
 
 
 
 
 
100
  for segment in segments:
101
  keywords = kw_model.extract_keywords(
102
  segment,
@@ -106,13 +143,15 @@ def extract_keywords_interface(text, top_n=15, diversity=0.4, max_ngram=3):
106
  )
107
  all_keywords.extend(keywords)
108
 
109
- # Постобработка ключевых слов
110
- processed_keywords = postprocess_keywords(all_keywords)
 
 
 
111
 
112
- # Возвращаем результат
113
  return {
114
  "keywords": [{"keyword": kw["keyword"], "score": kw["score"]} for kw in processed_keywords],
115
- "metrics": evaluate_keywords(processed_keywords, len(text))
116
  }
117
 
118
  # Gradio интерфейс
@@ -120,8 +159,8 @@ iface = gr.Interface(
120
  fn=extract_keywords_interface,
121
  inputs=[
122
  gr.Textbox(label="Введите текст", lines=10, placeholder="Введите текст для извлечения ключевых слов"),
123
- gr.Slider(5, 50, value=15, step=1, label="Количество ключевых слов (top_n)"),
124
- gr.Slider(0.0, 1.0, value=0.4, step=0.1, label="Разнообразие ключевых слов (diversity)"),
125
  gr.Slider(1, 3, value=3, step=1, label="Максимальная длина фраз (n-gram)")
126
  ],
127
  outputs="json",
 
5
  import re
6
 
7
  # Инициализация мультиязычной модели
8
+ # (Можно заменить на другую модель, если нужна ещё более быстрая или иная точность)
9
  model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')
10
  kw_model = KeyBERT(model)
11
 
 
20
  # Добавьте другие языки, если необходимо
21
  }
22
 
23
+ def detect_language(text: str) -> str:
24
  """
25
+ Определение языка текста с помощью langdetect.
26
+ Если язык определить не удалось, возвращаем 'en' (английский) по умолчанию.
27
  """
28
  try:
29
  return detect(text)
30
  except:
31
+ return "en"
32
 
33
+ def clean_text(text: str, lang: str) -> str:
34
  """
35
+ Удаление из текста стоп-слов на основе определённого языка.
36
  """
37
  stop_words = STOP_WORDS.get(lang, [])
38
  words = text.split()
39
  cleaned_text = " ".join([word for word in words if word.lower() not in stop_words])
40
  return cleaned_text
41
 
42
+ def segment_text(text: str, max_segment_length: int = 2000) -> list:
43
  """
44
+ Разделение текста на сегменты по предложениям, чтобы KeyBERT
45
+ мог обрабатывать длинные тексты по частям.
46
+ Увеличили max_segment_length до 2000 (ранее было 1000),
47
+ чтобы уменьшить общее число сегментов и улучшить скорость.
48
  """
49
  sentences = re.split(r'(?<=[.!?]) +', text)
50
  segments = []
 
56
  else:
57
  segments.append(current_segment.strip())
58
  current_segment = sentence
59
+
60
  if current_segment:
61
  segments.append(current_segment.strip())
62
 
63
  return segments
64
 
65
+ def postprocess_keywords(keywords: list, min_score: float = 0.5) -> list:
66
  """
67
+ Постобработка ключевых слов:
68
+ - убираем дубли и слишком низкий score,
69
+ - НЕ исключаем однословные фразы (раньше исключали),
70
+ - при желании можно смягчить логику удаления "вложенных" фраз.
71
  """
72
  unique_keywords = []
73
  seen = set()
74
+
75
+ # Сортируем по длине фразы (от самых длинных к коротким),
76
+ # чтобы при проверке "вложенности" не выкидывать большие фразы первыми.
77
  for kw in sorted(keywords, key=lambda x: len(x[0]), reverse=True):
78
+ phrase, score = kw[0], kw[1]
79
+ if phrase not in seen and score >= min_score:
80
+ # Если хотим менее агрессивно исключать частичные совпадения,
81
+ # можно убрать проверку "phrase in u_kw".
82
+ if not any(phrase in u_kw["keyword"] for u_kw in unique_keywords):
83
+ unique_keywords.append({"keyword": phrase, "score": score})
84
+ seen.add(phrase)
85
+
86
+ # Раньше здесь отсеивали короткие фразы:
87
+ # filtered_keywords = [kw for kw in unique_keywords if len(kw["keyword"].split()) > 1]
88
+ # Теперь разрешаем и однословные:
89
+ filtered_keywords = unique_keywords
90
+
91
  return filtered_keywords
92
 
93
+ def evaluate_keywords(keywords: list, text_length: int) -> dict:
94
  """
95
+ Оценка качества ключевых слов:
96
+ - average_score: средний рейтинг ключевых слов
97
+ - coverage: кол-во ключевых слов на 100 символов
98
  """
99
+ if not keywords:
100
+ return {"average_score": 0, "coverage": 0}
101
  avg_score = sum([kw["score"] for kw in keywords]) / len(keywords)
102
+ coverage = len(keywords) / (text_length / 100.0)
103
  return {"average_score": avg_score, "coverage": coverage}
104
 
105
+ def extract_keywords_interface(text: str,
106
+ top_n: int = 20,
107
+ diversity: float = 0.3,
108
+ max_ngram: int = 3) -> dict:
109
  """
110
  Извлечение ключевых слов через Gradio интерфейс.
111
+ Изменения по умолчанию:
112
+ - top_n=20 (было 15), чтобы извлекать больше ключей
113
+ - diversity=0.3 (было 0.4), чтобы не "выбрасывать" слишком похожие варианты
114
+ - max_segment_length внутри segment_text увеличен до 2000
115
+ - min_score=0.5 внутри postprocess_keywords
116
  """
117
  if not text or not text.strip():
118
+ return {
119
+ "keywords": [],
120
+ "metrics": {
121
+ "average_score": 0,
122
+ "coverage": 0
123
+ }
124
+ }
125
+
126
+ # 1. Определяем язык
127
  lang = detect_language(text)
128
+
129
+ # 2. Очищаем текст от базовых стоп-слов
130
  cleaned_text = clean_text(text, lang)
 
 
131
 
132
+ # 3. Сегментируем текст на большие блоки
133
+ segments = segment_text(cleaned_text, max_segment_length=2000)
134
+
135
+ # 4. Извлекаем ключи из каждого сегмента
136
+ all_keywords = []
137
  for segment in segments:
138
  keywords = kw_model.extract_keywords(
139
  segment,
 
143
  )
144
  all_keywords.extend(keywords)
145
 
146
+ # 5. Постобработка ключевых слов (снижение min_score и др.)
147
+ processed_keywords = postprocess_keywords(all_keywords, min_score=0.5)
148
+
149
+ # 6. Метрики: средний score + coverage
150
+ metrics = evaluate_keywords(processed_keywords, len(text))
151
 
 
152
  return {
153
  "keywords": [{"keyword": kw["keyword"], "score": kw["score"]} for kw in processed_keywords],
154
+ "metrics": metrics
155
  }
156
 
157
  # Gradio интерфейс
 
159
  fn=extract_keywords_interface,
160
  inputs=[
161
  gr.Textbox(label="Введите текст", lines=10, placeholder="Введите текст для извлечения ключевых слов"),
162
+ gr.Slider(5, 50, value=20, step=1, label="Количество ключевых слов (top_n)"),
163
+ gr.Slider(0.0, 1.0, value=0.3, step=0.1, label="Разнообразие ключевых слов (diversity)"),
164
  gr.Slider(1, 3, value=3, step=1, label="Максимальная длина фраз (n-gram)")
165
  ],
166
  outputs="json",