Automationscribe.com
  • Home
  • AI Scribe
  • AI Tools
  • Artificial Intelligence
  • Contact Us
No Result
View All Result
Automation Scribe
  • Home
  • AI Scribe
  • AI Tools
  • Artificial Intelligence
  • Contact Us
No Result
View All Result
Automationscribe.com
No Result
View All Result

Constructing Video Sport Recommender Techniques with FastAPI, PostgreSQL, and Render: Half 1

admin by admin
September 25, 2025
in Artificial Intelligence
0
Constructing Video Sport Recommender Techniques with FastAPI, PostgreSQL, and Render: Half 1
399
SHARES
2.3k
VIEWS
Share on FacebookShare on Twitter


Introduction

allow an utility to generate clever ideas for a consumer, successfully sorting related content material out from the remainder. On this article, we construct and deploy a dynamic online game recommender system leveraging PostgreSQL, FastAPI, and Render to suggest new video games for a consumer primarily based on these they’ve interacted with. The intent is to offer a transparent instance of how a standalone recommender system could be constructed, which may then be tied right into a front-end system or different utility.

For this mission, we use online game information accessible from Steams API however this might simply get replaced by no matter product information you’re excited about, the important thing steps would be the identical. We’ll cowl methods to retailer this information in a Database, vectorize the sport Tags, generate similarity scores primarily based on the video games a consumer has interacted with, and return a sequence of related suggestions. On the finish of this text, we’ll have this recommender system deployed as a Net Software with FastAPI such that at any time when a consumer interacts with a brand new Sport, we will dynamically generate and retailer a brand new set of suggestions for that consumer.

The next instruments will probably be used:

  • PostgreSQL
  • FastAPI
  • Docker
  • Render

These simply within the GitHub repository can discover it right here.

Desk of Contents

As a result of size of this mission, it’s divided into two articles. The primary portion covers the setup and idea behind this mission (steps 1–5 proven under), and the second half covers deploying it. For those who’re in search of the second half it’s positioned right here.

Half 1

  1. Dataset Overview
  2. General System Structure
  3. Database Setup
  4. FastAPI Setup
    – Fashions
    – Routes
  5. Constructing Similarity Pipeline
  1. Deploying a PostgreSQL database on Render
  2. Deploying a FastAPI app as a Render Net Software
    – Dockerizing our utility
    – Pushing Docker Picture to DockerHub
    – Pulling from DockerHub to Render

Dataset Overview

The dataset for this mission incorporates information for the highest ~2000 video games from the steamworks API. This information is free and licensed for private and business use, topic to the phrases of service, there’s a 200 requests/5 minute charge restrict that resulted in us working with solely a subset of the information. The phrases of service could be discovered right here.

An outline of the video games dataset is proven under. Many of the fields are comparatively self-descriptive; the important thing factor to notice is that the distinctive product identifier is appid. Along with this dataset, we even have a number of further tables that we’ll element under; an important one for our recommender system is a recreation tags desk, which incorporates the appid values mapped to every tag related to the sport (technique, RPG, card recreation, and so forth.). These had been drawn from the classes discipline proven within the Knowledge Overview after which pivoted to create the game_tags desk in order that there’s a novel row for every appip:class mixture.

Determine 2: Dataset Overview

For a extra detailed overview of the construction of our mission, see the diagram under.

Determine 3: Venture File Construction

Now we’ll present a fast overview of the structure of this mission after which dive into methods to populate our database.

Structure

For our recommender system system, we’ll use a PostgreSQL database with a FastAPI information entry + processing layer that may permit us so as to add or take away video games from a consumer’s recreation checklist. Customers making adjustments to their recreation library, by way of a FastAPI POST request, will even kick off a advice pipeline leveraging FastAPI’s Background Duties operate that may question their appreciated video games from the database, calculate a similarity rating with non-liked video games, and replace a user_recommendation desk with their new top-N advisable video games. Lastly, each the PostgreSQL database and FastAPI service will probably be deployed on Render to allow them to be accessed past our native atmosphere. For this deployment step, any cloud service may have been used, however we selected Render on this case for its simplicity.

To recap, our general workflow from the consumer’s perspective will appear like this:

  1. The consumer provides a recreation to their library by making a POST request from FastAPI to our database.
    • If we wished to connect our recommender system to a front-end utility, we may simply tie this Publish API right into a consumer interface.
  2. This submit request kicks off a FastAPI background job that runs our recommender pipeline.
  3. The recommender pipeline queries our database for the consumer’s recreation checklist and the worldwide video games checklist.
  4. A similarity rating is then calculated between the consumer’s video games and all video games utilizing our recreation tags.
  5. Lastly, our recommender pipeline makes a submit request to the database to replace the advisable video games desk for that consumer.
