koenverhagen commited on
Commit
28bbb93
1 Parent(s): bf42b03
Files changed (5) hide show
  1. .gitignore +2 -0
  2. createlookalike.py +31 -25
  3. environment.yml +189 -0
  4. schemas.py +18 -0
  5. server.py +52 -6
.gitignore CHANGED
@@ -3,3 +3,5 @@ venv
3
  *.xml
4
  .idea
5
  .DS_Store
 
 
 
3
  *.xml
4
  .idea
5
  .DS_Store
6
+ __pycache__/createlookalike.cpython-39.pyc
7
+ *.pyc
createlookalike.py CHANGED
@@ -1,3 +1,4 @@
 
1
  import tempfile as tfile
2
  from datetime import datetime
3
  from urllib.request import urlopen
@@ -17,10 +18,12 @@ import numpy as np
17
  from sklearn.decomposition import PCA
18
  from scipy.spatial import distance
19
  from collections import OrderedDict
20
- from remove import remove_files
21
 
22
- from generate_csv_file import generate_csv_files
23
- from load_data import load_data, get_shops
 
 
 
24
 
25
 
26
  def get_ids_from_feed(feed_url):
@@ -67,39 +70,29 @@ def load_image(url, img_id):
67
  return img, x
68
 
69
 
70
- def create_feature_files():
71
  model = keras.applications.VGG16(weights='imagenet', include_top=True)
72
  feat_extractor = Model(inputs=model.input, outputs=model.get_layer("fc2").output)
73
- final_json = []
74
- data = get_shops()
75
 
76
- if data:
77
- for p in data:
78
- final_json.append(calculate_shop(p, feat_extractor))
79
 
80
- load_data(generate_csv_files(final_json))
81
- remove_files()
82
-
83
- return
84
-
85
-
86
- def calculate_shop(shop, feat_extractor):
87
  start = datetime.today()
88
- if shop['id'] not in ['']: # temp
89
- print(shop['id'], shop['base_url'])
90
- google_xml_feed_url = '{}/google_xml_feed'.format(shop['base_url'])
91
  try:
92
  list_ids, shop_url = get_ids_from_feed(google_xml_feed_url)
93
  except Exception as e:
94
  list_ids = []
95
- print('could not get images from ', shop['id'], e)
96
  features = []
97
 
98
  list_of_fitted_designs = []
99
 
100
  design_json = {}
101
  if len(list_ids) > 0:
102
- for l in list_ids:
103
 
104
  try:
105
  img, x = load_image(shop_url, l)
@@ -146,15 +139,28 @@ def calculate_shop(shop, feat_extractor):
146
  for k, v in sorted_dict.items():
147
  design_list.append(v)
148
 
149
- design_dict = {im: design_list}
 
 
 
 
 
 
 
 
 
 
 
 
 
150
  # idx_closest = sorted(range(len(similar_idx)), key=lambda k: similar_idx[k])
151
 
152
- design_json.update(design_dict)
153
  # print(idx_closest)
154
 
155
  except Exception as e:
156
- print("could not create json with look-a-like for shop:", shop['id'], e)
157
 
158
  end = datetime.today()
159
 
160
- return {'shop_id': shop['id'], 'start_time': start, 'end_time': end, 'designs': design_json}
 
1
+ import asyncio
2
  import tempfile as tfile
3
  from datetime import datetime
4
  from urllib.request import urlopen
 
18
  from sklearn.decomposition import PCA
19
  from scipy.spatial import distance
20
  from collections import OrderedDict
 
21
 
22
+ # from remove import remove_files
23
+ #
24
+ # from generate_csv_file import generate_csv_files
25
+ # from load_data import load_data, get_shops
26
+ from schemas import Shop
27
 
28
 
29
  def get_ids_from_feed(feed_url):
 
70
  return img, x
71
 
72
 
73
+ async def create_feature_files(shop: Shop):
74
  model = keras.applications.VGG16(weights='imagenet', include_top=True)
75
  feat_extractor = Model(inputs=model.input, outputs=model.get_layer("fc2").output)
76
+ await calculate_shop(shop, feat_extractor)
 
