import logging import requests import os import pandas as pd from fastapi import FastAPI from rec_handler import Recommendations PATH_TO_RECOMENDATIONS = '../../recommendations/' FILENAME_PERS_RECOMENDATIONS = 'personal_als.parquet' FILENAME_TOP_POPULAR = 'top_popular.parquet' logger = logging.getLogger("uvicorn.error") rec_store = Recommendations() features_store_url = "http://localhost:8010" events_store_url = "http://localhost:8020" logger.info("Starting") rec_store.load( "personal", PATH_TO_RECOMENDATIONS+FILENAME_PERS_RECOMENDATIONS, columns=["user_id", "item_id", "score"], ) rec_store.load( "default", PATH_TO_RECOMENDATIONS+FILENAME_TOP_POPULAR, columns=["item_id", "rank"], ) # создаём приложение FastAPI app = FastAPI(title="recommendations") @app.post("/recommendations_offline") async def recommendations_offline(user_id: int, k: int = 100): """ Возвращает список рекомендаций длиной k для пользователя user_id """ recs = rec_store.get(user_id=user_id, k=k) return {"recs": recs} @app.post("/recommendations_online") async def recommendations_online(user_id: int, k: int = 100): """ Возвращает список онлайн-рекомендаций длиной k для пользователя user_id """ headers = {"Content-type": "application/json", "Accept": "text/plain"} # получаем последние события пользователя params = {"user_id": user_id, "k": 3} resp = requests.get(events_store_url + "/get", headers=headers, params=params) events = resp.json() events = events["events"] # получаем список похожих объектов if len(events) > 0: items = [] scores = [] for item_id in events: params = {"item_id": item_id, "k": k} headers = {"Content-type": "application/json", "Accept": "text/plain"} resp = requests.get(features_store_url + "/similar_items", headers=headers, params=params) if resp.status_code == 200: similar_items = resp.json() else: similar_items = None print(f"status code: {resp.status_code}") items += similar_items["item_id_2"] scores += similar_items["score"] combined = list(zip(items, scores)) combined = sorted(combined, key=lambda x: x[1], reverse=True) combined = [item for item, _ in combined] recs = combined[:k] else: recs = [] return {"recs": recs} @app.post("/recommendations") async def recommendations(user_id: int, k: int = 100): """ Возвращает список рекомендаций длиной k для пользователя user_id """ recs_offline = await recommendations_offline(user_id, k) recs_online = await recommendations_online(user_id, k) recs_offline = recs_offline["recs"] recs_online = recs_online["recs"] recs_blended = [] min_length = min(len(recs_offline), len(recs_online)) # чередуем элементы из списков, пока позволяет минимальная длина for i in range(min_length): recs_blended.append(recs_online[i]) recs_blended.append(recs_offline[i]) # добавляем оставшиеся элементы в конец recs_blended += recs_online[min_length:] recs_blended += recs_offline[min_length:] # оставляем только первые k рекомендаций recs_blended = recs_blended[:k] return {"recs": recs_blended}