Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A minimal collection of deployment scripts #145

Merged
merged 129 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
129 commits
Select commit Hold shift + click to select a range
f7a270d
slim scripts in progress
rfl-urbaniak Aug 19, 2024
5134435
retrained with pyro 1.9.1
rfl-urbaniak Aug 20, 2024
4f1748c
training and prediction for deployment test ready
rfl-urbaniak Aug 20, 2024
6fb6354
format lint
rfl-urbaniak Aug 20, 2024
bdf65a1
switch train_model and predict over to database source
jfeser Aug 28, 2024
e2b666a
use db to perform interventions
jfeser Aug 29, 2024
ab5a48f
refactor
jfeser Sep 3, 2024
3cc1bf4
add .env file with db info
jfeser Sep 3, 2024
a76480a
add missing files
jfeser Sep 3, 2024
e9bd649
fix causal_insight_slim.py so that app will load
jfeser Sep 4, 2024
2227b1c
work on getting predict ready to connect to api
jfeser Sep 4, 2024
6095236
data setup WIP
rfl-urbaniak Sep 5, 2024
6dcb1c7
added pg dataset, cursory EDA
rfl-urbaniak Sep 5, 2024
65b38d5
testing sqm
rfl-urbaniak Sep 5, 2024
9c52b0b
more api work
jfeser Sep 5, 2024
238d1b3
Merge branch 'ru-tracts-minimal-deployment' of github.com:BasisResear…
jfeser Sep 5, 2024
6e6ec3b
added all sqm columns to torch data loader
rfl-urbaniak Sep 6, 2024
591753b
scripts and mechanisms
jfeser Sep 9, 2024
9ed393c
added model compontents
rfl-urbaniak Aug 5, 2024
9bb6982
test get_n
rfl-urbaniak Aug 5, 2024
9f56a9e
tests for linear component
rfl-urbaniak Aug 5, 2024
b94be7f
test logistic component
rfl-urbaniak Aug 5, 2024
c1d8180
test ratio component
rfl-urbaniak Aug 5, 2024
592fa34
black upgraded
rfl-urbaniak Aug 5, 2024
4eed575
remove worktrees
rfl-urbaniak Aug 7, 2024
d2e11f1
small revision to clean
rfl-urbaniak Aug 7, 2024
418a888
clean up experimental notebooks structure
rfl-urbaniak Aug 7, 2024
f5e75aa
moved cleaning scripts, test model WIP
rfl-urbaniak Aug 7, 2024
b345066
tracts model test added
rfl-urbaniak Aug 7, 2024
5ef5295
added clean path script
rfl-urbaniak Aug 7, 2024
087d509
renaming model file
rfl-urbaniak Aug 7, 2024
3490733
add evaluation, format lint
rfl-urbaniak Aug 7, 2024
8b04614
add eval to model test
rfl-urbaniak Aug 7, 2024
61b0fc2
add trained guide and params
rfl-urbaniak Aug 7, 2024
b053058
modeling notebook
rfl-urbaniak Aug 7, 2024
062c7c6
clean notebook
rfl-urbaniak Aug 7, 2024
4e72837
slim scripts in progress
rfl-urbaniak Aug 19, 2024
bc1a657
retrained with pyro 1.9.1
rfl-urbaniak Aug 20, 2024
71aacf3
training and prediction for deployment test ready
rfl-urbaniak Aug 20, 2024
45d86f6
format lint
rfl-urbaniak Aug 20, 2024
2aea5aa
switch train_model and predict over to database source
jfeser Aug 28, 2024
68591de
use db to perform interventions
jfeser Aug 29, 2024
053a882
refactor
jfeser Sep 3, 2024
24b9be8
add missing files
jfeser Sep 3, 2024
c0eac8f
fix causal_insight_slim.py so that app will load
jfeser Sep 4, 2024
bfdf970
work on getting predict ready to connect to api
jfeser Sep 4, 2024
ece310a
more api work
jfeser Sep 5, 2024
e8ffc03
data setup WIP
rfl-urbaniak Sep 5, 2024
31fa638
added pg dataset, cursory EDA
rfl-urbaniak Sep 5, 2024
042f648
testing sqm
rfl-urbaniak Sep 5, 2024
f92766f
fix up paths
jfeser Sep 5, 2024
703ace2
take intervention as parameters
jfeser Sep 6, 2024
84ec622
copy postgrest api over from db-parcels
jfeser Sep 6, 2024
897870e
work on api
jfeser Sep 9, 2024
6c15638
build api container
jfeser Sep 9, 2024
d54b6e2
more work on api deployment
jfeser Sep 10, 2024
0eaf79c
perf improvements
jfeser Sep 10, 2024
05e80e6
fix connection pool exhaustion
jfeser Sep 10, 2024
5481c16
none safety
jfeser Sep 11, 2024
2bb8eaa
include all demographics and census tracts in frontend
jfeser Sep 11, 2024
be2fc5d
allow caching api responses
jfeser Sep 11, 2024
df5390f
add api runner
jfeser Sep 11, 2024
4a76369
return proper geojson features
jfeser Sep 11, 2024
20ef5ad
ensure geometry is in the right srid
jfeser Sep 11, 2024
cbeea8a
return featurecollections
jfeser Sep 11, 2024
256a9b1
Merge branch 'ru-tracts-minimal-deployment' of github.com:BasisResear…
jfeser Sep 11, 2024
a3c67e7
allow all origins in dev
jfeser Sep 11, 2024
b2b817d
use db_username to avoid shell issue
naiimic Sep 11, 2024
d7e9aa9
Merge branch 'ru-tracts-minimal-deployment' of https://github.com/Bas…
naiimic Sep 11, 2024
6554bc4
add load_dotenv to train_model
rfl-urbaniak Sep 12, 2024
1c64747
Merge branch 'staging-zoning' of https://github.com/BasisResearch/cit…
rfl-urbaniak Sep 12, 2024
d2e3d7b
pull orign from staging, format, lint
rfl-urbaniak Sep 12, 2024
72307dc
user-facing overview WIP
rfl-urbaniak Sep 12, 2024
b0c2e81
note to self in overview
rfl-urbaniak Sep 12, 2024
4ea4694
format
jfeser Sep 12, 2024
b1c9863
Merge branch 'ru-tracts-minimal-deployment' of github.com:BasisResear…
jfeser Sep 12, 2024
51728f5
Merge branch 'ru-tracts-minimal-deployment' of https://github.com/Bas…
rfl-urbaniak Sep 12, 2024
a723c64
added overview draft
rfl-urbaniak Sep 12, 2024
9835a69
switch predict endpoint to produce cumulative estimates
jfeser Sep 12, 2024
4c49ea9
scripts to grab private local env from home
rfl-urbaniak Sep 12, 2024
502ea83
clean makefile reference to grab
rfl-urbaniak Sep 12, 2024
3a5a78f
fixing param saving and passing pipeline
rfl-urbaniak Sep 12, 2024
e76b15b
up n_steps back to 2000
rfl-urbaniak Sep 12, 2024
e24ffe4
swap models, fix train->predict generate loader pipeline
rfl-urbaniak Sep 12, 2024
d9c7d3e
up n_steps to 2k again
rfl-urbaniak Sep 12, 2024
459b39d
minor changes
jfeser Sep 12, 2024
96e3842
Merge branch 'ru-tracts-minimal-deployment' of github.com:BasisResear…
jfeser Sep 12, 2024
94fb197
add missing params warning to predict
rfl-urbaniak Sep 12, 2024
5c039d5
Merge branch 'ru-tracts-minimal-deployment' of https://github.com/Bas…
rfl-urbaniak Sep 12, 2024
5772ca8
fixing duplicates in setup
rfl-urbaniak Sep 12, 2024
05905aa
fixing duplicates in setup
rfl-urbaniak Sep 12, 2024
6f60eb0
update gitignore
rfl-urbaniak Sep 12, 2024
6a67a15
remove unused predictor function
jfeser Sep 12, 2024
4c2a98f
improve use of multi-world counterfactual
jfeser Sep 12, 2024
c8ce72a
use different radii for yellow zone lines and stops
jfeser Sep 12, 2024
707db45
Merge branch 'ru-tracts-minimal-deployment' of github.com:BasisResear…
jfeser Sep 12, 2024
39e8eed
fix use of yellow zone radius
jfeser Sep 16, 2024
17a41d3
fix bug in demographics table construction
jfeser Sep 16, 2024
15524d3
use search_path to switch between dev and prod tables
jfeser Sep 16, 2024
b3f6405
format, lint
rfl-urbaniak Sep 30, 2024
246d0c4
simplify private env grabbing
rfl-urbaniak Sep 30, 2024
42f2c50
uncomment
jfeser Sep 30, 2024
52d03e2
Merge branch 'ru-tracts-minimal-deployment' of github.com:BasisResear…
jfeser Sep 30, 2024
052a39e
update .gitignore
jfeser Sep 30, 2024
17e6814
add new region fields to census tract data
jfeser Oct 1, 2024
d357a9d
frontend pipeline on linux
rfl-urbaniak Oct 1, 2024
1e27a1c
Merge branch 'ru-tracts-minimal-deployment' of https://github.com/Bas…
rfl-urbaniak Oct 1, 2024
be72dbf
preds to gitignore
rfl-urbaniak Oct 8, 2024
dbddefd
decrease predict iters to 5
rfl-urbaniak Oct 8, 2024
6a8d85f
format, lint
rfl-urbaniak Oct 8, 2024
582e7c1
adding year as variable
naiimic Oct 9, 2024
91bf11e
add population and population density
jfeser Oct 10, 2024
868f5c7
compute parking limits entirely in predict.py
jfeser Oct 11, 2024
299f3a2
fix bug in test
jfeser Oct 11, 2024
b790504
update model components & tests
rfl-urbaniak Oct 16, 2024
e0bed8e
model tests upgrade wip
rfl-urbaniak Oct 16, 2024
f9a89ef
tests update wip
rfl-urbaniak Oct 16, 2024
1c43f2c
udate gitignore
rfl-urbaniak Oct 16, 2024
c5687ac
train model works
rfl-urbaniak Oct 16, 2024
2ac1b2c
port predict, rename the current one
rfl-urbaniak Oct 16, 2024
16c1878
predictor wip
rfl-urbaniak Oct 16, 2024
8794222
test, format, lint
rfl-urbaniak Oct 16, 2024
d4d3017
datase pipeline now uses the predictor class
rfl-urbaniak Oct 16, 2024
35add30
format, lint
rfl-urbaniak Oct 16, 2024
d00e5b1
clean up predict and train
rfl-urbaniak Oct 16, 2024
247902c
format, lint
rfl-urbaniak Oct 16, 2024
0c41d25
ported and trained ts model
rfl-urbaniak Nov 15, 2024
76e2330
new predictor
rfl-urbaniak Nov 15, 2024
5858259
moved predictor notebook
rfl-urbaniak Nov 15, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .env
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
GOOGLE_CLOUD_PROJECT=cities-429602
GOOGLE_CLOUD_BUCKET=minneapolis-basis
SCHEMA=minneapolis

