MrSimple07 commited on
Commit
41ab11f
·
1 Parent(s): 050ac59

initial commit with the files

Browse files
Files changed (5) hide show
  1. README.md +4 -4
  2. app.py +455 -0
  3. config.py +230 -0
  4. questions.py +75 -0
  5. requirements.txt +14 -0
README.md CHANGED
@@ -1,8 +1,8 @@
1
  ---
2
- title: RAG AIEXP 01
3
- emoji: 🌍
4
- colorFrom: gray
5
- colorTo: blue
6
  sdk: gradio
7
  sdk_version: 5.42.0
8
  app_file: app.py
 
1
  ---
2
+ title: RAG AIEXP 0
3
+ emoji: 🔥
4
+ colorFrom: blue
5
+ colorTo: gray
6
  sdk: gradio
7
  sdk_version: 5.42.0
8
  app_file: app.py
app.py ADDED
@@ -0,0 +1,455 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from huggingface_hub import hf_hub_download, hf_hub_url
3
+ import faiss
4
+ import pandas as pd
5
+ import os
6
+ import json
7
+ import numpy as np
8
+ from pathlib import Path
9
+ import fitz # PyMuPDF
10
+ from llama_index.core import Document, VectorStoreIndex, Settings
11
+ from llama_index.embeddings.huggingface import HuggingFaceEmbedding
12
+ from llama_index.llms.google_genai import GoogleGenAI
13
+ from llama_index.core.query_engine import RetrieverQueryEngine
14
+ from llama_index.core.retrievers import VectorIndexRetriever
15
+ from llama_index.core.response_synthesizers import get_response_synthesizer, ResponseMode
16
+ from llama_index.core.prompts import PromptTemplate
17
+ import time
18
+ import sys
19
+ from config import *
20
+
21
+ query_engine = None
22
+ chunks_df = None
23
+ documents_df = None
24
+
25
+ def log_message(message):
26
+ print(message, flush=True)
27
+ sys.stdout.flush()
28
+
29
+ def load_documents_info():
30
+ global documents_df
31
+ try:
32
+ docs_path = os.path.join(download_dir, extracted_files)
33
+ if os.path.exists(docs_path):
34
+ documents_df = pd.read_csv(docs_path)
35
+ return documents_df
36
+ else:
37
+ documents_df = pd.DataFrame(columns=['document', 'file_name', 'file_link', 'file_size', 'total_pages', 'total_words', 'total_tokens'])
38
+ return documents_df
39
+ except Exception as e:
40
+ log_message(f"Error loading documents: {str(e)}")
41
+ return pd.DataFrame(columns=['document', 'file_name', 'file_link', 'file_size', 'total_pages', 'total_words', 'total_tokens'])
42
+
43
+ def extract_text_from_pdf(file_path):
44
+ doc = fitz.open(file_path)
45
+ text = ""
46
+ for page in doc:
47
+ text += page.get_text()
48
+ doc.close()
49
+ return text
50
+
51
+ def extract_text_from_txt(file_path):
52
+ with open(file_path, 'r', encoding='utf-8') as file:
53
+ return file.read()
54
+
55
+ def extract_text_from_csv(file_path):
56
+ df = pd.read_csv(file_path)
57
+ return df.to_string()
58
+
59
+ def extract_text_from_json(file_path):
60
+ with open(file_path, 'r', encoding='utf-8') as file:
61
+ data = json.load(file)
62
+ return json.dumps(data, indent=2, ensure_ascii=False)
63
+
64
+ def chunk_text(text, chunk_size=CHUNK_SIZE, chunk_overlap=CHUNK_OVERLAP):
65
+ chunks = []
66
+ start = 0
67
+ while start < len(text):
68
+ end = start + chunk_size
69
+ chunk = text[start:end]
70
+ chunks.append(chunk)
71
+ start = end - chunk_overlap
72
+ return chunks
73
+
74
+ def process_uploaded_file(file_path, file_name):
75
+ try:
76
+ file_extension = Path(file_path).suffix.lower()
77
+
78
+ if file_extension == '.pdf':
79
+ text = extract_text_from_pdf(file_path)
80
+ elif file_extension == '.txt':
81
+ text = extract_text_from_txt(file_path)
82
+ elif file_extension == '.csv':
83
+ text = extract_text_from_csv(file_path)
84
+ elif file_extension == '.json':
85
+ text = extract_text_from_json(file_path)
86
+ else:
87
+ return None, "Unsupported file type"
88
+
89
+ file_size = os.path.getsize(file_path)
90
+ word_count = len(text.split())
91
+ token_count = len(text) // 4 # rough token estimation
92
+
93
+ chunks = chunk_text(text)
94
+
95
+ return {
96
+ 'document': file_name,
97
+ 'file_name': file_name,
98
+ 'file_size': file_size,
99
+ 'total_words': word_count,
100
+ 'total_tokens': token_count,
101
+ 'extracted_text': text,
102
+ 'chunks': chunks
103
+ }, None
104
+
105
+ except Exception as e:
106
+ return None, str(e)
107
+
108
+ def add_to_vector_index(new_chunks, file_info):
109
+ global query_engine, chunks_df, documents_df
110
+
111
+ try:
112
+ embed_model = HuggingFaceEmbedding(model_name=EMBEDDING_MODEL)
113
+
114
+ new_documents = []
115
+ new_chunk_data = []
116
+
117
+ for i, chunk in enumerate(new_chunks):
118
+ doc_id = f"{file_info['file_name']}_{i}"
119
+ new_documents.append(Document(
120
+ text=chunk,
121
+ metadata={
122
+ "chunk_id": doc_id,
123
+ "document_id": file_info['file_name']
124
+ }
125
+ ))
126
+ new_chunk_data.append({
127
+ 'chunk_id': doc_id,
128
+ 'document_id': file_info['file_name'],
129
+ 'text': chunk
130
+ })
131
+
132
+ if chunks_df is not None:
133
+ new_chunks_df = pd.DataFrame(new_chunk_data)
134
+ chunks_df = pd.concat([chunks_df, new_chunks_df], ignore_index=True)
135
+ else:
136
+ chunks_df = pd.DataFrame(new_chunk_data)
137
+
138
+ if documents_df is not None:
139
+ new_doc_info = pd.DataFrame([{
140
+ 'document': file_info['document'],
141
+ 'file_name': file_info['file_name'],
142
+ 'file_size': file_info['file_size'],
143
+ 'total_words': file_info['total_words'],
144
+ 'total_tokens': file_info['total_tokens']
145
+ }])
146
+ documents_df = pd.concat([documents_df, new_doc_info], ignore_index=True)
147
+
148
+ all_documents = [Document(text=str(row['text']),
149
+ metadata={"chunk_id": row['chunk_id'], "document_id": row['document_id']})
150
+ for _, row in chunks_df.iterrows()]
151
+
152
+ vector_index = VectorStoreIndex.from_documents(all_documents)
153
+
154
+ retriever = VectorIndexRetriever(
155
+ index=vector_index,
156
+ similarity_top_k=RETRIEVER_TOP_K,
157
+ similarity_cutoff=SIMILARITY_THRESHOLD
158
+ )
159
+
160
+ custom_prompt_template = PromptTemplate(CUSTOM_PROMPT)
161
+ response_synthesizer = get_response_synthesizer(
162
+ response_mode=ResponseMode.TREE_SUMMARIZE,
163
+ text_qa_template=custom_prompt_template
164
+ )
165
+
166
+ query_engine = RetrieverQueryEngine(
167
+ retriever=retriever,
168
+ response_synthesizer=response_synthesizer
169
+ )
170
+
171
+ chunks_df.to_csv(os.path.join(download_dir, chunks_filename), index=False)
172
+ documents_df.to_csv(os.path.join(download_dir, extracted_files), index=False)
173
+
174
+ return True, None
175
+
176
+ except Exception as e:
177
+ return False, str(e)
178
+
179
+ def upload_and_process_file(files):
180
+ if not files:
181
+ return "No files selected", get_documents_table()
182
+
183
+ results = []
184
+ for file in files:
185
+ file_info, error = process_uploaded_file(file.name, os.path.basename(file.name))
186
+
187
+ if error:
188
+ results.append(f"❌ {os.path.basename(file.name)}: {error}")
189
+ continue
190
+
191
+ success, error = add_to_vector_index(file_info['chunks'], file_info)
192
+
193
+ if success:
194
+ results.append(f"✅ {file_info['file_name']}: Successfully processed and added to database")
195
+ else:
196
+ results.append(f"❌ {file_info['file_name']}: Error adding to database - {error}")
197
+
198
+ return "\n".join(results), get_documents_table()
199
+
200
+ def get_documents_table():
201
+ global documents_df
202
+ if documents_df is None or documents_df.empty:
203
+ return "<div style='padding: 20px; text-align: center; color: #666;'>No documents uploaded yet</div>"
204
+
205
+ html = "<div style='max-height: 500px; overflow-y: auto;'>"
206
+ html += "<table style='width: 100%; border-collapse: collapse; font-size: 14px;'>"
207
+ html += "<thead style='background-color: #f8f9fa; position: sticky; top: 0;'>"
208
+ html += "<tr style='border-bottom: 2px solid #dee2e6;'>"
209
+ html += "<th style='padding: 12px; text-align: left; border-right: 1px solid #dee2e6;'>File Name</th>"
210
+ html += "<th style='padding: 12px; text-align: center; border-right: 1px solid #dee2e6;'>Size (KB)</th>"
211
+ html += "<th style='padding: 12px; text-align: center; border-right: 1px solid #dee2e6;'>Words</th>"
212
+ html += "<th style='padding: 12px; text-align: center;'>Tokens</th>"
213
+ html += "</tr>"
214
+ html += "</thead>"
215
+ html += "<tbody>"
216
+
217
+ for _, row in documents_df.iterrows():
218
+ html += "<tr style='border-bottom: 1px solid #dee2e6;'>"
219
+ html += f"<td style='padding: 8px; border-right: 1px solid #dee2e6;'>{row['file_name']}</td>"
220
+ html += f"<td style='padding: 8px; text-align: center; border-right: 1px solid #dee2e6;'>{row['file_size']/1024:.1f}</td>"
221
+ html += f"<td style='padding: 8px; text-align: center; border-right: 1px solid #dee2e6;'>{row['total_words']}</td>"
222
+ html += f"<td style='padding: 8px; text-align: center;'>{row['total_tokens']}</td>"
223
+ html += "</tr>"
224
+
225
+ html += "</tbody></table></div>"
226
+ return html
227
+
228
+ def initialize_models():
229
+ global query_engine, chunks_df, documents_df
230
+
231
+ try:
232
+ log_message("🔄 Инициализация системы...")
233
+ os.makedirs(download_dir, exist_ok=True)
234
+
235
+ documents_df = load_documents_info()
236
+
237
+ try:
238
+ chunks_csv_path = hf_hub_download(
239
+ repo_id=REPO_ID,
240
+ filename=chunks_filename,
241
+ local_dir=download_dir,
242
+ repo_type="dataset",
243
+ token=HF_TOKEN
244
+ )
245
+ chunks_df = pd.read_csv(chunks_csv_path)
246
+ except:
247
+ log_message("📝 Создание пустой базы чанков...")
248
+ chunks_df = pd.DataFrame(columns=['chunk_id', 'document_id', 'text'])
249
+
250
+ log_message("🤖 Настройка моделей...")
251
+ embed_model = HuggingFaceEmbedding(model_name=EMBEDDING_MODEL)
252
+ llm = GoogleGenAI(model="gemini-2.0-flash", api_key=GOOGLE_API_KEY)
253
+
254
+ Settings.embed_model = embed_model
255
+ Settings.llm = llm
256
+
257
+ if not chunks_df.empty:
258
+ log_message("📝 Создание документов...")
259
+ documents = [Document(text=str(row['text']),
260
+ metadata={"chunk_id": row.get('chunk_id', i), "document_id": row.get('document_id', 'unknown')})
261
+ for i, (_, row) in enumerate(chunks_df.iterrows())]
262
+
263
+ log_message("🔍 Построение векторного индекса...")
264
+ vector_index = VectorStoreIndex.from_documents(documents)
265
+
266
+ retriever = VectorIndexRetriever(
267
+ index=vector_index,
268
+ similarity_top_k=RETRIEVER_TOP_K,
269
+ similarity_cutoff=SIMILARITY_THRESHOLD
270
+ )
271
+
272
+ custom_prompt_template = PromptTemplate(CUSTOM_PROMPT_NEW)
273
+ response_synthesizer = get_response_synthesizer(
274
+ response_mode=ResponseMode.TREE_SUMMARIZE,
275
+ text_qa_template=custom_prompt_template
276
+ )
277
+
278
+ query_engine = RetrieverQueryEngine(
279
+ retriever=retriever,
280
+ response_synthesizer=response_synthesizer
281
+ )
282
+
283
+ log_message("✅ Система успешно инициализирована!")
284
+ return True
285
+
286
+ except Exception as e:
287
+ log_message(f"❌ Ошибка инициализации: {str(e)}")
288
+ return False
289
+
290
+ def answer_question(question):
291
+ global query_engine
292
+
293
+ if query_engine is None:
294
+ return "<div style='background-color: #e53e3e; color: white; padding: 20px; border-radius: 10px;'>❌ Система не инициализирована или база документов пуста</div>", ""
295
+
296
+ try:
297
+ start_time = time.time()
298
+
299
+ response = query_engine.query(question)
300
+ retrieved_nodes = query_engine.retriever.retrieve(question)
301
+
302
+ end_time = time.time()
303
+ processing_time = end_time - start_time
304
+
305
+ sources_html = generate_sources_html(retrieved_nodes)
306
+
307
+ answer_with_time = f"""<div style='background-color: #2d3748; color: white; padding: 20px; border-radius: 10px; margin-bottom: 10px;'>
308
+ <h3 style='color: #63b3ed; margin-top: 0;'>📋 Ответ:</h3>
309
+ <div style='line-height: 1.6; font-size: 16px;'>{response.response}</div>
310
+ <div style='margin-top: 15px; padding-top: 10px; border-top: 1px solid #4a5568; font-size: 14px; color: #a0aec0;'>
311
+ ⏱️ Время обработки: {processing_time:.2f} сек
312
+ </div>
313
+ </div>"""
314
+
315
+ return answer_with_time, sources_html
316
+
317
+ except Exception as e:
318
+ error_msg = f"<div style='background-color: #e53e3e; color: white; padding: 20px; border-radius: 10px;'>❌ Ошибка обработки вопроса: {str(e)}</div>"
319
+ return error_msg, ""
320
+
321
+ def generate_sources_html(nodes):
322
+ html = "<div style='background-color: #2d3748; color: white; padding: 20px; border-radius: 10px; max-height: 400px; overflow-y: auto;'>"
323
+ html += "<h3 style='color: #63b3ed; margin-top: 0;'>📚 Источники:</h3>"
324
+
325
+ unique_docs = {}
326
+ for node in nodes:
327
+ metadata = node.metadata if hasattr(node, 'metadata') else {}
328
+ doc_id = metadata.get('document_id', 'unknown')
329
+ if doc_id not in unique_docs:
330
+ unique_docs[doc_id] = []
331
+ unique_docs[doc_id].append(node)
332
+
333
+ for doc_id, doc_nodes in unique_docs.items():
334
+ html += f"<div style='margin-bottom: 15px; padding: 15px; border: 1px solid #4a5568; border-radius: 8px; background-color: #1a202c;'>"
335
+ html += f"<h4 style='margin: 0 0 10px 0; color: #63b3ed;'>📄 {doc_id}</h4>"
336
+ html += f"<p style='margin: 0; color: #a0aec0; font-size: 14px;'>Найдено релевантных фрагментов: {len(doc_nodes)}</p>"
337
+ html += "</div>"
338
+
339
+ html += "</div>"
340
+ return html
341
+
342
+ def create_demo_interface():
343
+ with gr.Blocks(title="AIEXP - AI Expert для нормативной документации", theme=gr.themes.Soft()) as demo:
344
+
345
+ gr.Markdown("""
346
+ # AIEXP - Artificial Intelligence Expert
347
+
348
+ ## Инструмент для работы с нормативной документацией
349
+ """)
350
+
351
+ with gr.Tab("🔍 Поиск по документам"):
352
+ gr.Markdown("### Задайте вопрос по загруженной документации")
353
+
354
+ with gr.Row():
355
+ with gr.Column(scale=3):
356
+ question_input = gr.Textbox(
357
+ label="Ваш вопрос к базе знаний",
358
+ placeholder="Введите вопрос по документам...",
359
+ lines=3
360
+ )
361
+ ask_btn = gr.Button("🔍 Найти ответ", variant="primary", size="lg")
362
+
363
+ gr.Examples(
364
+ examples=[
365
+ "Какой стандарт устанавливает порядок признания протоколов испытаний продукции в области использования атомной энергии?",
366
+ "Кто несет ответственность за организацию и проведение признания протоколов испытаний продукции?",
367
+ "В каких случаях могут быть признаны протоколы испытаний, проведенные лабораториями, не включенными в перечисления?",
368
+ ],
369
+ inputs=question_input
370
+ )
371
+
372
+ with gr.Row():
373
+ with gr.Column(scale=2):
374
+ answer_output = gr.HTML(
375
+ label="",
376
+ value="<div style='background-color: #2d3748; color: white; padding: 20px; border-radius: 10px; text-align: center;'>Здесь появится ответ на ваш вопрос...</div>",
377
+ )
378
+
379
+ with gr.Column(scale=1):
380
+ sources_output = gr.HTML(
381
+ label="",
382
+ value="<div style='background-color: #2d3748; color: white; padding: 20px; border-radius: 10px; text-align: center;'>Здесь появятся источники...</div>",
383
+ )
384
+
385
+ ask_btn.click(
386
+ fn=answer_question,
387
+ inputs=[question_input],
388
+ outputs=[answer_output, sources_output]
389
+ )
390
+
391
+ question_input.submit(
392
+ fn=answer_question,
393
+ inputs=[question_input],
394
+ outputs=[answer_output, sources_output]
395
+ )
396
+
397
+ with gr.Tab("📚 Управление документами"):
398
+ gr.Markdown("### Загруженные документы и добавление новых файлов")
399
+
400
+ with gr.Row():
401
+ with gr.Column(scale=2):
402
+ documents_table = gr.HTML(
403
+ label="Список загруженных документов",
404
+ value=get_documents_table()
405
+ )
406
+
407
+ refresh_btn = gr.Button("🔄 Обновить список", variant="secondary")
408
+
409
+ with gr.Column(scale=1):
410
+ gr.Markdown("#### Загрузка новых документов")
411
+ gr.Markdown("Поддерживаемые форматы: PDF, TXT, CSV, JSON")
412
+
413
+ file_upload = gr.File(
414
+ file_count="multiple",
415
+ file_types=[".pdf", ".txt", ".csv", ".json"],
416
+ label="Выберите файлы для загрузки"
417
+ )
418
+
419
+ upload_btn = gr.Button("📤 Загрузить и обработать", variant="primary")
420
+
421
+ upload_status = gr.Textbox(
422
+ label="Статус загрузки",
423
+ lines=8,
424
+ max_lines=10,
425
+ interactive=False
426
+ )
427
+
428
+ upload_btn.click(
429
+ fn=upload_and_process_file,
430
+ inputs=[file_upload],
431
+ outputs=[upload_status, documents_table]
432
+ )
433
+
434
+ refresh_btn.click(
435
+ fn=lambda: get_documents_table(),
436
+ outputs=[documents_table]
437
+ )
438
+
439
+ return demo
440
+
441
+ if __name__ == "__main__":
442
+ log_message("🚀 Запуск AIEXP - AI Expert для нормативной документации")
443
+
444
+ if initialize_models():
445
+ log_message("🌟 Запуск веб-интерфейса...")
446
+ demo = create_demo_interface()
447
+ demo.launch(
448
+ server_name="0.0.0.0",
449
+ server_port=7860,
450
+ share=True,
451
+ debug=False
452
+ )
453
+ else:
454
+ log_message("❌ Невозможно запустить приложение из-за ошибки инициализации")
455
+ sys.exit(1)
config.py ADDED
@@ -0,0 +1,230 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+
3
+ EMBEDDING_MODEL = "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2"
4
+ RETRIEVER_TOP_K = 25
5
+ SIMILARITY_THRESHOLD = 0.7
6
+ RAG_FILES_DIR = "rag_files"
7
+ PROCESSED_DATA_FILE = "rag_files/processed_chunks.csv"
8
+
9
+ REPO_ID = "MrSimple01/AIEXP_RAG_FILES"
10
+ faiss_index_filename = "faiss_index.index"
11
+ chunks_filename = "processed_chunks.csv"
12
+
13
+ extracted_files = 'cleaned_extracted_tokens.csv'
14
+
15
+ download_dir = "rag_files"
16
+ HF_TOKEN = os.getenv('HF_TOKEN')
17
+ GOOGLE_API_KEY = os.getenv('GOOGLE_API_KEY')
18
+
19
+ CHUNK_SIZE = 1024
20
+ CHUNK_OVERLAP = 256
21
+
22
+
23
+ CUSTOM_PROMPT = """
24
+ You are a highly specialized Document Analysis Assistant (AIEXP). Your purpose is to provide precise, accurate, and contextually relevant answers by analyzing a set of normal regulatory documents (НД). Your responses must be entirely based on the provided context, without any external knowledge or assumptions.
25
+
26
+ **Core Tasks:**
27
+ Based on the user's query, perform one of the following tasks:
28
+ * **Information Retrieval:** Find and present specific information.
29
+ * **Summarization:** Provide a concise summary of a document or a section.
30
+ * **Semantic Analysis:** Compare a provided text against the requirements of the ND.
31
+ * **Action Planning:** Create a step-by-step plan based on ND requirements.
32
+
33
+ **Strict Rules for Response Generation:**
34
+ 1. Source Attribution is Mandatory: Every answer must explicitly cite its source from the provided context. Use one of the following formats:
35
+ * For content from a specific section/subsection:
36
+ `Согласно разделу [X] и подразделу [X.X]: [Ваш ответ]`
37
+ * For content that is not part of a specific subsection (e.g., from a general section, table, or figure):
38
+ `Согласно [Название документа] - [Номер и наименование пункта/таблицы/изображения]: [Ваш ответ]`
39
+ * If the source chunk has metadata for both section and subsection, always include both.
40
+ * If the source chunk has only a section, use the format `Согласно разделу [X]: [Ваш ответ]`.
41
+ 2. No Hallucinations: If the requested information is not explicitly found within the provided context, you must state that the information is not available. **Do not** attempt to infer, guess, or create a response. The correct response in this case is:
42
+ `Информация по вашему запросу не была найдена в нормативной документации.`
43
+ 3. Use ND Language: When possible, use terminology and phrasing directly from the ND to maintain accuracy and fidelity to the source document.
44
+ 4. Prioritize Precision: When answering, provide the most specific and direct information possible, avoiding vague or overly broad summaries unless explicitly asked to summarize.
45
+
46
+ **Context:**
47
+ {context_str}
48
+
49
+ **Question:**
50
+ {query_str}
51
+
52
+ **Answer:**
53
+ """
54
+
55
+
56
+ CUSTOM_PROMPT_NEW = """
57
+ Вы являетесь высокоспециализированным Ассистентом для анализа документов (AIEXP). Ваша цель - предоставлять точные, корректные и контекстно релевантные ответы на основе анализа нормативной документации (НД). Все ваши ответы должны основываться исключительно на предоставленном контексте без использования внешних знаний или предположений.
58
+
59
+ ОБЯЗАТЕЛЬНАЯ ЗАДАЧА - ИЗВЛЕЧЕНИЕ СТРУКТУРНОЙ ИНФОРМАЦИИ:
60
+ Для каждого ответа ОБЯЗАТЕЛЬНО определите и укажите:
61
+ 1. НОМЕР РАЗДЕЛА/ПОДРАЗДЕЛА/ПУНКТА (например: "3.1", "4.2.3", "Приложение А.1")
62
+ 2. НАЗВАНИЕ РАЗДЕЛА/ПОДРАЗДЕЛА/ПУНКТА (например: "Общие требования", "Процедура испытаний")
63
+ 3. НАЗВАНИЕ ДОКУМЕНТА-ИСТОЧНИКА
64
+ 4. ССЫЛКУ НА ДОКУМЕНТ (если доступна в метаданных)
65
+
66
+ ФОРМАТ ОБЯЗАТЕЛЬНОГО УКАЗАНИЯ ИСТОЧНИКОВ:
67
+ - **📍 Источник**: [Название документа]
68
+ - **📄 Раздел**: [Номер] - [Название раздела/подраздела]
69
+ - **🔗 Ссылка**: [ссылка на документ, если доступна]
70
+
71
+ ИНСТРУКЦИИ ПО ИЗВЛЕЧЕНИЮ СТРУКТУРНОЙ ИНФОРМАЦИИ:
72
+ 1. Ищите в тексте паттерны нумерации: "1.", "1.1.", "3.2.4.", "Приложение А", "Таблица 1", "Рисунок 2"
73
+ 2. Находите заголовки разделов после номеров (обычно выделены или идут сразу после номера)
74
+ 3. Если номер раздела не найден, ищите контекстные указания: "в данном разделе", "настоящий пункт"
75
+ 4. При отсутствии явной нумерации указывайте: "Раздел не определен"
76
+
77
+ ОПРЕДЕЛЕНИЕ ТИПА ЗАДАЧИ:
78
+ Проанализируйте запрос пользователя и определите тип задачи:
79
+
80
+ 1. КРАТКОЕ САММАРИ (ключевые слова: "кратко", "суммировать", "резюме", "основные моменты", "в двух словах"):
81
+ - Предоставьте структурированное резюме запрашиваемого раздела/пункта
82
+ - Выделите ключевые требования, процедуры или положения
83
+ - Используйте нумерованный список для лучшей читаемости
84
+ - Сохраняйте терминологию НД
85
+
86
+ 2. ПОИСК ДОКУМЕНТА И ПУНКТА (ключевые слова: "найти", "где", "какой документ", "в каком разделе", "ссылка"):
87
+ - Укажите конкретный документ и его структурное расположение
88
+ - Предоставьте точные номера разделов/подразделов/пунктов с их названиями
89
+ - Процитируйте релевантные фрагменты
90
+ - Если найдено несколько документов, перечислите все с указанием специфики каждого
91
+
92
+ 3. ПРОВЕРКА КОРРЕКТНОСТИ (ключевые слова: "правильно ли", "соответствует ли", "проверить", "корректно", "нарушение"):
93
+ - Сопоставьте предоставленную информацию с требованиями НД
94
+ - Четко укажите: "СООТВЕТСТВУЕТ" или "НЕ СООТВЕТСТВУЕТ"
95
+ - Перечислите конкретные требования НД с указанием разделов
96
+ - Укажите выявленные расхождения или подтвердите соответствие
97
+ - Процитируйте релевантные пункты НД с их номерами и названиями
98
+
99
+ 4. ПЛАН ДЕЙСТВИЙ (ключевые слова: "план", "алгоритм", "последовательность", "как действовать", "пошагово"):
100
+ - Создайте пронумерованный пошаговый план
101
+ - Каждый шаг должен содержать ссылку на соответствующий пункт НД с номером и названием
102
+ - Укажите необходимые документы или формы
103
+ - Добавьте временные рамки, если они указаны в НД
104
+ - Выделите критические требования или ограничения
105
+
106
+ ПРАВИЛА ФОРМИРОВАНИЯ ОТВЕТОВ:
107
+
108
+ 1. ОБЯЗАТЕЛЬНОЕ УКАЗАНИЕ ИСТОЧНИКОВ С СТРУКТУРНОЙ ИНФОРМАЦИЕЙ:
109
+ Начинайте каждый ответ с блока источников в формате:
110
+
111
+ **📍 Источник**: [Название документа]
112
+ **📄 Раздел**: [Номер] - [Название раздела/подраздела]
113
+ **🔗 Ссылка**: [ссылка, если доступна]
114
+
115
+ Затем продолжайте основной ответ.
116
+
117
+ 2. В ТЕКСТЕ ОТВЕТА используйте конкретные ссылки:
118
+ - "Согласно пункту 3.1 'Общие требования': [Ваш ответ]"
119
+ - "В разделе 4.2 'Процедура испытаний' указано: [Ваш ответ]"
120
+ - "Приложение А.1 'Формы документов' содержит: [Ваш ответ]"
121
+
122
+ 3. СТРОГОЕ СЛЕДОВАНИЕ КОНТЕКСТУ:
123
+ - Если информация не найдена: "Информация по вашему запросу не была найдена в нормативной документации."
124
+ - Если структурная информация не определена: "**📄 Раздел**: Не определен в предоставленном контексте"
125
+ - Не делайте предположений или выводов за пределами предоставленного контекста
126
+
127
+ 4. ИСПОЛЬЗОВАНИЕ ТЕРМИНОЛОГИИ НД:
128
+ - Применяйте официальную терминологию из документов
129
+ - Сохраняйте оригинальные формулировки ключевых требований
130
+ - При необходимости разъясняйте специальные термины на основе НД
131
+
132
+ 5. СТРУКТУРИРОВАНИЕ ОТВЕТОВ:
133
+ - Всегда начинайте с блока источников
134
+ - Для саммари: используйте маркированные или нумерованные списки
135
+ - Для проверки: четкая структура "Требование → Соответствие/Несоответствие"
136
+ - Для планов: пронумерованные шаги с подзадачами при необходимости
137
+ - Для поиска: указание полной иерархии документа
138
+
139
+ 6. ДОПОЛНИТЕЛЬНЫЕ РЕКОМЕНДАЦИИ:
140
+ - При множественных релевантных источниках - укажите все с их структурной информацией
141
+ - Выделяйте критически важные требования
142
+ - Указывайте альтернативные процедуры, если они предусмотрены НД
143
+ - Если в одном ответе используется информация из разных разделов, указывайте все релевантные разделы
144
+
145
+ ПРИМЕРЫ ПРАВИЛЬНОГО ФОРМАТА ОТВЕТА:
146
+
147
+ **📍 Источник**: ГОСТ Р 58771-2019
148
+ **📄 Раздел**: 4.2 - Требования к испытательным лабораториям
149
+ **🔗 Ссылка**: [ссылка на документ]
150
+
151
+ Согласно пункту 4.2 "Требования к испытательным лабораториям", лаборатория должна соответствовать следующим критериям:
152
+ 1. Наличие аккредитации...
153
+ 2. Квалифицированный персонал...
154
+
155
+ Контекст: {context_str}
156
+
157
+ Вопрос: {query_str}
158
+
159
+ Ответ:
160
+ """
161
+
162
+ # # CUSTOM_PROMPT_NEW = """
163
+ # Вы являетесь высокоспециализированным Ассистентом для анализа документов (AIEXP). Ваша цель - предоставлять точные, корректные и контекстно релевантные ответы на основе анализа нормативной документации (НД). Все ваши ответы должны основываться исключительно на предоставленном контексте без использования внешних знаний или предположений.
164
+
165
+ # ОПРЕДЕЛЕНИЕ ТИПА ЗАДАЧИ:
166
+ # Проанализируйте запрос пользователя и определите тип задачи:
167
+
168
+ # 1. КРАТКОЕ САММАРИ (ключевые слова: "кратко", "суммировать", "резюме", "основные моменты", "в двух словах"):
169
+ # - Предоставьте структурированное резюме запрашиваемого раздела/пункта
170
+ # - Выделите ключевые требования, процедуры или положения
171
+ # - Используйте нумерованный список для лучшей читаемости
172
+ # - Сохраняйте терминологию НД
173
+
174
+ # 2. ПОИСК ДОКУМЕНТА И ПУНКТА (ключевые слова: "найти", "где", "какой документ", "в каком разделе", "ссылка"):
175
+ # - Укажите конкретный документ и его структурное расположение
176
+ # - Предоставьте точные номера разделов/подразделов/пунктов
177
+ # - Процитируйте релевантные фрагменты
178
+ # - Если найдено несколько документов, перечислите все с указанием специфики каждого
179
+
180
+ # 3. ПРОВЕРКА КОРРЕКТНОСТИ (ключевые слова: "правильно ли", "соответствует ли", "проверить", "корректно", "нарушение"):
181
+ # - Сопоставьте предоставленную информацию с требованиями НД
182
+ # - Четко укажите: "СООТВЕТСТВУЕТ" или "НЕ СООТВЕТСТВУЕТ"
183
+ # - Перечислите конкретные требования НД
184
+ # - Укажите выявленные расхождения или подтвердите соответствие
185
+ # - Процитируйте релевантные пункты НД
186
+
187
+ # 4. ПЛАН ДЕЙСТВИЙ (ключевые слова: "план", "алгоритм", "последовательность", "как действовать", "пошагово"):
188
+ # - Создайте пронумерованный пошаговый план
189
+ # - Каждый шаг должен содержать ссылку на соответствующий пункт НД
190
+ # - Укажите необходимые документы или формы
191
+ # - Добавьте временные рамки, если они указаны в НД
192
+ # - Выделите критические требования или ограничения
193
+
194
+ # ПРАВИЛА ФОРМИРОВАНИЯ ОТВЕТОВ:
195
+
196
+ # 1. ОБЯЗАТЕЛЬНОЕ УКАЗАНИЕ ИСТОЧНИКОВ:
197
+ # - Для контента из конкретного раздела/подраздела:
198
+ # "Согласно разделу [X] и подразделу [X.X]: [Ваш ответ]"
199
+ # - Для контента вне подразделов (таблицы, рисунки, общие разделы):
200
+ # "Согласно [Название документа] - [Номер и наименование пункта/таблицы/рисунка]: [Ваш ответ]"
201
+ # - При наличии метаданных о разделе и подразделе - включайте оба
202
+ # - При наличии только раздела: "Согласно разделу [X]: [Ваш ответ]"
203
+
204
+ # 2. СТРОГОЕ СЛЕДОВАНИЕ КОНТЕКСТУ:
205
+ # - Если информация не найдена: "Информация по вашему запросу не была найдена в нормативной документации."
206
+ # - Не делайте предположений или выводов за пределами предоставленного контекста
207
+ # - Не используйте общие знания
208
+
209
+ # 3. ИСПОЛЬЗОВАНИЕ ТЕРМИНОЛОГИИ НД:
210
+ # - Применяйте официальную терминологию из документов
211
+ # - Сохраняйте оригинальные формулировки ключевых требований
212
+ # - При необходимости разъясняйте специальные термины на основе НД
213
+
214
+ # 4. СТРУКТУРИРОВАНИЕ ОТВЕТОВ:
215
+ # - Для саммари: используйте маркированные или нумерованные списки
216
+ # - Для проверки: четкая структура "Требование → Соответствие/Несоответствие"
217
+ # - Для планов: пронумерованные шаги с подзадачами при необходимости
218
+ # - Для поиска: указание иерархии документа
219
+
220
+ # 5. ДОПОЛНИТЕЛЬНЫЕ РЕКОМЕНДАЦИИ:
221
+ # - При множественных релевантных источниках - укажите все
222
+ # - Выделяйте критически важные требования
223
+ # - Указывайте альтернативные процедуры, если они предусмотрены НД
224
+
225
+ # Контекст: {context_str}
226
+
227
+ # Вопрос: {query_str}
228
+
229
+ # Ответ:
230
+ # """
questions.py ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ questions_for_rag = [
2
+ {
3
+ 'question': 'Опишите полный план действий, который должен быть выполнен организацией, если в процессе изготовления продукции, предназначенной для использования на объекте атомной энергии, было выявлено несоответствие.',
4
+ 'answer': 'Согласно ГОСТ Р 50.02.02-2017, при выявлении несоответствия необходимо: 1) классифицировать несоответствие (на основе его влияния на безопасность); 2) разработать и согласовать корректирующие действия; 3) выполнить эти действия; 4) оформить документ регистрации несоответствия и принятых решений, который содержит информацию о самом несоответствии, его классификации, причинах возникновения и предпринятых мерах.',
5
+ 'document_name': 'ГОСТ Р 50.02.02-2017',
6
+ 'section': '5.2 Общие положения и 6 Классификация несоответствий',
7
+ 'question_type': 'Составление плана действий согласно документации'
8
+ },
9
+ {
10
+ 'question': 'В чем заключается основная цель ГОСТ Р 50.02.01-2017 и какие ключевые термины он устанавливает для оценки соответствия в области использования атомной энергии?',
11
+ 'answer': 'Целью ГОСТ Р 50.02.01-2017 является установление терминов и соответствующих определений по оценке соответствия в области использования атомной энергии. Он включает такие ключевые термины, как "материал", "монтаж", "наладка", "объект использования атомной энергии (ОИАЭ)" и "обязательные требования".',
12
+ 'document_name': 'ГОСТ Р 50.02.01-2017',
13
+ 'section': 'Введение и 2 Термины и определения',
14
+ 'question_type': 'Краткое саммари какого-то пункта или раздела из документации'
15
+ },
16
+ {
17
+ 'question': 'Утверждается, что классификация несоответствий в ГОСТ Р 50.02.02-2017 применима только к продукции, поставляемой непосредственно на ОИАЭ. Проверьте правильность этого утверждения и объясните, на какую еще продукцию распространяется действие стандарта.',
18
+ 'answer': 'Утверждение неверно. Согласно пункту 1.1 ГОСТ Р 50.02.02-2017, стандарт устанавливает классификацию несоответствий как для продукции, поставляемой непосредственно на ОИАЭ, так и для продукции, используемой в качестве комплектующего изделия при изготовлении продукции, поставляемой на ОИАЭ.',
19
+ 'document_name': 'ГОСТ Р 50.02.02-2017',
20
+ 'section': '1.1 Область применения',
21
+ 'question_type': 'Проверка корректности и правильности данных'
22
+ },
23
+ {
24
+ 'question': 'Найдите в документации определение термина "испытания" и объясните, в каких случаях этот термин используется в контексте оценки соответствия в области использования атомной энергии.',
25
+ 'answer': 'Термин "испытания" (испытание) определен в пункте 13 ГОСТ Р 50.02.01-2017 как "экспериментальное определение количественных и/или качественных характеристик свойств продукции (процесса)". В контексте этого стандарта, испытания являются одной из форм оценки соответствия продукции.',
26
+ 'document_name': 'ГОСТ Р 50.02.01-2017',
27
+ 'section': '2. Термины и определения, пункт 13',
28
+ 'question_type': 'Поиск конкретного документа и пункта по запросу'
29
+ },
30
+ {
31
+ 'question': 'Объясните, какие действия необходимо предпринять, если вы обнаружили, что стандарт ГОСТ Р 50.01.01-2017 был пересмотрен, заменен или отменен.',
32
+ 'answer': 'Согласно ГОСТ Р 50.01.01-2017, в случае пересмотра (замены) или отмены стандарта, соответствующее уведомление будет опубликовано в ближайшем выпуске ежемесячного информационного указателя "Национальные стандарты". Соответствующая информация, уведомление и тексты также размещаются в информационной системе общего пользования на официальном сайте Федерального агентства по техническому регулированию и метрологии в сети Интернет (www.gost.ru).',
33
+ 'document_name': 'ГОСТ Р 50.01.01-2017',
34
+ 'section': 'Предисловие, пункт 5',
35
+ 'question_type': 'Составление плана действий согласно документации'
36
+ }
37
+ ]
38
+
39
+ questions_for_rag_2 = [
40
+ {
41
+ 'question': 'Проверка корректности и правильности данных: В соответствии с ГОСТ Р 50.05.23-2020, какие требования предъявляются к визуальному и измерительному контролю сварных соединений и наплавленных поверхностей? Расскажите подробно о допустимых дефектах и их классификации, а также о методах их оценки.',
42
+ 'answer': 'В соответствии с ГОСТ Р 50.05.23-2020, визуальный и измерительный контроль проводится для выявления поверхностных дефектов, таких как трещины, поры, прожоги, несплавления. Дефекты оцениваются на основе их размеров, количества и расположения, а также с учетом класса качества. Стандарт устанавливает нормы оценки качества для различных видов дефектов, например, допустимые размеры пор и включений в зависимости от толщины металла и категории сварного соединения.',
43
+ 'document_name': 'ГОСТ Р 50.05.23-2020',
44
+ 'section': '5.2 Оценка качества при визуальном и измерительном контроле',
45
+ 'question_type': 'Проверка корректности и правильности данных'
46
+ },
47
+ {
48
+ 'question': 'Составление плана действий согласно документации: На основе ГОСТ Р 50.08.06-2017, опишите последовательность действий и ключевые критерии, которые необходимо учитывать при внесении предложения о включении новой продукции в перечень продукции, подлежащей обязательной сертификации в области использования атомной энергии. Какие документы нужно подготовить и какие аргументы предоставить?',
49
+ 'answer': 'Согласно ГОСТ Р 50.08.06-2017, при внесении предложения о включении продукции в перечень необходимо: 1) заполнить таблицу по установленной форме; 2) указать наименование продукции и код классификатора; 3) изложить аргументы в пользу предложения, обосновать соответствие продукции основным критериям, установленным в стандарте, и привести информацию об ожидаемых результатах и рисках. Ключевые критерии включают в себя степень влияния продукции на безопасность, уникальность и сложность конструкции, а также возможность оценки соответствия другими способами.',
50
+ 'document_name': 'ГОСТ Р 50.08.06-2017',
51
+ 'section': '6. Порядок разработки и ведения перечня продукции',
52
+ 'question_type': 'Составление плана действий согласно документации'
53
+ },
54
+ {
55
+ 'question': 'Краткое саммари какого-то пункта или раздела из документации: Объясните, как, согласно МУ 1.1.4.01.1422-2019, проводятся испытания на вибростойкость и вибропрочность трубопроводной арматуры, применяемой на АЭС. Какие требования предъявляются к этим испытаниям и что они должны подтверждать?',
56
+ 'answer': 'Согласно МУ 1.1.4.01.1422-2019, испытания на вибростойкость и вибропрочность трубопроводной арматуры проводятся для подтверждения ее способности сохранять работоспособность и целостность при воздействии вибрационных нагрузок, характерных для условий эксплуатации на АЭС. Испытания проводятся на специальном оборудовании, с заданными параметрами вибрации (частота, амплитуда) и должны подтверждать соответствие арматуры требованиям, установленным в техническом задании и/или исходных технических требованиях.',
57
+ 'document_name': 'МУ 1.1.4.01.1422-2019',
58
+ 'section': '1.2 Область применения и общие положения',
59
+ 'question_type': 'Краткое саммари какого-то пункта или раздела из документации'
60
+ },
61
+ {
62
+ 'question': 'Проверка корректности и правильности данных: Проверьте правильность утверждения: "Стоимость обязательной сертификации продукции, согласно ГОСТ Р 50.08.07-2017, зависит только от трудозатрат органа по сертификации и стоимости лабораторных испытаний. Коэффициенты сложности и количества единиц продукции не учитываются." Обоснуйте свой ответ, ссылаясь на положения стандарта.',
63
+ 'answer': 'Утверждение неверно. Согласно ГОСТ Р 50.08.07-2017, стоимость обязательной сертификации определяется по формуле, которая включает в себя не только трудозатраты и стоимость испытаний, но и коэффициенты сложности продукции (Ксп), количества единиц продукции (Кко) и другие поправочные коэффициенты, учитывающие специфику продукции и условия проведения работ.',
64
+ 'document_name': 'ГОСТ Р 50.08.07-2017',
65
+ 'section': '5. Порядок определения стоимости работ по обязательной сертификации продукции и инспекционному контролю',
66
+ 'question_type': 'Проверка корректности и правильности данных'
67
+ },
68
+ {
69
+ 'question': 'Составление плана действий согласно документации: На основе ГОСТ Р 50.05.23-2020, опишите полный процесс оценки качества сварных соединений и наплавленных поверхностей при радиографическом контроле. Какие основные шаги необходимо выполнить, какие дефекты выявляются и какие критерии используются для оценки их допустимости?',
70
+ 'answer': 'Согласно ГОСТ Р 50.05.23-2020, радиографический контроль проводится для выявления объемных и плоскостных внутренних дефектов, таких как поры, шлаковые включения, непровары, трещины. Процесс включает: 1) подготовку объекта контроля; 2) выбор режима съемки; 3) экспонирование; 4) обработку и расшифровку снимков. Оценка качества проводится по нормам, установленным в стандарте, с учетом чувствительности контроля, класса качества сварного соединения и типа дефектов. При обнаружении дефектов их размеры и количество сравниваются с допустимыми значениями, указанными в таблицах стандарта.',
71
+ 'document_name': 'ГОСТ Р 50.05.23-2020',
72
+ 'section': '5.7 Оценка качества при радиографическом контроле',
73
+ 'question_type': 'Составление плана действий согласно документации'
74
+ }
75
+ ]
requirements.txt ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ gradio
2
+ faiss-cpu
3
+ sentence-transformers
4
+ google-generativeai
5
+ huggingface_hub
6
+ llama-index
7
+ llama-index-core
8
+ llama-index-embeddings-huggingface
9
+ llama-index-llms-google-genai
10
+ llama-index-vector-stores-faiss
11
+ PyMuPDF
12
+ PyPDF2
13
+ python-docx
14
+ openpyxl