Spaces:
Runtime error
Runtime error
Commit
·
8bbebf1
1
Parent(s):
eade13f
Update Dockerfile and app.py
Browse files- Dockerfile +6 -6
- app.py +23 -58
Dockerfile
CHANGED
|
@@ -2,9 +2,6 @@ FROM python:3.11-slim
|
|
| 2 |
|
| 3 |
WORKDIR /app
|
| 4 |
|
| 5 |
-
# Установка системных зависимостей, если нужно
|
| 6 |
-
RUN apt-get update && apt-get install -y git gcc && rm -rf /var/lib/apt/lists/*
|
| 7 |
-
|
| 8 |
# Сначала копируем requirements.txt, чтобы использовать кэш
|
| 9 |
COPY requirements.txt .
|
| 10 |
|
|
@@ -13,9 +10,12 @@ RUN pip3 install --no-cache-dir -r requirements.txt
|
|
| 13 |
|
| 14 |
# === НОВЫЙ БЛОК: Загрузка моделей при сборке ===
|
| 15 |
# Загрузка модели и токенизатора transformers
|
| 16 |
-
RUN python -c "
|
| 17 |
-
|
| 18 |
-
|
|
|
|
|
|
|
|
|
|
| 19 |
|
| 20 |
# Копируем остальные файлы и делаем новую загрузку
|
| 21 |
COPY . .
|
|
|
|
| 2 |
|
| 3 |
WORKDIR /app
|
| 4 |
|
|
|
|
|
|
|
|
|
|
| 5 |
# Сначала копируем requirements.txt, чтобы использовать кэш
|
| 6 |
COPY requirements.txt .
|
| 7 |
|
|
|
|
| 10 |
|
| 11 |
# === НОВЫЙ БЛОК: Загрузка моделей при сборке ===
|
| 12 |
# Загрузка модели и токенизатора transformers
|
| 13 |
+
RUN python -c "import spacy; spacy.cli.download('ru_core_news_lg')"
|
| 14 |
+
RUN python -c "import nltk; nltk.download('punkt_tab', download_dir='/usr/local/share/nltk_data')"
|
| 15 |
+
RUN python -c "import nltk; nltk.download('stopwords')"
|
| 16 |
+
|
| 17 |
+
# --- НОВАЯ СТРОКА: Загрузка модели spaCy ---
|
| 18 |
+
# Убедитесь, что `ru_core_news_lg` доступна в образе при сборке
|
| 19 |
|
| 20 |
# Копируем остальные файлы и делаем новую загрузку
|
| 21 |
COPY . .
|
app.py
CHANGED
|
@@ -19,74 +19,40 @@ from bs4 import BeautifulSoup
|
|
| 19 |
@st.cache_resource
|
| 20 |
def load_data():
|
| 21 |
# Загрузка датасета
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
data = load_dataset('Romyx/ru_QA_school_history', split='train')
|
| 25 |
-
df = pd.DataFrame(data)
|
| 26 |
-
st.success("Датасет загружен.")
|
| 27 |
-
except Exception as e:
|
| 28 |
-
st.error(f"Ошибка загрузки датасета: {e}")
|
| 29 |
-
raise e # Прерывает выполнение, если датасет не загрузился
|
| 30 |
-
|
| 31 |
-
# Предобработка сразу после загрузки
|
| 32 |
df['Pt_question'] = df['question'].apply(preprocess_text)
|
| 33 |
df['Pt_answer'] = df['answer'].apply(preprocess_text)
|
| 34 |
return df
|
| 35 |
|
| 36 |
@st.cache_resource
|
| 37 |
def load_model_and_tokenizer():
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
model = AutoModelForQuestionAnswering.from_pretrained(model_name)
|
| 44 |
-
st.success("Модель вопрос-ответа загружена.")
|
| 45 |
-
except Exception as e:
|
| 46 |
-
st.error(f"Ошибка загрузки модели вопрос-ответа: {e}")
|
| 47 |
-
raise e
|
| 48 |
return tokenizer, model
|
| 49 |
|
| 50 |
@st.cache_resource
|
| 51 |
def build_vectorizer(_df):
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
vectorizer = TfidfVectorizer()
|
| 56 |
-
tfidf_matrix = vectorizer.fit_transform(combined_texts)
|
| 57 |
-
st.success("TF-IDF векторайзер обучен.")
|
| 58 |
-
except Exception as e:
|
| 59 |
-
st.error(f"Ошибка обучения TF-IDF: {e}")
|
| 60 |
-
raise e
|
| 61 |
return vectorizer, tfidf_matrix
|
| 62 |
|
| 63 |
# === Предобработка текста ===
|
| 64 |
|
| 65 |
-
# Загрузка Spacy модели
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
st.info("Загрузка SpaCy модели...")
|
| 70 |
-
try:
|
| 71 |
-
# Убедитесь, что это имя совпадает с моделью, загруженной в Dockerfile
|
| 72 |
-
nlp = spacy.load('ru_core_news_lg')
|
| 73 |
-
st.success("SpaCy модель загружена.")
|
| 74 |
-
except OSError as e:
|
| 75 |
-
st.error(f"SpaCy модель 'ru_core_news_lg' не найдена. Проверьте Dockerfile: {e}")
|
| 76 |
-
raise e
|
| 77 |
-
return nlp
|
| 78 |
-
|
| 79 |
-
# Функция для получения нормальной формы слова
|
| 80 |
-
# Используем кэш внутри функции для избежания повторных вызовов spaCy
|
| 81 |
-
# Но для кэширования результатов между вызовами функции можно использовать кэш Streamlit или обычный словарь
|
| 82 |
-
# Для простоты, кэшируем в обычном словаре, но помните, что это не персистентный кэш между перезапусками
|
| 83 |
cache_dict = {}
|
| 84 |
|
| 85 |
-
def get_norm_form(
|
| 86 |
if word in cache_dict:
|
| 87 |
return cache_dict[word]
|
| 88 |
-
|
| 89 |
-
norm_form = nlp_model(word)[0].lemma_
|
| 90 |
cache_dict[word] = norm_form
|
| 91 |
return norm_form
|
| 92 |
|
|
@@ -110,12 +76,8 @@ def preprocess_text(text):
|
|
| 110 |
text = re.sub(r'[^\w\s]', '', text)
|
| 111 |
|
| 112 |
tokens = word_tokenize(text)
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
tokens = [token for token in tokens if token not in stop_words_set]
|
| 116 |
-
# Загружаем nlp модель из кэша Streamlit
|
| 117 |
-
nlp_model = load_spacy_model()
|
| 118 |
-
tokens = [get_norm_form(nlp_model, token) for token in tokens]
|
| 119 |
|
| 120 |
words_to_remove = {"ответ", "new"}
|
| 121 |
tokens = [token for token in tokens if token not in words_to_remove]
|
|
@@ -123,6 +85,8 @@ def preprocess_text(text):
|
|
| 123 |
return ' '.join(tokens)
|
| 124 |
|
| 125 |
|
|
|
|
|
|
|
| 126 |
# === Основная функция получения ответа ===
|
| 127 |
def get_answer_from_qa_model(user_question, df, vectorizer, tfidf_matrix, model, tokenizer):
|
| 128 |
processed = preprocess_text(user_question)
|
|
@@ -132,7 +96,7 @@ def get_answer_from_qa_model(user_question, df, vectorizer, tfidf_matrix, model,
|
|
| 132 |
|
| 133 |
# Проверка, что similarities не пустой
|
| 134 |
if len(similarities) == 0:
|
| 135 |
-
return "
|
| 136 |
|
| 137 |
best_match_idx = similarities.argmax()
|
| 138 |
best_score = similarities[best_match_idx]
|
|
@@ -140,7 +104,7 @@ def get_answer_from_qa_model(user_question, df, vectorizer, tfidf_matrix, model,
|
|
| 140 |
if best_score > 0.1:
|
| 141 |
# Проверка, что индекс не выходит за границы
|
| 142 |
if best_match_idx >= len(df):
|
| 143 |
-
return "
|
| 144 |
|
| 145 |
context = df.iloc[best_match_idx]['answer']
|
| 146 |
question = user_question
|
|
@@ -172,6 +136,7 @@ def get_answer_from_qa_model(user_question, df, vectorizer, tfidf_matrix, model,
|
|
| 172 |
|
| 173 |
return answer
|
| 174 |
|
|
|
|
| 175 |
# === Интерфейс Streamlit ===
|
| 176 |
|
| 177 |
def main():
|
|
|
|
| 19 |
@st.cache_resource
|
| 20 |
def load_data():
|
| 21 |
# Загрузка датасета
|
| 22 |
+
data = load_dataset('Romyx/ru_QA_school_history', split='train')
|
| 23 |
+
df = pd.DataFrame(data)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
df['Pt_question'] = df['question'].apply(preprocess_text)
|
| 25 |
df['Pt_answer'] = df['answer'].apply(preprocess_text)
|
| 26 |
return df
|
| 27 |
|
| 28 |
@st.cache_resource
|
| 29 |
def load_model_and_tokenizer():
|
| 30 |
+
# Загрузка предобученной модели вопрос-ответа (например, SberQuad)
|
| 31 |
+
model_name = "AlexKay/xlm-roberta-large-qa-multilingual-finedtuned-ru"
|
| 32 |
+
# замените на нужную модель, например, "bert-base-uncased"
|
| 33 |
+
tokenizer = AutoTokenizer.from_pretrained(model_name)
|
| 34 |
+
model = AutoModelForQuestionAnswering.from_pretrained(model_name)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
return tokenizer, model
|
| 36 |
|
| 37 |
@st.cache_resource
|
| 38 |
def build_vectorizer(_df):
|
| 39 |
+
combined_texts = _df['Pt_question'].tolist() + _df['Pt_answer'].tolist()
|
| 40 |
+
vectorizer = TfidfVectorizer()
|
| 41 |
+
tfidf_matrix = vectorizer.fit_transform(combined_texts)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
return vectorizer, tfidf_matrix
|
| 43 |
|
| 44 |
# === Предобработка текста ===
|
| 45 |
|
| 46 |
+
# Загрузка Spacy модели
|
| 47 |
+
nlp = spacy.load('ru_core_news_lg')
|
| 48 |
+
stop_words = set(stopwords.words('russian'))
|
| 49 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
cache_dict = {}
|
| 51 |
|
| 52 |
+
def get_norm_form(word):
|
| 53 |
if word in cache_dict:
|
| 54 |
return cache_dict[word]
|
| 55 |
+
norm_form = nlp(word)[0].lemma_
|
|
|
|
| 56 |
cache_dict[word] = norm_form
|
| 57 |
return norm_form
|
| 58 |
|
|
|
|
| 76 |
text = re.sub(r'[^\w\s]', '', text)
|
| 77 |
|
| 78 |
tokens = word_tokenize(text)
|
| 79 |
+
tokens = [token for token in tokens if token not in stop_words]
|
| 80 |
+
tokens = [get_norm_form(token) for token in tokens]
|
|
|
|
|
|
|
|
|
|
|
|
|
| 81 |
|
| 82 |
words_to_remove = {"ответ", "new"}
|
| 83 |
tokens = [token for token in tokens if token not in words_to_remove]
|
|
|
|
| 85 |
return ' '.join(tokens)
|
| 86 |
|
| 87 |
|
| 88 |
+
|
| 89 |
+
|
| 90 |
# === Основная функция получения ответа ===
|
| 91 |
def get_answer_from_qa_model(user_question, df, vectorizer, tfidf_matrix, model, tokenizer):
|
| 92 |
processed = preprocess_text(user_question)
|
|
|
|
| 96 |
|
| 97 |
# Проверка, что similarities не пустой
|
| 98 |
if len(similarities) == 0:
|
| 99 |
+
return "Датасет пуст или не загружен корректно."
|
| 100 |
|
| 101 |
best_match_idx = similarities.argmax()
|
| 102 |
best_score = similarities[best_match_idx]
|
|
|
|
| 104 |
if best_score > 0.1:
|
| 105 |
# Проверка, что индекс не выходит за границы
|
| 106 |
if best_match_idx >= len(df):
|
| 107 |
+
return "Ошибка: индекс вне диапазона."
|
| 108 |
|
| 109 |
context = df.iloc[best_match_idx]['answer']
|
| 110 |
question = user_question
|
|
|
|
| 136 |
|
| 137 |
return answer
|
| 138 |
|
| 139 |
+
|
| 140 |
# === Интерфейс Streamlit ===
|
| 141 |
|
| 142 |
def main():
|