haystack-ml-stack 0.4.8__tar.gz → 0.4.10__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.4.8 → haystack_ml_stack-0.4.10}/PKG-INFO +1 -1
- {haystack_ml_stack-0.4.8 → haystack_ml_stack-0.4.10}/README.md +0 -0
- {haystack_ml_stack-0.4.8 → haystack_ml_stack-0.4.10}/pyproject.toml +1 -1
- {haystack_ml_stack-0.4.8 → haystack_ml_stack-0.4.10}/src/haystack_ml_stack/__init__.py +0 -0
- {haystack_ml_stack-0.4.8 → haystack_ml_stack-0.4.10}/src/haystack_ml_stack/_kafka.py +2 -1
- {haystack_ml_stack-0.4.8 → haystack_ml_stack-0.4.10}/src/haystack_ml_stack/_serializers.py +3 -0
- haystack_ml_stack-0.4.10/src/haystack_ml_stack/_version.py +1 -0
- {haystack_ml_stack-0.4.8 → haystack_ml_stack-0.4.10}/src/haystack_ml_stack/app.py +12 -1
- {haystack_ml_stack-0.4.8 → haystack_ml_stack-0.4.10}/src/haystack_ml_stack/cache.py +0 -0
- {haystack_ml_stack-0.4.8 → haystack_ml_stack-0.4.10}/src/haystack_ml_stack/dynamo.py +14 -12
- {haystack_ml_stack-0.4.8 → haystack_ml_stack-0.4.10}/src/haystack_ml_stack/exceptions.py +0 -0
- {haystack_ml_stack-0.4.8 → haystack_ml_stack-0.4.10}/src/haystack_ml_stack/generated/__init__.py +0 -0
- {haystack_ml_stack-0.4.8 → haystack_ml_stack-0.4.10}/src/haystack_ml_stack/generated/v1/__init__.py +0 -0
- {haystack_ml_stack-0.4.8 → haystack_ml_stack-0.4.10}/src/haystack_ml_stack/generated/v1/features_pb2.py +34 -34
- {haystack_ml_stack-0.4.8 → haystack_ml_stack-0.4.10}/src/haystack_ml_stack/generated/v1/features_pb2.pyi +8 -2
- {haystack_ml_stack-0.4.8 → haystack_ml_stack-0.4.10}/src/haystack_ml_stack/model_store.py +0 -0
- {haystack_ml_stack-0.4.8 → haystack_ml_stack-0.4.10}/src/haystack_ml_stack/settings.py +0 -0
- {haystack_ml_stack-0.4.8 → haystack_ml_stack-0.4.10}/src/haystack_ml_stack/utils.py +2 -0
- {haystack_ml_stack-0.4.8 → haystack_ml_stack-0.4.10}/src/haystack_ml_stack.egg-info/PKG-INFO +1 -1
- {haystack_ml_stack-0.4.8 → haystack_ml_stack-0.4.10}/src/haystack_ml_stack.egg-info/SOURCES.txt +0 -0
- {haystack_ml_stack-0.4.8 → haystack_ml_stack-0.4.10}/src/haystack_ml_stack.egg-info/dependency_links.txt +0 -0
- {haystack_ml_stack-0.4.8 → haystack_ml_stack-0.4.10}/src/haystack_ml_stack.egg-info/requires.txt +0 -0
- {haystack_ml_stack-0.4.8 → haystack_ml_stack-0.4.10}/src/haystack_ml_stack.egg-info/top_level.txt +0 -0
- {haystack_ml_stack-0.4.8 → haystack_ml_stack-0.4.10}/tests/test_serializers.py +61 -0
- {haystack_ml_stack-0.4.8 → haystack_ml_stack-0.4.10}/tests/test_utils.py +0 -0
- haystack_ml_stack-0.4.8/src/haystack_ml_stack/_version.py +0 -1
- {haystack_ml_stack-0.4.8 → haystack_ml_stack-0.4.10}/setup.cfg +0 -0
|
File without changes
|
|
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
|
|
|
5
5
|
|
|
6
6
|
[project]
|
|
7
7
|
name = "haystack-ml-stack"
|
|
8
|
-
version = "0.4.
|
|
8
|
+
version = "0.4.10"
|
|
9
9
|
description = "Functions related to Haystack ML"
|
|
10
10
|
readme = "README.md"
|
|
11
11
|
authors = [{ name = "Oscar Vega", email = "oscar@haystack.tv" }]
|
|
File without changes
|
|
@@ -72,7 +72,7 @@ async def send_channels_to_kafka(
|
|
|
72
72
|
"userid": user.get("userid"),
|
|
73
73
|
"client_os": user.get("clientOs"),
|
|
74
74
|
"model_input": {"user": user, "channels": channels},
|
|
75
|
-
"model_output": model_output,
|
|
75
|
+
"model_output": {c: v for c, v in model_output.items() if c != "__meta__"},
|
|
76
76
|
"model_name": state["model_name"].replace(".pkl", "")
|
|
77
77
|
if state["model_name"]
|
|
78
78
|
else None,
|
|
@@ -83,6 +83,7 @@ async def send_channels_to_kafka(
|
|
|
83
83
|
"user_features": state.get("user_features", []),
|
|
84
84
|
"global_features": state.get("global_features", []),
|
|
85
85
|
"query_params": query_params,
|
|
86
|
+
**model_output.get("__meta__", {})
|
|
86
87
|
},
|
|
87
88
|
"processed_at": processed_at.isoformat(),
|
|
88
89
|
}
|
|
@@ -275,6 +275,8 @@ class UserPlaylistStatsSerializerV1(SimpleSerializer):
|
|
|
275
275
|
category_msg.active_days = int(stats["active_days"])
|
|
276
276
|
category_msg.total_watched = float(stats["total_watched"])
|
|
277
277
|
category_msg.capped_total_watched = float(stats["capped_total_watched"])
|
|
278
|
+
category_msg.capped_total_log_watched = float(stats.get("capped_total_log_watched", 0.0))
|
|
279
|
+
category_msg.first_active_date = str(stats.get("first_active_date", ""))
|
|
278
280
|
return root_msg
|
|
279
281
|
|
|
280
282
|
|
|
@@ -295,6 +297,7 @@ class GlobalChannelsSerializerV1(SimpleSerializer):
|
|
|
295
297
|
channel_msg.name = str(channel["name"])
|
|
296
298
|
channel_msg.category_group = str(channel["category_group"])
|
|
297
299
|
channel_msg.start_date = int(channel["start_date"])
|
|
300
|
+
channel_msg.required_features.extend(str(f) for f in (channel.get("required_features") or []))
|
|
298
301
|
return root_msg
|
|
299
302
|
|
|
300
303
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.4.10"
|
|
@@ -516,6 +516,7 @@ def create_channel_app(
|
|
|
516
516
|
)
|
|
517
517
|
|
|
518
518
|
model = state["model"]
|
|
519
|
+
exploration_mode = query_params.get("exploration") in ["True", "true", "1"]
|
|
519
520
|
try:
|
|
520
521
|
preprocess_start = time.perf_counter_ns()
|
|
521
522
|
model["params"]["query_params"] = query_params
|
|
@@ -526,6 +527,16 @@ def create_channel_app(
|
|
|
526
527
|
)
|
|
527
528
|
predict_start = time.perf_counter_ns()
|
|
528
529
|
model_output = model["predict"](model_input, model["params"])
|
|
530
|
+
if exploration_mode:
|
|
531
|
+
if "exploration" not in model:
|
|
532
|
+
raise ValueError("Model does not support exploration mode")
|
|
533
|
+
model_output = model["exploration"](
|
|
534
|
+
user,
|
|
535
|
+
channels,
|
|
536
|
+
model_output,
|
|
537
|
+
model["params"],
|
|
538
|
+
)
|
|
539
|
+
|
|
529
540
|
predict_end = time.perf_counter_ns()
|
|
530
541
|
except Exception as e:
|
|
531
542
|
logger.error("Model prediction failed: \n%s", traceback.format_exc())
|
|
@@ -547,7 +558,7 @@ def create_channel_app(
|
|
|
547
558
|
"retrieval_ms": retrieval_meta.retrieval_ms,
|
|
548
559
|
"preprocess_ms": (predict_start - preprocess_start) * 1e-6,
|
|
549
560
|
"predict_ms": (predict_end - predict_start) * 1e-6,
|
|
550
|
-
"total_channels": len(model_output),
|
|
561
|
+
"total_channels": len(model_output) - ("__meta__" in model_output),
|
|
551
562
|
}
|
|
552
563
|
newrelic.agent.record_custom_event(
|
|
553
564
|
"ChannelInference",
|
|
File without changes
|
|
@@ -499,31 +499,33 @@ def _process_channels(
|
|
|
499
499
|
if playlist_stats_global:
|
|
500
500
|
for stat in playlist_stats_global.values():
|
|
501
501
|
all_channels.update(stat.data.keys())
|
|
502
|
-
if playlist_stats_user:
|
|
503
|
-
for stat in playlist_stats_user.values():
|
|
504
|
-
all_channels.update(stat.data.keys())
|
|
505
502
|
|
|
506
503
|
all_channels = all_channels | set(DEFAULT_CHANNELS)
|
|
507
504
|
|
|
508
|
-
# My headlines will stay on top so not part of the candidates
|
|
505
|
+
# My headlines and local news will stay on top so not part of the candidates
|
|
506
|
+
# watch history and liked videos are always part of the bottom also
|
|
509
507
|
# The group labels are also ignored, not real channels for UI
|
|
510
|
-
ignore_channels =
|
|
508
|
+
ignore_channels = {"my headlines", "local news", "national_favorite", "local_favorite", "watch history", "liked videos", "nn_join_us"}
|
|
511
509
|
|
|
512
|
-
#
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
if "es" not in user.get("languages", []):
|
|
517
|
-
ignore_channels.add("live_es")
|
|
510
|
+
# Rules to filter candidates
|
|
511
|
+
channel_features = user.get("channelFeatures", {})
|
|
512
|
+
channel_eligibility = channel_features.get("eligibility", {})
|
|
513
|
+
channel_feature_predicates = channel_features.get("features", {})
|
|
518
514
|
|
|
519
515
|
inserted_channel_names = set()
|
|
520
516
|
if channel_candidates is not None:
|
|
521
517
|
preferred = set(user.get("preferredChannels", []) or [])
|
|
522
518
|
for ch in channel_candidates.data:
|
|
519
|
+
# Eligibility rules
|
|
520
|
+
if not channel_eligibility.get(ch.name, True):
|
|
521
|
+
ignore_channels.add(ch.name)
|
|
522
|
+
# Feature predicate rules for special channels
|
|
523
|
+
if ch.required_features and not all(channel_feature_predicates.get(f, False) for f in ch.required_features):
|
|
524
|
+
ignore_channels.add(ch.name)
|
|
523
525
|
# Rule for authors
|
|
524
526
|
if (
|
|
525
527
|
ch.category_group in ("national_favorite", "local_favorite")
|
|
526
|
-
and ch.name not in preferred
|
|
528
|
+
and (ch.name not in preferred or not channel_eligibility.get(ch.category_group, True))
|
|
527
529
|
):
|
|
528
530
|
ignore_channels.add(ch.name)
|
|
529
531
|
# Rule for shows
|
|
File without changes
|
{haystack_ml_stack-0.4.8 → haystack_ml_stack-0.4.10}/src/haystack_ml_stack/generated/__init__.py
RENAMED
|
File without changes
|
{haystack_ml_stack-0.4.8 → haystack_ml_stack-0.4.10}/src/haystack_ml_stack/generated/v1/__init__.py
RENAMED
|
File without changes
|
|
@@ -24,7 +24,7 @@ _sym_db = _symbol_database.Default()
|
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0e\x66\x65\x61tures.proto\x12\x1ahaystack_ml_stack.features\"7\n\x12\x45ntryContextCounts\x12\x10\n\x08\x61ttempts\x18\x01 \x01(\x05\x12\x0f\n\x07watched\x18\x02 \x01(\x05\"_\n\x0cSelectCounts\x12\x15\n\rtotal_selects\x18\x01 \x01(\x05\x12!\n\x19total_selects_and_watched\x18\x02 \x01(\x05\x12\x15\n\rtotal_browsed\x18\x03 \x01(\x05\"\xf3\x02\n\x14\x45ntryContextPWatched\x12@\n\x08\x61utoplay\x18\x01 \x01(\x0b\x32..haystack_ml_stack.features.EntryContextCounts\x12\x41\n\tsel_thumb\x18\x02 \x01(\x0b\x32..haystack_ml_stack.features.EntryContextCounts\x12\x43\n\x0b\x63hoose_next\x18\x03 \x01(\x0b\x32..haystack_ml_stack.features.EntryContextCounts\x12@\n\x08\x63h_swtch\x18\x04 \x01(\x0b\x32..haystack_ml_stack.features.EntryContextCounts\x12O\n\x17launch_first_in_session\x18\x05 \x01(\x0b\x32..haystack_ml_stack.features.EntryContextCounts\"\x85\x02\n\x0fPositionPSelect\x12;\n\tfirst_pos\x18\x01 \x01(\x0b\x32(.haystack_ml_stack.features.SelectCounts\x12<\n\nsecond_pos\x18\x02 \x01(\x0b\x32(.haystack_ml_stack.features.SelectCounts\x12;\n\tthird_pos\x18\x03 \x01(\x0b\x32(.haystack_ml_stack.features.SelectCounts\x12:\n\x08rest_pos\x18\x04 \x01(\x0b\x32(.haystack_ml_stack.features.SelectCounts\"\xa9\x01\n\x1f\x42rowsedDebiasedPositionPSelects\x12\x44\n\x0fup_to_4_browsed\x18\x01 \x01(\x0b\x32+.haystack_ml_stack.features.PositionPSelect\x12@\n\x0b\x61ll_browsed\x18\x02 \x01(\x0b\x32+.haystack_ml_stack.features.PositionPSelect\"\xb8\x01\n\x16PlaylistStatsForGlobal\x12\x15\n\rwatched_count\x18\x01 \x01(\x05\x12\x19\n\x11not_watched_count\x18\x02 \x01(\x05\x12\x1b\n\x13\x63\x61pped_watched_secs\x18\x03 \x01(\x02\x12\x1f\n\x17\x63\x61pped_not_watched_secs\x18\x04 \x01(\x02\x12\x14\n\x0cwatched_secs\x18\x05 \x01(\x02\x12\x18\n\x10not_watched_secs\x18\x06 \x01(\x02\"\
|
|
27
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0e\x66\x65\x61tures.proto\x12\x1ahaystack_ml_stack.features\"7\n\x12\x45ntryContextCounts\x12\x10\n\x08\x61ttempts\x18\x01 \x01(\x05\x12\x0f\n\x07watched\x18\x02 \x01(\x05\"_\n\x0cSelectCounts\x12\x15\n\rtotal_selects\x18\x01 \x01(\x05\x12!\n\x19total_selects_and_watched\x18\x02 \x01(\x05\x12\x15\n\rtotal_browsed\x18\x03 \x01(\x05\"\xf3\x02\n\x14\x45ntryContextPWatched\x12@\n\x08\x61utoplay\x18\x01 \x01(\x0b\x32..haystack_ml_stack.features.EntryContextCounts\x12\x41\n\tsel_thumb\x18\x02 \x01(\x0b\x32..haystack_ml_stack.features.EntryContextCounts\x12\x43\n\x0b\x63hoose_next\x18\x03 \x01(\x0b\x32..haystack_ml_stack.features.EntryContextCounts\x12@\n\x08\x63h_swtch\x18\x04 \x01(\x0b\x32..haystack_ml_stack.features.EntryContextCounts\x12O\n\x17launch_first_in_session\x18\x05 \x01(\x0b\x32..haystack_ml_stack.features.EntryContextCounts\"\x85\x02\n\x0fPositionPSelect\x12;\n\tfirst_pos\x18\x01 \x01(\x0b\x32(.haystack_ml_stack.features.SelectCounts\x12<\n\nsecond_pos\x18\x02 \x01(\x0b\x32(.haystack_ml_stack.features.SelectCounts\x12;\n\tthird_pos\x18\x03 \x01(\x0b\x32(.haystack_ml_stack.features.SelectCounts\x12:\n\x08rest_pos\x18\x04 \x01(\x0b\x32(.haystack_ml_stack.features.SelectCounts\"\xa9\x01\n\x1f\x42rowsedDebiasedPositionPSelects\x12\x44\n\x0fup_to_4_browsed\x18\x01 \x01(\x0b\x32+.haystack_ml_stack.features.PositionPSelect\x12@\n\x0b\x61ll_browsed\x18\x02 \x01(\x0b\x32+.haystack_ml_stack.features.PositionPSelect\"\xb8\x01\n\x16PlaylistStatsForGlobal\x12\x15\n\rwatched_count\x18\x01 \x01(\x05\x12\x19\n\x11not_watched_count\x18\x02 \x01(\x05\x12\x1b\n\x13\x63\x61pped_watched_secs\x18\x03 \x01(\x02\x12\x1f\n\x17\x63\x61pped_not_watched_secs\x18\x04 \x01(\x02\x12\x14\n\x0cwatched_secs\x18\x05 \x01(\x02\x12\x18\n\x10not_watched_secs\x18\x06 \x01(\x02\"\xc5\x01\n\x14PlaylistStatsForUser\x12\x12\n\ntotal_days\x18\x01 \x01(\x05\x12\x12\n\nstart_days\x18\x02 \x01(\x05\x12\x13\n\x0b\x61\x63tive_days\x18\x03 \x01(\x05\x12\x15\n\rtotal_watched\x18\x04 \x01(\x02\x12\x1c\n\x14\x63\x61pped_total_watched\x18\x05 \x01(\x02\x12 \n\x18\x63\x61pped_total_log_watched\x18\x06 \x01(\x02\x12\x19\n\x11\x66irst_active_date\x18\x07 \x01(\t\"^\n\x07\x43hannel\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x16\n\x0e\x63\x61tegory_group\x18\x02 \x01(\t\x12\x12\n\nstart_date\x18\x03 \x01(\x05\x12\x19\n\x11required_features\x18\x04 \x03(\t\"k\n\rStreamPSelect\x12\x0f\n\x07version\x18\x01 \x01(\x05\x12I\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32;.haystack_ml_stack.features.BrowsedDebiasedPositionPSelects\"a\n\x0eStreamPWatched\x12\x0f\n\x07version\x18\x01 \x01(\x05\x12>\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32\x30.haystack_ml_stack.features.EntryContextPWatched\"_\n\x0cUserPWatched\x12\x0f\n\x07version\x18\x01 \x01(\x05\x12>\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32\x30.haystack_ml_stack.features.EntryContextPWatched\"\xda\x01\n\x19UserPersonalizingPWatched\x12\x0f\n\x07version\x18\x01 \x01(\x05\x12M\n\x04\x64\x61ta\x18\x02 \x03(\x0b\x32?.haystack_ml_stack.features.UserPersonalizingPWatched.DataEntry\x1a]\n\tDataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12?\n\x05value\x18\x02 \x01(\x0b\x32\x30.haystack_ml_stack.features.EntryContextPWatched:\x02\x38\x01\"i\n\x0bUserPSelect\x12\x0f\n\x07version\x18\x01 \x01(\x05\x12I\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32;.haystack_ml_stack.features.BrowsedDebiasedPositionPSelects\"\xe3\x01\n\x18UserPersonalizingPSelect\x12\x0f\n\x07version\x18\x01 \x01(\x05\x12L\n\x04\x64\x61ta\x18\x02 \x03(\x0b\x32>.haystack_ml_stack.features.UserPersonalizingPSelect.DataEntry\x1ah\n\tDataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12J\n\x05value\x18\x02 \x01(\x0b\x32;.haystack_ml_stack.features.BrowsedDebiasedPositionPSelects:\x02\x38\x01\"\xa2\x01\n\x16StreamSimilarityScores\x12\x0f\n\x07version\x18\x01 \x01(\x05\x12J\n\x04\x64\x61ta\x18\x02 \x03(\x0b\x32<.haystack_ml_stack.features.StreamSimilarityScores.DataEntry\x1a+\n\tDataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x01:\x02\x38\x01\"\xd0\x01\n\x13GlobalPlaylistStats\x12\x0f\n\x07version\x18\x01 \x01(\x05\x12G\n\x04\x64\x61ta\x18\x02 \x03(\x0b\x32\x39.haystack_ml_stack.features.GlobalPlaylistStats.DataEntry\x1a_\n\tDataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x41\n\x05value\x18\x02 \x01(\x0b\x32\x32.haystack_ml_stack.features.PlaylistStatsForGlobal:\x02\x38\x01\"\xca\x01\n\x11UserPlaylistStats\x12\x0f\n\x07version\x18\x01 \x01(\x05\x12\x45\n\x04\x64\x61ta\x18\x02 \x03(\x0b\x32\x37.haystack_ml_stack.features.UserPlaylistStats.DataEntry\x1a]\n\tDataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12?\n\x05value\x18\x02 \x01(\x0b\x32\x30.haystack_ml_stack.features.PlaylistStatsForUser:\x02\x38\x01\"T\n\x0eGlobalChannels\x12\x0f\n\x07version\x18\x01 \x01(\x05\x12\x31\n\x04\x64\x61ta\x18\x02 \x03(\x0b\x32#.haystack_ml_stack.features.Channelb\x06proto3')
|
|
28
28
|
|
|
29
29
|
_globals = globals()
|
|
30
30
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
|
@@ -54,37 +54,37 @@ if not _descriptor._USE_C_DESCRIPTORS:
|
|
|
54
54
|
_globals['_PLAYLISTSTATSFORGLOBAL']._serialized_start=1011
|
|
55
55
|
_globals['_PLAYLISTSTATSFORGLOBAL']._serialized_end=1195
|
|
56
56
|
_globals['_PLAYLISTSTATSFORUSER']._serialized_start=1198
|
|
57
|
-
_globals['_PLAYLISTSTATSFORUSER']._serialized_end=
|
|
58
|
-
_globals['_CHANNEL']._serialized_start=
|
|
59
|
-
_globals['_CHANNEL']._serialized_end=
|
|
60
|
-
_globals['_STREAMPSELECT']._serialized_start=
|
|
61
|
-
_globals['_STREAMPSELECT']._serialized_end=
|
|
62
|
-
_globals['_STREAMPWATCHED']._serialized_start=
|
|
63
|
-
_globals['_STREAMPWATCHED']._serialized_end=
|
|
64
|
-
_globals['_USERPWATCHED']._serialized_start=
|
|
65
|
-
_globals['_USERPWATCHED']._serialized_end=
|
|
66
|
-
_globals['_USERPERSONALIZINGPWATCHED']._serialized_start=
|
|
67
|
-
_globals['_USERPERSONALIZINGPWATCHED']._serialized_end=
|
|
68
|
-
_globals['_USERPERSONALIZINGPWATCHED_DATAENTRY']._serialized_start=
|
|
69
|
-
_globals['_USERPERSONALIZINGPWATCHED_DATAENTRY']._serialized_end=
|
|
70
|
-
_globals['_USERPSELECT']._serialized_start=
|
|
71
|
-
_globals['_USERPSELECT']._serialized_end=
|
|
72
|
-
_globals['_USERPERSONALIZINGPSELECT']._serialized_start=
|
|
73
|
-
_globals['_USERPERSONALIZINGPSELECT']._serialized_end=
|
|
74
|
-
_globals['_USERPERSONALIZINGPSELECT_DATAENTRY']._serialized_start=
|
|
75
|
-
_globals['_USERPERSONALIZINGPSELECT_DATAENTRY']._serialized_end=
|
|
76
|
-
_globals['_STREAMSIMILARITYSCORES']._serialized_start=
|
|
77
|
-
_globals['_STREAMSIMILARITYSCORES']._serialized_end=
|
|
78
|
-
_globals['_STREAMSIMILARITYSCORES_DATAENTRY']._serialized_start=
|
|
79
|
-
_globals['_STREAMSIMILARITYSCORES_DATAENTRY']._serialized_end=
|
|
80
|
-
_globals['_GLOBALPLAYLISTSTATS']._serialized_start=
|
|
81
|
-
_globals['_GLOBALPLAYLISTSTATS']._serialized_end=
|
|
82
|
-
_globals['_GLOBALPLAYLISTSTATS_DATAENTRY']._serialized_start=
|
|
83
|
-
_globals['_GLOBALPLAYLISTSTATS_DATAENTRY']._serialized_end=
|
|
84
|
-
_globals['_USERPLAYLISTSTATS']._serialized_start=
|
|
85
|
-
_globals['_USERPLAYLISTSTATS']._serialized_end=
|
|
86
|
-
_globals['_USERPLAYLISTSTATS_DATAENTRY']._serialized_start=
|
|
87
|
-
_globals['_USERPLAYLISTSTATS_DATAENTRY']._serialized_end=
|
|
88
|
-
_globals['_GLOBALCHANNELS']._serialized_start=
|
|
89
|
-
_globals['_GLOBALCHANNELS']._serialized_end=
|
|
57
|
+
_globals['_PLAYLISTSTATSFORUSER']._serialized_end=1395
|
|
58
|
+
_globals['_CHANNEL']._serialized_start=1397
|
|
59
|
+
_globals['_CHANNEL']._serialized_end=1491
|
|
60
|
+
_globals['_STREAMPSELECT']._serialized_start=1493
|
|
61
|
+
_globals['_STREAMPSELECT']._serialized_end=1600
|
|
62
|
+
_globals['_STREAMPWATCHED']._serialized_start=1602
|
|
63
|
+
_globals['_STREAMPWATCHED']._serialized_end=1699
|
|
64
|
+
_globals['_USERPWATCHED']._serialized_start=1701
|
|
65
|
+
_globals['_USERPWATCHED']._serialized_end=1796
|
|
66
|
+
_globals['_USERPERSONALIZINGPWATCHED']._serialized_start=1799
|
|
67
|
+
_globals['_USERPERSONALIZINGPWATCHED']._serialized_end=2017
|
|
68
|
+
_globals['_USERPERSONALIZINGPWATCHED_DATAENTRY']._serialized_start=1924
|
|
69
|
+
_globals['_USERPERSONALIZINGPWATCHED_DATAENTRY']._serialized_end=2017
|
|
70
|
+
_globals['_USERPSELECT']._serialized_start=2019
|
|
71
|
+
_globals['_USERPSELECT']._serialized_end=2124
|
|
72
|
+
_globals['_USERPERSONALIZINGPSELECT']._serialized_start=2127
|
|
73
|
+
_globals['_USERPERSONALIZINGPSELECT']._serialized_end=2354
|
|
74
|
+
_globals['_USERPERSONALIZINGPSELECT_DATAENTRY']._serialized_start=2250
|
|
75
|
+
_globals['_USERPERSONALIZINGPSELECT_DATAENTRY']._serialized_end=2354
|
|
76
|
+
_globals['_STREAMSIMILARITYSCORES']._serialized_start=2357
|
|
77
|
+
_globals['_STREAMSIMILARITYSCORES']._serialized_end=2519
|
|
78
|
+
_globals['_STREAMSIMILARITYSCORES_DATAENTRY']._serialized_start=2476
|
|
79
|
+
_globals['_STREAMSIMILARITYSCORES_DATAENTRY']._serialized_end=2519
|
|
80
|
+
_globals['_GLOBALPLAYLISTSTATS']._serialized_start=2522
|
|
81
|
+
_globals['_GLOBALPLAYLISTSTATS']._serialized_end=2730
|
|
82
|
+
_globals['_GLOBALPLAYLISTSTATS_DATAENTRY']._serialized_start=2635
|
|
83
|
+
_globals['_GLOBALPLAYLISTSTATS_DATAENTRY']._serialized_end=2730
|
|
84
|
+
_globals['_USERPLAYLISTSTATS']._serialized_start=2733
|
|
85
|
+
_globals['_USERPLAYLISTSTATS']._serialized_end=2935
|
|
86
|
+
_globals['_USERPLAYLISTSTATS_DATAENTRY']._serialized_start=2842
|
|
87
|
+
_globals['_USERPLAYLISTSTATS_DATAENTRY']._serialized_end=2935
|
|
88
|
+
_globals['_GLOBALCHANNELS']._serialized_start=2937
|
|
89
|
+
_globals['_GLOBALCHANNELS']._serialized_end=3021
|
|
90
90
|
# @@protoc_insertion_point(module_scope)
|
|
@@ -81,22 +81,28 @@ class PlaylistStatsForUser(_message.Message):
|
|
|
81
81
|
ACTIVE_DAYS_FIELD_NUMBER: _ClassVar[int]
|
|
82
82
|
TOTAL_WATCHED_FIELD_NUMBER: _ClassVar[int]
|
|
83
83
|
CAPPED_TOTAL_WATCHED_FIELD_NUMBER: _ClassVar[int]
|
|
84
|
+
CAPPED_TOTAL_LOG_WATCHED_FIELD_NUMBER: _ClassVar[int]
|
|
85
|
+
FIRST_ACTIVE_DATE_FIELD_NUMBER: _ClassVar[int]
|
|
84
86
|
total_days: int
|
|
85
87
|
start_days: int
|
|
86
88
|
active_days: int
|
|
87
89
|
total_watched: float
|
|
88
90
|
capped_total_watched: float
|
|
89
|
-
|
|
91
|
+
capped_total_log_watched: float
|
|
92
|
+
first_active_date: str
|
|
93
|
+
def __init__(self, total_days: _Optional[int] = ..., start_days: _Optional[int] = ..., active_days: _Optional[int] = ..., total_watched: _Optional[float] = ..., capped_total_watched: _Optional[float] = ..., capped_total_log_watched: _Optional[float] = ..., first_active_date: _Optional[str] = ...) -> None: ...
|
|
90
94
|
|
|
91
95
|
class Channel(_message.Message):
|
|
92
96
|
__slots__ = ()
|
|
93
97
|
NAME_FIELD_NUMBER: _ClassVar[int]
|
|
94
98
|
CATEGORY_GROUP_FIELD_NUMBER: _ClassVar[int]
|
|
95
99
|
START_DATE_FIELD_NUMBER: _ClassVar[int]
|
|
100
|
+
REQUIRED_FEATURES_FIELD_NUMBER: _ClassVar[int]
|
|
96
101
|
name: str
|
|
97
102
|
category_group: str
|
|
98
103
|
start_date: int
|
|
99
|
-
|
|
104
|
+
required_features: _containers.RepeatedScalarFieldContainer[str]
|
|
105
|
+
def __init__(self, name: _Optional[str] = ..., category_group: _Optional[str] = ..., start_date: _Optional[int] = ..., required_features: _Optional[_Iterable[str]] = ...) -> None: ...
|
|
100
106
|
|
|
101
107
|
class StreamPSelect(_message.Message):
|
|
102
108
|
__slots__ = ()
|
|
File without changes
|
|
File without changes
|
{haystack_ml_stack-0.4.8 → haystack_ml_stack-0.4.10}/src/haystack_ml_stack.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{haystack_ml_stack-0.4.8 → haystack_ml_stack-0.4.10}/src/haystack_ml_stack.egg-info/requires.txt
RENAMED
|
File without changes
|
{haystack_ml_stack-0.4.8 → haystack_ml_stack-0.4.10}/src/haystack_ml_stack.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
@@ -150,3 +150,64 @@ def test_user_bias_serializers():
|
|
|
150
150
|
"User pselect serialization does not match expected value."
|
|
151
151
|
)
|
|
152
152
|
return
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def test_user_playlist_stats_serializer_backward_compatibility():
|
|
156
|
+
serializer = SerializerRegistry[("USER", "PLAYLIST_CATEGORY_STATS#3M", "v1")]
|
|
157
|
+
|
|
158
|
+
# Case 1: true old binary — built without fields 6 and 7, identical to what
|
|
159
|
+
# the old serializer would have written before the proto change
|
|
160
|
+
old_msg = features_pb2_v1.UserPlaylistStats()
|
|
161
|
+
old_msg.version = 1
|
|
162
|
+
entry = old_msg.data["sports"]
|
|
163
|
+
entry.total_days = 30
|
|
164
|
+
entry.start_days = 5
|
|
165
|
+
entry.active_days = 10
|
|
166
|
+
entry.total_watched = 120.5
|
|
167
|
+
entry.capped_total_watched = 100.0
|
|
168
|
+
old_binary = old_msg.SerializeToString()
|
|
169
|
+
|
|
170
|
+
result = serializer.deserialize(old_binary)
|
|
171
|
+
assert result.data["sports"].total_days == 30
|
|
172
|
+
assert result.data["sports"].capped_total_watched == 100.0
|
|
173
|
+
assert result.data["sports"].capped_total_log_watched == 0.0
|
|
174
|
+
assert result.data["sports"].first_active_date == ""
|
|
175
|
+
|
|
176
|
+
# Case 2: new data with new fields — full round-trip
|
|
177
|
+
new_data = {
|
|
178
|
+
"version": 1,
|
|
179
|
+
"data": {
|
|
180
|
+
"sports": {
|
|
181
|
+
"total_days": 30,
|
|
182
|
+
"start_days": 5,
|
|
183
|
+
"active_days": 10,
|
|
184
|
+
"total_watched": 120.5,
|
|
185
|
+
"capped_total_watched": 100.0,
|
|
186
|
+
"capped_total_log_watched": 4.8,
|
|
187
|
+
"first_active_date": "2024-01-15",
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
}
|
|
191
|
+
binary = serializer.serialize(new_data)
|
|
192
|
+
result = serializer.deserialize(binary)
|
|
193
|
+
assert abs(result.data["sports"].capped_total_log_watched - 4.8) < 1e-6
|
|
194
|
+
assert result.data["sports"].first_active_date == "2024-01-15"
|
|
195
|
+
|
|
196
|
+
# Case 3: old-format dict missing the new fields — .get() fallback
|
|
197
|
+
old_format_data = {
|
|
198
|
+
"version": 1,
|
|
199
|
+
"data": {
|
|
200
|
+
"sports": {
|
|
201
|
+
"total_days": 30,
|
|
202
|
+
"start_days": 5,
|
|
203
|
+
"active_days": 10,
|
|
204
|
+
"total_watched": 120.5,
|
|
205
|
+
"capped_total_watched": 100.0,
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
}
|
|
209
|
+
binary = serializer.serialize(old_format_data)
|
|
210
|
+
result = serializer.deserialize(binary)
|
|
211
|
+
assert result.data["sports"].total_days == 30
|
|
212
|
+
assert result.data["sports"].capped_total_log_watched == 0.0
|
|
213
|
+
assert result.data["sports"].first_active_date == ""
|
|
File without changes
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.4.8"
|
|
File without changes
|