Determine 4: Recommender System Diagram

Setting Up the Database

Earlier than we construct our recommender system, step one is to arrange our database. Our primary database diagram is proven in Determine 5. We beforehand mentioned our recreation desk above; that is the bottom dataset that the remainder of our information is mostly derived from. A full checklist of our tables is right here:

  • Sport Desk: Comprises base recreation information for every distinctive recreation in our database
  • Consumer Desk: A Dummy consumer desk containing instance info populated for instance.
  • User_Game Desk: Comprises the mappings between all video games {that a} consumer has ‘appreciated’; this desk is among the base tables used to generate suggestions by capturing what video games a consumer is excited about.
  • Game_Tags Desk: This incorporates an appid:game_tag mapping, the place recreation tag may very well be one thing like ‘technique’, ‘rpg’, ‘comedy’, a descriptive tag that captures a part of the essence of a recreation. There are a number of tags mapped to every appid.
  • User_Recommendation Desk: That is our goal desk that will probably be up to date by our pipeline. Each time a consumer interacts with a brand new recreation, our advice pipeline will run and generate a brand new sequence of suggestions for that consumer that will probably be saved right here.
Determine 5: Database Diagram

To arrange these tables, we will merely run our src/load_database.py file. This file creates and populates our tables in a few steps which might be outlined under. Be aware, proper now we’re going to deal with understanding methods to write this information to a generic database, so all it’s a must to know now could be that the External_Database_Url under is the URL to no matter database you need to use. Within the second half of this text, we’ll stroll by means of methods to arrange a database on Render and duplicate the URL into your .env file.

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, Session
from sqlalchemy.ext.declarative import declarative_base
import os
from dotenv import load_dotenv
from utils.db_handler import DatabaseHandler
import pandas as pd
import uuid
import sys
from sqlalchemy.exc import OperationalError
import psycopg2

# Loading environmental variables
load_dotenv(override=True)

# Assemble PostgreSQL connection URL for Render
URL_database = os.environ.get("External_Database_Url")

# Initialize DatabaseHandler with our URL
engine = DatabaseHandler(URL_database)

# loading preliminary consumer information
users_df = pd.read_csv("Knowledge/customers.csv")
games_df = pd.read_csv("Knowledge/video games.csv")
user_games_df = pd.read_csv("Knowledge/user_games.csv")
user_recommendations_df = pd.read_csv("Knowledge/user_recommendations.csv")
game_tags_df = pd.read_csv("Knowledge/game_tags.csv")

First, we load 5 CSV information into dataframes from our Knowledge folder; we’ve one file for every of the tables proven in our database diagram. We additionally set up a connection to our information by declaring an engine variable; this engine variable makes use of a customized DataBaseHandler class with the initialization technique proven under. This class takes a connection string to our database on Render(or your most well-liked cloud service), handed in from our .env file, and incorporates all of our database join, replace, delete, and take a look at functionalities.

After loading our information and instantiating our DatabaseHandler class, we then need to outline a question to create every of the 5 tables and execute these queries utilizing the DatabaseHandler.create_table operate. This can be a quite simple operate that connects to our database, executes the question, and closes the connection, leaving us with the 5 tables proven in our database diagram; nonetheless, they’re at present empty.

# Defining queries to create tables
user_table_creation_query = """CREATE TABLE IF NOT EXISTS customers (
    id UUID PRIMARY KEY,
    username VARCHAR(255) UNIQUE NOT NULL,
    password VARCHAR(255) NOT NULL,
    e-mail VARCHAR(255) NOT NULL,
    position VARCHAR(50) NOT NULL
    )
    """
game_table_creation_query = """CREATE TABLE IF NOT EXISTS video games (
    id UUID PRIMARY KEY,
    appid VARCHAR(255) UNIQUE NOT NULL,
    title VARCHAR(255) NOT NULL,
    sort VARCHAR(255),
    is_free BOOLEAN DEFAULT FALSE,
    short_description TEXT,
    detailed_description TEXT,
    builders VARCHAR(255),
    publishers VARCHAR(255),
    worth VARCHAR(255),
    genres VARCHAR(255),
    classes VARCHAR(255),
    release_date VARCHAR(255),
    platforms TEXT,
    metacritic_score FLOAT,
    suggestions INTEGER
    )
    """

user_games_query = """CREATE TABLE IF NOT EXISTS user_games (
    id UUID PRIMARY KEY,
    username VARCHAR(255) NOT NULL,
    appid VARCHAR(255) NOT NULL,
    shelf VARCHAR(50) DEFAULT 'Wish_List',
    ranking FLOAT DEFAULT 0.0,
    evaluate TEXT
    )
    """
