opex792 commited on
Commit
496ca18
·
verified ·
1 Parent(s): 429c3b2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +174 -109
app.py CHANGED
@@ -7,15 +7,19 @@ import threading
7
  import queue
8
  import torch
9
 
10
- # Загружаем модель
11
- model_name = "HIT-TMG/KaLM-embedding-multilingual-mini-instruct-v1.5"
12
- model = SentenceTransformer(model_name)
13
- # model.max_seq_length = 8192 # Убираем явное ограничение длины последовательности
14
 
15
- # Имя файла для сохранения эмбеддингов
16
- embeddings_file = f"movie_embeddings_{model_name.replace('/', '_')}.json"
17
- # Имя файла для сохранения эмбеддингов запросов
18
- query_embeddings_file = f"query_embeddings_{model_name.replace('/', '_')}.json"
 
 
 
 
 
19
 
20
  # Загружаем данные из файла movies.json
21
  try:
@@ -25,94 +29,125 @@ except FileNotFoundError:
25
  print("Ошибка: Файл movies.json не найден.")
26
  movies_data = []
27
 
28
- # Загружаем эмбеддинги фильмов
29
- if os.path.exists(embeddings_file):
30
- with open(embeddings_file, "r", encoding="utf-8") as f:
31
- movie_embeddings = json.load(f)
32
- print("Загружены эмбеддинги фильмов из файла.")
 
 
 
 
 
 
 
 
33
  else:
34
- movie_embeddings = {}
35
 
36
- # Загружаем эмбеддинги запросов
37
- if os.path.exists(query_embeddings_file):
38
- with open(query_embeddings_file, "r", encoding="utf-8") as f:
39
- query_embeddings = json.load(f)
40
- print("Загружены эмбеддинги запросов из файла.")
41
  else:
42
- query_embeddings = {}
 
 
 
 
 
 
 
 
 
 
 
 
43
 
44
- # Очередь для необработанных фильмов
45
- movies_queue = queue.Queue()
46
  for movie in movies_data:
47
- if movie["name"] not in movie_embeddings:
48
- movies_queue.put(movie)
 
 
 
 
 
 
49
 
50
- # Флаг, указывающий, что обработка фильмов завершена
51
- processing_complete = False
52
- # Флаг, указывающий, что выполняется поиск
53
- search_in_progress = False
54
 
55
- # Блокировка для доступа к movie_embeddings
56
- movie_embeddings_lock = threading.Lock()
 
57
 
58
  # Размер пакета для обработки эмбеддингов
59
- batch_size = 32 # Увел��чиваем размер пакета в 2 раза
60
 
61
- # Инструкция для запроса
62
- query_prompt = "Инструкция: Найди релевантные фильмы по запросу. \n Запрос: "
63
 
64
- def encode_string(text, prompt=None):
65
  """Кодирует строку в эмбеддинг с использованием инструкции, если она задана."""
66
  if prompt:
67
- return model.encode(text, prompt=prompt, convert_to_tensor=True, normalize_embeddings=True)
68
  else:
69
- return model.encode(text, convert_to_tensor=True, normalize_embeddings=True)
70
 
71
- def process_movies():
72
  """
73
  Обрабатывает фильмы из очереди, создавая для них эмбеддинги.
74
  """
75
- global processing_complete
76
  while True:
