Image

Создание системы рекомендаций видеоигр с помощью FastAPI, PostgreSQL и Render: Часть 2

Развертывание рекомендательной системы FastAPI + PostgreSQL как веб-приложения на Render

Делиться

40c3bd5f00cb3c044542cbac60d63fa2

Начиная

В части 1 мы рассмотрели процесс настройки системы рекомендаций настольных игр с использованием FastAPI и PostgreSQL. Во второй части мы продолжим этот проект и покажем, как развернуть его в облачном сервисе, в данном случае Render, чтобы сделать его доступным для пользователей.

Чтобы воплотить это в реальность, мы будем работать над настройкой нашей базы данных PostgreSQL на Render, заполнением ее нашими данными, Dockerизацией нашего приложения FastAPI и, наконец, развертыванием его в веб-приложении Render.

Оглавление

  1. Развертывание базы данных PostgreSQL на Render
  2. Развертывание приложения FastAPI как приложения для рендеринга веб-сайтов
    – Докеризация нашего приложения
    – Отправка образа Docker в DockerHub
    – Извлечение из DockerHub в Render

Используемые инструменты

  • Оказывать
  • Docker Desktop
  • Докер-хаб

Развертывание при рендеринге

Теперь у нас есть база данных PostgreSQL и приложение FastAPI, работающие локально, и пришло время развернуть его в облачном сервисе, к которому будет иметь доступ клиентское приложение или конечный пользователь (через Swagger). Для этого проекта мы будем использовать Render; Render — это облачная платформа, которая для небольших проектов предлагает более простую настройку, чем крупные облачные провайдеры, такие как AWS и Azure.

Чтобы начать работу, перейдите в Render и создайте новую учётную запись. Затем вы можете создать новый проект, нажав кнопку «Новый проект», показанную ниже. Обратите внимание: на момент написания статьи у Render есть пробный период, который позволит вам бесплатно пользоваться им в течение первого месяца. Мы называем этот проект fastapi-test и перейдём к нему после его создания.

fb64feab434c5435d2225fcfaeae2487

Каждый проект содержит всё необходимое для его работы в автономной среде. В данном случае нам нужны два компонента: база данных и веб-сервер для нашего приложения FastAPI. Начнём с создания базы данных.

1a3a6663293caaa5b3124ea7d7712f0b

Это очень просто: мы выбираем «Создать новую службу», как показано на рисунке 3, а затем выбираем «Postgres». Затем мы переходим к полю, показанному на рисунке 4, для настройки базы данных. Называем нашу базу данных «fastapi-database» и выбираем бесплатный тарифный план. Render позволяет использовать бесплатный тарифный план только в течение ограниченного времени, но для данного примера этого будет достаточно, а если вам нужно поддерживать базу данных в течение длительного времени, цена будет вполне разумной.

60670a9e8133518fff9c6a6c38a833ad

После ввода данных о базе данных и нажатия кнопки «Создать» её настройка займёт всего минуту. Вы увидите экран, показанный на рисунке 5. Мы сохраним переменные «URL внутренней базы данных» и «URL внешней базы данных» в файле .env, так как они понадобятся нам для подключения из нашего приложения FastAPI. Затем мы можем протестировать подключение к базе данных, используя переменную «URL внешней базы данных» (подключение с локальной машины происходит вне среды рендеринга), и создать таблицы на локальной машине, прежде чем перейти к настройке приложения FastAPI.

c12dcee631d357c9a04c03fb75e3d565

Затем мы запускаем наш тестовый скрипт подключения к базе данных, который пытается подключиться к ней, используя переменную External_Database_Url в качестве строки подключения, и создаёт тестовую таблицу. Обратите внимание, что наша переменная External_Database_Url — это полная строка подключения к базе данных, поэтому мы можем передать её как единственный входной параметр. Успешное выполнение должно привести к выводу, показанному на рисунке 6.

6a6c07efb1f6bd793aa0f9caa0ca4bf1