recommendation_table_creation_query = """CREATE TABLE IF NOT EXISTS user_recommendations (
    id UUID PRIMARY KEY,
    username VARCHAR(255),
    appid VARCHAR(255),
    similarity FLOAT
    )
    """

game_tags_creation_query = """CREATE TABLE IF NOT EXISTS game_tags (
    id UUID PRIMARY KEY,
    appid VARCHAR(255) NOT NULL,
    class VARCHAR(255) NOT NULL
    )
    """



# Operating queries to create tables
engine.delete_table('user_recommendations')
engine.delete_table('user_games')
engine.delete_table('game_tags')
engine.delete_table('video games')
engine.delete_table('customers')

# Create tables
engine.create_table(user_table_creation_query)
engine.create_table(game_table_creation_query)
engine.create_table(user_games_query)
engine.create_table(recommendation_table_creation_query)
engine.create_table(game_tags_creation_query)

Following the preliminary desk setup, we then run a top quality verify to make sure every of our datasets has the required ID column, populate the information from the dataframes into the suitable desk, after which take a look at to make sure that the tables had been populated appropriately. The test_table operate returns a dictionary that will probably be of the shape {‘table_exists’: True, ‘table_has_data’: True} if the setup labored appropriately.

# Making certain every row of every dataframe has a novel ID
if 'id' not in users_df.columns:
    users_df['id'] = [str(uuid.uuid4()) for _ in range(len(users_df))]
if 'id' not in games_df.columns:
    games_df['id'] = [str(uuid.uuid4()) for _ in range(len(games_df))]
if 'id' not in user_games_df.columns:
    user_games_df['id'] = [str(uuid.uuid4()) for _ in range(len(user_games_df))]
if 'id' not in user_recommendations_df.columns:
    user_recommendations_df['id'] = [str(uuid.uuid4()) for _ in range(len(user_recommendations_df))]
if 'id' not in game_tags_df.columns:
    game_tags_df['id'] = [str(uuid.uuid4()) for _ in range(len(game_tags_df))]

# Populates the 4 tables with information from the dataframes
engine.populate_table_dynamic(users_df, 'customers')
engine.populate_table_dynamic(games_df, 'video games')
engine.populate_table_dynamic(user_games_df, 'user_games')
engine.populate_table_dynamic(user_recommendations_df, 'user_recommendations')
engine.populate_table_dynamic(game_tags_df, 'game_tags')

# Testing if the tables had been created and populated appropriately
print(engine.test_table('customers'))
print(engine.test_table('video games'))
print(engine.test_table('user_games'))
print(engine.test_table('user_recommendations'))
print(engine.test_table('game_tags'))

Getting Began with FastAPI

Now that we’ve our database arrange and populated, we have to construct the strategies to entry, replace, and delete information, utilizing FastAPI. FastAPI permits us to simply construct standardized(and quick) API’s to allow interplay with our database. The FastAPI docs supply an excellent step-by-step tutorial that may be discovered right here. As a high-level abstract, there are a number of nice options that make FastAPI very best for serving because the interplay layer between a database and a front-end utility.

  1. Standardization: FastAPI permits us to outline routes to work together with our tables in a standardized approach utilizing GET, POST, DELETE, UPDATE, and so forth. strategies. This standardization permits us to construct an information entry layer in pure Python that may then be work together with all kinds of front-end utility. We merely name the API strategies we would like within the entrance finish, no matter what language its constructed in.
  2. Knowledge Validation: As we’ll present under, we have to outline a Pydantic information mannequin for every object we work together with(assume our video games and consumer tables). The primary benefit of that is that it ensures all our variables have outlined information varieties, for instance, if we outline our Sport object such that the ranking discipline is of sort float and a consumer tries to make a submit request so as to add a brand new entry with a ranking of “nice” it wont work. This built-in information validation will assist us stop all kinds of information high quality points from as our system scales.
  3. Asynchronous: FastAPI features can run asynchronously, which means considered one of them isn’t depending on the opposite ending. This will considerably enhance the efficiency as a result of we received’t have a gradual Quick job ready on a gradual one to finish.
  4. Swagger Docs Constructed In: FastAPI has a built-in UI that we will navigate to on localhost, enabling us to simply take a look at and work together with our routes.

FastAPI Fashions

The FastAPI portion of our mission depends on two important information: fashions.py, which defines the information fashions that we’ll be interacting with (video games, customers, and so forth.), and important.py, which defines our precise FastAPI App and incorporates our routes. Within the context of FastAPI, Routes outline the completely different paths for processing requests. For instance, we would have a /video games path to request video games from our database.