77
- if search_in_progress:
78
- time.sleep(1) # Ждем, пока поиск не завершится
79
- continue
80
-
81
- batch = []
82
- while not movies_queue.empty() and len(batch) < batch_size:
83
- try:
84
- movie = movies_queue.get(timeout=1)
85
- batch.append(movie)
86
- except queue.Empty:
87
- break
88
-
89
- if not batch:
90
- print("Очередь фильмов пуста.")
91
- processing_complete = True
92
- break
93
-
94
- titles = [movie["name"] for movie in batch]
95
- embedding_strings = [
96
- f"Название: {movie['name']}\nГод: {movie['year']}\nЖанры: {movie['genresList']}\nОписание: {movie['description']}"
97
- for movie in batch
98
- ]
99
-
100
- print(f"Создаются эмбеддинги для фильмов: {', '.join(titles)}...")
101
- embeddings = model.encode(embedding_strings, convert_to_tensor=True, batch_size=batch_size, normalize_embeddings=True).tolist()
102
-
103
- with movie_embeddings_lock:
104
- for title, embedding in zip(titles, embeddings):
105
- movie_embeddings[title] = embedding
106
- # Сохраняем эмбеддинги в файл после обработки каждого пакета
107
- with open(embeddings_file, "w", encoding="utf-8") as f:
108
- json.dump(movie_embeddings, f, ensure_ascii=False, indent=4)
109
- print(f"Эмбеддинги для фильмов: {', '.join(titles)} созданы и сохранены.")
110
-
111
- print("Обработка фильмов завершена.")
112
-
113
- def get_query_embedding(query):
 
 
 
 
 
 
 
 
114
  """
115
- Возвращает эмбеддинг для запроса с инструкцией.
116
  Если эмбеддинг уже создан, возвращает его из словаря.
117
  Иначе создает эмбеддинг, сохраняет его и возвращает.
118
  """
@@ -121,7 +156,7 @@ def get_query_embedding(query):
121
  return query_embeddings[query]
122
  else:
123
  print(f"Создается эмбеддинг для запроса '{query}'...")
124
- embedding = encode_string(query, prompt=query_prompt).tolist()
125
  query_embeddings[query] = embedding
126
  # Сохраняем эмбеддинги запросов в файл
127
  with open(query_embeddings_file, "w", encoding="utf-8") as f:
@@ -129,32 +164,53 @@ def get_query_embedding(query):
129
  print(f"Эмбеддинг для запроса '{query}' создан и сохранен.")
130
  return embedding
131
 
132
- def search_movies(query, top_k=10):
133
  """
134
  Ищет наиболее похожие фильмы по запросу с использованием инструкции.
135
 
136
  Args:
137
  query: Текстовый запрос.
 
 
 
138
  top_k: Количество возвращаемых результатов.
 
139
 
140
  Returns:
141
  Строку с результатами поиска в формате HTML.
142
  """
143
- global search_in_progress
144
- search_in_progress = True
 
 
 
 
 
145
  start_time = time.time()
146
  print(f"\n\033[1mПоиск по запросу: '{query}'\033[0m")
147
 
148
  print(f"Начало создания эмбеддинга для запроса: {time.strftime('%Y-%m-%d %H:%M:%S')}")
149
- query_embedding_tensor = encode_string(query, prompt=query_prompt)
 
 
 
 
150
  print(f"Окончание создания эмбеддинга для запроса: {time.strftime('%Y-%m-%d %H:%M:%S')}")
151
 
152
- with movie_embeddings_lock:
153
- current_movie_embeddings = movie_embeddings.copy()
 
 
 
 
154
 
155
  if not current_movie_embeddings:
156
- search_in_progress = False
157
- return "<p>Пока что нет обработанных фильмов. Попробуйте позже.</p>"
 
 
 
 
158
 
159
  # Преобразуем эмбеддинги фильмов в тензор
160
  movie_titles = list(current_movie_embeddings.keys())
@@ -186,29 +242,38 @@ def search_movies(query, top_k=10):
186
  end_time = time.time()
187
  execution_time = end_time - start_time
188
  print(f"Поиск завершен за {execution_time:.4f} секунд.")
189
- search_in_progress = False
 
 
 
 
190
  return results_html
191
 
192
- # Поток для обработки фильмов
193
- processing_thread = threading.Thread(target=process_movies)
194
-
195
- # Создаем интерфейс Gradio
196
- iface = gr.Interface(
197
- fn=search_movies,
198
- inputs=gr.Textbox(label="Введите запрос:"),
199
- outputs=gr.HTML(label="Результаты п��иска:"),
200
- title="Поиск фильмов по описанию",
201
- description="Введите запрос, и система найдет наиболее похожие фильмы по их описаниям.",
202
- examples=[
203
- ["Фильм про ограбление"],
204
- ["Комедия 2019 года"],
205
- ["Фантастика про космос"],
206
- ],
207
- )
208
-
209
- # Запускаем поток для обработки фильмов
210
- processing_thread.start()
211
-
212
- # Запускаем приложение
213
- iface.queue()
214
- iface.launch()
 
 
 
 
 
 
7
  import queue