из sqlalchemy import create_engine из sqlalchemy.orm import sessionmaker, Session из sqlalchemy.ext.declarative import declarative_base import os из dotenv import load_dotenv из utils.db_handler import DatabaseHandler import pandas as pd import uuid import sys из sqlalchemy.exc import OperationalError import psycopg2 # Загрузка переменных среды из файла .env (override=True перезагружает измененные значения) load_dotenv(override=True) # загрузка URL внешней базы данных database_url = os.environ.get(«External_Database_Url») if not database_url: print(«❌ External_Database_Url не найден в переменных среды») print(«Проверьте, содержит ли ваш файл .env: External_Database_Url=your_render_postgres_url») sys.exit(1) print(f»Database URL загружен: {database_url[:50]}…») # Анализ URL базы данных для извлечения компонентов для тестирования из urllib.parse import urlparse import socket def parse_database_url(url): «»»Анализ URL базы данных для извлечения компонентов подключения»»» parsed = urlparse(url) return { 'host': parsed.hostname, 'port': parsed.port или 5432, 'database': parsed.path.lstrip('/'), 'username': parsed.username, 'password': parsed.password } db_params = parse_database_url(database_url) def test_network_connectivity(): «»»Проверка сетевого подключения к конечной точке Render PostgreSQL»»» print(«n=== Тесты сетевого подключения ===») # 1. Тест разрешения DNS try: ip_address = socket.gethostbyname(db_params['host']) print(f»✅ Разрешение DNS успешно») except socket.gaierror as e: print(f»❌ Разрешение DNS не удалось: {e}») return False # 2. Тест подключения порта try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(10) # 10-секундный тайм-аут result = sock.connect_ex((db_params['host'], int(db_params['port']))) sock.close() if result == 0: print(f»✅ Порт {db_params['port']} доступен») return True else: print(f»❌ Порт {db_params['port']} НЕдоступен») print(» Это может указывать на проблему с сетевым подключением») return False except Exception as e: print(f»❌ Проверка подключения к порту не удалась: {e}») return False # Запуск тестов подключения network_ok = test_network_connectivity() if not network_ok: print(«n🔍 ШАГИ ПО УСТРАНЕНИЮ НЕПОЛАДОК:») print(«1. Проверьте подключение к Интернету») print(«2. Убедитесь, что URL-адрес Render PostgreSQL верный») print(«3. Убедитесь, что экземпляр Render PostgreSQL активен») print(«4. Проверьте, нет ли сбоев в работе службы Render») sys.exit(1) print(«n=== Попытка подключения к базе данных ===») # подключитесь к базе данных с помощью psycopg2 try: conn = psycopg2.connect( host=db_params['host'], database=db_params['database'], user=db_params['username'], password=db_params['password'], port=db_params['port'], connect_timeout=30 # 30-секундный тайм-аут ) # Если соединение установлено успешно, вы можете выполнять операции с базой данных cursor = conn.cursor() # Пример: выполнение простого запроса cursor.execute(«SELECT version();») db_version = cursor.fetchone() print(f»✅ Версия базы данных PostgreSQL: {db_version[0]}») # Тестовое создание простой таблицы для проверки прав доступа cursor.execute(«CREATE TABLE IF NOT EXISTS connection_test (id SERIAL PRIMARY KEY, test_time TIMESTAMP DEFAULT NOW());») conn.commit() print(«✅ Права доступа к базе данных проверены — можно создавать таблицы») cursor.close() conn.close() print(«✅ Подключение к psycopg2 успешно установлено!») except psycopg2.OperationalError as e: print(f»❌ Ошибка подключения к базе данных: {e}») if «timeout» in str(e).lower(): print(«n🔍 УСТРАНЕНИЕ НЕПОЛАДОК С ТАЙМ-АУТОМ:») print(«- Проверьте подключение к Интернету») print(«- Убедитесь, что URL-адрес Render PostgreSQL верный») print(«- Проверьте, нет ли проблем со службой Render») elif «authentation» in str(e).lower(): print(«n🔍 УСТРАНЕНИЕ НЕПОЛАДОК С АУТЕНТИФИКАЦИЕЙ:») print(«- Убедитесь, что URL-адрес базы данных содержит правильные учетные данные») print(«- Проверьте, активна ли служба Render PostgreSQL») print(«- Убедитесь, что URL-адрес базы данных не устарел и не изменился») sys.exit(1) except Exception as e: print(f»❌ Неожиданная ошибка: {e}») sys.exit(1) # Если мы попали сюда, соединение установлено успешно, поэтому выходим из теста print(f»n✅ Все тесты пройдены! Соединение с Render PostgreSQL работает.») print(f»✅ Подключено к базе данных: {db_params['database']}») print(«✅ Готово к использованию в вашем приложении!»)

