MrSimple07 commited on
Commit
57e4dbd
·
1 Parent(s): f48820b

simplest version

Browse files
Files changed (2) hide show
  1. documents_prep.py +127 -94
  2. utils.py +103 -8
documents_prep.py CHANGED
@@ -9,66 +9,56 @@ from my_logging import log_message
9
  # Configuration
10
  CHUNK_SIZE = 1500
11
  CHUNK_OVERLAP = 256
12
-
13
  def chunk_text_documents(documents):
 
14
  text_splitter = SentenceSplitter(
15
  chunk_size=CHUNK_SIZE,
16
- chunk_overlap=CHUNK_OVERLAP
17
  )
18
 
 
19
  chunked = []
 
20
  for doc in documents:
 
 
 
 
 
 
 
21
  chunks = text_splitter.get_nodes_from_documents([doc])
22
  for i, chunk in enumerate(chunks):
23
  chunk.metadata.update({
24
  'chunk_id': i,
25
  'total_chunks': len(chunks),
26
- 'chunk_size': len(chunk.text) # Add chunk size
 
27
  })
28
  chunked.append(chunk)
29
 
30
- # Log statistics
31
  if chunked:
32
  avg_size = sum(len(c.text) for c in chunked) / len(chunked)
33
- min_size = min(len(c.text) for c in chunked)
34
- max_size = max(len(c.text) for c in chunked)
35
- log_message(f"✓ Text: {len(documents)} docs → {len(chunked)} chunks")
36
- log_message(f" Size stats: avg={avg_size:.0f}, min={min_size}, max={max_size} chars")
37
 
38
  return chunked
39
 
40
-
41
- def normalize_doc_id(doc_id):
42
- if not doc_id or doc_id == 'unknown':
43
- return doc_id
44
-
45
- doc_id = str(doc_id).strip()
46
-
47
- # Normalize spacing: "ГОСТ Р" variations
48
- import re
49
- doc_id = re.sub(r'ГОСТ\s*Р', 'ГОСТ Р', doc_id, flags=re.IGNORECASE)
50
- doc_id = re.sub(r'НП\s*-', 'НП-', doc_id, flags=re.IGNORECASE)
51
-
52
- return doc_id
53
-
54
-
55
- def chunk_table_by_rows(table_data, doc_id, max_rows=5):
56
  headers = table_data.get('headers', [])
57
  rows = table_data.get('data', [])
58
  table_num = table_data.get('table_number', 'unknown')
59
  table_title = table_data.get('table_title', '')
60
  section = table_data.get('section', '')
61
 
62
- doc_id = normalize_doc_id(doc_id)
63
-
64
  table_num_clean = str(table_num).strip()
65
 
 
66
  import re
67
  if 'приложени' in section.lower():
68
  appendix_match = re.search(r'приложени[еия]\s*(\d+|[а-яА-Я])', section.lower())
69
  if appendix_match:
70
- appendix_num = appendix_match.group(1).upper()
71
- table_identifier = f"{table_num_clean} Приложение {appendix_num}"
72
  else:
73
  table_identifier = table_num_clean
74
  else:
@@ -77,67 +67,99 @@ def chunk_table_by_rows(table_data, doc_id, max_rows=5):
77
  if not rows:
78
  return []
79
 
80
- log_message(f" 📊 Processing: {doc_id} - {table_identifier} ({len(rows)} rows)")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
 
82
- if len(rows) <= max_rows:
83
- content = format_table_content(table_data, headers, rows, doc_id, table_identifier)
84
- chunk_size = len(content)
 
 
 
 
 
 
 
85
 
86
- metadata = {
87
- 'type': 'table',
88
- 'document_id': doc_id,
89
- 'table_number': table_num_clean,
90
- 'table_identifier': table_identifier,
91
- 'table_title': table_title,
92
- 'section': section,
93
- 'total_rows': len(rows),
94
- 'chunk_size': chunk_size,
95
- 'is_complete_table': True
96
- }
97
 
98
- log_message(f" Chunk: 1/1, {chunk_size} chars, doc={doc_id}, table={table_identifier}")
 
 
 
 
99
 