First, let’s talk about our fashions.py file. On this file, we outline all of our fashions. Whereas we’ve completely different fashions for various objects the final method would be the identical so we’ll solely talk about the video games mannequin, proven under, intimately. The very first thing you’ll discover under is that we’ve two precise courses outlined for our Sport object: a GameModel class that inherits from the Pydantic base mannequin, and a Sport class that inherits from the sqlalchemy declarative_base. The pure query then is, why do we’ve two courses for one information construction(our recreation’s information construction)?

If we weren’t utilizing an SQL database for this mission and as a substitute learn every of our CSV information right into a dataframe each time important.py was run, then we wouldn’t want the Sport class, solely the GameModel class. On this situation, we’d learn in our video games.csv dataframe, and FastAPI would use the GameModel class to make sure datatypes had been appropriately adhered to.

Nonetheless, as a result of we’re utilizing an SQL database, it makes extra sense to have separate courses for our API and our database, as the 2 courses have barely completely different jobs. Our API class handles information validation, serialization, and non-obligatory fields, and our database class handles database-specific considerations like defining major/international keys, defining which desk the item maps to, and defending safe information. To reiterate the final level, we would have delicate fields in our database which might be for inside consumption solely, and we don’t need to expose them to a consumer by means of an API( password for instance). We are able to deal with this concern by having a separate user-facing Pydantic class and an Inside SQL Alchemy one.

Under is an instance of how this may be carried out for our Video games object; we’ve separate courses outlined for our different tables, which could be discovered right here; nonetheless, the final construction is identical.

from pydantic import BaseModel
from uuid import UUID,uuid4
from typing import Non-compulsory
from enum import Enum
from sqlalchemy import Column, String, Float, Integer
import sqlalchemy.dialects.postgresql as pg
from sqlalchemy.dialects.postgresql import UUID as SA_UUID
from sqlalchemy.ext.declarative import declarative_base
import uuid
from uuid import UUID

# loading sql mannequin
from sqlmodel import Discipline, Session, SQLModel, create_engine, choose

# Initialize the bottom class for SQLAlchemy fashions
Base = declarative_base()

# That is the Sport mannequin for the database
class Sport(Base):
    __tablename__ = "optigame_products"  # Desk title within the PostgreSQL database

    id = Column(pg.UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, distinctive=True, nullable=False)
    appid = Column(String, distinctive=True, nullable=False)  
    title = Column(String, nullable=False)  
    sort = Column(String, nullable=True)  
    is_free = Column(pg.BOOLEAN, nullable=True, default=False)  #
    short_description = Column(String, nullable=True)  
    detailed_description = Column(String, nullable=True)  
    builders = Column(String, nullable=True)  
    publishers = Column(String, nullable=True)  
    worth = Column(String, nullable=True)  
    genres = Column(String, nullable=True)  
    classes = Column(String, nullable=True)  
    release_date = Column(String, nullable=True)  
    platforms = Column(String, nullable=True)  
    metacritic_score = Column(Float, nullable=True)  
    suggestions = Column(Integer, nullable=True)  

class GameModel(BaseModel):
    id: Non-compulsory[UUID] = None
    appid: str
    title: str
    sort: Non-compulsory[str] = None
    is_free: Non-compulsory[bool] = False
    short_description: Non-compulsory[str] = None
    detailed_description: Non-compulsory[str] = None
    builders: Non-compulsory[str] = None
    publishers: Non-compulsory[str] = None
    worth: Non-compulsory[str] = None
    genres: Non-compulsory[str] = None
    classes: Non-compulsory[str] = None
    release_date: Non-compulsory[str] = None
    platforms: Non-compulsory[str] = None
    metacritic_score: Non-compulsory[float] = None
    suggestions: Non-compulsory[int] = None

    class Config:
        orm_mode = True  # Allow ORM mode to work with SQLAlchemy objects
        from_attributes = True # Allow attribute entry for SQLAlchemy objects

Setting Up FastAPI Routes

After we’ve our Fashions outlined, we will then create strategies to work together with these fashions and request information from the database(GET), add information to the Database(POST), or take away information from the database(DELETE). Under is an instance of how we will outline a GET request for our video games mannequin. We have now some preliminary setup firstly of our important.py operate to fetch the database URL and hook up with it. Then we initialize our app and add middleware to outline which URLs we’ll settle for requests from. As a result of we’ll be deploying the FastAPI mission on Render and sending requests to it from our native machine, the one origin we’re permitting is localhost port 8000. We then outline our app.get technique known as fetch_products, which takes an appid enter, queries our database for Sport objects the place appid is the same as our filtered appid, and returns these merchandise.

