Andhika Bagas commited on
Commit
f15767b
·
1 Parent(s): 60d8961

chore: init project

Browse files
.gitattributes CHANGED
@@ -33,3 +33,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ *.xlsx
37
+ *.csv
Dockerfile ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.9
2
+
3
+ WORKDIR /code
4
+
5
+ COPY ./requirements.txt /code/requirements.txt
6
+
7
+ RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
8
+
9
+ RUN useradd -m -u 1000 user
10
+
11
+ USER user
12
+
13
+ ENV HOME=/home/user \
14
+ PATH=/home/user/.local/bin:$PATH
15
+
16
+ WORKDIR $HOME/app
17
+
18
+ COPY --chown=user . $HOME/app
19
+
20
+ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
LICENSE.md ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2022 Himesh Samarasekera
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
Procfile ADDED
@@ -0,0 +1 @@
 
 
1
+ web: uvicorn main:app --host 0.0.0.0 --port $PORT
__pycache__/main.cpython-310.pyc ADDED
Binary file (4.71 kB). View file
 
forecaster_southeast.py ADDED
Binary file (176 kB). View file
 
main.py ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+ # encoding: utf-8
3
+
4
+ from fastapi import FastAPI, Form, Depends
5
+ from pydantic import BaseModel
6
+ import numpy as np
7
+ import pandas as pd
8
+ from xgboost import XGBRegressor
9
+ from sklearn.preprocessing import StandardScaler
10
+ from sklearn.preprocessing import MinMaxScaler
11
+ from sklearn.preprocessing import RobustScaler
12
+ from skforecast.ForecasterAutoreg import ForecasterAutoreg
13
+
14
+ from sklearn.metrics import mean_squared_error, mean_absolute_percentage_error
15
+
16
+ import joblib
17
+
18
+ app = FastAPI()
19
+
20
+ class Msg(BaseModel):
21
+ msg: str
22
+
23
+
24
+ class RetrainRequest(BaseModel):
25
+ lag: int
26
+ differentiation: str
27
+ transformer: str
28
+ externalTransformation: str
29
+ test_size: int
30
+
31
+ class PredictRequest(BaseModel):
32
+ steps: int
33
+ test_size: int
34
+ externalTransformation: str
35
+
36
+ @app.get("/welcomeMessage")
37
+ async def welcome():
38
+ return {"message": "Hello World. Welcome to FastAPI!"}
39
+
40
+ @app.get("/")
41
+ async def root():
42
+ return {"message": "Hello World"}
43
+
44
+ def form_retrain(lag: str = Form(...), differentiation: str = Form(...), transformer: str = Form(...), externalTransformation: str = Form (...), test_size: str = Form(...)):
45
+ return RetrainRequest(lag=int(lag), differentiation=str(differentiation), transformer=transformer, externalTransformation=externalTransformation, test_size=int(test_size))
46
+
47
+ def form_prediction(steps: str = Form(...), externalTransformation: str = Form (...), test_size: str = Form(...)):
48
+ return PredictRequest(steps=int(steps), externalTransformation=externalTransformation, test_size=int(test_size))
49
+
50
+ def apply_transformation(data, transform_type):
51
+ if transform_type == 'Log':
52
+ return np.log1p(data)
53
+ elif transform_type == 'Square Root':
54
+ return np.sqrt(data)
55
+ else:
56
+ return data
57
+
58
+ def reverse_transformation(transformed_data, transform_type):
59
+ if transform_type == 'Log':
60
+ return np.expm1(transformed_data)
61
+ elif transform_type == 'Square Root':
62
+ return np.square(transformed_data)
63
+ else:
64
+ return transformed_data
65
+
66
+ @app.post("/retrain")
67
+ async def retrain(requess: RetrainRequest = Depends(form_retrain), test_size: int = 3):
68
+ with open('ammonia_market_monthly_avg_new.xlsx', 'rb') as file:
69
+ df = pd.read_excel(file)
70
+
71
+ df['date'] = pd.to_datetime(df['date'], format='%Y-%m-%d')
72
+ df.set_index('date', inplace=True)
73
+
74
+ lags = requess.lag
75
+ differentiation = requess.differentiation
76
+ if differentiation == "0":
77
+ differentiation = None
78
+ else:
79
+ differentiation = int(differentiation)
80
+
81
+ transformer_y = requess.transformer
82
+ test_size = requess.test_size
83
+ externalTransformation=requess.externalTransformation
84
+
85
+ target_column = 'southeast_asia'
86
+ train = df.iloc[:-(test_size)]
87
+ test = df.iloc[-(test_size):]
88
+
89
+ train_transformed = apply_transformation(train[target_column], externalTransformation)
90
+
91
+ if transformer_y == 'StandardScaler':
92
+ transformer_y = StandardScaler()
93
+ elif transformer_y == 'MinMaxScaler':
94
+ transformer_y = MinMaxScaler()
95
+ elif transformer_y == 'RobustScaler':
96
+ transformer_y = RobustScaler()
97
+ else:
98
+ transformer_y = None
99
+
100
+ forecaster = ForecasterAutoreg(
101
+ regressor = XGBRegressor(random_state=123),
102
+ lags = lags,
103
+ differentiation = differentiation,
104
+ transformer_y = transformer_y
105
+ )
106
+
107
+ forecaster.fit(y=train_transformed)
108
+ predictions = forecaster.predict(steps=test_size)
109
+ pred = reverse_transformation(predictions, externalTransformation)
110
+
111
+ df_reset = df.reset_index()
112
+ last_date = df_reset.iloc[-(test_size)]['date']
113
+ months_ahead = pd.date_range(last_date, periods=test_size, freq='M')
114
+
115
+ preds = round(pred, 2).tolist()
116
+ actual = test[target_column]
117
+ date_value_pairs = dict(zip(months_ahead.tolist(), preds))
118
+ rmse = np.sqrt(mean_squared_error(actual, preds))
119
+ mape = mean_absolute_percentage_error(actual, preds)
120
+ joblib.dump(forecaster, filename='forecaster_new.py')
121
+
122
+ return {
123
+ 'predictions': date_value_pairs,
124
+ 'actual': actual,
125
+ 'rmse': rmse,
126
+ 'mape': mape
127
+ }
128
+
129
+ @app.post("/predict")
130
+ async def predict(requess: PredictRequest = Depends(form_prediction), steps: int = 3, externalTransformation: str = "None", test_size: int = 3):
131
+ try:
132
+ with open('forecaster_new.py', 'rb') as file:
133
+ forecaster_southeast = joblib.load(file)
134
+ except FileNotFoundError:
135
+ forecaster_southeast = joblib.load('forecaster_southeast.py')
136
+
137
+ try:
138
+ with open('ammonia_market_monthly_avg_new.xlsx', 'rb') as file:
139
+ df = pd.read_excel(file)
140
+ except FileNotFoundError:
141
+ df = pd.read_excel('ammonia_market_monthly_avg_2010_2020.xlsx')
142
+
143
+ df['date'] = pd.to_datetime(df['date'], format='%Y-%m-%d')
144
+ df.set_index('date', inplace=True)
145
+
146
+ steps = requess.steps
147
+ test_size = requess.test_size
148
+
149
+ predictions = forecaster_southeast.predict(steps=steps)
150
+ pred = reverse_transformation(predictions, requess.externalTransformation)
151
+ preds = round(pred, 2).tolist()
152
+
153
+ df_reset = df.reset_index()
154
+ last_date = df_reset.iloc[-(test_size)]['date']
155
+ months_ahead = pd.date_range(last_date, periods=steps, freq='M')
156
+ date_value_pairs = dict(zip(months_ahead.tolist(), preds))
157
+
158
+ return {
159
+ "steps": steps,
160
+ "predictions": date_value_pairs
161
+ }
pyproject.toml ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [tool.poetry]
2
+ name = "railway-fastapi-template"
3
+ version = "0.1.0"
4
+ description = "This example starts up a FastAPI server"
5
+ authors = ["DeviousLab <deviouslab@gmail.com>"]
6
+ license = "MIT"
7
+
8
+ [tool.poetry.dependencies]
9
+ python = "^3.10"
10
+ fastapi = "^0.80.0"
11
+ uvicorn = "^0.18.3"
12
+
13
+ [tool.poetry.dev-dependencies]
14
+
15
+ [build-system]
16
+ requires = ["poetry-core>=1.0.0"]
17
+ build-backend = "poetry.core.masonry.api"
requirements.txt ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ anyio>=3.7.1
2
+ click==8.1.7
3
+ fastapi==0.103.2
4
+ h11==0.14.0
5
+ httptools==0.6.0
6
+ idna==3.4
7
+ pydantic==2.4.2
8
+ python-dotenv==1.0.0
9
+ python-multipart==0.0.6
10
+ PyYAML==6.0.1
11
+ sniffio==1.3.0
12
+ starlette>=0.27.0
13
+ typing_extensions==4.8.0
14
+ uvicorn==0.23.2
15
+ watchfiles==0.20.0
16
+ websockets==11.0.3
17
+ scikit-learn
18
+ jinja2