77
 
 
 
 
78
 
79
+ async def calculate_shop(shop: Shop, feat_extractor) -> None:
 
 
 
 
 
 
80
  start = datetime.today()
81
+ if shop.id: # temp
82
+ print(shop.id, shop.base_url)
83
+ google_xml_feed_url = '{}/google_xml_feed'.format(shop.base_url)
84
  try:
85
  list_ids, shop_url = get_ids_from_feed(google_xml_feed_url)
86
  except Exception as e:
87
  list_ids = []
88
+ print('could not get images from ', shop.id, e)
89
  features = []
90
 
91
  list_of_fitted_designs = []
92
 
93
  design_json = {}
94
  if len(list_ids) > 0:
95
+ for l in list_ids[:100]:
96
 
97
  try:
98
  img, x = load_image(shop_url, l)
 
139
  for k, v in sorted_dict.items():
140
  design_list.append(v)
141
 
142
+ design_dict = {"shop_id": shop.id, "design": im,
143
+ "results": design_list
144
+ }
145
+
146
+ print(design_dict)
147
+ try:
148
+ response = requests.post(shop.webhook_url, json=design_dict)
149
+ if response.status_code == 200:
150
+ print(f"result for {im} is sent to {shop.webhook_url}")
151
+ else:
152
+ print(f"Error sending data {shop.webhook_url} to for result {im}: {response.status_code}")
153
+ except Exception as e:
154
+ print(f"Error sending data {shop.webhook_url} to for result {im}: {response.status_code}", e)
155
+
156
  # idx_closest = sorted(range(len(similar_idx)), key=lambda k: similar_idx[k])
157
 
158
+ # design_json.update(design_dict)
159
  # print(idx_closest)
160
 
161
  except Exception as e:
162
+ print("could not create json with look-a-like for shop:", shop.id, e)
163
 
164
  end = datetime.today()
165
 