100
- return [Document(text=content, metadata=metadata)]
 
101
 
102
- chunks = []
103
- overlap = 2
 
104
 
105
- for i in range(0, len(rows), max_rows - overlap):
106
- chunk_rows = rows[i:min(i+max_rows, len(rows))]
107
- chunk_num = i // (max_rows - overlap)
108
-
109
- content = format_table_content(
110
- table_data,
111
- headers,
112
- chunk_rows,
113
- doc_id,
114
- table_identifier,
115
- chunk_info=f"Строки {i+1}-{i+len(chunk_rows)} из {len(rows)}"
116
- )
117
 
118
- chunk_size = len(content)
 
 
 
 
 
 
 
 
 
119
 
120
  metadata = {
121
  'type': 'table',
122
  'document_id': doc_id,
 
123
  'table_number': table_num_clean,
124
  'table_identifier': table_identifier,
125
  'table_title': table_title,
126
  'section': section,
127
- 'chunk_id': chunk_num,
128
- 'row_start': i,
129
- 'row_end': i + len(chunk_rows),
130
- 'total_rows': len(rows),
131
- 'chunk_size': chunk_size,
132
- 'total_chunks': (len(rows) + max_rows - overlap - 1) // (max_rows - overlap),
133
- 'is_complete_table': False
134
  }
135
 
136
- log_message(f" Chunk: {chunk_num+1}, rows {i}-{i+len(chunk_rows)}, {chunk_size} chars")
137
 
138
- chunks.append(Document(text=content, metadata=metadata))
 
 
 
139
 
140
- return chunks
 
 
 
 
 
 
 
141
 
142
 
143
  def format_table_content(table_data, headers, rows, doc_id, table_identifier, chunk_info=""):
@@ -383,13 +405,16 @@ def extract_sections_from_json(json_path):
383
 
384
 
385
  def load_table_documents(repo_id, hf_token, table_dir):
 
386
  log_message("Loading tables...")
387
 
388
  files = list_repo_files(repo_id=repo_id, repo_type="dataset", token=hf_token)
389
  table_files = [f for f in files if f.startswith(table_dir) and f.endswith('.json')]
390
 
 
 
391
  all_chunks = []
392
- doc_table_count = {}
393
 
394
  for file_path in table_files:
395
  try:
@@ -403,39 +428,40 @@ def load_table_documents(repo_id, hf_token, table_dir):
403
  with open(local_path, 'r', encoding='utf-8') as f:
404
  data = json.load(f)
405
 
406
- file_doc_id = normalize_doc_id(data.get('document_id', data.get('document', 'unknown')))
407
 
408
  for sheet in data.get('sheets', []):
409
- sheet_doc_id = normalize_doc_id(sheet.get('document_id', sheet.get('document', file_doc_id)))
 
 
 
 
410
 
411
  chunks = chunk_table_by_rows(sheet, sheet_doc_id)
412
  all_chunks.extend(chunks)
413
-
414
- if sheet_doc_id not in doc_table_count:
415
- doc_table_count[sheet_doc_id] = 0
416
- doc_table_count[sheet_doc_id] += len(chunks)
417
 
418
  except Exception as e:
419
  log_message(f"Error loading {file_path}: {e}")
420
 
421
- log_message(f"\n{'='*60}")
422
- log_message("TABLE LOADING SUMMARY:")
423
- for doc_id, count in sorted(doc_table_count.items()):
424
- log_message(f" {doc_id}: {count} table chunks")
425
- log_message(f"TOTAL: {len(all_chunks)} table chunks")
426
- log_message(f"{'='*60}\n")
427
 
 
428
  return all_chunks
429
 
430
-
431
  def load_image_documents(repo_id, hf_token, image_dir):
432
- """Load image descriptions"""
433
  log_message("Loading images...")
434
 
435
  files = list_repo_files(repo_id=repo_id, repo_type="dataset", token=hf_token)
436
  csv_files = [f for f in files if f.startswith(image_dir) and f.endswith('.csv')]
437
 
