Update app.py
Browse files
app.py
CHANGED
@@ -13,7 +13,7 @@ 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, JSONResponse
|
@@ -46,7 +46,7 @@ logging.info("Модель загружена успешно.")
|
|
46 |
|
47 |
# Jina AI Reranker API
|
48 |
JINA_API_URL = 'https://api.jina.ai/v1/rerank'
|
49 |
-
JINA_API_KEY = os.environ.get("JINA_API_KEY")
|
50 |
if JINA_API_KEY is None:
|
51 |
raise ValueError("JINA_API_KEY environment variable not set.")
|
52 |
JINA_RERANKER_MODEL = "jina-reranker-v2-base-multilingual"
|
@@ -173,14 +173,14 @@ def get_movie_data_from_db(conn, movie_ids):
|
|
173 |
logging.error(f"Ошибка при получении данных фильмов из БД: {e}")
|
174 |
return movie_data_dict
|
175 |
|
176 |
-
def get_jina_ai_balance():
|
177 |
"""Получает остаток баланса Jina AI."""
|
178 |
try:
|
179 |
headers = {
|
180 |
'Content-Type': 'application/json'
|
181 |
}
|
182 |
params = {
|
183 |
-
'api_key':
|
184 |
}
|
185 |
response = requests.get(JINA_DASHBOARD_API_URL, headers=headers, params=params)
|
186 |
response.raise_for_status()
|
@@ -190,10 +190,15 @@ def get_jina_ai_balance():
|
|
190 |
logging.error(f"Ошибка при запросе к API баланса Jina AI: {e}")
|
191 |
return None
|
192 |
|
193 |
-
def rerank_with_api(query, results, top_k, rerank_top_k=None):
|
194 |
"""Переранжирует результаты с помощью Jina AI Reranker API."""
|
195 |
logging.info(f"Начало переранжирования для запроса: '{query}'")
|
196 |
|
|
|
|
|
|
|
|
|
|
|
197 |
# Получаем данные фильмов из БД
|
198 |
conn = get_db_connection()
|
199 |
movie_ids = [movie_id for movie_id, _ in results]
|
@@ -208,14 +213,16 @@ def rerank_with_api(query, results, top_k, rerank_top_k=None):
|
|
208 |
else:
|
209 |
logging.warning(f"Данные для фильма с ID {movie_id} не найдены в БД.")
|
210 |
|
|
|
|
|
211 |
headers = {
|
212 |
'Content-Type': 'application/json',
|
213 |
-
'Authorization': f'Bearer {JINA_API_KEY}'
|
214 |
}
|
215 |
data = {
|
216 |
"model": JINA_RERANKER_MODEL,
|
217 |
"query": query,
|
218 |
-
"top_n": rerank_top_k or top_k
|
219 |
"documents": documents
|
220 |
}
|
221 |
logging.info(f"Отправка данных на реранжировку (documents count): {len(data['documents'])}, top_n: {data['top_n']}")
|
@@ -236,13 +243,13 @@ def rerank_with_api(query, results, top_k, rerank_top_k=None):
|
|
236 |
logging.warning("Ответ от API не содержит ключа 'results'.")
|
237 |
|
238 |
logging.info("Переранжирование завершено.")
|
239 |
-
return reranked_results, True,
|
240 |
|
241 |
except requests.exceptions.RequestException as e:
|
242 |
logging.error(f"Ошибка при запросе к API реранжировщика: {e}")
|
243 |
-
return results, False,
|
244 |
|
245 |
-
def search_movies_internal(query: str, top_k: int = 25, rerank_top_k: int = None):
|
246 |
"""Внутренняя функция для поиска фильмов по запросу (используется и в Gradio, и в API)."""
|
247 |
start_time = time.time()
|
248 |
|
@@ -295,14 +302,18 @@ def search_movies_internal(query: str, top_k: int = 25, rerank_top_k: int = None
|
|
295 |
results = []
|
296 |
finally:
|
297 |
conn.close()
|
298 |
-
|
299 |
-
#
|
300 |
-
|
|
|
|
|
|
|
|
|
|
|
301 |
|
302 |
if not rerank_success:
|
303 |
logging.warning("Переранжировка не удалась, ис��ользуются сырые результаты.")
|
304 |
reranked_results = results[:top_k] # Используем срез для ограничения количества результатов
|
305 |
-
reranked_count = 0
|
306 |
else:
|
307 |
reranked_results = reranked_results[:top_k]
|
308 |
|
@@ -350,7 +361,7 @@ def search_movies_internal(query: str, top_k: int = 25, rerank_top_k: int = None
|
|
350 |
search_time = time.time() - start_time
|
351 |
logging.info(f"Поиск выполнен за {search_time:.2f} секунд.")
|
352 |
|
353 |
-
jina_balance = get_jina_ai_balance()
|
354 |
|
355 |
return {
|
356 |
"status": "success",
|
@@ -377,12 +388,35 @@ def search_movies_internal(query: str, top_k: int = 25, rerank_top_k: int = None
|
|
377 |
}, 0
|
378 |
|
379 |
@app.get("/search/", response_model=dict)
|
380 |
-
async def api_search_movies(query: str = Query(..., description="Поисковый запрос"),
|
381 |
top_k: int = Query(25, description="Количество возвращаемых результатов"),
|
382 |
-
rerank_top_k: int = Query(None, description="Количество фильмов для передачи в реранкер (если не указано, то top_k*2)")
|
383 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
384 |
try:
|
385 |
-
results, _ = search_movies_internal(query, top_k, rerank_top_k)
|
386 |
return results
|
387 |
except Exception as e:
|
388 |
raise HTTPException(status_code=500, detail=str(e))
|
|
|
13 |
from concurrent.futures import ThreadPoolExecutor
|
14 |
import requests
|
15 |
from fastapi import FastAPI, HTTPException, Query
|
16 |
+
from typing import List, Optional
|
17 |
import uvicorn
|
18 |
from starlette.requests import Request
|
19 |
from starlette.responses import HTMLResponse, JSONResponse
|
|
|
46 |
|
47 |
# Jina AI Reranker API
|
48 |
JINA_API_URL = 'https://api.jina.ai/v1/rerank'
|
49 |
+
JINA_API_KEY = os.environ.get("JINA_API_KEY") # Используем переменную окружения
|
50 |
if JINA_API_KEY is None:
|
51 |
raise ValueError("JINA_API_KEY environment variable not set.")
|
52 |
JINA_RERANKER_MODEL = "jina-reranker-v2-base-multilingual"
|
|
|
173 |
logging.error(f"Ошибка при получении данных фильмов из БД: {e}")
|
174 |
return movie_data_dict
|
175 |
|
176 |
+
def get_jina_ai_balance(api_key: str):
|
177 |
"""Получает остаток баланса Jina AI."""
|
178 |
try:
|
179 |
headers = {
|
180 |
'Content-Type': 'application/json'
|
181 |
}
|
182 |
params = {
|
183 |
+
'api_key': api_key
|
184 |
}
|
185 |
response = requests.get(JINA_DASHBOARD_API_URL, headers=headers, params=params)
|
186 |
response.raise_for_status()
|
|
|
190 |
logging.error(f"Ошибка при запросе к API баланса Jina AI: {e}")
|
191 |
return None
|
192 |
|
193 |
+
def rerank_with_api(query, results, top_k, rerank_top_k=None, api_key=None):
|
194 |
"""Переранжирует результаты с помощью Jina AI Reranker API."""
|
195 |
logging.info(f"Начало переранжирования для запроса: '{query}'")
|
196 |
|
197 |
+
# Если rerank_top_k равен 0, не используем реранкер
|
198 |
+
if rerank_top_k == 0:
|
199 |
+
logging.info("Переранжирование отключено (rerank_top_k = 0).")
|
200 |
+
return results, False, 0
|
201 |
+
|
202 |
# Получаем данные фильмов из БД
|
203 |
conn = get_db_connection()
|
204 |
movie_ids = [movie_id for movie_id, _ in results]
|
|
|
213 |
else:
|
214 |
logging.warning(f"Данные для фильма с ID {movie_id} не найдены в БД.")
|
215 |
|
216 |
+
reranked_count = min(rerank_top_k or top_k*2, len(documents))
|
217 |
+
|
218 |
headers = {
|
219 |
'Content-Type': 'application/json',
|
220 |
+
'Authorization': f'Bearer {api_key or JINA_API_KEY}'
|
221 |
}
|
222 |
data = {
|
223 |
"model": JINA_RERANKER_MODEL,
|
224 |
"query": query,
|
225 |
+
"top_n": rerank_top_k or top_k*2,
|
226 |
"documents": documents
|
227 |
}
|
228 |
logging.info(f"Отправка данных на реранжировку (documents count): {len(data['documents'])}, top_n: {data['top_n']}")
|
|
|
243 |
logging.warning("Ответ от API не содержит ключа 'results'.")
|
244 |
|
245 |
logging.info("Переранжирование завершено.")
|
246 |
+
return reranked_results, True, reranked_count
|
247 |
|
248 |
except requests.exceptions.RequestException as e:
|
249 |
logging.error(f"Ошибка при запросе к API реранжировщика: {e}")
|
250 |
+
return results, False, reranked_count
|
251 |
|
252 |
+
def search_movies_internal(query: str, top_k: int = 25, rerank_top_k: Optional[int] = None, jina_api_key: Optional[str] = None):
|
253 |
"""Внутренняя функция для поиска фильмов по запросу (используется и в Gradio, и в API)."""
|
254 |
start_time = time.time()
|
255 |
|
|
|
302 |
results = []
|
303 |
finally:
|
304 |
conn.close()
|
305 |
+
|
306 |
+
# Используем реранкер только если rerank_top_k не равен 0
|
307 |
+
if rerank_top_k != 0:
|
308 |
+
reranked_results, rerank_success, reranked_count = rerank_with_api(query, results, top_k, rerank_top_k, jina_api_key)
|
309 |
+
else:
|
310 |
+
reranked_results = results
|
311 |
+
rerank_success = False
|
312 |
+
reranked_count = 0
|
313 |
|
314 |
if not rerank_success:
|
315 |
logging.warning("Переранжировка не удалась, ис��ользуются сырые результаты.")
|
316 |
reranked_results = results[:top_k] # Используем срез для ограничения количества результатов
|
|
|
317 |
else:
|
318 |
reranked_results = reranked_results[:top_k]
|
319 |
|
|
|
361 |
search_time = time.time() - start_time
|
362 |
logging.info(f"Поиск выполнен за {search_time:.2f} секунд.")
|
363 |
|
364 |
+
jina_balance = get_jina_ai_balance(jina_api_key or JINA_API_KEY)
|
365 |
|
366 |
return {
|
367 |
"status": "success",
|
|
|
388 |
}, 0
|
389 |
|
390 |
@app.get("/search/", response_model=dict)
|
391 |
+
async def api_search_movies(query: str = Query(..., description="Поисковый запрос"),
|
392 |
top_k: int = Query(25, description="Количество возвращаемых результатов"),
|
393 |
+
rerank_top_k: Optional[int] = Query(None, description="Количество фильмов для передачи в реранкер (если не указано, то top_k*2)"),
|
394 |
+
jina_api_key: Optional[str] = Query(None, description="API ключ Jina AI (если не указан, используется значение из переменной окружения JINA_API_KEY)")):
|
395 |
+
"""
|
396 |
+
API endpoint для поиска фильмов.
|
397 |
+
|
398 |
+
Parameters
|
399 |
+
----------
|
400 |
+
query : str
|
401 |
+
Поисковый запрос.
|
402 |
+
top_k : int, optional
|
403 |
+
Количество возвращаемых результатов, по умолчанию 25.
|
404 |
+
rerank_top_k : Optional[int], optional
|
405 |
+
Количество фильмов для передачи в реранкер.
|
406 |
+
Если 0 - реранкер не используется.
|
407 |
+
Если не указано, то используется top_k*2.
|
408 |
+
По умолчанию None.
|
409 |
+
jina_api_key : Optional[str], optional
|
410 |
+
API ключ Jina AI. Если не указан, используется значение из переменной окружения JINA_API_KEY.
|
411 |
+
По умолчанию None.
|
412 |
+
|
413 |
+
Returns
|
414 |
+
-------
|
415 |
+
dict
|
416 |
+
Словарь с результатами поиска.
|
417 |
+
"""
|
418 |
try:
|
419 |
+
results, _ = search_movies_internal(query, top_k, rerank_top_k, jina_api_key)
|
420 |
return results
|
421 |
except Exception as e:
|
422 |
raise HTTPException(status_code=500, detail=str(e))
|