166
+ # return {'shop_id': shop.id, 'start_time': start, 'end_time': end, 'designs': design_json}
environment.yml ADDED
@@ -0,0 +1,189 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # packages in environment at /Users/koenverhagen/miniforge3/envs/tf:
2
+ #
3
+ # Name Version Build Channel
4
+ absl-py 1.4.0 pyhd8ed1ab_0 conda-forge
5
+ aiohttp 3.8.4 py39h02fc5c5_0 conda-forge
6
+ aiosignal 1.3.1 pyhd8ed1ab_0 conda-forge
7
+ anyio 3.6.2 pyhd8ed1ab_0 conda-forge
8
+ aom 3.5.0 h7ea286d_0 conda-forge
9
+ astunparse 1.6.3 pyhd8ed1ab_0 conda-forge
10
+ async-timeout 4.0.2 pyhd8ed1ab_0 conda-forge
11
+ attrs 22.2.0 pyh71513ae_0 conda-forge
12
+ blinker 1.6.2 pyhd8ed1ab_0 conda-forge
13
+ blosc 1.21.3 h1d6ff8b_0 conda-forge
14
+ brotli 1.0.9 h1a8c8d9_8 conda-forge
15
+ brotli-bin 1.0.9 h1a8c8d9_8 conda-forge
16
+ brotlipy 0.7.0 py39h02fc5c5_1005 conda-forge
17
+ brunsli 0.1 h9f76cd9_0 conda-forge
18
+ bzip2 1.0.8 h3422bc3_4 conda-forge
19
+ c-ares 1.18.1 h3422bc3_0 conda-forge
20
+ c-blosc2 2.8.0 h303ed30_1 conda-forge
21
+ ca-certificates 2022.12.7 h4653dfc_0 conda-forge
22
+ cached-property 1.5.2 hd8ed1ab_1 conda-forge
23
+ cached_property 1.5.2 pyha770c72_1 conda-forge
24
+ cachetools 5.3.0 pyhd8ed1ab_0 conda-forge
25
+ certifi 2022.12.7 pyhd8ed1ab_0 conda-forge
26
+ cffi 1.15.1 py39h7e6b969_3 conda-forge
27
+ cfitsio 4.2.0 h2f961c4_0 conda-forge
28
+ charls 2.4.1 hb7217d7_0 conda-forge
29
+ charset-normalizer 2.1.1 pyhd8ed1ab_0 conda-forge
30
+ click 8.1.3 unix_pyhd8ed1ab_2 conda-forge
31
+ cloudpickle 2.2.1 pyhd8ed1ab_0 conda-forge
32
+ contourpy 1.0.7 py39haaf3ac1_0 conda-forge
33
+ cryptography 40.0.2 py39he2a39a8_0 conda-forge
34
+ cycler 0.11.0 pyhd8ed1ab_0 conda-forge
35
+ cytoolz 0.12.0 py39h02fc5c5_1 conda-forge
36
+ dask-core 2023.4.0 pyhd8ed1ab_0 conda-forge
37
+ dav1d 1.0.0 he4db4b2_1 conda-forge
38
+ fastapi 0.95.1 pyhd8ed1ab_0 conda-forge
39
+ flatbuffers 23.3.3 hb7217d7_0 conda-forge
40
+ fonttools 4.39.3 py39h02fc5c5_0 conda-forge
41
+ freetype 2.12.1 hd633e50_1 conda-forge
42
+ frozenlist 1.3.3 py39h02fc5c5_0 conda-forge
43
+ fsspec 2023.4.0 pyh1a96a4e_0 conda-forge
44
+ gast 0.4.0 pyh9f0ad1d_0 conda-forge
45
+ giflib 5.2.1 h1a8c8d9_3 conda-forge
46
+ google-auth 2.17.3 pyh1a96a4e_0 conda-forge
47
+ google-auth-oauthlib 0.4.6 pyhd8ed1ab_0 conda-forge
48
+ google-pasta 0.2.0 pyh8c360ce_0 conda-forge
49
+ grpcio 1.51.1 py39h3adb8dc_1 conda-forge
50
+ h11 0.14.0 pyhd8ed1ab_0 conda-forge
51
+ h5py 3.8.0 nompi_py39hbcdb4fd_101 conda-forge
52
+ hdf5 1.14.0 nompi_h6b85c65_103 conda-forge
53
+ icu 72.1 he12128b_0 conda-forge
54
+ idna 3.4 pyhd8ed1ab_0 conda-forge
55
+ imagecodecs 2023.1.23 py39h6655518_2 conda-forge
56
+ imageio 2.28.0 pyh24c5eb1_0 conda-forge
57
+ importlib-metadata 6.6.0 pyha770c72_0 conda-forge
58
+ importlib-resources 5.12.0 pyhd8ed1ab_0 conda-forge
59
+ importlib_metadata 6.6.0 hd8ed1ab_0 conda-forge
60
+ importlib_resources 5.12.0 pyhd8ed1ab_0 conda-forge
61
+ joblib 1.2.0 pyhd8ed1ab_0 conda-forge
62
+ jxrlib 1.1 h27ca646_2 conda-forge
63
+ keras 2.11.0 pyhd8ed1ab_0 conda-forge
64
+ keras-preprocessing 1.1.2 pyhd8ed1ab_0 conda-forge
65
+ kiwisolver 1.4.4 py39haaf3ac1_1 conda-forge
66
+ krb5 1.20.1 h69eda48_0 conda-forge
67
+ lcms2 2.15 hd835a16_1 conda-forge
68
+ lerc 4.0.0 h9a09cb3_0 conda-forge
69
+ libabseil 20220623.0 cxx17_h28b99d4_6 conda-forge
70
+ libaec 1.0.6 hb7217d7_1 conda-forge
71
+ libavif 0.11.1 h3d80962_0 conda-forge
72
+ libblas 3.9.0 16_osxarm64_openblas conda-forge
73
+ libbrotlicommon 1.0.9 h1a8c8d9_8 conda-forge
74
+ libbrotlidec 1.0.9 h1a8c8d9_8 conda-forge
75
+ libbrotlienc 1.0.9 h1a8c8d9_8 conda-forge
76
+ libcblas 3.9.0 16_osxarm64_openblas conda-forge
77
+ libcurl 8.0.1 heffe338_0 conda-forge
78
+ libcxx 16.0.2 h4653b0c_0 conda-forge
79
+ libdeflate 1.18 h1a8c8d9_0 conda-forge
80
+ libedit 3.1.20191231 hc8eb9b7_2 conda-forge
81
+ libev 4.33 h642e427_1 conda-forge
82
+ libffi 3.4.2 h3422bc3_5 conda-forge
83
+ libgfortran 5.0.0 12_2_0_hd922786_31 conda-forge
84
+ libgfortran5 12.2.0 h0eea778_31 conda-forge
85
+ libgrpc 1.51.1 hb15be72_1 conda-forge
86
+ libiconv 1.17 he4db4b2_0 conda-forge
87
+ libjpeg-turbo 2.1.5.1 h1a8c8d9_0 conda-forge
88
+ liblapack 3.9.0 16_osxarm64_openblas conda-forge
89
+ libnghttp2 1.52.0 hae82a92_0 conda-forge
90
+ libopenblas 0.3.21 openmp_hc731615_3 conda-forge
91
+ libpng 1.6.39 h76d750c_0 conda-forge
92
+ libprotobuf 3.21.12 hb5ab8b9_0 conda-forge
93
+ libsqlite 3.40.0 h76d750c_1 conda-forge
94
+ libssh2 1.10.0 h7a5bd25_3 conda-forge
95
+ libtiff 4.5.0 h4f7d55c_6 conda-forge
96
+ libwebp-base 1.3.0 h1a8c8d9_0 conda-forge
97
+ libxcb 1.13 h9b22ae9_1004 conda-forge
98
+ libxml2 2.10.4 h2aff0a6_0 conda-forge
99
+ libxslt 1.1.37 h1bd8bc4_0 conda-forge
100
+ libzlib 1.2.13 h03a7124_4 conda-forge
101
+ libzopfli 1.0.3 h9f76cd9_0 conda-forge
102
+ llvm-openmp 16.0.2 h1c12783_0 conda-forge
103
+ locket 1.0.0 pyhd8ed1ab_0 conda-forge
104
+ lxml 4.9.2 py39h0520ce3_0 conda-forge
105
+ lz4-c 1.9.4 hb7217d7_0 conda-forge
106
+ markdown 3.4.3 pyhd8ed1ab_0 conda-forge
107
+ markupsafe 2.1.2 py39h02fc5c5_0 conda-forge
108
+ matplotlib 3.7.1 py39hdf13c20_0 conda-forge
109
+ matplotlib-base 3.7.1 py39h35e9e80_0 conda-forge
110
+ multidict 6.0.4 py39h02fc5c5_0 conda-forge
111
+ munkres 1.1.4 pyh9f0ad1d_0 conda-forge
112
+ ncurses 6.3 h07bb92c_1 conda-forge
113
+ networkx 3.1 pyhd8ed1ab_0 conda-forge
114
+ numpy 1.24.3 py39h485cf63_0 conda-forge
115
+ oauthlib 3.2.2 pyhd8ed1ab_0 conda-forge
116
+ openjpeg 2.5.0 hbc2ba62_2 conda-forge
117
+ openssl 3.1.0 h53f4e23_2 conda-forge
118
+ opt_einsum 3.3.0 pyhd8ed1ab_1 conda-forge
119
+ packaging 23.1 pyhd8ed1ab_0 conda-forge
120
+ pandas 2.0.1 py39h6b13a34_0 conda-forge
121
+ partd 1.4.0 pyhd8ed1ab_0 conda-forge
122
+ pillow 9.5.0 py39hfc21214_0 conda-forge
123
+ pip 23.1.1 pyhd8ed1ab_0 conda-forge
124
+ platformdirs 3.3.0 pyhd8ed1ab_0 conda-forge
125
+ pooch 1.7.0 pyha770c72_3 conda-forge
126
+ protobuf 4.21.12 py39h23fbdae_0 conda-forge
127
+ pthread-stubs 0.4 h27ca646_1001 conda-forge
128
+ pyasn1 0.4.8 py_0 conda-forge
129
+ pyasn1-modules 0.2.7 py_0 conda-forge
130
+ pycparser 2.21 pyhd8ed1ab_0 conda-forge
131
+ pydantic 1.10.7 py39h02fc5c5_0 conda-forge
132
+ pyjwt 2.6.0 pyhd8ed1ab_0 conda-forge
133
+ pyopenssl 23.1.1 pyhd8ed1ab_0 conda-forge
134
+ pyparsing 3.0.9 pyhd8ed1ab_0 conda-forge
135
+ pysocks 1.7.1 pyha2e5f31_6 conda-forge
136
+ python 3.9.16 hea58f1e_0_cpython conda-forge
137
+ python-dateutil 2.8.2 pyhd8ed1ab_0 conda-forge
138
+ python-flatbuffers 23.1.21 pyhd8ed1ab_0 conda-forge
139
+ python-multipart 0.0.6 pyhd8ed1ab_0 conda-forge
140
+ python-tzdata 2023.3 pyhd8ed1ab_0 conda-forge
141
+ python_abi 3.9 3_cp39 conda-forge
142
+ pytz 2023.3 pyhd8ed1ab_0 conda-forge
143
+ pyu2f 0.1.5 pyhd8ed1ab_0 conda-forge
144
+ pywavelets 1.4.1 py39h4d8bf0d_0 conda-forge
145
+ pyyaml 6.0 py39h02fc5c5_5 conda-forge
146
+ re2 2023.02.01 hb7217d7_0 conda-forge
147
+ readline 8.2 h92ec313_1 conda-forge
148
+ requests 2.28.2 pyhd8ed1ab_1 conda-forge
149
+ requests-oauthlib 1.3.1 pyhd8ed1ab_0 conda-forge
150
+ rsa 4.9 pyhd8ed1ab_0 conda-forge
151
+ scikit-image 0.19.3 py39hde7b980_2 conda-forge
152
+ scikit-learn 1.2.2 py39h6180588_1 conda-forge
153
+ scipy 1.10.1 py39hba9bd2d_0 conda-forge
154
+ setuptools 67.7.2 pyhd8ed1ab_0 conda-forge
155
+ six 1.16.0 pyh6c4a22f_0 conda-forge
156
+ snappy 1.1.10 h17c5cce_0 conda-forge
157
+ sniffio 1.3.0 pyhd8ed1ab_0 conda-forge
158
+ starlette 0.26.1 pyhd8ed1ab_0 conda-forge
159
+ tensorboard 2.11.2 pyhd8ed1ab_0 conda-forge
160
+ tensorboard-data-server 0.6.1 py39he2a39a8_4 conda-forge
161
+ tensorboard-plugin-wit 1.8.1 pyhd8ed1ab_0 conda-forge
162
+ tensorflow 2.11.1 cpu_py39h6861412_0 conda-forge
163
+ tensorflow-base 2.11.1 cpu_py39hfdb8388_0 conda-forge
164
+ tensorflow-estimator 2.11.1 cpu_py39hf592239_0 conda-forge
165
+ termcolor 2.3.0 pyhd8ed1ab_0 conda-forge
166
+ threadpoolctl 3.1.0 pyh8a188c0_0 conda-forge
167
+ tifffile 2023.4.12 pyhd8ed1ab_0 conda-forge
168
+ tk 8.6.12 he1e0b03_0 conda-forge
169
+ toolz 0.12.0 pyhd8ed1ab_0 conda-forge
170
+ tornado 6.3 py39h02fc5c5_0 conda-forge
171
+ typing-extensions 4.5.0 hd8ed1ab_0 conda-forge
172
+ typing_extensions 4.5.0 pyha770c72_0 conda-forge
173
+ tzdata 2023c h71feb2d_0 conda-forge
174
+ unicodedata2 15.0.0 py39h02fc5c5_0 conda-forge
175
+ urllib3 1.26.15 pyhd8ed1ab_0 conda-forge
176
+ uvicorn 0.21.1 py39h2804cbe_0 conda-forge
177
+ werkzeug 2.2.3 pyhd8ed1ab_0 conda-forge
178
+ wheel 0.40.0 pyhd8ed1ab_0 conda-forge
179
+ wrapt 1.15.0 py39h02fc5c5_0 conda-forge
180
+ xorg-libxau 1.0.9 h27ca646_0 conda-forge
181
+ xorg-libxdmcp 1.1.3 h27ca646_0 conda-forge
182
+ xz 5.2.6 h57fd34a_0 conda-forge
183
+ yaml 0.2.5 h3422bc3_2 conda-forge
184
+ yarl 1.9.1 py39h0f82c59_0 conda-forge
185
+ zfp 1.0.0 hb6e4faa_3 conda-forge
186
+ zipp 3.15.0 pyhd8ed1ab_0 conda-forge
187
+ zlib 1.2.13 h03a7124_4 conda-forge
188
+ zlib-ng 2.0.7 h1a8c8d9_0 conda-forge
189
+ zstd 1.5.2 hf913c23_6 conda-forge
schemas.py ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel
2
+
3
+
4
+ # ---------------------------------------------------------------------------
5
+ # - Base request model -
6
+ # ---------------------------------------------------------------------------
7
+
8
+
9
+
10
+ class Design(BaseModel):
11
+ design_id: str
12
+ shop_id: str
13
+
14
+
15
+ class Shop(BaseModel):
16
+ id: str
17
+ base_url: str
18
+ webhook_url: str
server.py CHANGED
@@ -1,8 +1,13 @@
1
- from fastapi import FastAPI, Response, Request, Header, Form, UploadFile, Body
 
 
 
 
2
  from starlette.middleware.cors import CORSMiddleware