Be aware the under snipped incorporates simply the setup and first get technique, the remainder are pretty related and obtainable on the Repo, so we received’t give an in-depth clarification for every one right here.

from fastapi import FastAPI, Relies upon, HTTPException, BackgroundTasks
from uuid import uuid4, UUID
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Session
from dotenv import load_dotenv
import os

# Load atmosphere variables
load_dotenv()

# safety imports
from fastapi.middleware.cors import CORSMiddleware
from fastapi.safety import OAuth2PasswordBearer

# customized imports
from src.fashions import Consumer, Sport, GameModel, UserModel,  UserGameModel, UserGame, GameSimilarity,GameSimilarityModel, UserRecommendation, UserRecommendationModel
from src.similarity_pipeline import UserRecommendationService

# Load the database connection string from atmosphere variable or .env file
DATABASE_URL = os.environ.get("Internal_Database_Url")

# creating connection to the database
engine = create_engine(DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()

# Create the database tables (if they do not exist already)
Base.metadata.create_all(bind=engine)

# Dependency to get the database session
def get_db():
    db = SessionLocal()
    strive:
        yield db
    lastly:
        db.shut()

# Initialize the FastAPI app
app = FastAPI(title="Sport Retailer API", model="1.0.0")

# Add CORS middleware to permit requests 
origins = ["http://localhost:8000"]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,  
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)



#-------------------------------------------------#
# ----------PART 1: GET METHODS-------------------#
#-------------------------------------------------#
@app.get("/")
async def root():
    return {"message": "Good day World"}


@app.get("/api/v1/video games/")
async def fetch_products(appid: str = None, db: Session = Relies upon(get_db)):
    # Question the database utilizing the SQLAlchemy Sport mannequin
    if appid:
        merchandise = db.question(Sport).filter(Sport.appid == appid).all()
    else:
        merchandise = db.question(Sport).all()
    return [GameModel.from_orm(product) for product in products]

As soon as we’ve our important.py outlined, we will lastly run it from our base mission listing utilizing the command under.

uvicorn src.important:app --reload

As soon as that is finished, we will navigate to http://127.0.0.1:8000/docs and see the under interactive FastAPI atmosphere. From this web page, we will take a look at any of our strategies outlined in our important.py file. Within the case of our fetch_products operate, we will cross it an appid and return any matching video games from our database.

Determine 6: FastAPI Swagger Docs

Constructing our Similarity Pipeline

We have now our database arrange and may entry and replace information by way of FastAPI; it’s now time to show to the central characteristic of this mission: a recommender pipeline. Recommender techniques are a well-researched discipline, and we’re not including any innovation right here; nonetheless, it will supply a transparent instance of methods to implement a primary recommender system utilizing FastAPI.

Getting Began — Tips on how to Suggest Merchandise?

If we take into consideration the query “How would I like to recommend new merchandise {that a} consumer will like?”, there are two approaches that make intuitive sense.

  1. Collaborative Advice Techniques: If I’ve a sequence of customers and a sequence of merchandise, I may determine customers with related pursuits by taking a look at their general basket of merchandise after which determine merchandise ‘lacking’ from a given consumer’s basket. For instance, if I’ve customers 1–3 and merchandise A-C, customers 1–2 like all three merchandise, however consumer 3 has so far solely appreciated merchandise A + B, then I’d suggest them product C. This logically is sensible; all three customers have a excessive diploma of overlap in merchandise that they’ve appreciated, however product C is lacking from consumer 3’s basket, there’s a excessive chance that they want it as properly. This technique of producing suggestions by evaluating like customers is known as collaborative filtering.
  2. Content material-Primarily based Advice System: If I’ve a sequence of merchandise, I may determine merchandise which might be just like merchandise {that a} consumer has appreciated and suggest these merchandise. For instance, if I’ve a sequence of tags for every recreation, I may convert every recreation’s sequence of tags right into a vector of 1s and 0s after which use a similarity measure (on this case, a cosine similarity measure) to measure the similarity between video games primarily based on their vectors. As soon as I’ve finished this, I can then return the highest N most related video games to these appreciated by a consumer primarily based on their similarity rating.

Extra on Recommender Techniques could be discovered right here.

As a result of our preliminary dataset doesn’t have a big quantity of customers, we don’t have the required information to recommend gadgets primarily based on consumer similarity, which is called a chilly begin downside. Because of this, we’ll as a substitute develop a content-based recommender system as we’ve a major quantity of recreation information to work with.

