diff --git a/.idea/museum-analytics.iml b/.idea/museum-analytics.iml new file mode 100644 index 0000000..e7dfc29 --- /dev/null +++ b/.idea/museum-analytics.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 3dcae2e..9a8f5ac 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,6 @@ This project uses environment variables to secure sensitive information. Follow ``` 3. Build and start the museum analytics server with docker: ```Bash - cd ./museum_analytics + cd ./api docker build --network=host --no-cache -t museum-analytics-server . ``` \ No newline at end of file diff --git a/api/.dockerignore b/api/.dockerignore new file mode 100644 index 0000000..e1f8c6f --- /dev/null +++ b/api/.dockerignore @@ -0,0 +1,9 @@ +.git +../.idea +.venv +**/__pycache__ +**/.ipynb_checkpoints +**/*.pyc +api/app/.env +api/app/exp +*.ipynb diff --git a/Dockerfile b/api/Dockerfile similarity index 82% rename from Dockerfile rename to api/Dockerfile index f46f842..9829afc 100644 --- a/Dockerfile +++ b/api/Dockerfile @@ -16,7 +16,7 @@ COPY pyproject.toml poetry.lock ./ RUN --mount=type=cache,target=/root/.cache/pypoetry \ poetry install --only main --no-root --no-ansi -COPY . . +COPY .. . EXPOSE 8000 -CMD ["uvicorn", "museum_analytics.museum_api:app", "--host", "0.0.0.0", "--port", "8000"] \ No newline at end of file +CMD ["uvicorn", "app.museum_api:app", "--host", "0.0.0.0", "--port", "8000"] \ No newline at end of file diff --git a/museum_analytics/.env.example b/api/app/.env.example similarity index 100% rename from museum_analytics/.env.example rename to api/app/.env.example diff --git a/museum_analytics/__init__.py b/api/app/__init__.py similarity index 100% rename from museum_analytics/__init__.py rename to api/app/__init__.py diff --git a/museum_analytics/constants.py b/api/app/constants.py similarity index 100% rename from museum_analytics/constants.py rename to api/app/constants.py diff --git a/museum_analytics/data/worldcities.csv b/api/app/data/worldcities.csv similarity index 100% rename from museum_analytics/data/worldcities.csv rename to api/app/data/worldcities.csv diff --git a/museum_analytics/data_setup.py b/api/app/data_setup.py similarity index 99% rename from museum_analytics/data_setup.py rename to api/app/data_setup.py index ca1ab15..cbd6beb 100644 --- a/museum_analytics/data_setup.py +++ b/api/app/data_setup.py @@ -1,7 +1,7 @@ import os import requests from dotenv import load_dotenv -from museum_analytics import constants +from app import constants from io import StringIO import pandas as pd diff --git a/api/app/exp/__init__.py b/api/app/exp/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/museum_analytics/exp/data.py b/api/app/exp/data.py similarity index 99% rename from museum_analytics/exp/data.py rename to api/app/exp/data.py index 19958f6..756c455 100644 --- a/museum_analytics/exp/data.py +++ b/api/app/exp/data.py @@ -3,7 +3,7 @@ import requests import wikipediaapi from bs4 import BeautifulSoup from dotenv import load_dotenv -from museum_analytics import constants +from api.app import constants from io import StringIO import pandas as pd diff --git a/museum_analytics/museum_api.py b/api/app/museum_api.py similarity index 96% rename from museum_analytics/museum_api.py rename to api/app/museum_api.py index ca8d81b..ec3046b 100644 --- a/museum_analytics/museum_api.py +++ b/api/app/museum_api.py @@ -3,15 +3,15 @@ Museum visitors vs. city population: regression model + FastAPI service. Run locally (from the repo root): - uvicorn museum_analytics.museum_api:app --reload + uvicorn api.museum_api:app --reload or run this file directly (e.g. from the IDE): - python museum_analytics/museum_api.py + python api/museum_api.py Or with a DataFrame you already have in memory: - from museum_analytics.museum_api import create_app + from api.museum_api import create_app import uvicorn uvicorn.run(create_app(df), port=8000) @@ -25,13 +25,13 @@ from pathlib import Path if __package__ in (None, ""): # Started as a script (python museum_api.py): put the repo root on the - # path so the `museum_analytics` package imports below resolve. + # path so the `api` package imports below resolve. sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) from dataclasses import dataclass, field from typing import Literal import numpy as np import pandas as pd -from museum_analytics import constants, data_setup +from app import data_setup, constants from fastapi import FastAPI, HTTPException, Query from pydantic import BaseModel, Field from sklearn.linear_model import LinearRegression @@ -252,7 +252,7 @@ def create_app( return [Prediction(population=p, predicted_visitors=float(v)) for p, v in zip(req.populations, preds)] - @app.get("/data") + @app.get("data") def data(): """Every row the model was fitted on, with its prediction.""" m = get_model() @@ -290,7 +290,7 @@ def _load_data() -> pd.DataFrame | None: return museum_data -# Module-level app so `uvicorn museum_analytics.museum_api:app` works. +# Module-level app so `uvicorn api.museum_api:app` works. app = create_app( _load_data(), scale=os.environ.get("MUSEUM_SCALE", "log"), # type: ignore[arg-type] diff --git a/poetry.lock b/api/poetry.lock similarity index 100% rename from poetry.lock rename to api/poetry.lock diff --git a/api/poetry.toml b/api/poetry.toml new file mode 100644 index 0000000..1b08ff7 --- /dev/null +++ b/api/poetry.toml @@ -0,0 +1,3 @@ + +[virtualenvs] +in-project = true \ No newline at end of file diff --git a/pyproject.toml b/api/pyproject.toml similarity index 99% rename from pyproject.toml rename to api/pyproject.toml index 6e92caa..2ade1e2 100644 --- a/pyproject.toml +++ b/api/pyproject.toml @@ -22,6 +22,7 @@ dependencies = [ # "matplotlib (>=3.11.2,<4.0.0)", ] + [tool.poetry.group.dev.dependencies] jupyterlab = "^4.6.4" matplotlib = "^3.11.2" diff --git a/museum_analytics/museum_regression.ipynb b/notebooks/museum_regression.ipynb similarity index 98% rename from museum_analytics/museum_regression.ipynb rename to notebooks/museum_regression.ipynb index 94a36ea..95c996f 100644 --- a/museum_analytics/museum_regression.ipynb +++ b/notebooks/museum_regression.ipynb @@ -9,7 +9,7 @@ "\n", "This notebook talks to the `museum_api` FastAPI server over HTTP: it starts the server (or uses one you already run), sends it the data, and plots the regression it returns.\n", "\n", - "**Setup:** put `museum_api.py` next to this notebook, then `pip install scikit-learn pandas fastapi uvicorn requests matplotlib`." + "**Setup:** put `../api/app/museum_api.py` next to this notebook, then `pip install scikit-learn pandas fastapi uvicorn requests matplotlib`." ] }, { @@ -84,7 +84,7 @@ "\n", "if not server_up():\n", " import uvicorn\n", - " from museum_api import create_app\n", + " from api.app.museum_api import create_app\n", " server = uvicorn.Server(uvicorn.Config(create_app(), host=\"127.0.0.1\", port=8000, log_level=\"warning\"))\n", " threading.Thread(target=server.run, daemon=True).start()\n", " for _ in range(50):\n",