antimoda1 commited on
Commit
e9c73b1
·
1 Parent(s): ad6245d
Files changed (1) hide show
  1. app.py +79 -93
app.py CHANGED
@@ -97,7 +97,7 @@ def perform_search(query, top_k):
97
  """Этап 1: Поиск и возврат результатов"""
98
 
99
  if not query:
100
- return None, None, [], [], "Введите вопрос для поиска"
101
 
102
  # Выполняем поиск
103
  scores = retrieval.bm25_search(query)
@@ -111,7 +111,7 @@ def perform_search(query, top_k):
111
 
112
  status = f"Найдено {len(scores)} чанков. Top-{top_k} выбраны."
113
 
114
- return None, scores, chunk_ids, top_k_indices, status
115
 
116
  def filter_chunks_by_documents(top_k_indices, all_scores, selected_docs):
117
  """Фильтрует чанки по выбранным документам"""
@@ -136,7 +136,75 @@ def filter_chunks_by_documents(top_k_indices, all_scores, selected_docs):
136
 
137
  return filtered_indices
138
 
139
- def format_retrieval_results(filtered_indices, all_scores, top_k_results):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
  """Форматирует результаты retrieval для отображения в текстовом поле
141
 
142
  Алгоритм:
@@ -217,62 +285,7 @@ def format_retrieval_results(filtered_indices, all_scores, top_k_results):
217
  if added_count > top_k_results or iteration_added == 0:
218
  break
219
 
220
- # Форматируем результаты для вывода
221
- chunks_with_info = []
222
- for idx in selected:
223
- if idx >= len(retrieval.docs_metadata) or idx >= len(retrieval.chunks):
224
- continue
225
-
226
- doc_id = retrieval.docs_metadata[idx]
227
- doc_name = retrieval.docs_names[doc_id] if doc_id < len(retrieval.docs_names) else "Неизвестный документ"
228
-
229
- chunks_with_info.append({
230
- 'index': idx,
231
- 'doc_name': doc_name,
232
- 'doc_id': doc_id,
233
- 'chunk_text': retrieval.chunks[idx]
234
- })
235
-
236
- if not chunks_with_info:
237
- return "Нет валидных чанков"
238
-
239
- # Группируем чанки по документам
240
- docs_chunks = {}
241
- for chunk_info in chunks_with_info:
242
- doc_name = chunk_info['doc_name']
243
- if doc_name not in docs_chunks:
244
- docs_chunks[doc_name] = []
245
- docs_chunks[doc_name].append(chunk_info['index'])
246
-
247
- # Форматируем вывод
248
- result_lines = []
249
- for doc_name in sorted(docs_chunks.keys()):
250
- chunk_indices = sorted(docs_chunks[doc_name])
251
-
252
- # Группируем подряд идущие индексы
253
- groups = []
254
- current_group = [chunk_indices[0]]
255
-
256
- for i in range(1, len(chunk_indices)):
257
- if chunk_indices[i] == chunk_indices[i-1] + 1:
258
- current_group.append(chunk_indices[i])
259
- else:
260
- groups.append(current_group)
261
- current_group = [chunk_indices[i]]
262
- groups.append(current_group)
263
-
264
- # Собираем текст для каждой группы
265
- group_texts = []
266
- for group in groups:
267
- sentences = [retrieval.chunks[idx] for idx in group]
268
- group_texts.append(", ".join(sentences))
269
-
270
- # Выводим документ с многоточием между группами
271
- doc_output = f"Документ {doc_name}:\n" + " ... ".join(group_texts)
272
- result_lines.append(doc_output)
273
- result_lines.append("") # Пустая строка между документами
274
-
275
- return "\n".join(result_lines)
276
 
277
  def ask_llm(query, filtered_indices_state):
278
  """Этап 2: Отправка отфильтрованных чанков в LLM с потоковой выдачей"""
@@ -287,40 +300,13 @@ def ask_llm(query, filtered_indices_state):
287
  yield "Нет выбранных чанков для отправки в LLM"
288
  return
289
 
290
- # Сортируем чанки сначала по документу, потом по chunk_id
291
- chunks_with_doc = []
292
- for idx in chunks_to_use:
293
- if idx >= len(retrieval.docs_metadata):
294
- continue
295
- doc_id = retrieval.docs_metadata[idx]
296
- doc_name = retrieval.docs_names[doc_id]
297
- chunks_with_doc.append((doc_name, idx, doc_id))
298
 
299
- if not chunks_with_doc:
300
  yield "Нет валидных чанков для отправки"
301
  return
302
 
303
- # Сортируем: сначала по имени документа, потом по chunk_id
304
- chunks_with_doc.sort(key=lambda x: (x[0], x[1]))
305
-
306
- # Собираем текст выбранных чанков в правильном порядке
307
- context_parts = []
308
- current_doc = None
309
-
310
- for doc_name, idx, doc_id in chunks_with_doc:
311
- # Добавляем разделитель между документами
312
- if current_doc != doc_name:
313
- if current_doc is not None:
314
- context_parts.append("\n---\n")
315
- context_parts.append(f"=== Документ: {doc_name} ===\n")
316
- current_doc = doc_name
317
-
318
- # Добавляем чанк с его номером
319
- chunk_text = retrieval.chunks[idx]
320
- context_parts.append(f"[Чанк {idx}]\n{chunk_text}\n")
321
-
322
- context = "".join(context_parts)
323
-
324
  # Формируем промпт и отправляем в LLM
325
  prompt = wrap_prompt(context, query)
326
 
@@ -417,14 +403,14 @@ with gr.Blocks(title="RAG Application", theme=gr.themes.Soft()) as iface:
417
  search_btn.click(
418
  fn=perform_search,
419
  inputs=[search_query_input, top_k_slider],
420
- outputs=[None, all_scores_state, all_chunk_ids_state, top_k_indices_state, search_status]
421
  ).then(
422
  fn=filter_chunks_by_documents,
423
  inputs=[top_k_indices_state, all_scores_state, docs_after],
424
  outputs=[filtered_indices_state]
425
  ).then(
426
  fn=format_retrieval_results,
427
- inputs=[filtered_indices_state, all_scores_state, display_k_slider],
428
  outputs=[retrieval_results]
429
  )
430
 
@@ -435,14 +421,14 @@ with gr.Blocks(title="RAG Application", theme=gr.themes.Soft()) as iface:
435
  outputs=[filtered_indices_state]
436
  ).then(
437
  fn=format_retrieval_results,
438
- inputs=[filtered_indices_state, all_scores_state, display_k_slider],
439
  outputs=[retrieval_results]
440
  )
441
 
442
  # Обработчик изменения слайдера отображения
443
  display_k_slider.change(
444
  fn=format_retrieval_results,
445
- inputs=[filtered_indices_state, all_scores_state, display_k_slider],
446
  outputs=[retrieval_results]
447
  )
448
 
 
97
  """Этап 1: Поиск и возврат результатов"""
98
 
99
  if not query:
100
+ return None, [], [], "Введите вопрос для поиска"
101
 
102
  # Выполняем поиск
103
  scores = retrieval.bm25_search(query)
 
111
 
112
  status = f"Найдено {len(scores)} чанков. Top-{top_k} выбраны."
113
 
114
+ return scores, chunk_ids, top_k_indices, status
115
 
116
  def filter_chunks_by_documents(top_k_indices, all_scores, selected_docs):
117
  """Фильтрует чанки по выбранным документам"""
 
136
 
137
  return filtered_indices
138
 
139
+ def format_selected_chunks(selected_indices):
140
+ """Форматирует выбранные чанки в единый текст для вывода и LLM
141
+
142
+ Возвращает текст в формате:
143
+ Документ {название}:
144
+ Предложение1 Предложение2 ... Предложение5 Предложение6
145
+ """
146
+ if not selected_indices:
147
+ return ""
148
+
149
+ # Форматируем результаты для вывода
150
+ chunks_with_info = []
151
+ for idx in selected_indices:
152
+ if idx >= len(retrieval.docs_metadata) or idx >= len(retrieval.chunks):
153
+ continue
154
+
155
+ doc_id = retrieval.docs_metadata[idx]
156
+ doc_name = retrieval.docs_names[doc_id] if doc_id < len(retrieval.docs_names) else "Неизвестный документ"
157
+
158
+ chunks_with_info.append({
159
+ 'index': idx,
160
+ 'doc_name': doc_name,
161
+ 'doc_id': doc_id,
162
+ 'chunk_text': retrieval.chunks[idx]
163
+ })
164
+
165
+ if not chunks_with_info:
166
+ return "Нет валидных чанков"
167
+
168
+ # Группируем чанки по документам
169
+ docs_chunks = {}
170
+ for chunk_info in chunks_with_info:
171
+ doc_name = chunk_info['doc_name']
172
+ if doc_name not in docs_chunks:
173
+ docs_chunks[doc_name] = []
174
+ docs_chunks[doc_name].append(chunk_info['index'])
175
+
176
+ # Форматируем вывод
177
+ result_lines = []
178
+ for doc_name in sorted(docs_chunks.keys()):
179
+ chunk_indices = sorted(docs_chunks[doc_name])
180
+
181
+ # Группируем подряд идущие индексы
182
+ groups = []
183
+ current_group = [chunk_indices[0]]
184
+
185
+ for i in range(1, len(chunk_indices)):
186
+ if chunk_indices[i] == chunk_indices[i-1] + 1:
187
+ current_group.append(chunk_indices[i])
188
+ else:
189
+ groups.append(current_group)
190
+ current_group = [chunk_indices[i]]
191
+ groups.append(current_group)
192
+
193
+ # Собираем текст для каждой группы БЕЗ запятых
194
+ group_texts = []
195
+ for group in groups:
196
+ sentences = [retrieval.chunks[idx] for idx in group]
197
+ group_texts.append(" ".join(sentences))
198
+
199
+ # Выводим документ с многоточием между группами
200
+ doc_output = f"Документ {doc_name}:\n" + " ... ".join(group_texts)
201
+ result_lines.append(doc_output)
202
+ result_lines.append("") # Пустая строка между документами
203
+
204
+ return "\n".join(result_lines)
205
+
206
+
207
+ def format_retrieval_results(filtered_indices, top_k_results):
208
  """Форматирует результаты retrieval для отображения в текстовом поле
