Wplotnikow commited on
Commit
2160154
·
verified ·
1 Parent(s): d0e25a2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +21 -30
app.py CHANGED
@@ -7,11 +7,9 @@ import torch
7
  from transformers import T5ForConditionalGeneration, T5Tokenizer
8
 
9
  def is_header(txt):
10
- # Абсолютно короткая фраза без знака препинания и вся в верхнем регистре — заголовок
11
  if not txt or len(txt) < 35:
12
  if txt == txt.upper() and not txt.endswith(('.', ':', '?', '!')):
13
  return True
14
- # Также часто заголовок — просто пара слов с заглавных (мало слов и нет в конце точки):
15
  if txt.istitle() and len(txt.split()) < 6 and not txt.endswith(('.', ':', '?', '!')):
16
  return True
17
  return False
@@ -22,7 +20,7 @@ def get_blocks_from_docx():
22
  return [], []
23
  doc = Document(docx_list[0])
24
  blocks = []
25
- non_header_blocks = []
26
  for p in doc.paragraphs:
27
  txt = p.text.strip()
28
  if (
@@ -32,35 +30,31 @@ def get_blocks_from_docx():
32
  ):
33
  blocks.append(txt)
34
  if not is_header(txt) and len(txt) > 25:
35
- non_header_blocks.append(txt)
36
- # Таблицы
37
  for table in doc.tables:
38
  for row in table.rows:
39
  row_text = " | ".join(cell.text.strip() for cell in row.cells if cell.text.strip())
40
  if row_text and len(row_text.split()) > 3 and len(row_text) > 25:
41
  blocks.append(row_text)
42
  if not is_header(row_text):
43
- non_header_blocks.append(row_text)
44
- # Убираем дубли
45
- seen = set()
46
- blocks_clean = []
47
- non_hdr_clean = []
48
  for b in blocks:
49
  if b not in seen:
50
  blocks_clean.append(b)
51
  seen.add(b)
52
- seen = set()
53
- for b in non_header_blocks:
54
  if b not in seen:
55
- non_hdr_clean.append(b)
56
  seen.add(b)
57
- return blocks_clean, non_hdr_clean
58
 
59
  blocks, normal_blocks = get_blocks_from_docx()
60
  if not blocks or not normal_blocks:
61
- # Если ничего не нашли фэйк заглушка
62
- blocks = ["База знаний пуста: проверьте содержание и формат вашего .docx!"]
63
- normal_blocks = ["База знаний пуста: проверьте содержание и формат вашего .docx!"]
64
 
65
  vectorizer = TfidfVectorizer(lowercase=True).fit(blocks)
66
  matrix = vectorizer.transform(blocks)
@@ -85,41 +79,38 @@ def ask_chatbot(question):
85
  question = question.strip()
86
  if not question:
87
  return "Пожалуйста, введите вопрос."
88
- if not normal_blocks or normal_blocks == ["База знаний пуста: проверьте содержание и формат вашего .docx!"]:
89
  return "Ошибка: база знаний пуста. Проверьте .docx и перезапустите Space."
90
 
91
  user_vec = vectorizer.transform([question.lower()])
92
  sims = cosine_similarity(user_vec, matrix)
93
  n_blocks = min(3, len(blocks))
94
  if n_blocks == 0:
95
- return "База знаний пуста: загрузите методичку с осмысленными абзацами!"
96
- # Получаем индексы лучших блоков среди ВСЕХ
97
- top_idxs = list(reversed(sims.argsort()[-n_blocks:]))
98
- # Для генерации контекста используем все блоки, но...
99
  context_blocks = []
100
  for rank, idx in enumerate(top_idxs):
101
- if 0 <= idx < len(blocks):
 
102
  context_blocks.append(blocks[idx])
103
  context = " ".join(context_blocks)
104
- # ...для финального ответа ищем САМЫЙ релевантный не-заголовок (абзац)!
105
- # (обычно первый релевантен)
106
  best_normal_block = ""
107
  max_sim = -1
108
- for idx, nb in enumerate(normal_blocks):
109
  v_nb = vectorizer.transform([nb.lower()])
110
  sim = cosine_similarity(user_vec, v_nb)[0]
111
  if sim > max_sim:
112
  max_sim = sim
113
  best_normal_block = nb
114
- # Если совсем всё плохо — fallback на обычный context
115
  if not best_normal_block:
116
  best_normal_block = context_blocks if context_blocks else ""
117
- # Генерируем развернутый ответ с подложкой из максимального контекста
118
  answer = rut5_answer(question, context)