3
- from pydantic import BaseModel
4
- import json
5
- from load_data import get_design_data, get_design_resolutions_for_shop
 
6
 
7
  app = FastAPI()
8
  app.add_middleware(
@@ -13,5 +18,46 @@ app.add_middleware(
13
  allow_headers=["*"], # Allows all headers
14
  )
15
 
16
- # API_TOKEN = os.environ["API_TOKEN"]
17
- API_TOKEN = '34dsadfF$$%#$TGREGEFGE%Q*)(*&%'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import asyncio
3
+ from concurrent.futures import ThreadPoolExecutor
4
+
5
+ from fastapi import FastAPI, Response, Request, Header, Form, UploadFile, Body, BackgroundTasks
6
  from starlette.middleware.cors import CORSMiddleware
7
+ # import json
8
+ # from load_data import get_design_data, get_design_resolutions_for_shop
9
+ from createlookalike import create_feature_files
10
+ from schemas import Shop
11
 
12
  app = FastAPI()
13
  app.add_middleware(
 
18
  allow_headers=["*"], # Allows all headers
19
  )
20
 
21
+
22
+ API_TOKEN = '34dsadfF$$%#$TGREGEFGE%Q*)(*&%'
23
+
24
+
25
+ executor = ThreadPoolExecutor()
26
+
27
+
28
+ # ---------------------------------------------------------------------------
29
+ # - Token auth method -
30
+ # ---------------------------------------------------------------------------
31
+ def check_auth(authorization_header):
32
+ if authorization_header == API_TOKEN:
33
+ return True
34
+ else:
35
+ return False
36
+
37
+
38
+
39
+
40
+
41
+ @app.get("/")
42
+ async def root():
43
+ return {"message": "where are you looking for?"}
44
+
45
+
46
+
47
+
48
+
49
+
50
+ @app.post("/lal_for_shop")
51
+ async def submit_async_task(background_tasks: BackgroundTasks, request: Request, response: Response, shop: Shop):
52
+ loop = asyncio.new_event_loop()
53
+ authorization_token = request.headers.get("Authorization", None)
54
+ check_token = True # check_auth(authorization_token)
55
+ if check_token:
56
+ task = asyncio.create_task(create_feature_files(shop))
57
+ return {"message": f"shop calculation for shop {shop.id} submitted"}
58
+ else:
59
+ response.status_code = 401
60
+ return response
61
+
62
+
63
+