-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
27 changed files
with
997 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
DB_USERNAME=postgres | ||
DB_PASSWORD=postgres | ||
DB_DATABASE=pred-city-env-service | ||
DB_HOST=db | ||
DB_PORT=5432 | ||
|
||
DB_DATABASE_TEST=pred-city-env-service-test | ||
DB_HOST_TEST=db-test | ||
DB_PORT_TEST=5432 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,13 @@ | ||
# pred-city-env | ||
Проект "Прогнозирование негативных аспектов развития городской среды" на БММ 2023 | ||
>Проект "Прогнозирование негативных аспектов развития городской среды" на БММ 2023. | ||
--- | ||
|
||
## Цели | ||
... | ||
|
||
## Архитектура | ||
Архитектуру проекта можно разделить на 4 части: | ||
- База данных для хранения результатов анализа | ||
- [ML модель](ml_research/README.md) для прогнозирования негативных аспектов | ||
- [Frontend](frontend/README.md) для визуализации данных | ||
- [Backend](backend/README.md) для предоставления доступа клиентам |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
# Byte-compiled / optimized / DLL files | ||
__pycache__/ | ||
*.py[cod] | ||
*$py.class | ||
|
||
# C extensions | ||
*.so | ||
|
||
# Distribution / packaging | ||
.Python | ||
build/ | ||
develop-eggs/ | ||
dist/ | ||
downloads/ | ||
eggs/ | ||
.eggs/ | ||
lib/ | ||
lib64/ | ||
parts/ | ||
sdist/ | ||
var/ | ||
wheels/ | ||
pip-wheel-metadata/ | ||
share/python-wheels/ | ||
*.egg-info/ | ||
.installed.cfg | ||
*.egg | ||
MANIFEST | ||
|
||
# PyInstaller | ||
# Usually these files are written by a python script from a template | ||
# before PyInstaller builds the exe, so as to inject date/other infos into it. | ||
*.manifest | ||
*.spec | ||
|
||
# Installer logs | ||
pip-log.txt | ||
pip-delete-this-directory.txt | ||
|
||
# Unit test / coverage reports | ||
htmlcov/ | ||
.tox/ | ||
.nox/ | ||
.coverage | ||
.coverage.* | ||
.cache | ||
nosetests.xml | ||
coverage.xml | ||
*.cover | ||
*.py,cover | ||
.hypothesis/ | ||
.pytest_cache/ | ||
|
||
# Translations | ||
*.mo | ||
*.pot | ||
|
||
# Django stuff: | ||
*.log | ||
local_settings.py | ||
db.sqlite3 | ||
db.sqlite3-journal | ||
|
||
# Flask stuff: | ||
instance/ | ||
.webassets-cache | ||
|
||
# Scrapy stuff: | ||
.scrapy | ||
|
||
# Sphinx documentation | ||
docs/_build/ | ||
|
||
# PyBuilder | ||
target/ | ||
|
||
# Jupyter Notebook | ||
.ipynb_checkpoints | ||
|
||
# IPython | ||
profile_default/ | ||
ipython_config.py | ||
|
||
# pyenv | ||
.python-version | ||
|
||
# pipenv | ||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. | ||
# However, in case of collaboration, if having platform-specific dependencies or dependencies | ||
# having no cross-platform support, pipenv may install dependencies that don't work, or not | ||
# install all needed dependencies. | ||
#Pipfile.lock | ||
|
||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow | ||
__pypackages__/ | ||
|
||
# Celery stuff | ||
celerybeat-schedule | ||
celerybeat.pid | ||
|
||
# SageMath parsed files | ||
*.sage.py | ||
|
||
# Environments | ||
# .env | ||
.venv | ||
env/ | ||
venv/ | ||
ENV/ | ||
env.bak/ | ||
venv.bak/ | ||
|
||
# Spyder project settings | ||
.spyderproject | ||
.spyproject | ||
|
||
# Rope project settings | ||
.ropeproject | ||
|
||
# mkdocs documentation | ||
/site | ||
|
||
# mypy | ||
.mypy_cache/ | ||
.dmypy.json | ||
dmypy.json | ||
|
||
# Pyre type checker | ||
.pyre/ | ||
|
||
# other | ||
.idea/ | ||
poetry.lock |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
FROM python:3.10-slim | ||
|
||
WORKDIR /backend_app | ||
|
||
RUN apt-get update && apt-get install -y libpq-dev netcat | ||
|
||
COPY *.py pytest.ini pyproject.toml ./ | ||
COPY core/ ./core/ | ||
COPY routers/ ./routers/ | ||
# COPY tasks/ ./tasks/ | ||
COPY tests/ ./tests/ | ||
|
||
# RUN pip3 install -r requirements.txt | ||
RUN poetry install | ||
|
||
COPY entrypoint.sh . | ||
RUN sed -i 's/\r$//g' entrypoint.sh | ||
RUN chmod +x entrypoint.sh | ||
|
||
ENTRYPOINT ["/backend_app/entrypoint.sh"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# Backend сервиса | ||
|
||
## Цели | ||
... | ||
|
||
## Архитектура | ||
... | ||
|
||
## JSON:API | ||
... | ||
|
||
## Примеры | ||
... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import os | ||
|
||
from pydantic import PostgresDsn | ||
from pydantic_settings import BaseSettings | ||
|
||
|
||
class Settings(BaseSettings): | ||
DB_DATABASE: str = os.environ.get("DB_DATABASE", "pred-city-env-service") | ||
DB_USERNAME: str = os.environ.get("DB_USERNAME", "postgres") | ||
DB_PASSWORD: str = os.environ.get("DB_PASSWORD", "postgres") | ||
DB_HOST: str = os.environ.get("DB_HOST", "localhost") | ||
DB_PORT: int = os.environ.get("DB_PORT", 5432) | ||
|
||
DB_DATABASE_TEST: str = os.environ.get( | ||
"DB_DATABASE_TEST", "pred-city-env-service-test" | ||
) | ||
DB_HOST_TEST: str = os.environ.get("DB_HOST_TEST", "localhost") | ||
DB_PORT_TEST: int = os.environ.get("DB_PORT_TEST", 5432) | ||
|
||
SQLALCHEMY_DATABASE_URL: PostgresDsn = f"postgresql+asyncpg://{DB_USERNAME}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_DATABASE}" | ||
SQLALCHEMY_DATABASE_TEST_URL: PostgresDsn = f"postgresql+asyncpg://{DB_USERNAME}:{DB_PASSWORD}@{DB_HOST_TEST}:{DB_PORT_TEST}/{DB_DATABASE_TEST}" | ||
|
||
|
||
settings = Settings() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
from datetime import datetime, timedelta | ||
from typing import Optional | ||
|
||
from config import settings | ||
from fastapi import Depends, HTTPException | ||
from fastapi.security import OAuth2PasswordBearer | ||
from jose import JWTError, jwt | ||
from passlib.context import CryptContext | ||
from sqlalchemy.ext.asyncio import AsyncSession | ||
|
||
from .database import get_session | ||
from .model_utils import get_user_by_username | ||
|
||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl=settings.TOKEN_URL) | ||
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") | ||
|
||
|
||
def create_access_token(subject: str, expires_delta: Optional[timedelta] = None) -> str: | ||
if expires_delta: | ||
expire = datetime.utcnow() + expires_delta | ||
else: | ||
expire = datetime.utcnow() + timedelta(hours=8) | ||
to_encode = {"sub": str(subject), "exp": expire} | ||
encoded_jwt = jwt.encode( | ||
to_encode, settings.JWT_SECRET_KEY, algorithm=settings.JWT_ALGORITHM | ||
) | ||
return encoded_jwt | ||
|
||
|
||
def verify_password(plain_password, hashed_password): | ||
return pwd_context.verify(plain_password, hashed_password) | ||
|
||
|
||
def get_password_hash(password): | ||
return pwd_context.hash(password) | ||
|
||
|
||
def decode_token(token): | ||
try: | ||
payload = jwt.decode( | ||
token, settings.JWT_SECRET_KEY, algorithms=settings.JWT_ALGORITHM | ||
) | ||
username = payload.get("sub") | ||
if username is None: | ||
raise JWTError | ||
except JWTError: | ||
return None | ||
return username | ||
|
||
|
||
async def get_current_user( | ||
db: AsyncSession = Depends(get_session), token: str = Depends(oauth2_scheme) | ||
): | ||
username = decode_token(token) | ||
if username is None: | ||
raise HTTPException( | ||
status_code=401, | ||
detail="Invalid username or password", | ||
) | ||
user = await get_user_by_username(username, db) | ||
if user is None: | ||
raise HTTPException( | ||
status_code=401, | ||
detail="Invalid username or password", | ||
) | ||
return user |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
from typing import AsyncGenerator | ||
|
||
from config import settings | ||
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine | ||
from sqlalchemy.orm import declarative_base, sessionmaker | ||
|
||
engine = create_async_engine(settings.SQLALCHEMY_DATABASE_URL) | ||
Base = declarative_base() | ||
async_session = sessionmaker( | ||
engine, class_=AsyncSession, expire_on_commit=False, autocommit=False | ||
) | ||
|
||
|
||
async def init_db(): | ||
async with engine.begin() as conn: | ||
await conn.run_sync(Base.metadata.create_all) | ||
|
||
|
||
async def get_session() -> AsyncGenerator[AsyncSession, None]: | ||
async with async_session() as session: | ||
yield session |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import asyncio | ||
import random | ||
|
||
import pandas as pd | ||
|
||
from .database import get_session, init_db | ||
|
||
|
||
async def _init_all_db(): | ||
pass | ||
|
||
|
||
if __name__ == "__main__": | ||
asyncio.run(_init_all_db()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
from sqlalchemy import select, update | ||
from sqlalchemy.ext.asyncio import AsyncSession | ||
from sqlalchemy.sql import func | ||
|
||
from .database import Base, engine | ||
from .models import Car, Location | ||
|
||
|
||
async def get_zip_codes(db: AsyncSession): | ||
return (await db.scalars(select(Location.zip))).all() | ||
|
||
|
||
async def get_user_by_id(id: int, db: AsyncSession) -> User: | ||
query = select(User).where(User.id == id) | ||
return (await db.scalars(query)).first() | ||
|
||
|
||
async def get_user_by_username(username: str, db: AsyncSession) -> User: | ||
query = select(User).where(User.username == username) | ||
return (await db.scalars(query)).first() | ||
|
||
|
||
async def get_count(db: AsyncSession, model: Base): | ||
return (await db.scalars(func.count(model.id))).first() | ||
|
||
|
||
async def get_by_id(db: AsyncSession, model: Base, id: int): | ||
return (await db.scalars(select(model).where(model.id == id))).first() | ||
|
||
|
||
async def get_all(db: AsyncSession, model: Base): | ||
return (await db.scalars(select(model))).all() | ||
|
||
|
||
async def get_location(db: AsyncSession, zip: int): | ||
return (await db.scalars(select(Location).where(Location.zip == zip))).first() | ||
|
||
|
||
async def update_cars_position_random(): | ||
query = update(Car).values( | ||
current_loc=select(Location.zip).order_by(func.random() + Car.id).limit(1) | ||
) | ||
async with engine.begin() as conn: | ||
await conn.execute(query) | ||
|
||
|
||
async def create_model(db: AsyncSession, model: Base): | ||
db.add(model) | ||
await db.commit() | ||
await db.refresh(model) | ||
return model | ||
|
||
|
||
async def delete_model(db: AsyncSession, model: Base): | ||
await db.delete(model) | ||
await db.commit() |
Oops, something went wrong.