To construct our pipeline, we’ve to deal with two challenges: (1) How will we go about calculating similarity scores for a consumer, and (2) how will we automate this to run at any time when a consumer makes an replace to their video games?

We’ll go over how a similarity pipeline could be triggered every time a consumer makes a POST request by ‘liking’ a recreation, after which cowl methods to construct the pipeline itself.

Tying Recommender Pipeline to FastAPI

For now, think about we’ve a Advice Service that may replace our user_recommendation desk. We need to make sure that this service is known as at any time when a consumer updates their preferences. We are able to implement this in a few steps as proven under; first, we outline a generate_recommendations_background operate, this operate is liable for connecting to our database, operating the similarity pipeline, after which closing the connection. Subsequent, we have to guarantee that is known as when a consumer makes a submit request(i.e., likes a brand new recreation); to do that, we merely add the operate name on the finish of our create_user_game submit request operate.

The results of this workflow is that at any time when a consumer makes a submit request to our user_game desk, they name the create_user_game operate, add a brand new user_game object to the database, after which run the similarity pipeline as a background operate.

Be aware: The Under submit technique and helper operate are saved in important.py with the remainder of our FastAPI strategies.

# importing similarity pipeline
from src.similarity_pipeline import UserRecommendationService

# Background job operate
def generate_recommendations_background(username: str, database_url: str):
    """Background job to generate suggestions for a consumer"""
    # Create a brand new database session for the background job
    background_engine = create_engine(database_url)
    BackgroundSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=background_engine)
    
    db = BackgroundSessionLocal()
    strive:
        recommendation_service = UserRecommendationService(db, database_url)
        recommendation_service.generate_recommendations_for_user(username)
    lastly:
        db.shut()

# Publish technique which calls background job operate
@app.submit("/api/v1/user_game/")
async def create_user_game(user_game: UserGameModel, background_tasks: BackgroundTasks, db: Session = Relies upon(get_db)):
    # Examine if the entry already exists
    current = db.question(UserGame).filter_by(username=user_game.username, appid=user_game.appid).first()
    if current:
        elevate HTTPException(status_code=400, element="Consumer already has this recreation.")

    # Put together information with defaults
    user_game_data = {
        "username": user_game.username,
        "appid": user_game.appid,
        "shelf": user_game.shelf if user_game.shelf shouldn't be None else "Wish_List",
        "ranking": user_game.ranking if user_game.ranking shouldn't be None else 0.0,
        "evaluate": user_game.evaluate if user_game.evaluate shouldn't be None else ""
    }
    if user_game.id shouldn't be None:
        user_game_data["id"] = UUID(str(user_game.id))

    # Save the consumer recreation to database
    db_user_game = UserGame(**user_game_data)
    db.add(db_user_game)
    db.commit()
    db.refresh(db_user_game)
    
    # Set off background job to generate suggestions for this consumer
    background_tasks.add_task(generate_recommendations_background, user_game.username, DATABASE_URL)
    
    return db_user_game

Constructing Recommender Pipeline

Now that we perceive how our similarity pipeline could be triggered when a consumer updates their appreciated video games, it’s time to dive into the mechanics of how the advice pipeline works. Our advice pipeline is saved in similarity_pipeline.py and incorporates our UserRecommendationService class that we confirmed methods to import and instantiate above. This class incorporates a sequence of helper features which might be in the end all known as within the generate_recommendations_for_user technique. There are 7 primary steps known as so that we’ll stroll by means of one after the other.

  1. Fetching a consumer’s Video games: To generate related recreation suggestions, we have to retrieve the video games {that a} consumer has already added to their recreation basket. That is finished by calling our fetch_user_games helper operate. This operate queries our user_games desk utilizing the consumer’s ID, which is making the submit request as an enter, and returning all video games of their basket.
  2. Fetching recreation tags: To check video games, we want a dimension to match them on, and that dimension is the tags related to every recreation(technique, board recreation, and so forth.). To retrieve the sport:tag mapping, we name our fetch_all_game_tags operate, which returns the tags for all of the video games in our database
  3. Vectorizing recreation tags: To check the similarity between video games A and B, we first have to vectorize the sport tags utilizing our create_game_vectors operate. This operate takes a sequence of all tags in alphabetical order and checks if every of the tags is related to a given recreation. For instance, if our whole set of tags was [boardgame, deckbuilding, resource-management] and recreation 1 simply had the boardgame tag related to it, then its vector can be [1, 0, 0].
  4. Creating our customers vector: as soon as we’ve a vector representing every recreation, we then want an mixture consumer vector to match it to. To realize this, we use our create_user_vector operate, which generates an mixture vector of the identical size as our recreation vectors that we will then use to generate a similarity rating between our consumer and each different recreation.
  5. Calculate Similarity: We use the vectors created in steps 3 and 4 in our calculate_user_recommendations, which calculates a cosine similarity rating starting from 0–1 and measuring the similarity between every recreation and our consumer mixture video games
  6. Deleting previous Suggestions: Earlier than we populate our user_recommendations desk with new suggestions for a consumer, we first need to delete the previous ones with delete_existing_recommendations. This deletes simply the suggestions for the consumer who made the submit request; the others stay the identical.
  7. Populate new Suggestions: After deleting the previous suggestions, we then populate the brand new ones with save_recommendations.