8
  import torch
9
 
10
+ # Загружаем модели
11
+ model_name_kalm = "HIT-TMG/KaLM-embedding-multilingual-mini-instruct-v1.5"
12
+ model_kalm = SentenceTransformer(model_name_kalm)
 
13
 
14
+ model_name_bge = "BAAI/bge-m3"
15
+ model_bge = SentenceTransformer(model_name_bge)
16
+
17
+ # Имена файлов для сохранения эмбеддингов
18
+ embeddings_file_kalm = f"movie_embeddings_{model_name_kalm.replace('/', '_')}.json"
19
+ query_embeddings_file_kalm = f"query_embeddings_{model_name_kalm.replace('/', '_')}.json"
20
+
21
+ embeddings_file_bge = f"movie_embeddings_{model_name_bge.replace('/', '_')}.json"
22
+ query_embeddings_file_bge = f"query_embeddings_{model_name_bge.replace('/', '_')}.json"
23
 
24
  # Загружаем данные из файла movies.json
25
  try:
 
29
  print("Ошибка: Файл movies.json не найден.")
30
  movies_data = []
31
 
32
+ # Загружаем эмбеддинги фильмов для KaLM
33
+ if os.path.exists(embeddings_file_kalm):
34
+ with open(embeddings_file_kalm, "r", encoding="utf-8") as f:
35
+ movie_embeddings_kalm = json.load(f)
36
+ print("Загружены эмбеддинги фильмов для KaLM из файла.")
37
+ else:
38
+ movie_embeddings_kalm = {}
39
+
40
+ # Загружаем эмбеддинги запросов для KaLM
41
+ if os.path.exists(query_embeddings_file_kalm):
42
+ with open(query_embeddings_file_kalm, "r", encoding="utf-8") as f:
43
+ query_embeddings_kalm = json.load(f)
44
+ print("Загружены эмбеддинги запросов для KaLM из файла.")
45
  else:
46
+ query_embeddings_kalm = {}
47
 
48
+ # Загружаем эмбеддинги фильмов для BGE-M3
49
+ if os.path.exists(embeddings_file_bge):
50
+ with open(embeddings_file_bge, "r", encoding="utf-8") as f:
51
+ movie_embeddings_bge = json.load(f)
52
+ print("Загружены эмбеддинги фильмов для BGE-M3 из файла.")
53
  else:
54
+ movie_embeddings_bge = {}
55
+
56
+ # Загружаем эмбеддинги запросов для BGE-M3
57
+ if os.path.exists(query_embeddings_file_bge):
58
+ with open(query_embeddings_file_bge, "r", encoding="utf-8") as f:
59
+ query_embeddings_bge = json.load(f)
60
+ print("Загружены эмбеддинги запросов для BGE-M3 из файла.")
61
+ else:
62
+ query_embeddings_bge = {}
63
+
64
+ # Очереди для необработанных фильмов
65
+ movies_queue_kalm = queue.Queue()
66
+ movies_queue_bge = queue.Queue()
67
 
 
 
68
  for movie in movies_data:
69
+ if movie["name"] not in movie_embeddings_kalm:
70
+ movies_queue_kalm.put(movie)
71
+ if movie["name"] not in movie_embeddings_bge:
72
+ movies_queue_bge.put(movie)
73
+
74
+ # Флаги, указывающие, что обработка фильмов завершена
75
+ processing_complete_kalm = False
76
+ processing_complete_bge = False
77
 
78
+ # Флаги, указывающие, что выполняется поиск
79
+ search_in_progress_kalm = False
80
+ search_in_progress_bge = False
 
81
 
82
+ # Блокировки для доступа к эмбеддингам
83
+ movie_embeddings_lock_kalm = threading.Lock()
84
+ movie_embeddings_lock_bge = threading.Lock()
85
 
86
  # Размер пакета для обработки эмбеддингов
87
+ batch_size = 32
88
 
89
+ # Инструкция для запроса KaLM
90
+ query_prompt_kalm = "Инструкция: Найди релевантные фильмы по запросу. \n Запрос: "
91
 
92
+ def encode_string(text, model, prompt=None):
93
  """Кодирует строку в эмбеддинг с использованием инструкции, если она задана."""
94
  if prompt:
95
+ return model.encode(text, prompt=prompt, convert_to_tensor=True, normalize_embeddings=True, batch_size=batch_size)
96
  else:
97
+ return model.encode(text, convert_to_tensor=True, normalize_embeddings=True, batch_size=batch_size)
98
 
99
+ def process_movies(model, embeddings_file, movie_embeddings, movies_queue, processing_complete_flag, lock, model_name):
100
  """
101
  Обрабатывает фильмы из очереди, создавая для них эмбеддинги.
102
  """
 
103
  while True:
104
+ if model_name == "HIT-TMG/KaLM-embedding-multilingual-mini-instruct-v1.5" and search_in_progress_kalm:
105
+ time.sleep(1) # Ждем, пока поиск не завершится
106
+ continue
107
+ elif model_name == "BAAI/bge-m3" and search_in_progress_bge:
108
+ time.sleep(1) # Ждем, пока поиск не завершится
109
+ continue
110
+
111
+ batch = []
112
+ while not movies_queue.empty() and len(batch) < batch_size:
113
+ try:
114
+ movie = movies_queue.get(timeout=1)
115
+ batch.append(movie)
116
+ except queue.Empty:
117
+ break
118
+
119
+ if not batch:
120
+ print(f"Очередь фильмов для {model_name} пуста.")
121
+ if model_name == "HIT-TMG/KaLM-embedding-multilingual-mini-instruct-v1.5":
122
+ global processing_complete_kalm
123
+ processing_complete_kalm = True
124
+ elif model_name == "BAAI/bge-m3":
125
+ global processing_complete_bge
126
+ processing_complete_bge = True
127
+ break
128
+
129
+ titles = [movie["name"] for movie in batch]
130
+ embedding_strings = [
131
+ f"Название: {movie['name']}\nГод: {movie['year']}\nЖанры: {movie['genresList']}\nОписание: {movie['description']}"
132
+ for movie in batch
133
+ ]
134
+
135
+ print(f"Создаются эмбеддинги для фильмов ({model_name}): {', '.join(titles)}...")
136
+ embeddings = model.encode(embedding_strings, convert_to_tensor=True, batch_size=batch_size, normalize_embeddings=True).tolist()
137
+
138
+ with lock:
139
+ for title, embedding in zip(titles, embeddings):
140
+ movie_embeddings[title] = embedding
141
+ # Сохраняем эмбеддинги в файл после обработки каждого пакета
142
+ with open(embeddings_file, "w", encoding="utf-8") as f:
143
+ json.dump(movie_embeddings, f, ensure_ascii=False, indent=4)
144
+ print(f"Эмбеддинги для фильмов ({model_name}): {', '.join(titles)} созданы и сохранены.")
145
+
146
+ print(f"Обработка фильмов для {model_name} завершена.")
147
+
148
+ def get_query_embedding(query, model, query_embeddings, query_embeddings_file, prompt=None):
149
  """
150
+ Возвращает эмбеддинг для запроса с инструкцией.
151
  Если эмбеддинг уже создан, возвращает его из словаря.
152
  Иначе создает эмбеддинг, сохраняет его и возвращает.
153
  """
 
156
  return query_embeddings[query]
157
  else:
158
  print(f"Создается эмбеддинг для запроса '{query}'...")
159
+ embedding = encode_string(query, model, prompt=prompt).tolist()
160
  query_embeddings[query] = embedding
161
  # Сохраняем эмбеддинги запросов в файл
162
  with open(query_embeddings_file, "w", encoding="utf-8") as f:
 
164
  print(f"Эмбеддинг для запроса '{query}' создан и сохранен.")
165
  return embedding
166
 
167
+ def search_movies(query, model, movie_embeddings, movies_data, top_k=10, search_in_progress_flag=None, query_prompt=None):
168
  """
169
  Ищет наиболее похожие фильмы по запросу с использованием инструкции.
170
 
171
  Args:
172
  query: Текстовый запрос.
173
+ model: Модель для эмбеддингов.
174
+ movie_embeddings: Словарь с эмбеддингами фильмов.
175
+ movies_data: Данные о фильмах.
176
  top_k: Количество возвращаемых результатов.
177
+ search_in_progress_flag: Флаг, указывающий, что выполняется поиск.
178
 
179
  Returns:
180
  Строку с результатами поиска в формате HTML.
181
  """