Загрузка базы данных

Теперь, когда мы убедились, что можем подключиться к нашей базе данных с локального компьютера, пришло время настроить таблицы базы данных и заполнить их. Для загрузки базы данных мы воспользуемся файлом src/load_database.py, который мы уже рассматривали в отдельных частях скрипта в начале статьи, поэтому здесь мы не будем вдаваться в подробности. Единственное, что стоит отметить, — это то, что мы снова используем External_Database_Url в качестве строки подключения, а затем, в конце, используем функцию test_table, которую мы определили как часть класса DatabaseHandler. Эта функция пытается подключиться к переданному ей имени таблицы и возвращает количество строк в ней.

Запуск этого скрипта должен привести к выводу, показанному на рисунке 11, где каждая из таблиц была создана, а затем в конце мы повторно проверяем, можем ли мы вернуть из них данные, и показываем, что выходные строки соответствуют входным строкам.

ea9c7263be57c3301800b2cb8a75b21d

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 # Загрузка переменных среды из файла .env load_dotenv(override=True) # Создание URL-адреса подключения PostgreSQL для рендеринга URL_database = os.environ.get(«External_Database_Url») # Инициализация DatabaseHandler с помощью созданного URL-адреса engine = DatabaseHandler(URL_database) # загрузка начальных данных пользователя users_df = pd.read_csv(«Data/steam_users.csv») games_df = pd.read_csv(«Data/steam_games.csv») user_games_df = pd.read_csv(«Data/steam_user_games.csv») user_recommendations_df = pd.read_csv(«Data/user_recommendations.csv») game_tags_df = pd.read_csv(«Data/steam_game_tags.csv») # Определение запросов для создания таблиц user_table_creation_query = «»»СОЗДАТЬ ТАБЛИЦУ, ЕСЛИ НЕ СУЩЕСТВУЕТ users ( id UUID ПЕРВИЧНЫЙ КЛЮЧ, имя пользователя VARCHAR(255) УНИКАЛЬНЫЙ НЕ NULL, пароль VARCHAR(255) НЕ NULL, эл. почта VARCHAR(255) НЕ NULL, роль VARCHAR(50) НЕ NULL ) «»» game_table_creation_query = «»»СОЗДАТЬ ТАБЛИЦУ, ЕСЛИ НЕ СУЩЕСТВУЕТ games (id UUID PRIMARY KEY, appid VARCHAR(255) UNIQUE NOT NULL, name VARCHAR(255) NOT NULL, type VARCHAR(255), is_free BOOLEAN DEFAULT FALSE, short_description TEXT, detailed_description TEXT, developers VARCHAR(255), publishers VARCHAR(255), price VARCHAR(255), genres VARCHAR(255), categories VARCHAR(255), release_date VARCHAR(255), platform 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) ПО УМОЛЧАНИЮ 'Wish_List', рейтинг FLOAT ПО УМОЛЧАНИЮ 0.0, отзыв ТЕКСТ ) «»» advice_table_creation_query = «»»СОЗДАТЬ ТАБЛИЦУ, ЕСЛИ НЕ СУЩЕСТВУЕТ user_recommendations ( id UUID ПЕРВИЧНЫЙ КЛЮЧ, имя пользователя VARCHAR(255), appid VARCHAR(255), сходство FLOAT ) «»» game_tags_creation_query = «»»СОЗДАТЬ ТАБЛИЦУ, ЕСЛИ НЕ СУЩЕСТВУЕТ game_tags ( id UUID ПЕРВИЧНЫЙ КЛЮЧ, appid VARCHAR(255) NOT NULL, категория VARCHAR(255) NOT NULL ) «»» # Выполнение запросов для создания таблиц engine.delete_table('user_recommendations') engine.delete_table('user_games') engine.delete_table('game_tags') engine.delete_table('games') engine.delete_table('users') # Создание таблиц 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) # Обеспечение того, чтобы каждая строка каждого кадра данных имела уникальный идентификатор если 'id' отсутствует в users_df.columns: users_df['id'] = [str(uuid.uuid4()) for _ in range(len(users_df))] если 'id' отсутствует в games_df.columns: games_df['id'] = [str(uuid.uuid4()) for _ in range(len(games_df))] если 'id' отсутствует в 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))] # Заполняет 4 таблицы данными из фреймов данных engine.populate_table_dynamic(users_df, 'users') engine.populate_table_dynamic(games_df, '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') # Проверка того, были ли таблицы созданы и заполнены правильно print(engine.test_table('users')) print(engine.test_table('games')) print(engine.test_table('user_games')) print(engine.test_table('user_recommendations')) print(engine.test_table('game_tags'))