209
 
210
  Алгоритм:
 
285
  if added_count > top_k_results or iteration_added == 0:
286
  break
287
 
288
+ return format_selected_chunks(list(selected))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
289
 
290
  def ask_llm(query, filtered_indices_state):
291
  """Этап 2: Отправка отфильтрованных чанков в LLM с потоковой выдачей"""
 
300
  yield "Нет выбранных чанков для отправки в LLM"
301
  return
302
 
303
+ # Форматируем контекст используя ту же функцию, что и в интерфейсе
304
+ context = format_selected_chunks(list(chunks_to_use))
 
 
 
 
 
 
305
 
306
+ if not context or context == "Нет валидных чанков":
307
  yield "Нет валидных чанков для отправки"
308
  return
309
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
310
  # Формируем промпт и отправляем в LLM
311
  prompt = wrap_prompt(context, query)
312
 
 
403
  search_btn.click(
404
  fn=perform_search,
405
  inputs=[search_query_input, top_k_slider],
406
+ outputs=[all_scores_state, all_chunk_ids_state, top_k_indices_state, search_status]
407
  ).then(
408
  fn=filter_chunks_by_documents,
409
  inputs=[top_k_indices_state, all_scores_state, docs_after],
410
  outputs=[filtered_indices_state]
411
  ).then(
412
  fn=format_retrieval_results,
413
+ inputs=[filtered_indices_state, display_k_slider],
414
  outputs=[retrieval_results]
415
  )
416
 
 
421
  outputs=[filtered_indices_state]
422
  ).then(
423
  fn=format_retrieval_results,
424
+ inputs=[filtered_indices_state, display_k_slider],
425
  outputs=[retrieval_results]
426
  )
427
 
428
  # Обработчик изменения слайдера отображения
429
  display_k_slider.change(
430
  fn=format_retrieval_results,
431
+ inputs=[filtered_indices_state, display_k_slider],
432
  outputs=[retrieval_results]
433
  )
434