119
- # Если слишком кратко — дублируем релевантный фрагмент (абзац)
120
  if len(answer.strip().split()) < 8 or answer.count('.') < 2:
121
  answer += "\n\n" + best_normal_block
122
- # Финальный ответ — если сгенерированный ответ случайно "превратился" в заголовок, заменяем его на абзац!
123
  if is_header(answer):
124
  answer = best_normal_block
125
  return answer
 
7
  from transformers import T5ForConditionalGeneration, T5Tokenizer
8
 
9
  def is_header(txt):
 
10
  if not txt or len(txt) < 35:
11
  if txt == txt.upper() and not txt.endswith(('.', ':', '?', '!')):
12
  return True
 
13
  if txt.istitle() and len(txt.split()) < 6 and not txt.endswith(('.', ':', '?', '!')):
14
  return True
15
  return False
 
20
  return [], []
21
  doc = Document(docx_list[0])
22
  blocks = []
23
+ normal_blocks = []
24
  for p in doc.paragraphs:
25
  txt = p.text.strip()
26
  if (
 
30
  ):
31
  blocks.append(txt)
32
  if not is_header(txt) and len(txt) > 25:
33
+ normal_blocks.append(txt)
 
34
  for table in doc.tables:
35
  for row in table.rows:
36
  row_text = " | ".join(cell.text.strip() for cell in row.cells if cell.text.strip())
37
  if row_text and len(row_text.split()) > 3 and len(row_text) > 25:
38
  blocks.append(row_text)
39
  if not is_header(row_text):
40
+ normal_blocks.append(row_text)
41
+ # remove duplicates
42
+ seen = set(); blocks_clean = []
 
 
43
  for b in blocks:
44
  if b not in seen:
45
  blocks_clean.append(b)
46
  seen.add(b)
47
+ seen = set(); normal_blocks_clean = []
48
+ for b in normal_blocks:
49
  if b not in seen:
50
+ normal_blocks_clean.append(b)
51
  seen.add(b)
52
+ return blocks_clean, normal_blocks_clean
53
 
54
  blocks, normal_blocks = get_blocks_from_docx()
55
  if not blocks or not normal_blocks:
56
+ blocks = ["База знаний пуста: проверьте содержимое и структуру вашего .docx!"]
57
+ normal_blocks = ["База знаний пуста: проверьте содержимое и структуру вашего .docx!"]
 
58
 
59
  vectorizer = TfidfVectorizer(lowercase=True).fit(blocks)
60
  matrix = vectorizer.transform(blocks)
 
79
  question = question.strip()
80
  if not question:
81
  return "Пожалуйста, введите вопрос."
82
+ if not normal_blocks or normal_blocks == ["База знаний пуста: проверьте содержимое и структуру вашего .docx!"]:
83
  return "Ошибка: база знаний пуста. Проверьте .docx и перезапустите Space."
84
 
85
  user_vec = vectorizer.transform([question.lower()])
86
  sims = cosine_similarity(user_vec, matrix)
87
  n_blocks = min(3, len(blocks))
88
  if n_blocks == 0:
89
+ return "Ошибка: база знаний отсутствует или пуста."
90
+ # Корректная обработка индексов!
91
+ sorted_idxs = sims.argsort()
92
+ top_idxs = list(map(int, sorted_idxs[-n_blocks:][::-1]))
93
  context_blocks = []
94
  for rank, idx in enumerate(top_idxs):
95
+ idx = int(idx)
96
+ if 0 <= idx < len(blocks): # строгое попадание в диапазон
97
  context_blocks.append(blocks[idx])
98
  context = " ".join(context_blocks)
99
+ # Ответ только из абзацев, не заголовков!
100
+ # Ищем наиболее релевантный "нормальный" блок
101
  best_normal_block = ""
102
  max_sim = -1
103
+ for nb in normal_blocks:
104
  v_nb = vectorizer.transform([nb.lower()])
105
  sim = cosine_similarity(user_vec, v_nb)[0]
106
  if sim > max_sim:
107
  max_sim = sim
108
  best_normal_block = nb
 
109
  if not best_normal_block:
110
  best_normal_block = context_blocks if context_blocks else ""
 
111
  answer = rut5_answer(question, context)
 
112
  if len(answer.strip().split()) < 8 or answer.count('.') < 2:
113
  answer += "\n\n" + best_normal_block
 
114
  if is_header(answer):
115
  answer = best_normal_block
116
  return answer