haystack-ml-stack 0.3.2__tar.gz → 0.3.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {haystack_ml_stack-0.3.2 → haystack_ml_stack-0.3.4}/PKG-INFO +1 -1
- {haystack_ml_stack-0.3.2 → haystack_ml_stack-0.3.4}/pyproject.toml +1 -1
- {haystack_ml_stack-0.3.2 → haystack_ml_stack-0.3.4}/src/haystack_ml_stack/__init__.py +1 -1
- {haystack_ml_stack-0.3.2 → haystack_ml_stack-0.3.4}/src/haystack_ml_stack/app.py +18 -2
- {haystack_ml_stack-0.3.2 → haystack_ml_stack-0.3.4}/src/haystack_ml_stack/utils.py +2 -2
- {haystack_ml_stack-0.3.2 → haystack_ml_stack-0.3.4}/src/haystack_ml_stack.egg-info/PKG-INFO +1 -1
- {haystack_ml_stack-0.3.2 → haystack_ml_stack-0.3.4}/tests/test_utils.py +127 -0
- {haystack_ml_stack-0.3.2 → haystack_ml_stack-0.3.4}/README.md +0 -0
- {haystack_ml_stack-0.3.2 → haystack_ml_stack-0.3.4}/setup.cfg +0 -0
- {haystack_ml_stack-0.3.2 → haystack_ml_stack-0.3.4}/src/haystack_ml_stack/_serializers.py +0 -0
- {haystack_ml_stack-0.3.2 → haystack_ml_stack-0.3.4}/src/haystack_ml_stack/cache.py +0 -0
- {haystack_ml_stack-0.3.2 → haystack_ml_stack-0.3.4}/src/haystack_ml_stack/dynamo.py +0 -0
- {haystack_ml_stack-0.3.2 → haystack_ml_stack-0.3.4}/src/haystack_ml_stack/exceptions.py +0 -0
- {haystack_ml_stack-0.3.2 → haystack_ml_stack-0.3.4}/src/haystack_ml_stack/generated/__init__.py +0 -0
- {haystack_ml_stack-0.3.2 → haystack_ml_stack-0.3.4}/src/haystack_ml_stack/generated/v1/__init__.py +0 -0
- {haystack_ml_stack-0.3.2 → haystack_ml_stack-0.3.4}/src/haystack_ml_stack/generated/v1/features_pb2.py +0 -0
- {haystack_ml_stack-0.3.2 → haystack_ml_stack-0.3.4}/src/haystack_ml_stack/generated/v1/features_pb2.pyi +0 -0
- {haystack_ml_stack-0.3.2 → haystack_ml_stack-0.3.4}/src/haystack_ml_stack/model_store.py +0 -0
- {haystack_ml_stack-0.3.2 → haystack_ml_stack-0.3.4}/src/haystack_ml_stack/settings.py +0 -0
- {haystack_ml_stack-0.3.2 → haystack_ml_stack-0.3.4}/src/haystack_ml_stack.egg-info/SOURCES.txt +0 -0
- {haystack_ml_stack-0.3.2 → haystack_ml_stack-0.3.4}/src/haystack_ml_stack.egg-info/dependency_links.txt +0 -0
- {haystack_ml_stack-0.3.2 → haystack_ml_stack-0.3.4}/src/haystack_ml_stack.egg-info/requires.txt +0 -0
- {haystack_ml_stack-0.3.2 → haystack_ml_stack-0.3.4}/src/haystack_ml_stack.egg-info/top_level.txt +0 -0
- {haystack_ml_stack-0.3.2 → haystack_ml_stack-0.3.4}/tests/test_serializers.py +0 -0
|
@@ -6,6 +6,8 @@ from http import HTTPStatus
|
|
|
6
6
|
from typing import Any, Dict, List, Optional
|
|
7
7
|
import time
|
|
8
8
|
from contextlib import asynccontextmanager, AsyncExitStack
|
|
9
|
+
import traceback
|
|
10
|
+
import json
|
|
9
11
|
|
|
10
12
|
import aiobotocore.session
|
|
11
13
|
from aiobotocore.config import AioConfig
|
|
@@ -160,6 +162,7 @@ def create_app(
|
|
|
160
162
|
"user_cache_size": len(user_features_cache),
|
|
161
163
|
"model_name": state.get("model_name"),
|
|
162
164
|
"stream_features": state.get("stream_features", []),
|
|
165
|
+
"user_features": state.get("user_features", []),
|
|
163
166
|
}
|
|
164
167
|
|
|
165
168
|
@app.post("/score", status_code=HTTPStatus.OK)
|
|
@@ -172,10 +175,23 @@ def create_app(
|
|
|
172
175
|
|
|
173
176
|
try:
|
|
174
177
|
data = await request.json()
|
|
175
|
-
except
|
|
178
|
+
except json.JSONDecodeError as e:
|
|
179
|
+
body = await request.body()
|
|
180
|
+
logger.error(
|
|
181
|
+
"Received malformed json. Raw body: %s\n%s",
|
|
182
|
+
body.decode(errors="replace"),
|
|
183
|
+
traceback.format_exc(),
|
|
184
|
+
)
|
|
176
185
|
raise HTTPException(
|
|
177
186
|
status_code=HTTPStatus.BAD_REQUEST, detail="Invalid JSON payload"
|
|
178
187
|
) from e
|
|
188
|
+
except Exception as e:
|
|
189
|
+
logger.error(
|
|
190
|
+
"Unexpected exception when parsing request.\n %s", traceback.format_exc()
|
|
191
|
+
)
|
|
192
|
+
raise HTTPException(
|
|
193
|
+
status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail="Unknown exception"
|
|
194
|
+
) from e
|
|
179
195
|
query_params = {}
|
|
180
196
|
for k in request.query_params.keys():
|
|
181
197
|
values = request.query_params.getlist(k)
|
|
@@ -253,7 +269,7 @@ def create_app(
|
|
|
253
269
|
model_output = model["predict"](model_input, model["params"])
|
|
254
270
|
predict_end = time.perf_counter_ns()
|
|
255
271
|
except Exception as e:
|
|
256
|
-
logger.error("Model prediction failed: %s",
|
|
272
|
+
logger.error("Model prediction failed: \n%s", traceback.format_exc())
|
|
257
273
|
raise HTTPException(
|
|
258
274
|
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
|
|
259
275
|
detail="Model prediction failed",
|
|
@@ -204,7 +204,7 @@ def device_watched_count_cleanups(
|
|
|
204
204
|
|
|
205
205
|
counts_obj: StreamPWatched = stream.get(
|
|
206
206
|
f"PWATCHED#24H#{device_type}", StreamPWatched()
|
|
207
|
-
)
|
|
207
|
+
).data
|
|
208
208
|
if out is None:
|
|
209
209
|
out = {}
|
|
210
210
|
out = _cleanup_entry_context_counts(
|
|
@@ -336,7 +336,7 @@ def user_pwatched_cleanup(
|
|
|
336
336
|
"launch_first_in_session",
|
|
337
337
|
]
|
|
338
338
|
_validate_pwatched_entry_context(entry_contexts)
|
|
339
|
-
counts_obj = user.get("PWATCHED#6M", UserPWatched())
|
|
339
|
+
counts_obj = user.get("PWATCHED#6M", UserPWatched()).data
|
|
340
340
|
out = _cleanup_entry_context_counts(
|
|
341
341
|
counts_obj=counts_obj,
|
|
342
342
|
entry_contexts=entry_contexts,
|
|
@@ -372,6 +372,58 @@ def test_stream_pwatched_cleanup():
|
|
|
372
372
|
assert (actual == expected).all()
|
|
373
373
|
|
|
374
374
|
|
|
375
|
+
def test_device_stream_pwatched_cleanup():
|
|
376
|
+
stream_pwatched_data = {
|
|
377
|
+
"version": 1,
|
|
378
|
+
"data": {
|
|
379
|
+
"autoplay": {"attempts": 1, "watched": 1},
|
|
380
|
+
"ch_swtch": {"attempts": 2, "watched": 0},
|
|
381
|
+
},
|
|
382
|
+
}
|
|
383
|
+
stream_pwatched = features_pb2_v1.StreamPWatched()
|
|
384
|
+
ProtoParseDict(js_dict=stream_pwatched_data, message=stream_pwatched)
|
|
385
|
+
stream = {"PWATCHED#24H#TV": stream_pwatched}
|
|
386
|
+
out = {}
|
|
387
|
+
utils.device_watched_count_cleanups(
|
|
388
|
+
stream=stream,
|
|
389
|
+
entry_contexts=["autoplay", "ch_swtch", "sel_thumb"],
|
|
390
|
+
device_type="TV",
|
|
391
|
+
out=out,
|
|
392
|
+
)
|
|
393
|
+
expected = pd.Series(
|
|
394
|
+
{
|
|
395
|
+
"STREAM_AUTOPLAY_TV_24H_TOTAL_ATTEMPTS": 1,
|
|
396
|
+
"STREAM_AUTOPLAY_TV_24H_TOTAL_WATCHED": 1,
|
|
397
|
+
"STREAM_CH_SWTCH_TV_24H_TOTAL_ATTEMPTS": 2,
|
|
398
|
+
"STREAM_CH_SWTCH_TV_24H_TOTAL_WATCHED": 0,
|
|
399
|
+
"STREAM_SEL_THUMB_TV_24H_TOTAL_ATTEMPTS": 0,
|
|
400
|
+
"STREAM_SEL_THUMB_TV_24H_TOTAL_WATCHED": 0,
|
|
401
|
+
}
|
|
402
|
+
)
|
|
403
|
+
actual = pd.Series(out).loc[expected.index]
|
|
404
|
+
assert (actual == expected).all()
|
|
405
|
+
stream = {"PWATCHED#24H#MOBILE": stream_pwatched}
|
|
406
|
+
out = {}
|
|
407
|
+
utils.device_watched_count_cleanups(
|
|
408
|
+
stream=stream,
|
|
409
|
+
entry_contexts=["autoplay", "ch_swtch", "sel_thumb"],
|
|
410
|
+
device_type="MOBILE",
|
|
411
|
+
out=out,
|
|
412
|
+
)
|
|
413
|
+
expected = pd.Series(
|
|
414
|
+
{
|
|
415
|
+
"STREAM_AUTOPLAY_MOBILE_24H_TOTAL_ATTEMPTS": 1,
|
|
416
|
+
"STREAM_AUTOPLAY_MOBILE_24H_TOTAL_WATCHED": 1,
|
|
417
|
+
"STREAM_CH_SWTCH_MOBILE_24H_TOTAL_ATTEMPTS": 2,
|
|
418
|
+
"STREAM_CH_SWTCH_MOBILE_24H_TOTAL_WATCHED": 0,
|
|
419
|
+
"STREAM_SEL_THUMB_MOBILE_24H_TOTAL_ATTEMPTS": 0,
|
|
420
|
+
"STREAM_SEL_THUMB_MOBILE_24H_TOTAL_WATCHED": 0,
|
|
421
|
+
}
|
|
422
|
+
)
|
|
423
|
+
actual = pd.Series(out).loc[expected.index]
|
|
424
|
+
assert (actual == expected).all()
|
|
425
|
+
|
|
426
|
+
|
|
375
427
|
def test_stream_global_pselect_cleanup():
|
|
376
428
|
stream_pselect_data = {
|
|
377
429
|
"version": 1,
|
|
@@ -508,3 +560,78 @@ def test_stream_similarity_top_category_functions():
|
|
|
508
560
|
assert all(
|
|
509
561
|
actual_key == expected_key for actual_key, expected_key in zip(actual, expected)
|
|
510
562
|
)
|
|
563
|
+
|
|
564
|
+
|
|
565
|
+
def test_user_pwatched_cleanup():
|
|
566
|
+
user_pwatched_data = {
|
|
567
|
+
"version": 1,
|
|
568
|
+
"data": {
|
|
569
|
+
"sel_thumb": {"attempts": 1, "watched": 1},
|
|
570
|
+
"ch_swtch": {"attempts": 2, "watched": 0},
|
|
571
|
+
},
|
|
572
|
+
}
|
|
573
|
+
user_pwatched_msg = features_pb2_v1.UserPWatched()
|
|
574
|
+
ProtoParseDict(js_dict=user_pwatched_data, message=user_pwatched_msg)
|
|
575
|
+
user = {"PWATCHED#6M": user_pwatched_msg}
|
|
576
|
+
out = {}
|
|
577
|
+
utils.user_pwatched_cleanup(
|
|
578
|
+
user=user, entry_contexts=["autoplay", "sel_thumb", "ch_swtch"], out=out
|
|
579
|
+
)
|
|
580
|
+
expected = pd.Series(
|
|
581
|
+
{
|
|
582
|
+
"USER_AUTOPLAY_6M_TOTAL_ATTEMPTS": 0,
|
|
583
|
+
"USER_AUTOPLAY_6M_TOTAL_WATCHED": 0,
|
|
584
|
+
"USER_SEL_THUMB_6M_TOTAL_ATTEMPTS": 1,
|
|
585
|
+
"USER_SEL_THUMB_6M_TOTAL_WATCHED": 1,
|
|
586
|
+
"USER_CH_SWTCH_6M_TOTAL_ATTEMPTS": 2,
|
|
587
|
+
"USER_CH_SWTCH_6M_TOTAL_WATCHED": 0,
|
|
588
|
+
}
|
|
589
|
+
)
|
|
590
|
+
actual = pd.Series(out).loc[expected.index]
|
|
591
|
+
assert (expected == actual).all()
|
|
592
|
+
|
|
593
|
+
|
|
594
|
+
def test_user_pselect_cleanup():
|
|
595
|
+
user_pselect_data = {
|
|
596
|
+
"version": 1,
|
|
597
|
+
"data": {
|
|
598
|
+
"all_browsed": {
|
|
599
|
+
"first_pos": {
|
|
600
|
+
"total_selects": 0,
|
|
601
|
+
"total_selects_and_watched": 0,
|
|
602
|
+
"total_browsed": 1,
|
|
603
|
+
},
|
|
604
|
+
"rest_pos": {
|
|
605
|
+
"total_selects": 2,
|
|
606
|
+
"total_selects_and_watched": 2,
|
|
607
|
+
"total_browsed": 1,
|
|
608
|
+
},
|
|
609
|
+
},
|
|
610
|
+
"up_to_4_browsed": {
|
|
611
|
+
"first_pos": {
|
|
612
|
+
"total_selects": 0,
|
|
613
|
+
"total_selects_and_watched": 0,
|
|
614
|
+
"total_browsed": 1,
|
|
615
|
+
},
|
|
616
|
+
"rest_pos": {
|
|
617
|
+
"total_selects": 2,
|
|
618
|
+
"total_selects_and_watched": 2,
|
|
619
|
+
"total_browsed": 0,
|
|
620
|
+
},
|
|
621
|
+
},
|
|
622
|
+
},
|
|
623
|
+
}
|
|
624
|
+
user_pselect_msg = features_pb2_v1.UserPSelect()
|
|
625
|
+
ProtoParseDict(js_dict=user_pselect_data, message=user_pselect_msg)
|
|
626
|
+
user = {"PSELECT#6M": user_pselect_msg}
|
|
627
|
+
out = {}
|
|
628
|
+
utils.user_pselect_cleanup(user=user, position_debiasing="up_to_4_browsed", out=out)
|
|
629
|
+
expected = pd.Series(
|
|
630
|
+
{
|
|
631
|
+
"USER_6M_TOTAL_BROWSED_UP_TO_4_BROWSED": 1,
|
|
632
|
+
"USER_6M_TOTAL_SELECTS_UP_TO_4_BROWSED": 2,
|
|
633
|
+
"USER_6M_TOTAL_SELECTS_AND_WATCHED_UP_TO_4_BROWSED": 2,
|
|
634
|
+
}
|
|
635
|
+
)
|
|
636
|
+
actual = pd.Series(out).loc[expected.index]
|
|
637
|
+
assert (actual == expected).all()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{haystack_ml_stack-0.3.2 → haystack_ml_stack-0.3.4}/src/haystack_ml_stack/generated/__init__.py
RENAMED
|
File without changes
|
{haystack_ml_stack-0.3.2 → haystack_ml_stack-0.3.4}/src/haystack_ml_stack/generated/v1/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{haystack_ml_stack-0.3.2 → haystack_ml_stack-0.3.4}/src/haystack_ml_stack.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{haystack_ml_stack-0.3.2 → haystack_ml_stack-0.3.4}/src/haystack_ml_stack.egg-info/requires.txt
RENAMED
|
File without changes
|
{haystack_ml_stack-0.3.2 → haystack_ml_stack-0.3.4}/src/haystack_ml_stack.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|