Update app.py
Browse files
app.py
CHANGED
@@ -12,6 +12,11 @@ import logging
|
|
12 |
from sklearn.preprocessing import normalize
|
13 |
from concurrent.futures import ThreadPoolExecutor
|
14 |
import requests
|
|
|
|
|
|
|
|
|
|
|
15 |
|
16 |
# Настройка логирования
|
17 |
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
@@ -70,6 +75,9 @@ batch_size = 32
|
|
70 |
# Количество потоков для параллельной обработки
|
71 |
num_threads = 5
|
72 |
|
|
|
|
|
|
|
73 |
def get_db_connection():
|
74 |
"""Устанавливает соединение с базой данных."""
|
75 |
try:
|
@@ -354,9 +362,9 @@ def rerank_with_api(query, results, top_k):
|
|
354 |
except requests.exceptions.RequestException as e:
|
355 |
logging.error(f"Ошибка при запросе к API реранжировщика: {e}")
|
356 |
return []
|
357 |
-
|
358 |
-
def
|
359 |
-
"""
|
360 |
global search_in_progress
|
361 |
search_in_progress = True
|
362 |
start_time = time.time()
|
@@ -364,7 +372,7 @@ def search_movies(query, top_k=25):
|
|
364 |
try:
|
365 |
conn = get_db_connection()
|
366 |
if conn is None:
|
367 |
-
|
368 |
|
369 |
query_crc32 = calculate_crc32(query)
|
370 |
query_embedding = get_embedding_from_db(conn, query_cache_table, "query_crc32", query_crc32, model_name)
|
@@ -416,34 +424,65 @@ def search_movies(query, top_k=25):
|
|
416 |
movie_data_dict = get_movie_data_from_db(conn, movie_ids)
|
417 |
conn.close()
|
418 |
|
419 |
-
|
420 |
for movie_id, score in reranked_results:
|
421 |
# Находим данные фильма
|
422 |
movie_data, _ = movie_data_dict.get(movie_id, (None, None))
|
423 |
if movie_data:
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
|
|
|
|
|
|
429 |
else:
|
430 |
logging.warning(f"Данные для фильма с ID {movie_id} не найдены в БД.")
|
431 |
|
432 |
search_time = time.time() - start_time
|
433 |
logging.info(f"Поиск выполнен за {search_time:.2f} секунд.")
|
434 |
|
435 |
-
return
|
436 |
|
437 |
except Exception as e:
|
438 |
logging.error(f"Ошибка при выполнении поиска: {e}")
|
439 |
-
|
440 |
|
441 |
finally:
|
442 |
search_in_progress = False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
443 |
|
444 |
-
|
445 |
-
|
446 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
447 |
|
448 |
# Создаем интерфейс Gradio
|
449 |
iface = gr.Interface(
|
@@ -454,5 +493,14 @@ iface = gr.Interface(
|
|
454 |
description="Введите описание фильма, который вы ищете, и система найдет наиболее похожие фильмы."
|
455 |
)
|
456 |
|
457 |
-
#
|
458 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
from sklearn.preprocessing import normalize
|
13 |
from concurrent.futures import ThreadPoolExecutor
|
14 |
import requests
|
15 |
+
from fastapi import FastAPI, HTTPException, Query
|
16 |
+
from typing import List
|
17 |
+
import uvicorn
|
18 |
+
from starlette.requests import Request
|
19 |
+
from starlette.responses import HTMLResponse
|
20 |
|
21 |
# Настройка логирования
|
22 |
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
|
|
75 |
# Количество потоков для параллельной обработки
|
76 |
num_threads = 5
|
77 |
|
78 |
+
# FastAPI приложение
|
79 |
+
app = FastAPI()
|
80 |
+
|
81 |
def get_db_connection():
|
82 |
"""Устанавливает соединение с базой данных."""
|
83 |
try:
|
|
|
362 |
except requests.exceptions.RequestException as e:
|
363 |
logging.error(f"Ошибка при запросе к API реранжировщика: {e}")
|
364 |
return []
|
365 |
+
|
366 |
+
def search_movies_internal(query: str, top_k: int = 25):
|
367 |
+
"""Внутренняя функция для поиска фильмов по запросу (используется и в Gradio, и в API)."""
|
368 |
global search_in_progress
|
369 |
search_in_progress = True
|
370 |
start_time = time.time()
|
|
|
372 |
try:
|
373 |
conn = get_db_connection()
|
374 |
if conn is None:
|
375 |
+
raise Exception("Ошибка подключения к базе данных")
|
376 |
|
377 |
query_crc32 = calculate_crc32(query)
|
378 |
query_embedding = get_embedding_from_db(conn, query_cache_table, "query_crc32", query_crc32, model_name)
|
|
|
424 |
movie_data_dict = get_movie_data_from_db(conn, movie_ids)
|
425 |
conn.close()
|
426 |
|
427 |
+
formatted_results = []
|
428 |
for movie_id, score in reranked_results:
|
429 |
# Находим данные фильма
|
430 |
movie_data, _ = movie_data_dict.get(movie_id, (None, None))
|
431 |
if movie_data:
|
432 |
+
formatted_results.append({
|
433 |
+
"movie_id": movie_id,
|
434 |
+
"name": movie_data['name'],
|
435 |
+
"year": movie_data['year'],
|
436 |
+
"genres": [genre['name'] for genre in movie_data['genres']],
|
437 |
+
"description": movie_data.get('description', ''),
|
438 |
+
"relevance_score": score
|
439 |
+
})
|
440 |
else:
|
441 |
logging.warning(f"Данные для фильма с ID {movie_id} не найдены в БД.")
|
442 |
|
443 |
search_time = time.time() - start_time
|
444 |
logging.info(f"Поиск выполнен за {search_time:.2f} секунд.")
|
445 |
|
446 |
+
return formatted_results, search_time
|
447 |
|
448 |
except Exception as e:
|
449 |
logging.error(f"Ошибка при выполнении поиска: {e}")
|
450 |
+
raise
|
451 |
|
452 |
finally:
|
453 |
search_in_progress = False
|
454 |
+
|
455 |
+
def search_movies(query, top_k=25):
|
456 |
+
"""Функция поиска фильмов для Gradio интерфейса."""
|
457 |
+
try:
|
458 |
+
results, search_time = search_movies_internal(query, top_k)
|
459 |
+
output = f"<p>Время поиска: {search_time:.2f} сек</p>"
|
460 |
+
for result in results:
|
461 |
+
output += f"<h3>{result['name']} ({result['year']})</h3>\n"
|
462 |
+
output += f"<p><strong>Жанры:</strong> {', '.join(result['genres'])}</p>\n"
|
463 |
+
output += f"<p><strong>Описание:</strong> {result['description']}</p>\n"
|
464 |
+
output += f"<p><strong>Релевантность (reranker score):</strong> {result['relevance_score']:.4f}</p>\n"
|
465 |
+
output += "<hr>\n"
|
466 |
+
return output
|
467 |
+
except Exception as e:
|
468 |
+
return f"<p>Произошла ошибка при выполнении поиска: {e}</p>"
|
469 |
|
470 |
+
@app.get("/search/", response_model=List[dict])
|
471 |
+
async def api_search_movies(query: str = Query(..., description="Поисковый ��апрос"), top_k: int = Query(25, description="Количество возвращаемых результатов")):
|
472 |
+
"""API endpoint для поиска фильмов."""
|
473 |
+
try:
|
474 |
+
results, _ = search_movies_internal(query, top_k)
|
475 |
+
return results
|
476 |
+
except Exception as e:
|
477 |
+
raise HTTPException(status_code=500, detail=str(e))
|
478 |
+
|
479 |
+
# Запускаем обработку фильмов в отдельном потоке (если ещё не запущена)
|
480 |
+
if not 'processing_thread' in globals():
|
481 |
+
processing_thread = threading.Thread(target=process_movies)
|
482 |
+
processing_thread.start()
|
483 |
+
elif not processing_thread.is_alive():
|
484 |
+
processing_thread = threading.Thread(target=process_movies)
|
485 |
+
processing_thread.start()
|
486 |
|
487 |
# Создаем интерфейс Gradio
|
488 |
iface = gr.Interface(
|
|
|
493 |
description="Введите описание фильма, который вы ищете, и система найдет наиболее похожие фильмы."
|
494 |
)
|
495 |
|
496 |
+
# Встраиваем Gradio в FastAPI
|
497 |
+
app = gr.mount_gradio_app(app, iface, path="/")
|
498 |
+
|
499 |
+
# Рут-эндпоинт для демонстрации, что FastAPI работает
|
500 |
+
@app.get("/api")
|
501 |
+
async def root():
|
502 |
+
return {"message": "FastAPI is running. Access the API documentation at /docs"}
|
503 |
+
|
504 |
+
# Запускаем FastAPI
|
505 |
+
if __name__ == "__main__":
|
506 |
+
uvicorn.run(app, host="0.0.0.0", port=7860)
|