182
+ if search_in_progress_flag is not None:
183
+ if model == model_kalm:
184
+ global search_in_progress_kalm
185
+ search_in_progress_kalm = True
186
+ elif model == model_bge:
187
+ global search_in_progress_bge
188
+ search_in_progress_bge = True
189
  start_time = time.time()
190
  print(f"\n\033[1mПоиск по запросу: '{query}'\033[0m")
191
 
192
  print(f"Начало создания эмбеддинга для запроса: {time.strftime('%Y-%m-%d %H:%M:%S')}")
193
+ if model == model_kalm:
194
+ query_embedding_tensor = encode_string(query, model_kalm, prompt=query_prompt)
195
+ else:
196
+ query_embedding_tensor = encode_string(query, model)
197
+
198
  print(f"Окончание создания эмбеддинга для запроса: {time.strftime('%Y-%m-%d %H:%M:%S')}")
199
 
200
+ if model == model_kalm:
201
+ with movie_embeddings_lock_kalm:
202
+ current_movie_embeddings = movie_embeddings.copy()
203
+ elif model == model_bge:
204
+ with movie_embeddings_lock_bge:
205
+ current_movie_embeddings = movie_embeddings.copy()
206
 
207
  if not current_movie_embeddings:
208
+ if search_in_progress_flag is not None:
209
+ if model == model_kalm:
210
+ search_in_progress_kalm = False
211
+ elif model == model_bge:
212
+ search_in_progress_bge = False
213
+ return "<p>Пока что нет обработанных фильмов. Попробуйте позже.</p>"
214
 
215
  # Преобразуем эмбеддинги фильмов в тензор
216
  movie_titles = list(current_movie_embeddings.keys())
 
242
  end_time = time.time()
243
  execution_time = end_time - start_time
244
  print(f"Поиск завершен за {execution_time:.4f} секунд.")
245
+ if search_in_progress_flag is not None:
246
+ if model == model_kalm:
247
+ search_in_progress_kalm = False
248
+ elif model == model_bge:
249
+ search_in_progress_bge = False
250
  return results_html
251
 
252
+ # Потоки для обработки фильмов
253
+ processing_thread_kalm = threading.Thread(target=process_movies, args=(model_kalm, embeddings_file_kalm, movie_embeddings_kalm, movies_queue_kalm, processing_complete_kalm, movie_embeddings_lock_kalm, model_name_kalm))
254
+ processing_thread_bge = threading.Thread(target=process_movies, args=(model_bge, embeddings_file_bge, movie_embeddings_bge, movies_queue_bge, processing_complete_bge, movie_embeddings_lock_bge, model_name_bge))
255
+
256
+ # Запускаем потоки для обработки фильмов
257
+ processing_thread_kalm.start()
258
+ processing_thread_bge.start()
259
+
260
+ def search_with_kalm(query):
261
+ return search_movies(query, model_kalm, movie_embeddings_kalm, movies_data, top_k=10, search_in_progress_flag=search_in_progress_kalm, query_prompt=query_prompt_kalm)
262
+ def search_with_bge(query):
263
+ return search_movies(query, model_bge, movie_embeddings_bge, movies_data, top_k=10, search_in_progress_flag=search_in_progress_bge)
264
+
265
+ with gr.Blocks() as demo:
266
+ with gr.Tab("KaLM"):
267
+ text_input_kalm = gr.Textbox(label="Введите запрос для KaLM")
268
+ text_output_kalm = gr.HTML()
269
+ text_button_kalm = gr.Button("Поиск с KaLM")
270
+ with gr.Tab("BGE-M3"):
271
+ text_input_bge = gr.Textbox(label="Введите запрос для BGE-M3")
272
+ text_output_bge = gr.HTML()
273
+ text_button_bge = gr.Button("Поиск с BGE-M3")
274
+
275
+ text_button_kalm.click(search_with_kalm, inputs=text_input_kalm, outputs=text_output_kalm)
276
+ text_button_bge.click(search_with_bge, inputs=text_input_bge, outputs=text_output_bge)
277
+
278
+ demo.queue()
279
+ demo.launch()