ENV=dev
INSTANCE_CONNECTION_NAME=cities-429602:us-central1:cities-devel
DB_SEARCH_PATH=dev,public
HOST=34.123.100.76
SCHEMA=minneapolis
DATABASE=cities
USERNAME=postgres
DB_USERNAME=postgres
3 changes: 3 additions & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
source venv/bin/activate
dotenv
export PASSWORD=VA.TlSR#Z%mu**Q9
23 changes: 17 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,18 @@ cities.egg-info/*
cities.egg-info/
*/__pycache__
*.pyc
**/*.pyc
**/*.pyc
tests/__pycache__/
.mypy_cache/

**/*.Rproj.user/
**/*.Rproj/
**/*.Rhistory
**/*.Rdata
**/*.RData

build/

.vscode/settings.json
tests/.coverage
tests/pytest_report/
Expand All @@ -23,9 +31,6 @@ tests/.coverage
.vscode/launch.json
data/sql/counties_database.db
data/sql/msa_database.db
.Rproj.user
**/*.RData
**/*.Rhistory

# data
data/minneapolis/processed/values_long.csv
Expand All @@ -34,5 +39,11 @@ data/minneapolis/sourced/demographic/**
data/minneapolis/preds/**
data/minneapolis/sourced/parcel_to_census_tract_mappings/**
data/minneapolis/sourced/parcel_to_parking_info_mappings/**

data/minneapolis/.pgpass
cities/deployment/tracts_minneapolis/tracts_model_guide.pkl
cities/deployment/tracts_minneapolis/tracts_model_params.pth
/build/
docs/experimental_notebooks/zoning/interactions_preds.dill
docs/experimental_notebooks/zoning/population_preds.dill
docs/experimental_notebooks/zoning/waic_dict_7.pkl
docs/experimental_notebooks/zoning/waic_dict_13.pkl
docs/experimental_notebooks/zoning/waic_dict_14.pkl
28 changes: 20 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ format_path: FORCE
./scripts/clean_path.sh $(path)

lint: FORCE
./scripts/lint.sh
./scripts/lint.sh

test: FORCE
test: FORCE
./scripts/test.sh

test_all: FORCE
Expand All @@ -22,10 +22,22 @@ test_all: FORCE
test_notebooks: FORCE
./scripts/test_notebooks.sh

done: FORCE
./scripts/clean.sh
./scripts/lint.sh
./scripts/test.sh
./scripts/test_notebooks.sh
api/requirements.txt: FORCE
pip-compile --extra api --output-file api/requirements.txt

api-container-build: FORCE
mkdir -p build
#cd build && python ../cities/deployment/tracts_minneapolis/train_model.py
cp -r cities build
cp -r api/* build
cp .env build
cd build && docker build --platform linux/amd64 -t cities-api .

api-container-push:
docker tag cities-api us-east1-docker.pkg.dev/cities-429602/cities/cities-api
docker push us-east1-docker.pkg.dev/cities-429602/cities/cities-api

run-api-local:
docker run --rm -it -e PORT=8081 -e PASSWORD -p 3001:8081 cities-api

FORCE:
FORCE:
10 changes: 10 additions & 0 deletions api/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM python:3.12

WORKDIR /usr/src/app

COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD [ "python", "main.py" ]
232 changes: 232 additions & 0 deletions api/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
import os

from typing import Annotated

from dotenv import load_dotenv
from fastapi import FastAPI, Depends, Query
from fastapi.middleware.gzip import GZipMiddleware
import uvicorn

import psycopg2
from psycopg2.pool import ThreadedConnectionPool

load_dotenv()

ENV = os.getenv("ENV")
USERNAME = os.getenv("DB_USERNAME")
PASSWORD = os.getenv("PASSWORD")
HOST = os.getenv("HOST")
DATABASE = os.getenv("DATABASE")
DB_SEARCH_PATH = os.getenv("DB_SEARCH_PATH")
INSTANCE_CONNECTION_NAME = os.getenv("INSTANCE_CONNECTION_NAME")

app = FastAPI()

if ENV == "dev":
from fastapi.middleware.cors import CORSMiddleware

origins = [
"http://localhost",
"http://localhost:5000",
]
app.add_middleware(CORSMiddleware, allow_origins=origins, allow_credentials=True)

app.add_middleware(GZipMiddleware, minimum_size=1000, compresslevel=5)


if ENV == "dev":
host = HOST
else:
host = f"/cloudsql/{INSTANCE_CONNECTION_NAME}"

pool = ThreadedConnectionPool(
1,
10,
user=USERNAME,
password=PASSWORD,
host=HOST,
database=DATABASE,
options=f"-csearch_path={DB_SEARCH_PATH}",
)


def get_db() -> psycopg2.extensions.connection:
db = pool.getconn()
try:
yield db
finally:
pool.putconn(db)


predictor = None


def get_predictor(db: psycopg2.extensions.connection = Depends(get_db)):
from cities.deployment.tracts_minneapolis.predict import TractsModelPredictor

global predictor
if predictor is None:
predictor = TractsModelPredictor(db)
return predictor


Limit = Annotated[float, Query(ge=0, le=1)]
Radius = Annotated[float, Query(ge=0)]
Year = Annotated[int, Query(ge=2000, le=2030)]


@app.middleware("http")
async def add_cache_control_header(request, call_next):
response = await call_next(request)
response.headers["Cache-Control"] = "public, max-age=300"
return response


if ENV == "dev":

@app.middleware("http")
async def add_acess_control_header(request, call_next):
response = await call_next(request)
response.headers["Access-Control-Allow-Origin"] = "*"
return response


@app.get("/demographics")
async def read_demographics(
category: Annotated[str, Query(max_length=100)], db=Depends(get_db)
):
with db.cursor() as cur:
cur.execute(
"""
select tract_id, "2011", "2012", "2013", "2014", "2015", "2016", "2017", "2018", "2019", "2020", "2021", "2022"
from api__demographics where description = %s
""",
(category,),
)
return [[desc[0] for desc in cur.description]] + cur.fetchall()


@app.get("/census-tracts")
async def read_census_tracts(year: Year, db=Depends(get_db)):
with db.cursor() as cur:
cur.execute("select * from api__census_tracts where year_ = %s", (year,))
row = cur.fetchone()

return row[1] if row is not None else None


@app.get("/high-frequency-transit-lines")
async def read_high_frequency_transit_lines(year: Year, db=Depends(get_db)):
with db.cursor() as cur:
cur.execute(
"""
select line_geom_json
from api__high_frequency_transit_lines
where '%s-01-01'::date <@ valid
""",
(year,),
)
row = cur.fetchone()

return row[0] if row is not None else None


@app.get("/high-frequency-transit-stops")
async def read_high_frequency_transit_stops(year: Year, db=Depends(get_db)):
with db.cursor() as cur:
cur.execute(
"""
select stop_geom_json
from api__high_frequency_transit_lines
where '%s-01-01'::date <@ valid
""",
(year,),
)
row = cur.fetchone()

return row[0] if row is not None else None


@app.get("/yellow-zone")
async def read_yellow_zone(
year: Year, line_radius: Radius, stop_radius: Radius, db=Depends(get_db)
):
with db.cursor() as cur:
cur.execute(
"""
select
st_asgeojson(st_transform(st_union(st_buffer(line_geom, %s, 'quad_segs=4'), st_buffer(stop_geom, %s, 'quad_segs=4')), 4269))::json
from api__high_frequency_transit_lines
where '%s-01-01'::date <@ valid
""",
(line_radius, stop_radius, year),
)
row = cur.fetchone()

if row is None:
return None

return {
"type": "FeatureCollection",
"features": [
{"type": "Feature", "properties": {"id": "0"}, "geometry": row[0]}
],
}


@app.get("/blue-zone")
async def read_blue_zone(year: Year, radius: Radius, db=Depends(get_db)):
with db.cursor() as cur:
cur.execute(
"""
select st_asgeojson(st_transform(st_buffer(line_geom, %s, 'quad_segs=4'), 4269))::json
from api__high_frequency_transit_lines
where '%s-01-01'::date <@ valid
""",
(radius, year),
)
row = cur.fetchone()

if row is None:
return None

return {
"type": "FeatureCollection",
"features": [
{"type": "Feature", "properties": {"id": "0"}, "geometry": row[0]}
],
}

@app.get("/predict")
async def read_predict(
blue_zone_radius: Radius,
yellow_zone_line_radius: Radius,
yellow_zone_stop_radius: Radius,
blue_zone_limit: Limit,
yellow_zone_limit: Limit,
year: Year,
db=Depends(get_db),
predictor=Depends(get_predictor),
):

result = predictor.predict_cumulative_by_year(
db,
intervention={
"radius_blue": blue_zone_radius,
"limit_blue": blue_zone_limit,
"radius_yellow_line": yellow_zone_line_radius,
"radius_yellow_stop": yellow_zone_stop_radius,
"limit_yellow": yellow_zone_limit,
"reform_year": year,
},
)
return {
"census_tracts": [str(t) for t in result["census_tracts"]],
"years": result["years"],
"housing_units_factual": result["housing_units_factual"],
"housing_units_counterfactual": result["housing_units_counterfactual"],
}


if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=int(os.getenv("PORT", 8000)))
Loading
Loading