from sqlalchemy.orm import Session
from sqlalchemy import create_engine, textual content
from src.fashions import UserGame, UserRecommendation
from sklearn.metrics.pairwise import cosine_similarity
import pandas as pd
import uuid
from typing import Checklist
import logging

# Arrange logging
logging.basicConfig(degree=logging.INFO)
logger = logging.getLogger(__name__)

class UserRecommendationService:
    def __init__(self, db_session: Session, database_url: str):
        self.db = db_session
        self.database_url = database_url
        self.engine = create_engine(database_url)

    def fetch_user_games(self, username: str) -> pd.DataFrame:
        """Fetch all video games for a selected consumer"""
        question = textual content("SELECT username, appid FROM user_games WHERE username = :username")
        with self.engine.join() as conn:
            outcome = conn.execute(question, {"username": username})
            information = outcome.fetchall()
            return pd.DataFrame(information, columns=['username', 'appid'])

    def fetch_all_category(self) -> pd.DataFrame:
        """Fetch all recreation tags"""
        question = textual content("SELECT appid, class FROM class")
        with self.engine.join() as conn:
            outcome = conn.execute(question)
            information = outcome.fetchall()
            return pd.DataFrame(information, columns=['appid', 'category'])

    def create_game_vectors(self, tag_df: pd.DataFrame) -> tuple[pd.DataFrame, List[str], Checklist[str]]:
        """Create recreation vectors from tags"""
        unique_tags = tag_df['category'].drop_duplicates().sort_values().tolist()
        unique_games = tag_df['appid'].drop_duplicates().sort_values().tolist()
        
        game_vectors = []
        for recreation in unique_games:
            tags = tag_df[tag_df['appid'] == recreation]['category'].tolist()
            vector = [1 if tag in tags else 0 for tag in unique_tags]
            game_vectors.append(vector)
        
        return pd.DataFrame(game_vectors, columns=unique_tags, index=unique_games), unique_tags, unique_games

    def create_user_vector(self, user_games_df: pd.DataFrame, game_vectors: pd.DataFrame, unique_tags: Checklist[str]) -> pd.DataFrame:
        """Create consumer vector from their performed video games"""
        if user_games_df.empty:
            return pd.DataFrame([[0] * len(unique_tags)], columns=unique_tags, index=['unknown_user'])
        
        username = user_games_df.iloc[0]['username']
        user_games = user_games_df['appid'].tolist()
        
        # Solely hold video games that exist in game_vectors
        user_games = [g for g in user_games if g in game_vectors.index]
        
        if not user_games:
            user_vector = [0] * len(unique_tags)
        else:
            played_game_vectors = game_vectors.loc[user_games]
            user_vector = played_game_vectors.imply(axis=0).tolist()
        
        return pd.DataFrame([user_vector], columns=unique_tags, index=[username])

    def calculate_user_recommendations(self, user_vector: pd.DataFrame, game_vectors: pd.DataFrame, top_n: int = 20) -> pd.DataFrame:
        """Calculate similarity between consumer vector and all recreation vectors"""
        username = user_vector.index[0]
        user_vector_data = user_vector.iloc[0].values.reshape(1, -1)
        
        # Calculate similarities
        similarities = cosine_similarity(user_vector_data, game_vectors)
        similarity_df = pd.DataFrame(similarities.T, index=game_vectors.index, columns=[username])
        
        # Get high N suggestions
        top_games = similarity_df[username].nlargest(top_n)
        
        suggestions = []
        for appid, similarity in top_games.gadgets():
            suggestions.append({
                "username": username,
                "appid": appid,
                "similarity": float(similarity)
            })
        
        return pd.DataFrame(suggestions)

    def delete_existing_recommendations(self, username: str):
        """Delete current suggestions for a consumer"""
        self.db.question(UserRecommendation).filter(UserRecommendation.username == username).delete()
        self.db.commit()

    def save_recommendations(self, recommendations_df: pd.DataFrame):
        """Save new suggestions to database"""
        for _, row in recommendations_df.iterrows():
            advice = UserRecommendation(
                id=uuid.uuid4(),
                username=row['username'],
                appid=row['appid'],
                similarity=row['similarity']
            )
            self.db.add(advice)
        self.db.commit()

    def generate_recommendations_for_user(self, username: str, top_n: int = 20):
        """Fundamental technique to generate suggestions for a selected consumer"""
        strive:
            logger.information(f"Beginning advice technology for consumer: {username}")
            
            # 1. Fetch consumer's video games
            user_games_df = self.fetch_user_games(username)
            if user_games_df.empty:
                logger.warning(f"No video games discovered for consumer: {username}")
                return
            
            # 2. Fetch all recreation tags
            tag_df = self.fetch_all_category()
            if tag_df.empty:
                logger.error("No recreation tags present in database")
                return
            
            # 3. Create recreation vectors
            game_vectors, unique_tags, unique_games = self.create_game_vectors(tag_df)
            
            # 4. Create consumer vector
            user_vector = self.create_user_vector(user_games_df, game_vectors, unique_tags)
            
            # 5. Calculate suggestions
            recommendations_df = self.calculate_user_recommendations(user_vector, game_vectors, top_n)
            
            # 6. Delete current suggestions
            self.delete_existing_recommendations(username)
            
            # 7. Save new suggestions
            self.save_recommendations(recommendations_df)
            
            logger.information(f"Efficiently generated {len(recommendations_df)} suggestions for consumer: {username}")
            
        besides Exception as e:
            logger.error(f"Error producing suggestions for consumer {username}: {str(e)}")
            self.db.rollback()
            elevate