Развертывание приложения FastAPI на Render

Первая половина нашего проекта уже развернута на Render, и пришло время настроить наше приложение FastAPI. Для этого мы воспользуемся сервисом хостинга веб-приложений Render, который позволит нам развернуть наше приложение FastAPI как веб-приложение, к которому смогут обращаться внешние сервисы. Если бы мы хотели создать полнофункциональное приложение, мы могли бы разрешить нашему фронтенду отправлять запросы приложению FastAPI на Render и возвращать данные пользователю. Однако, поскольку на данный момент мы не заинтересованы в создании фронтенд-компонента, мы будем взаимодействовать с нашим приложением через документацию Swagger.

Контейнеризация нашего приложения с помощью Docker

Мы настроили наш проект FastAPI в локальной среде, но теперь нам нужно перенести его вместе со всем кодом, зависимостями и переменными окружения в контейнер на Render. Это может оказаться непростой задачей. К счастью, Docker берёт на себя все сложные этапы и позволяет нам сделать это с помощью простого файла конфигурации и пары команд. Для тех, кто ещё не использовал Docker, есть отличное руководство здесь. Вкратце, Docker — это инструмент, который упрощает процесс развёртывания и управления приложениями, позволяя упаковать наше приложение со всеми его зависимостями в образ, а затем развернуть этот образ в сервисе, таком как Render. В этом проекте мы используем DockerHub в качестве репозитория образов, который служит центральным хранилищем с контролем версий для нашего образа, который затем можно загрузить в Render.

Общую схему работы над этим проектом можно представить следующим образом: приложение FastAPI работает локально → С помощью Docker делается снимок состояния, который сохраняется как образ Docker → Этот образ отправляется в DockerHub → Render извлекает этот образ и использует его для запуска контейнера, который запускает приложение на сервере рендеринга. Для начала работы с этим процессом, который мы рассмотрим далее, требуется установленный Docker Desktop. Процесс установки Docker прост и доступен здесь: https://www.docker.com/products/docker-desktop/

Кроме того, если у вас ещё нет учётной записи Docker Hub, вам понадобится учётная запись Docker Hub, поскольку она будет служить репозиторием для сохранения образов Docker и их последующей загрузки в Render. Создать Docker Hub можно здесь: https://hub.docker.com/.

Создание образа Docker

Чтобы создать образ Docker для нашего проекта, сначала убедитесь, что Docker Desktop запущен. Если это не так, при попытке создать образ Docker, скорее всего, возникнет ошибка. Чтобы убедиться, что приложение Docker Desktop запущено, откройте его из строки поиска или с рабочего стола, нажмите на три точки в левом нижнем углу, как показано ниже, и убедитесь, что вы видите зелёную точку, а затем надпись «Docker Desktop запущен».

169ba6c0535f8eda36482da01b53013f

