Bjg6742635 commited on
Commit
8bbebf1
·
1 Parent(s): eade13f

Update Dockerfile and app.py

Browse files
Files changed (2) hide show
  1. Dockerfile +6 -6
  2. 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 "from transformers import AutoTokenizer, AutoModelForQuestionAnswering; \
17
- AutoTokenizer.from_pretrained('AlexKay/xlm-roberta-large-qa-multilingual-finedtuned-ru'); \
18
- AutoModelForQuestionAnswering.from_pretrained('AlexKay/xlm-roberta-large-qa-multilingual-finedtuned-ru')"
 
 
 
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
- st.info("Загрузка датасета...")
23
- try:
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
- st.info("Загрузка модели вопрос-ответа...")
39
- try:
40
- # Убедитесь, что это имя совпадает с именем модели, загруженной в Dockerfile
41
- model_name = "AlexKay/xlm-roberta-large-qa-multilingual-finedtuned-ru"
42
- tokenizer = AutoTokenizer.from_pretrained(model_name)
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
- st.info("Обучение TF-IDF векторайзера...")
53
- try:
54
- combined_texts = _df['Pt_question'].tolist() + _df['Pt_answer'].tolist()
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 модели при запуске скрипта (не внутри @st.cache_resource, если она в образе)
66
- # Используем @st.cache_resource для загрузки nlp модели, чтобы она кэшировалась
67
- @st.cache_resource
68
- def load_spacy_model():
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(nlp_model, word): # Передаём nlp_model как аргумент
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
- # stop_words загружается при старте
114
- stop_words_set = set(stopwords.words('russian'))
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():