438
  documents = []
 
 
439
  for file_path in csv_files:
440
  try:
441
  local_path = hf_hub_download(
@@ -448,22 +474,28 @@ def load_image_documents(repo_id, hf_token, image_dir):
448
  df = pd.read_csv(local_path)
449
 
450
  for _, row in df.iterrows():
451
- content = f"Документ: {row.get('Обозначение документа', 'unknown')}\n"
452
- content += f"Рисунок: {row.get('№ Изображения', 'unknown')}\n"
 
 
 
 
 
 
 
 
453
  content += f"Название: {row.get('Название изображения', '')}\n"
454
  content += f"Описание: {row.get('Описание изображение', '')}\n"
455
- content += f"Раздел: {row.get('Раздел документа', '')}\n"
456
-
457
- chunk_size = len(content)
458
 
459
  documents.append(Document(
460
  text=content,
461
  metadata={
462
  'type': 'image',
463
- 'document_id': str(row.get('Обозначение документа', 'unknown')),
464
- 'image_number': str(row.get('№ Изображения', 'unknown')),
 
465
  'section': str(row.get('Раздел документа', '')),
466
- 'chunk_size': chunk_size
467
  }
468
  ))
469
  except Exception as e:
@@ -471,11 +503,12 @@ def load_image_documents(repo_id, hf_token, image_dir):
471
 
472
  if documents:
473
  avg_size = sum(d.metadata['chunk_size'] for d in documents) / len(documents)
474
- log_message(f"✓ Loaded {len(documents)} images (avg size: {avg_size:.0f} chars)")
475
 
476
  return documents
477
 
478
 
 
479
  def load_all_documents(repo_id, hf_token, json_dir, table_dir, image_dir):
480
  """Main loader - combines all document types"""
481
  log_message("="*60)
 
9
  # Configuration
10
  CHUNK_SIZE = 1500
11
  CHUNK_OVERLAP = 256
 
12
  def chunk_text_documents(documents):
13
+ """Chunk with deduplication"""
14
  text_splitter = SentenceSplitter(
15
  chunk_size=CHUNK_SIZE,
16
+ chunk_overlap=300 # Increased overlap
17
  )
18
 
19
+ seen_texts = set()
20
  chunked = []
21
+
22
  for doc in documents:
23
+ # Skip duplicates or too-short content
24
+ text_normalized = doc.text.strip()
25
+ if len(text_normalized) < 50 or text_normalized in seen_texts:
26
+ continue
27
+
28
+ seen_texts.add(text_normalized)
29
+
30
  chunks = text_splitter.get_nodes_from_documents([doc])
31
  for i, chunk in enumerate(chunks):
32
  chunk.metadata.update({
33
  'chunk_id': i,
34
  'total_chunks': len(chunks),
35
+ 'chunk_size': len(chunk.text),
36
+ 'document_group': normalize_doc_id(doc.metadata.get('document_id', 'unknown'))
37
  })
38
  chunked.append(chunk)
39
 
 
40
  if chunked:
41
  avg_size = sum(len(c.text) for c in chunked) / len(chunked)
42
+ log_message(f"✓ Text: {len(documents)} docs → {len(chunked)} chunks (avg: {avg_size:.0f} chars)")
 
 
 
43
 
44
  return chunked
45
 
46
+ def chunk_table_by_rows(table_data, doc_id, max_chars=2000):
47
+ """Chunk tables by content size, not fixed rows"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  headers = table_data.get('headers', [])
49
  rows = table_data.get('data', [])
50
  table_num = table_data.get('table_number', 'unknown')
51
  table_title = table_data.get('table_title', '')
52
  section = table_data.get('section', '')
53
 
 
 
54
  table_num_clean = str(table_num).strip()
55
 
56
+ # Create unique identifier
57
  import re
58
  if 'приложени' in section.lower():
59
  appendix_match = re.search(r'приложени[еия]\s*(\d+|[а-яА-Я])', section.lower())
60
  if appendix_match:
61
+ table_identifier = f"{table_num_clean} (Приложение {appendix_match.group(1).upper()})"
 
62
  else:
63
  table_identifier = table_num_clean
64
  else:
 
67
  if not rows:
68
  return []
69
 
70
+ # Estimate base metadata size
71
+ base_content = f"Документ: {doc_id}\nТаблица: {table_identifier}\n"
72
+ if table_title:
73
+ base_content += f"Название: {table_title}\n"
74
+ if section:
75
+ base_content += f"Раздел: {section}\n"
76
+
77
+ header_content = ""
78
+ if headers:
79
+ header_content = "Столбцы: " + " | ".join(str(h) for h in headers) + "\n\n"
80
+
81
+ base_size = len(base_content) + len(header_content)
82
+
83
+ # Group rows by size
84
+ chunks = []
85
+ current_rows = []
86
+ current_size = base_size
87
 
88
+ for row in rows:
89
+ # Estimate row size
90
+ if isinstance(row, dict):
91
+ row_str = " | ".join(f"{k}: {v}" for k, v in row.items()
92
+ if v and str(v).strip() and str(v).lower() not in ['nan', 'none', ''])
93
+ elif isinstance(row, list):
94
+ row_str = " | ".join(str(v) for v in row
95
+ if v and str(v).strip() and str(v).lower() not in ['nan', 'none', ''])
96
+ else:
97
+ row_str = str(row)
98
 
99
+ row_size = len(row_str) + 2 # +2 for newline
 
 
 
 
 
 
 
 
 
 
100
 
101
+ # If adding this row exceeds limit and we have rows, create chunk
102
+ if current_size + row_size > max_chars and current_rows:
103
+ chunks.append(current_rows[:])
104
+ current_rows = []
105
+ current_size = base_size
106
 
107
+ current_rows.append(row)
108
+ current_size += row_size
109
 
110
+ # Add remaining rows
111
+ if current_rows:
112
+ chunks.append(current_rows)
113
 
114
+ # Create documents
115
+ documents = []
116
+ for chunk_idx, chunk_rows in enumerate(chunks):
117
+ content = base_content
118
+ content += f"Таблица {table_identifier} документа {doc_id}\n"
119
+ if len(chunks) > 1:
120
+ content += f"Часть {chunk_idx+1} из {len(chunks)}\n"
121
+ content += "\n" + header_content
 
 
 
 
122
 
123
+ for idx, row in enumerate(chunk_rows, 1):
124
+ if isinstance(row, dict):
125
+ parts = [f"{k}: {v}" for k, v in row.items()
126
+ if v and str(v).strip() and str(v).lower() not in ['nan', 'none', '']]
127
+ if parts:
128
+ content += f"{idx}. {' | '.join(parts)}\n"
129
+ elif isinstance(row, list):
130
+ parts = [str(v) for v in row if v and str(v).strip() and str(v).lower() not in ['nan', 'none', '']]
131
+ if parts:
132
+ content += f"{idx}. {' | '.join(parts)}\n"
133
 
134
  metadata = {
135
  'type': 'table',
136
  'document_id': doc_id,
137
+ 'document_group': normalize_doc_id(doc_id),
138
  'table_number': table_num_clean,
139
  'table_identifier': table_identifier,
140
  'table_title': table_title,
141
  'section': section,
142
+ 'chunk_id': chunk_idx,
143
+ 'total_chunks': len(chunks),
144
+ 'chunk_size': len(content),
145
+ 'is_complete_table': len(chunks) == 1
 
 
 
146
  }
147
 
148
+ documents.append(Document(text=content, metadata=metadata))
149
 
150
+ log_message(f" Chunk {chunk_idx+1}: {len(chunk_rows)} rows, {len(content)} chars")
151
+ log_message(f" Meta: doc={doc_id}, table={table_identifier}, group={metadata['document_group']}")
152
+
153
+ log_message(f" Table {table_identifier} ({doc_id}): {len(rows)} rows → {len(chunks)} chunks")
154
 
155
+ return documents
156
+
157
+
158
+ def normalize_doc_id(doc_id):
159
+ import re
160
+ normalized = re.sub(r'\s+', ' ', str(doc_id).strip().upper())
161
+ normalized = normalized.replace('ГОСТ Р', 'ГОСТР').replace('ГОСТР', 'ГОСТ Р')
162
+ return normalized
163
 
164
 
165
  def format_table_content(table_data, headers, rows, doc_id, table_identifier, chunk_info=""):
 
405
 
406
 
407
  def load_table_documents(repo_id, hf_token, table_dir):
408
+ """Load ALL tables including from multi-document files"""
409
  log_message("Loading tables...")
410
 
411
  files = list_repo_files(repo_id=repo_id, repo_type="dataset", token=hf_token)
412
  table_files = [f for f in files if f.startswith(table_dir) and f.endswith('.json')]
413
 
414
+ log_message(f"Found {len(table_files)} table files")
415
+
416
  all_chunks = []
417
+ doc_id_stats = {}
418
 
419
  for file_path in table_files:
420
  try:
 
428
  with open(local_path, 'r', encoding='utf-8') as f:
429
  data = json.load(f)
430
 
431
+ file_doc_id = data.get('document_id', data.get('document', 'unknown'))
432
 
433
  for sheet in data.get('sheets', []):
434
+ sheet_doc_id = sheet.get('document_id', sheet.get('document', file_doc_id))
435
+
436
+ # Track which documents we're loading
437
+ if sheet_doc_id not in doc_id_stats:
438
+ doc_id_stats[sheet_doc_id] = 0
439
 
440
  chunks = chunk_table_by_rows(sheet, sheet_doc_id)
441
  all_chunks.extend(chunks)
442
+ doc_id_stats[sheet_doc_id] += len(chunks)
 
 
 
443
 
444
  except Exception as e:
445
  log_message(f"Error loading {file_path}: {e}")
446
 
447
+ # Log what we loaded
448
+ log_message(f"\nTable loading summary:")
449
+ for doc_id, count in sorted(doc_id_stats.items()):
450
+ log_message(f" {doc_id}: {count} chunks")
 
 
451
 
452
+ log_message(f"\n✓ Total table chunks: {len(all_chunks)}")
453
  return all_chunks
454
 
 
455
  def load_image_documents(repo_id, hf_token, image_dir):
456
+ """Load with proper linking"""
457
  log_message("Loading images...")
458
 
459
  files = list_repo_files(repo_id=repo_id, repo_type="dataset", token=hf_token)
460
  csv_files = [f for f in files if f.startswith(image_dir) and f.endswith('.csv')]
461
 
462
  documents = []
463
+ seen = set()
464
+
465
  for file_path in csv_files:
466
  try:
467
  local_path = hf_hub_download(
 
474
  df = pd.read_csv(local_path)
475
 
476
  for _, row in df.iterrows():
477
+ doc_id = str(row.get('Обозначение документа', 'unknown'))
478
+ img_num = str(row.get('№ Изображения', 'unknown'))
479
+
480
+ key = f"{doc_id}_{img_num}"
481
+ if key in seen:
482
+ continue
483
+ seen.add(key)
484
+
485
+ content = f"Документ: {doc_id}\n"
486
+ content += f"Рисунок: {img_num}\n"
487
  content += f"Название: {row.get('Название изображения', '')}\n"
488
  content += f"Описание: {row.get('Описание изображение', '')}\n"
 
 
 
489
 
490
  documents.append(Document(
491
  text=content,
492
  metadata={
493
  'type': 'image',
494
+ 'document_id': doc_id,
495
+ 'document_group': normalize_doc_id(doc_id),
496
+ 'image_number': img_num,
497
  'section': str(row.get('Раздел документа', '')),
498
+ 'chunk_size': len(content)
499
  }
500
  ))
501
  except Exception as e:
 
503
 
504
  if documents:
505
  avg_size = sum(d.metadata['chunk_size'] for d in documents) / len(documents)
506
+ log_message(f"✓ Images: {len(documents)} loaded (avg: {avg_size:.0f} chars)")
507
 
508
  return documents
509
 
510
 
511
+
512
  def load_all_documents(repo_id, hf_token, json_dir, table_dir, image_dir):
513
  """Main loader - combines all document types"""
514
  log_message("="*60)
utils.py CHANGED
@@ -66,6 +66,33 @@ def answer_question(question, query_engine, reranker):
66
  retrieved = query_engine.retriever.retrieve(enhanced_query)
67
  log_message(f"Retrieved {len(retrieved)} nodes")
68
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  doc_ids = [n.metadata.get('document_id', 'unknown') for n in retrieved]
70
  table_nums = [n.metadata.get('table_number', '') for n in retrieved if n.metadata.get('type') == 'table']
71
  log_message(f"Retrieved from documents: {set(doc_ids)}")
@@ -104,19 +131,87 @@ def answer_question(question, query_engine, reranker):
104
 
105
  context = "\n\n" + ("="*70 + "\n\n").join(context_parts)
106
  from config import CUSTOM_PROMPT
107
- prompt = f"""Ты эксперт по технической документации.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
 
109
  КОНТЕКСТ:
110
  {context}
111
 
112
  ВОПРОС: {question}
113
-
114
- ИНСТРУКЦИИ:
115
- 1. Используй ТОЛЬКО контекст выше
116
- 2. Укажи источник: документ и номер таблицы
117
- 3. Если информации нет - четко скажи об этом
118
-
119
- ОТВЕТ:"""
120
 
121
  response = query_engine.query(prompt)
122
  sources = format_sources(reranked)
 
66
  retrieved = query_engine.retriever.retrieve(enhanced_query)
67
  log_message(f"Retrieved {len(retrieved)} nodes")
68
 
69
+ doc_stats = {}
70
+ for n in retrieved:
71
+ doc_id = n.metadata.get('document_id', 'unknown')
72
+ doc_type = n.metadata.get('type', 'text')
73
+
74
+ if doc_id not in doc_stats:
75
+ doc_stats[doc_id] = {'tables': set(), 'text': 0, 'images': 0}
76
+
77
+ if doc_type == 'table':
78
+ table_id = n.metadata.get('table_identifier', n.metadata.get('table_number', '?'))
79
+ doc_stats[doc_id]['tables'].add(table_id)
80
+ elif doc_type == 'image':
81
+ doc_stats[doc_id]['images'] += 1
82
+ else:
83
+ doc_stats[doc_id]['text'] += 1
84
+
85
+ for doc_id in sorted(doc_stats.keys()):
86
+ stats = doc_stats[doc_id]
87
+ parts = []
88
+ if stats['tables']:
89
+ parts.append(f"tables={list(stats['tables'])[:5]}")
90
+ if stats['text']:
91
+ parts.append(f"text={stats['text']}")
92
+ if stats['images']:
93
+ parts.append(f"images={stats['images']}")
94
+ log_message(f" {doc_id}: {', '.join(parts)}")
95
+
96
  doc_ids = [n.metadata.get('document_id', 'unknown') for n in retrieved]
97
  table_nums = [n.metadata.get('table_number', '') for n in retrieved if n.metadata.get('type') == 'table']
98
  log_message(f"Retrieved from documents: {set(doc_ids)}")
 
131
 
132
  context = "\n\n" + ("="*70 + "\n\n").join(context_parts)
133
  from config import CUSTOM_PROMPT
134
+ prompt = f"""
135
+ Вы являетесь высокоспециализированным Ассистентом для анализа нормативных документов (AIEXP). Ваша цель - предоставлять точные, корректные и контекстно релевантные ответы исключительно на основе предоставленного контекста из нормативной документации.
136
+
137
+ ПРАВИЛА АНАЛИЗА ЗАПРОСА:
138
+
139
+ 1. ПРЯМЫЕ ВОПРОСЫ БЕЗ ДОКУМЕНТАЛЬНОГО КОНТЕКСТА:
140
+ Если пользователь задает вопрос типа "В каких случаях могут быть признаны протоколы испытаний?" без предоставления дополнительных документов, найдите соответствующую информацию в доступном контексте и предоставьте полный ответ с указанием источников.
141
+
142
+ 2. ОПРЕДЕЛЕНИЕ ТИПА ЗАДАЧИ:
143
+
144
+ а) ПОИСК И ОТВЕТ НА ВОПРОС (ключевые слова: "в каких случаях", "когда", "кто", "что", "как", "почему"):
145
+ - Найдите релевантную информацию в контексте
146
+ - Предоставьте развернутый ответ
147
+ - Обязательно укажите конкретные документы и разделы
148
+ - Процитируйте ключевые положения
149
+
150
+ б) КРАТКОЕ САММАРИ (ключевые слова: "кратко", "суммировать", "резюме", "основные моменты"):
151
+ - Предоставьте структурированное резюме
152
+ - Выделите ключевые требования
153
+ - Используйте нумерованный список
154
+
155
+ в) ПОИСК ДОКУМЕНТА И ПУНКТА (ключевые слова: "найти", "где", "какой документ", "в каком разделе"):
156
+ - Укажите конкретный документ и структурное расположение
157
+ - Предоставьте точные номера разделов/пунктов
158
+
159
+ г) ПРОВЕРКА КОРРЕКТНОСТИ (ключевые слова: "правильно ли", "соответствует ли", "проверить"):
160
+ - Четко укажите: "СООТВЕТСТВУЕТ" или "НЕ СООТВЕТСТВУЕТ"
161
+ - Перечислите конкретные требования
162
+
163
+ д) ПЛАН ДЕЙСТВИЙ (ключевые слова: "план", "алгоритм", "пошагово"):
164
+ - Создайте пронумерованный план
165
+ - Укажите ссылки на соответствующие пункты НД
166
+
167
+ ПРАВИЛА ФОРМИРОВАНИЯ ОТВЕТОВ:
168
+
169
+ Работай исключительно с информацией из предоставленного конт��кста. Запрещено использовать:
170
+ - Общие знания
171
+ - Информацию из интернета
172
+ - Данные из предыдущих диалогов
173
+ - Собственные предположения
174
+
175
+ 1. СТРУКТУРА ОТВЕТА:
176
+ - Начинайте с прямого ответа на вопрос
177
+ - Затем указывайте нормативные основания
178
+ - Завершайте ссылками на конкретные документы и разделы
179
+
180
+ 2. РАБОТА С КОНТЕКСТОМ:
181
+ - Если информация найдена в контексте - предоставьте полный ответ
182
+ - Если информация не найдена: "Информация по вашему запросу не найдена в доступной нормативной документации"
183
+ - Не делайте предположений за пределами контекста
184
+ - Не используйте общие знания
185
+
186
+ 3. ТЕРМИНОЛОГИЯ И ЦИТИРОВАНИЕ:
187
+ - Сохраняйте официальную терминологию НД
188
+ - Цитируйте точные формулировки ключевых требований
189
+ - При множественных источниках - укажите все релевантные
190
+
191
+ 4. ФОРМАТИРОВАНИЕ:
192
+ - Для перечислений: используйте нумерованные списки
193
+ - Выделяйте критически важные требования
194
+ - Структурируйте ответ логически
195
+
196
+ # КАК РАБОТАТЬ С ЗАПРОСОМ
197
+
198
+ **Шаг 1:** Определи, что именно ищет пользователь (термин, требование, процедура, условие)
199
+
200
+ **Шаг 2:** Найди релевантную информацию в контексте
201
+
202
+ **Шаг 3:** Сформируй ответ:
203
+ - Если нашел: укажи документ и пункт, процитируй нужную часть
204
+ - Если не нашел: четко сообщи об отсутствии информации
205
+
206
+ **Шаг 4:** При наличии нескольких источников:
207
+ - Представь их последовательно с указанием источника каждого
208
+ - Если источников много (>4) — сначала дай их список, потом цитаты
209
 
210
  КОНТЕКСТ:
211
  {context}
212
 
213
  ВОПРОС: {question}
214
+ """
 
 
 
 
 
 
215
 
216
  response = query_engine.query(prompt)
217
  sources = format_sources(reranked)