Wrapping Up

On this article, we lined methods to arrange a PostgreSQL database and FastAPI utility to run a recreation recommender system. Nonetheless, we haven’t but gone over methods to deploy this technique to a cloud service to permit others to work together with it. For half two masking precisely this, learn on in Half 2.

Figures: All photos, until in any other case famous, are by the writer.

Hyperlinks

  1. Github Repository for Venture: https://github.com/pinstripezebra/recommender_system
  2. FastAPI Docs: https://fastapi.tiangolo.com/tutorial/
  3. Recommender Techniques: https://en.wikipedia.org/wiki/Recommender_system
  4. Cosine Similarity: https://en.wikipedia.org/wiki/Cosine_similarity)
Tags: BuildingFastAPIgamePartPostgreSQLRecommenderRenderSystemsVideo
Previous Post

Decoding Nonlinear Alerts In Massive Observational Datasets

Next Post

DoWhile loops now supported in Amazon Bedrock Flows

Next Post
DoWhile loops now supported in Amazon Bedrock Flows

DoWhile loops now supported in Amazon Bedrock Flows

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Popular News

  • How Aviva constructed a scalable, safe, and dependable MLOps platform utilizing Amazon SageMaker

    How Aviva constructed a scalable, safe, and dependable MLOps platform utilizing Amazon SageMaker

    402 shares
    Share 161 Tweet 101
  • Diffusion Mannequin from Scratch in Pytorch | by Nicholas DiSalvo | Jul, 2024

    402 shares
    Share 161 Tweet 101
  • Unlocking Japanese LLMs with AWS Trainium: Innovators Showcase from the AWS LLM Growth Assist Program

    402 shares
    Share 161 Tweet 101
  • Streamlit fairly styled dataframes half 1: utilizing the pandas Styler

    401 shares
    Share 160 Tweet 100
  • Autonomous mortgage processing utilizing Amazon Bedrock Knowledge Automation and Amazon Bedrock Brokers

    401 shares
    Share 160 Tweet 100

About Us

Automation Scribe is your go-to site for easy-to-understand Artificial Intelligence (AI) articles. Discover insights on AI tools, AI Scribe, and more. Stay updated with the latest advancements in AI technology. Dive into the world of automation with simplified explanations and informative content. Visit us today!

Category

  • AI Scribe
  • AI Tools
  • Artificial Intelligence

Recent Posts

  • Automate Amazon QuickSight knowledge tales creation with agentic AI utilizing Amazon Nova Act
  • This Puzzle Exhibits Simply How Far LLMs Have Progressed in a Little Over a Yr
  • Accountable AI: How PowerSchool safeguards tens of millions of scholars with AI-powered content material filtering utilizing Amazon SageMaker AI
  • Home
  • Contact Us
  • Disclaimer
  • Privacy Policy
  • Terms & Conditions

© 2024 automationscribe.com. All rights reserved.

No Result
View All Result
  • Home
  • AI Scribe
  • AI Tools
  • Artificial Intelligence
  • Contact Us

© 2024 automationscribe.com. All rights reserved.