| """表达层:渐进式通知体系""" |
|
|
| from enum import Enum |
| from dataclasses import dataclass |
| from typing import Optional |
|
|
|
|
| class NotificationLevel(Enum): |
| BREATHING = 1 |
| TITLE = 2 |
| FULL = 3 |
|
|
|
|
| @dataclass |
| class ExpressionOutput: |
| """表达层输出""" |
| level: NotificationLevel |
| title: str |
| body: str |
| reason: Optional[str] = None |
| animation: str = "fade_in" |
|
|
|
|
| class ExpressionLayer: |
| """ |
| 表达层:将决策转化为用户可感知的交互 |
| |
| 三级通知体系: |
| 1. 呼吸光效:仅暗示,不占用注意力 |
| 2. 标题预览:一行文字,表明意向 |
| 3. 完整消息:用户决定查看后才展开 |
| """ |
|
|
| def __init__(self): |
| self._dismissed: set = set() |
|
|
| def render(self, message: str, decision_confidence: float, |
| should_show_reason: bool = True) -> ExpressionOutput: |
| """根据决策置信度决定通知等级""" |
| |
| if decision_confidence > 0.85: |
| level = NotificationLevel.FULL |
| title = self._extract_title(message) |
| reason = None if not should_show_reason else "我有把握你会需要这个" |
|
|
| |
| elif decision_confidence > 0.70: |
| level = NotificationLevel.TITLE |
| title = message[:40] + ("..." if len(message) > 40 else "") |
| reason = "不太确定是否合适,你先看看标题?" |
|
|
| |
| else: |
| level = NotificationLevel.BREATHING |
| title = "" |
| reason = None |
|
|
| return ExpressionOutput( |
| level=level, |
| title=title, |
| body=message if level == NotificationLevel.FULL else title, |
| reason=reason, |
| ) |
|
|
| def dismiss(self, message_id: str): |
| self._dismissed.add(message_id) |
|
|
| def is_dismissed(self, message_id: str) -> bool: |
| return message_id in self._dismissed |
|
|
| @staticmethod |
| def _extract_title(text: str, max_len: int = 30) -> str: |
| """提取消息的第一句作为标题""" |
| first = text.split("。")[0].split("!")[0].split("?")[0] |
| return first[:max_len] + ("..." if len(first) > max_len else "") |
|
|