Spaces:
Sleeping
Sleeping
File size: 12,225 Bytes
c9db278 654b449 aa622c0 c9db278 1eaf3d8 c9db278 1b98e0e c9db278 a50849a aa622c0 a50849a 1b98e0e c9db278 aa622c0 a50849a 1eaf3d8 a50849a 1eaf3d8 a50849a 1eaf3d8 a50849a 1eaf3d8 a50849a 1eaf3d8 c9db278 1eaf3d8 c9db278 654b449 648d16e 654b449 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 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 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 |
import os
import google.generativeai as genai
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
from llama_index.llms.google_genai import GoogleGenAI
from llama_index.core import Settings
from llama_index.core.llms import ChatMessage, MessageRole
import os
from huggingface_hub import hf_hub_download
# Configuration
EMBEDDING_MODEL = "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2"
RETRIEVER_TOP_K = 10
RETRIEVER_SIMILARITY_CUTOFF = 0.7
RAG_FILES_DIR = "processed_data"
PROCESSED_DATA_FILE = "processed_data/processed_chunks.csv"
UPLOAD_FOLDER = "UPLOADED_DOCUMENTS"
INDEX_STATE_FILE = "processed_data/index_store.json"
GOOGLE_API_KEY = os.getenv('GOOGLE_API_KEY', "AIzaSyDemsCp7JIdRNDRyP6DkYdMox1DLZwPcPE")
HF_REPO_ID = "MrSimple01/AIEXP_RAG_FILES"
HF_TOKEN = os.getenv('HF_TOKEN')
LLM_MODEL = "gemini-2.0-flash"
CHUNK_SIZE = 1024
CHUNK_OVERLAP = 256
MAX_CHUNK_SIZE = 2048
MIN_CHUNK_SIZE = 750
SIMILARITY_THRESHOLD = 0.7
def download_pretrained_files():
"""Download pre-trained RAG files from HuggingFace Hub"""
try:
print("Downloading pre-trained RAG files from HuggingFace Hub...")
# Files to download
files_to_download = [
"faiss_index.index",
"processed_chunks.csv",
"chunk_metadata.pkl",
"config.pkl",
"documents.pkl",
"default__vector_store.json",
"docstore.json",
"index_store.json"
]
# Ensure RAG_FILES_DIR exists
os.makedirs(RAG_FILES_DIR, exist_ok=True)
os.makedirs("processed_data", exist_ok=True)
downloaded_files = {}
for filename in files_to_download:
try:
print(f"Downloading {filename}...")
# Download to RAG_FILES_DIR for most files, processed_data for CSV
target_dir = "processed_data" if filename == "processed_chunks.csv" else RAG_FILES_DIR
file_path = hf_hub_download(
repo_id=HF_REPO_ID,
filename=filename,
local_dir=target_dir,
repo_type="dataset",
token=HF_TOKEN
)
downloaded_files[filename] = file_path
print(f"✓ Downloaded {filename}")
except Exception as e:
print(f"✗ Failed to download {filename}: {e}")
continue
# Verify critical files
critical_files = ["faiss_index.index", "processed_chunks.csv"]
missing_critical = [f for f in critical_files if f not in downloaded_files]
if missing_critical:
print(f"❌ Missing critical files: {missing_critical}")
return False
print(f"✅ Successfully downloaded {len(downloaded_files)}/{len(files_to_download)} files")
return True
except Exception as e:
print(f"❌ Failed to download pre-trained files: {e}")
return False
def setup_llm_settings():
"""Setup embedding and LLM models"""
# Configure Google API
if GOOGLE_API_KEY:
genai.configure(api_key=GOOGLE_API_KEY)
# Set embedding model
embed_model = HuggingFaceEmbedding(model_name=EMBEDDING_MODEL)
Settings.embed_model = embed_model
# Set LLM - IMPORTANT: This prevents OpenAI default
if GOOGLE_API_KEY:
try:
llm = GoogleGenAI(model=LLM_MODEL, api_key=GOOGLE_API_KEY)
Settings.llm = llm
print("Google GenAI LLM initialized successfully")
except Exception as e:
print(f"Warning: Could not initialize Google GenAI LLM: {e}")
# Set a dummy LLM to prevent OpenAI default
from llama_index.core.llms.mock import MockLLM
Settings.llm = MockLLM()
else:
print("Warning: GOOGLE_API_KEY not found. Using MockLLM.")
from llama_index.core.llms.mock import MockLLM
Settings.llm = MockLLM()
CUSTOM_PROMPT = """
Вы являетесь высокоспециализированным Ассистентом для анализа документов (AIEXP). Ваша цель - предоставлять точные, корректные и контекстно релевантные ответы на основе анализа нормативной документации (НД). Все ваши ответы должны основываться исключительно на предоставленном контексте без использования внешних знаний или предположений.
ОПРЕДЕЛЕНИЕ ТИПА ЗАДАЧИ:
Проанализируйте запрос пользователя и определите тип задачи:
1. КРАТКОЕ САММАРИ (ключевые слова: "кратко", "суммировать", "резюме", "основные моменты", "в двух словах"):
- Предоставьте структурированное резюме запрашиваемого раздела/пункта
- Выделите ключевые требования, процедуры или положения
- Используйте нумерованный список для лучшей читаемости
- Сохраняйте терминологию НД
2. ПОИСК ДОКУМЕНТА И ПУНКТА (ключевые слова: "найти", "где", "какой документ", "в каком разделе", "ссылка"):
- Укажите конкретный документ и его структурное расположение
- Предоставьте точные номера разделов/подразделов/пунктов
- Процитируйте релевантные фрагменты
- Если найдено несколько документов, перечислите все с указанием специфики каждого
3. ПРОВЕРКА КОРРЕКТНОСТИ (ключевые слова: "правильно ли", "соответствует ли", "проверить", "корректно", "нарушение"):
- Сопоставьте предоставленную информацию с требованиями НД
- Четко укажите: "СООТВЕТСТВУЕТ" или "НЕ СООТВЕТСТВУЕТ"
- Перечислите конкретные требования НД
- Укажите выявленные расхождения или подтвердите соответствие
- Процитируйте релевантные пункты НД
4. ПЛАН ДЕЙСТВИЙ (ключевые слова: "план", "алгоритм", "последовательность", "как действовать", "пошагово"):
- Создайте пронумерованный пошаговый план
- Каждый шаг должен содержать ссылку на соответствующий пункт НД
- Укажите необходимые документы или формы
- Добавьте временные рамки, если они указаны в НД
- Выделите критические требования или ограничения
ПРАВИЛА ФОРМИРОВАНИЯ ОТВЕТОВ:
1. ОБЯЗАТЕЛЬНОЕ УКАЗАНИЕ ИСТОЧНИКОВ:
- Для контента из конкретного раздела/подраздела:
"Согласно разделу [X] и подразделу [X.X]: [Ваш ответ]"
- Для контента вне подразделов (таблицы, рисунки, общие разделы):
"Согласно [Название документа] - [Номер и наименование пункта/таблицы/рисунка]: [Ваш ответ]"
- При наличии метаданных о разделе и подразделе - включайте оба
- При наличии только раздела: "Согласно разделу [X]: [Ваш ответ]"
2. СТРОГОЕ СЛЕДОВАНИЕ КОНТЕКСТУ:
- Если информация не найдена: "Информация по вашему запросу не была найдена в нормативной документации."
- Не делайте предположений или выводов за пределами предоставленного контекста
- Не используйте общие знания
3. ИСПОЛЬЗОВАНИЕ ТЕРМИНОЛОГИИ НД:
- Применяйте официальную терминологию из документов
- Сохраняйте оригинальные формулировки ключевых требований
- При необходимости разъясняйте специальные термины на основе НД
4. СТРУКТУРИРОВАНИЕ ОТВЕТОВ:
- Для саммари: используйте маркированные или нумерованные списки
- Для проверки: четкая структура "Требование → Соответствие/Несоответствие"
- Для планов: пронумерованные шаги с подзадачами при необходимости
- Для поиска: указание иерархии документа
5. ДОПОЛНИТЕЛЬНЫЕ РЕКОМЕНДАЦИИ:
- При множественных релевантных источниках - укажите все
- Выделяйте критически важные требования
- Указывайте альтернативные процедуры, если они предусмотрены НД
Контекст: {context_str}
Вопрос: {query_str}
Ответ:
"""
LLM_MODEL_PREPROCESS = "gemini-1.5-flash"
def preprocess_query_with_context(user_query, chat_history=None, llm=None):
if not chat_history:
return user_query
if not llm:
llm = GoogleGenAI(model=LLM_MODEL_PREPROCESS, temperature=0.1)
# Format chat history into a string for the prompt
history_context = "\n".join([
f"User: {item['user']}\nAssistant: {item['assistant']}"
for item in chat_history[-3:] # Consider only the last 3 exchanges for conciseness
])
preprocessing_prompt = f"""Analyze the user's current question in the context of their chat history and improve it for better document retrieval.
Chat History:
{history_context}
Current Question: {user_query}
Tasks:
1. If the question refers to previous context, make it self-contained.
2. Add relevant keywords that would help find documents.
3. Maintain the legal/regulatory focus.
4. Keep it concise but specific.
Return ONLY the improved question:
"""
try:
messages = [ChatMessage(role=MessageRole.USER, content=preprocessing_prompt)]
response = llm.chat(messages)
improved_query = response.message.content.strip()
# Fallback to the original query if the preprocessing fails or provides an overly long response
if len(improved_query) > len(user_query) * 3 or not improved_query:
return user_query
return improved_query
except Exception as e:
print(f"Query preprocessing failed: {e}")
return user_query
def create_chat_context_prompt(base_response, chat_history=None):
if not chat_history:
return base_response
base_aware_response = base_response
if len(chat_history) > 0:
last_exchange = chat_history[-1]
if any(keyword in last_exchange['user'].lower() for keyword in ['закон', 'кодекс', 'статья']):
# Add a conversational prefix
base_aware_response = f"Продолжая тему нормативных документов: {base_response}"
return base_aware_response
|