feat(wrapped): 新增梗图年鉴(Emoji Universe)卡片

- 后端新增 card_04_emoji_universe:统计表情包/emoji 使用与画像

- 前端新增 Card04EmojiUniverse + VueBits Stack/ImageTrail 交互展示

- 更新 Wrapped manifest/Hero 预览与用例覆盖
This commit is contained in:
2977094657
2026-02-13 22:40:39 +08:00
parent 2a1ae2150f
commit 7a0c39e39d
8 changed files with 4375 additions and 3 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -16,15 +16,16 @@ from .cards.card_00_global_overview import build_card_00_global_overview
from .cards.card_01_cyber_schedule import WeekdayHourHeatmap, build_card_01_cyber_schedule, compute_weekday_hour_heatmap
from .cards.card_02_message_chars import build_card_02_message_chars
from .cards.card_03_reply_speed import build_card_03_reply_speed
from .cards.card_04_emoji_universe import build_card_04_emoji_universe
logger = get_logger(__name__)
# We use this number to version the cache filename so adding more cards won't accidentally serve
# an older partial cache.
_IMPLEMENTED_UPTO_ID = 3
_IMPLEMENTED_UPTO_ID = 4
# Bump this when we change card payloads/ordering while keeping the same implemented_upto.
_CACHE_VERSION = 9
_CACHE_VERSION = 15
# "Manifest" is used by the frontend to render the deck quickly, then lazily fetch each card.
@@ -58,6 +59,13 @@ _WRAPPED_CARD_MANIFEST: tuple[dict[str, Any], ...] = (
"category": "B",
"kind": "chat/reply_speed",
},
{
"id": 4,
"title": "这一年,你的表情包里藏了多少心情?",
"scope": "global",
"category": "B",
"kind": "emoji/annual_universe",
},
)
_WRAPPED_CARD_ID_SET = {int(c["id"]) for c in _WRAPPED_CARD_MANIFEST}
@@ -274,7 +282,7 @@ def build_wrapped_annual_response(
) -> dict[str, Any]:
"""Build annual wrapped response for the given account/year.
For now we implement cards up to id=3 (plus a meta overview card id=0).
For now we implement cards up to id=4 (plus a meta overview card id=0).
"""
account_dir = _resolve_account_dir(account)
@@ -317,6 +325,8 @@ def build_wrapped_annual_response(
cards.append(build_card_02_message_chars(account_dir=account_dir, year=y))
# Page 5: reply speed / best chat buddy.
cards.append(build_card_03_reply_speed(account_dir=account_dir, year=y))
# Page 6: annual emoji universe / meme almanac.
cards.append(build_card_04_emoji_universe(account_dir=account_dir, year=y))
obj: dict[str, Any] = {
"account": account_dir.name,
@@ -508,6 +518,8 @@ def build_wrapped_annual_card(
card = build_card_02_message_chars(account_dir=account_dir, year=y)
elif cid == 3:
card = build_card_03_reply_speed(account_dir=account_dir, year=y)
elif cid == 4:
card = build_card_04_emoji_universe(account_dir=account_dir, year=y)
else:
# Should be unreachable due to _WRAPPED_CARD_ID_SET check.
raise ValueError(f"Unknown Wrapped card id: {cid}")