More setup

This commit is contained in:
Jacob Windsor 2025-02-19 12:39:01 +01:00
parent 239068e7f6
commit 861eac6d46
8 changed files with 128 additions and 31 deletions

2
.gitignore vendored
View File

@ -172,3 +172,5 @@ cython_debug/
# PyPI configuration file
.pypirc
venv

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"python.defaultInterpreterPath": ".venv/bin/python",
}

View File

@ -1,14 +1,14 @@
# Variables
APP_NAME=app/main.py
VENV_DIR=venv
REQ_FILE=requirements.txt
REQ_FILE=backend/requirements.txt
# Create virtual environment
venv:
python3 -m venv $(VENV_DIR)
# Install dependencies
install: venv
install:
$(VENV_DIR)/bin/pip install -r $(REQ_FILE)
# Run the application

View File

@ -1,27 +0,0 @@
from fastapi import APIRouter, HTTPException
from app.models.prediction import HousePredictionInput, HousePredictionOutput
from app.services.ml_model import HousePricePredictor
router = APIRouter()
model = HousePricePredictor()
@router.get("/predictions/house-price",
response_model=HousePredictionOutput,
summary="Get a house price prediction",
description="Predicts the price of a house based on its features"
)
async def predict_price(input_data: HousePredictionInput) -> HousePredictionOutput:
try:
predicted_price, confidence_score, similar_listings = model.predict(
input_data.square_feet,
input_data.bedrooms,
input_data.bathrooms
)
return HousePredictionOutput(
predicted_price=predicted_price,
confidence_score=confidence_score,
similar_listings=similar_listings
)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))

View File

@ -1,6 +1,6 @@
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from app.routers import predictions
from backend.app.dtos import predictions
app = FastAPI(
title="Housing Price Predictor API",

View File

@ -0,0 +1,118 @@
import os
import subprocess
from collections.abc import AsyncGenerator
from contextlib import asynccontextmanager
import asyncpg
import pg8000
import pg8000.dbapi
from google.cloud.sql.connector import Connector, IPTypes, create_async_connector
from sqlalchemy import Engine
from sqlalchemy.ext.asyncio import (
AsyncConnection,
AsyncEngine,
AsyncSession,
async_sessionmaker,
create_async_engine,
)
from sqlmodel import create_engine
from ..config import get_settings
from ..db.seed import seed
from ..models.base_db_model import BaseDBModel
async def _get_async_engine() -> AsyncEngine:
settings = get_settings()
if settings.app.environment == "development":
engine = create_async_engine(
f"postgresql+asyncpg://{settings.db.username}:{settings.db.password}@localhost/{settings.db.db_name}",
future=True,
)
else:
connector = await create_async_connector()
async def getconn() -> asyncpg.Connection:
return await connector.connect_async(
settings.db.connection_name,
"asyncpg",
user=settings.db.username,
password=settings.db.password,
db=settings.db.db_name,
ip_type=IPTypes.PUBLIC,
)
engine = create_async_engine("postgresql+asyncpg://", async_creator=getconn, future=True)
return engine
async def get_session() -> AsyncGenerator[AsyncSession, None]:
"""
Initialize a database session and return it.
Use this when interacting via the ORM.
"""
engine = await _get_async_engine()
async_session = async_sessionmaker(bind=engine, expire_on_commit=False)
async with async_session() as session:
yield session
@asynccontextmanager
async def get_connection() -> AsyncGenerator[AsyncConnection, None]:
"""
Initialize a database connection and return it.
Only use this when you need to execute raw SQL queries.
"""
engine = await _get_async_engine()
async with engine.connect() as connection:
yield connection
await engine.dispose()
def _get_engine() -> Engine:
settings = get_settings()
if settings.app.environment == "development":
engine = create_engine(
f"postgresql+pg8000://{settings.db.username}:{settings.db.password}@localhost/{settings.db.db_name}"
)
else:
connector = Connector()
def getconn() -> pg8000.dbapi.Connection:
conn: pg8000.dbapi.Connection = connector.connect(
settings.db.connection_name,
"pg8000",
user=settings.db.username,
password=settings.db.password,
db=settings.db.db_name,
ip_type=IPTypes.PUBLIC,
)
return conn
engine = create_engine("postgresql+pg8000://", creator=getconn)
return engine
def create_db_and_tables():
# TODO Move this to use asyncpg
engine = _get_engine()
BaseDBModel.metadata.create_all(engine)
if get_settings().app.environment == "development":
seed(engine)
def startup_migrations():
"""Run Alembic migrations"""
print("Running Alembic migrations...")
api_path = os.path.dirname(os.path.abspath(__file__)) + "/../.."
try:
subprocess.run(["alembic", "upgrade", "head"], check=True, cwd=api_path)
print("Migrations applied successfully!")
except subprocess.CalledProcessError as e:
print(f"Error applying migrations: {e}")

View File

@ -1,4 +1,5 @@
fastapi
uvicorn
sqlmodel
pydantic
pydantic
sqlalchemy