Далее нам нужно указать Docker, как собрать наш образ. Для этого нужно определить Dockerfile. Наш Dockerfile показан на рисунке 9. Мы сохраняем его в каталоге верхнего уровня. Он содержит инструкции, сообщающие Docker, как упаковать наше приложение в образ, который можно развернуть на другом оборудовании. Давайте разберёмся с этим файлом, чтобы понять, что он делает.

  1. ИЗ: Выбор базового образа: Первая строка в нашем Dockerfile определяет базовый образ, который мы хотим использовать для расширения нашего приложения. В данном случае мы используем образ python:3.13-slim-bullseye — облегчённый образ на базе Debian, который послужит основой для нашего приложения.
  2. WORKDIR: Изменение рабочего каталога: здесь мы устанавливаем каталог по умолчанию внутри нашего контейнера на /app.
  3. RUN: Проверка обновлений системных зависимостей
  4. КОПИЯ: Копирование файла requirements.txt. Крайне важно, чтобы файл requirements.txt был актуальным и содержал все библиотеки, необходимые для проекта, иначе образ не будет работать правильно, когда мы попытаемся его развернуть.
  5. ЗАПУСК: Установка файла requirements.txt
  6. КОПИРОВАТЬ: Скопировать весь наш проект из локального каталога в /app, который мы создали на шаге 2.
  7. RUN: Создание каталога журналов в /app/logs
  8. РАСКРЫТЬ: Задокументируйте, что порт, который мы будем раскрывать, — это порт 8000.
  9. ENV: Устанавливает наш путь Python на /app
  10. CMD: запускает наше приложение FastAPI с помощью Uvicorn, устанавливает наше приложение в соответствии с указанным в src.main:app, запускает наше приложение на порту 8000
f8ef5a6a4ed8e28e2f51b8f5fabf4dd0

Определив Dockerfile, мы получаем набор инструкций, которые можно передать Docker для контейнеризации нашего приложения в образ, который затем можно отправить в Docker Hub. Теперь это можно сделать с помощью пары команд из терминала VS Code, показанных ниже. Каждую из этих строк нужно выполнить отдельно в терминале VS Code из корневого каталога вашего проекта.

  1. Сначала мы создаём образ Docker, что, вероятно, займёт минуту-другую. В данном случае мы называем наш образ «recommendersystem».
  2. Далее мы добавляем теги к нашему образу, синтаксис здесь следующий: имя_образа имя_пользователя/папка_docker_hub:имя_образа_на_dockerhub
  3. Наконец, мы снова помещаем наш образ в Dockerhub, указав имя_пользователя/папку_docker_hub:имя_образа_на_dockerhub

docker build -t recommendersystem . docker tag recommendersystem seelucas/fastapi_tutorial:fastapi_on_render docker push seelucas/fastapi_tutorial:fastapi_on_render

После этого мы сможем войти в DockerHub, перейти к нашему проекту и увидеть, что у нас есть изображение, имя которого совпадает с тем, что мы дали ему в предыдущих трех командах, в данном случае — fastapi_on_render.

c65996cff1045bdc1e210ef1c0da2377

Извлечение образа Docker для рендеринга

Теперь у нас есть образ Docker на DockerHub, и пришло время развернуть его на Render. Для этого перейдите в тот же проект, в котором мы создали нашу базу данных, «fastapi-test», выберите «New» в правом верхнем углу, а затем выберите «Web Service», так как наше приложение FastAPI будет развёрнуто как веб-приложение.

Поскольку мы развёртываем образ из Dockerhub, мы указываем, что наш исходный код — это существующий образ, и, как показано на рисунке 11, вставляем путь к каталогу Dockerhub к образу, который хотим развернуть, в поле «URL образа» в Render. После этого мы получаем уведомление о том, что это приватный образ, а это значит, что нам потребуется создать токен доступа Dockerhub, который затем можно будет использовать для безопасного извлечения образа из DockerHub в Render.

a36dca1db4a20c1b658ed04fd068dd45

К счастью, создать токен доступа DockerHub довольно просто: переходим в учётную запись DockerHub -> Настройки → Токен личного доступа. Экран должен выглядеть, как на рисунке 12. Мы указываем имя токена доступа, срок действия и разрешения. Поскольку мы загружаем изображение в Render, нам нужен только доступ на чтение, а не на запись или удаление, поэтому выбираем этот вариант.

