Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
129 changes: 129 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# 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/
Empty file added chatgpt/__init__.py
Empty file.
8 changes: 6 additions & 2 deletions chatgpt/app_tests.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
def test_create_demand(client):
response = client.post('/demand', json={'floor': 3})
response = client.post('/demand', json={'floor': 3,'elevator_id':1})
assert response.status_code == 201
assert response.get_json() == {'message': 'Demand created'}


def test_create_state(client):
response = client.post('/state', json={'floor': 5, 'vacant': True})
response = client.post('/state', json={'floor': 5, 'vacant': True,'elevator_id':1})
assert response.status_code == 201
assert response.get_json() == {'message': 'State created'}

def test_create_elevator(client):
response = client.post('/elevator',json={'name':"Elevator A"})
assert response.status_code == 201
Binary file added chatgpt/elevator.db
Binary file not shown.
88 changes: 70 additions & 18 deletions chatgpt/main.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,25 @@
from flask import Flask, request, jsonify
from flask import Flask, Blueprint, request, jsonify
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
from models import db, Elevator, ElevatorDemand, ElevatorState
import pandas as pd

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///elevator.db'
db = SQLAlchemy(app)


class ElevatorDemand(db.Model):
id = db.Column(db.Integer, primary_key=True)
timestamp = db.Column(db.DateTime, default=datetime.utcnow)
floor = db.Column(db.Integer, nullable=False)


class ElevatorState(db.Model):
id = db.Column(db.Integer, primary_key=True)
timestamp = db.Column(db.DateTime, default=datetime.utcnow)
floor = db.Column(db.Integer, nullable=False)
vacant = db.Column(db.Boolean, nullable=False)
db.init_app(app)

@app.route('/elevator', methods=['POST'])
def create_elevator():
data = request.get_json()
elevator = Elevator(name=data['name'])
db.session.add(elevator)
db.session.commit()
return jsonify({'message': 'Elevator created', 'elevator_id': elevator.id}), 201

@app.route('/demand', methods=['POST'])
def create_demand():
data = request.get_json()
new_demand = ElevatorDemand(floor=data['floor'])
new_demand = ElevatorDemand(floor=data['floor'],elevator_id=data['elevator_id'])
db.session.add(new_demand)
db.session.commit()
return jsonify({'message': 'Demand created'}), 201
Expand All @@ -32,12 +28,68 @@ def create_demand():
@app.route('/state', methods=['POST'])
def create_state():
data = request.get_json()
new_state = ElevatorState(floor=data['floor'], vacant=data['vacant'])
new_state = ElevatorState(
floor=data['floor'],
vacant=data['vacant'],
elevator_id=data['elevator_id']
)
db.session.add(new_state)
db.session.commit()
return jsonify({'message': 'State created'}), 201


@app.route('/dataset', methods=['GET'])
def generate_dataset():
date_str = request.args.get('date') # YYYY-MM-DD
enddate_str = request.args.get('enddate') # YYYY-MM-DD
holiday_param = request.args.get('holiday', 'false').lower()
if not date_str:
return jsonify({'error': 'You must provide a date in format YYYY-MM-DD'}), 400

try:
date = pd.to_datetime(date_str)
except:
return jsonify({'error': 'Invalid date format'}), 400

start = pd.Timestamp(date.date())
if enddate_str:
try:
# end = pd.to_datetime(enddate_str)
end = pd.to_datetime(enddate_str) + pd.Timedelta(days=1)
except:
return jsonify({'error': 'Invalid end date format'}), 400
else:
end = start + pd.Timedelta(days=1)
is_holiday = holiday_param in ['true', '1', 'yes']

demands = ElevatorDemand.query.filter(
ElevatorDemand.timestamp >= start,
ElevatorDemand.timestamp < end
).all()

data = [{
'timestamp': d.timestamp,
'floor': d.floor
} for d in demands]

df = pd.DataFrame(data)

if df.empty:
return jsonify([])

# features
df['hour'] = df['timestamp'].dt.hour
df['minute'] = df['timestamp'].dt.minute
df['weekday'] = df['timestamp'].dt.weekday
df['month'] = df['timestamp'].dt.month
df['is_holiday'] = is_holiday
df['is_weekend'] = df['weekday'].isin([5, 6])

df['timestamp'] = df['timestamp'].dt.strftime('%Y-%m-%dT%H:%M:%S')

return jsonify(df.to_dict(orient='records'))

if __name__ == '__main__':
db.create_all()
with app.app_context():
db.create_all()
app.run(debug=True)
35 changes: 35 additions & 0 deletions chatgpt/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from datetime import datetime
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()


class ElevatorDemand(db.Model):
__tablename__ = 'elevator_demands'
id = db.Column(db.Integer, primary_key=True)
timestamp = db.Column(db.DateTime, default=datetime.now)
floor = db.Column(db.Integer, nullable=False)

elevator_id = db.Column(db.Integer, db.ForeignKey('elevators.id'), nullable=False)
elevator = db.relationship('Elevator', back_populates='demands')


class ElevatorState(db.Model):
__tablename__ = 'elevator_states'
id = db.Column(db.Integer, primary_key=True)
timestamp = db.Column(db.DateTime, default=datetime.now)
floor = db.Column(db.Integer, nullable=False)
vacant = db.Column(db.Boolean, nullable=False)

elevator_id = db.Column(db.Integer, db.ForeignKey('elevators.id'), nullable=False)
elevator = db.relationship('Elevator', back_populates='states')

class Elevator(db.Model):
__tablename__ = 'elevators'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), nullable=False)

demands = db.relationship('ElevatorDemand', back_populates='elevator', cascade="all, delete-orphan")
states = db.relationship('ElevatorState', back_populates='elevator', cascade="all, delete-orphan")


2 changes: 2 additions & 0 deletions chatgpt/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ Flask==2.0.2
Flask-SQLAlchemy==2.5.1
pytest==6.2.5
pytest-flask==1.2.0
Werkzeug==2.2.3
SQLAlchemy==1.4.46
35 changes: 35 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,38 @@ Below is a list of some things from previous submissions that haven't worked out
- Built a full website with bells and whistles
- Spent more than the time allowed (you won't get bonus points for creating an intricate solution, we want a fit for purpose solution)
- Overcomplicated the system mentally and failed to start


## Answer

### Data Structure and Modeling

Three main tables are defined in the relational database:
- `Elevator`: Represents a single elevator. This enables the system to scale to multiple elevators, each with its own state and demand events.
- `ElevatorDemand` : Logs every time an elevator is requested from a floor. It includes a `timestamp`, `floor`, and `elevator_id`.
- `ElevatorState`: Periodically logs the current state of an elevator (e.g., current floor and whether it's vacancy). Useful for operational tracking, this table is not directly involved in demand prediction.

### Key Assumptions


1. Demand is Independent of Elevator State:

- Users do not know the elevator's position when they request it.

- Therefore, demand is modeled as an external event driven by time patterns, not internal elevator logic.

2. Time-Based Demand Prediction:

- The ML model aims to predict the floor from which the next request will likely occur, using features such as:

- Time of day
- Day of the week
- Whether it is a holiday (is_holiday)
- Whether it is a weekend (is_weekend)

- The elevator's current location is not used in the prediction.

3. Proactive Elevator Movement (future feature):

If an elevator remains idle for a defined period, it could use the ML model to proactively move to the floor most likely to generate a request.