d77796e6219b55e8267e5fafefb7d6dc

Наконец, выбор «Сгенерировать» сгенерирует наш токен, который затем нужно скопировать для визуализации и ввести, как показано на рисунке 13.

abaa424c2d00c9cf0b2b7b113621938b

После того, как мы нажмём «Добавить учётные данные», как показано выше, загрузка займёт около минуты, пока учётные данные будут сохранены. Затем мы вернёмся на предыдущий экран, где сможем выбрать учётные данные для подключения к DockerHub. В данном случае мы используем только что созданные учётные данные из руководства и выберем «Подключиться». Таким образом, будет установлено подключение, которое можно использовать для загрузки образа Docker из DockerHub в Render for Deployment.

fbe461ff95ec7324abba0d05b3e87de0

На следующей странице мы приступаем к настройке нашего приложения Render Web, выбрав бесплатный вариант, а затем, что важно, в разделе «Переменные среды» копируем и вставляем наш файл .env. Хотя мы не используем все переменные из этого файла, мы используем «Internal_Database_Url» — URL-адрес, который FastAPI будет искать в нашем файле main.py. Без этого мы не сможем подключиться к нашей базе данных, поэтому крайне важно указать его. Примечание: ранее для тестирования мы использовали «External_Database_Url», поскольку запускали скрипт с локального компьютера, который находится вне нашей среды Render; однако здесь и база данных, и веб-сервер находятся в одной среде Render, поэтому мы используем Internal_Database_Url в файле main.py.

После ввода переменных среды мы выбираем «Развернуть веб-службу».

a39d1a366deb79f342f61955053a467f

Развертывание службы займет несколько минут, но затем вы должны получить уведомление, как показано ниже, о том, что служба развернута, со ссылкой на рендеринг вверху, по которой мы можем получить доступ.

30596b4c1d245cd340b1dd66181867ae

Перейдя по этой ссылке, мы перейдём к методу Hello World. Если добавить /docs в конец, мы перейдём к документации Swagger, как показано на рисунке 17. Здесь мы можем проверить и убедиться, что наше веб-приложение FastAPI подключено к базе данных, используя метод Fetch All Users. Ниже мы видим, что он действительно возвращает данные.

7363c94bbee18041124bd6990c1af904

Наконец, мы хотим проверить, обновляется ли наша система рекомендаций пользователей динамически. В вашем предыдущем вызове API мы видим, что в нашей базе данных есть пользователь «user_username». Используя метод Fetch Suggested Game с этим именем пользователя, мы видим, что наиболее подходящим является appid = B08BHHRSPK.

25d5158032f7bda0f28be6cb59d2a6d3

Мы обновляем понравившиеся игры наших пользователей, выбирая случайную игру из нашего списка игр appid = B0BHTKGN7F, которой оказывается «The Elder Scrolls: Skyrim Boardgame», и используя наш метод POST user_games.

b5ce2e2c44e145200bf54357aaada5c4

Добавление игры в таблицу игр пользователя должно автоматически запускать конвейер рекомендаций для этого пользователя и генерировать новые рекомендации. Если мы перейдём в консоль, то увидим, что это, по всей видимости, произошло, поскольку мы видим сообщение о создании новых рекомендаций пользователя, показанное ниже.

82f56bd709a2e1939b24612e39e3dce6

Если вернуться к документации Swagger, можно снова попробовать метод получения рекомендаций, и на рисунке 21 мы увидим, что список рекомендаций действительно отличается от предыдущего. Наш конвейер рекомендаций теперь автоматически обновляется по мере добавления пользователями новых данных и доступен за пределами нашей локальной среды.

b975b8b19206329eb26d36df319a3000

Подведение итогов:

В этом проекте мы показали, как настроить и развернуть систему рекомендаций, использующую уровень взаимодействия FastAPI с базой данных PostgreSQL для генерации интеллектуальных рекомендаций настольных игр для наших пользователей. Мы могли бы предпринять дополнительные шаги для повышения надежности этой системы, например, внедрить гибридную систему рекомендаций по мере накопления пользовательских данных или включить маркировку пользователей для охвата большего количества функций. Кроме того, хотя мы не рассматривали это в подробностях, мы использовали рабочий процесс GitHub для пересборки и публикации образа Docker при каждом обновлении нашей основной ветки. Этот код доступен в .github/workflows. Это значительно ускорило разработку, поскольку нам не приходилось вручную пересобирать образ Docker при каждом небольшом изменении.

Надеюсь, вам понравилось чтение и это поможет вам создавать и развертывать свои проекты с помощью FastAPI.

LinkedIn: https://www.linkedin.com/in/lucas-see-6b439188/

Электронная почта: [email protected]

Рисунки : Все изображения, если не указано иное, принадлежат автору.

Ссылки:

  1. Репозиторий Github для проекта: https://github.com/pinstripezebra/recommender_system
  2. Документация FastAPI: https://fastapi.tiangolo.com/tutorial/
  3. Учебное пособие по Docker: https://www.youtube.com/watch?v=b0HMimUb4f0
  4. Загрузка Docker Desktop: https://www.youtube.com/watch?v=b0HMimUb4f0
  5. Docker Hub: https://hub.docker.com/

Источник: towardsdatascience.com

✅ Найденные теги: новости, Создание
Каталог бесплатных опенсорс-решений, которые можно развернуть локально и забыть о подписках

галерея

Фото сгенерированных лиц: исследование показывает, что люди не могут отличить настоящие лица от сгенерированных
Нейросети построили капитализм за трое суток: 100 агентов Claude заперли…
Скетч: цифровой осьминог и виртуальный мир внутри компьютера с человечком.
Сцена с жестами пальцами, где один жест символизирует "VPN", а другой "KHP".
‼️Paramount купила Warner Bros. Discovery — сумма сделки составила безумные…
Скриншот репозитория GitHub "Claude Scientific Skills" AI для научных исследований.
Структура эффективного запроса Claude с элементами задачи, контекста и референса.
Эскиз и готовая веб-страница платформы для AI-дизайна в современном темном режиме.
ideipro logotyp
Image Not Found
Звёздное небо с галактиками и туманностями, космос, Вселенная, астрофотография.

Система оповещения обсерватории Рубина отправила 800 000 сигналов в первую ночь наблюдений.

Астрономы будут получать оповещения о небесных явлениях в течение нескольких минут после их обнаружения. Теренс О'Брайен, редактор раздела «Выходные». Публикации этого автора будут добавляться в вашу ежедневную рассылку по электронной почте и в ленту новостей на главной…

Мар 2, 2026
Женщина с длинными тёмными волосами в синем свете, нейтральный фон.

Расследование в отношении 61-фунтовой машины, которая «пожирает» пластик и выплевывает кирпичи.

Обзор компактного пресса для мягкого пластика Clear Drop — и что будет дальше. Шон Холлистер, старший редактор Публикации этого автора будут добавляться в вашу ежедневную рассылку по электронной почте и в ленту новостей на главной странице вашего…

Мар 2, 2026
Черный углеродное волокно с текстурой плетения, отражающий свет.

Материал будущего: как работает «бессмертный» композит

Учёные из Университета штата Северная Каролина представили композит нового поколения, способный самостоятельно восстанавливаться после серьёзных повреждений.  Речь идёт о модифицированном армированном волокном полимере (FRP), который не просто сохраняет прочность при малом весе, но и способен «залечивать» внутренние…

Мар 2, 2026
Круглый экран с изображением замка и горы, рядом электронная плата.

Круглый дисплей Waveshare для креативных проектов

Круглый 7-дюймовый сенсорный дисплей от Waveshare создан для разработчиков и дизайнеров, которым нужен нестандартный экран.  Это IPS-панель с разрешением 1 080×1 080 пикселей, поддержкой 10-точечного ёмкостного сенсора, оптической склейкой и защитным закалённым стеклом, выполненная в круглом форм-факторе.…

Мар 2, 2026

Впишите свой почтовый адрес и мы будем присылать вам на почту самые свежие новости в числе самых первых