""" Android view.textclassifier 组件 — TextClassifier, TextClassification, TextLinks, TextSelection 等 方法签名完全对齐 Android SDK """ import re from typing import Any, Callable, Dict, List, Optional, Set, Tuple from .._core import Stub, AndroidOnlyError # ═══════════════════════════════════════════════════════════════ # EntityConfig # ═══════════════════════════════════════════════════════════════ class EntityConfig(Stub): """EntityConfig — 实体配置""" class Builder(Stub): """EntityConfig.Builder — 实体配置构建器""" def __init__(self): super().__init__() self._include_types: Optional[Set[str]] = None self._exclude_types: Optional[Set[str]] = None self._include_from_textclassifier = True def includeTypesFromTextClassifier(self) -> "EntityConfig.Builder": self._include_from_textclassifier = True return self def excludeTypes(self, varargs: List[str]) -> "EntityConfig.Builder": self._exclude_types = set(varargs) return self def includeTypes(self, varargs: List[str]) -> "EntityConfig.Builder": self._include_types = set(varargs) return self def build(self) -> "EntityConfig": config = EntityConfig() config._include_types = self._include_types config._exclude_types = self._exclude_types config._include_from_textclassifier = self._include_from_textclassifier return config def getEntityTypes(self) -> Optional[List[str]]: if self._include_types: return list(self._include_types) return None def __init__(self): super().__init__() self._include_types: Optional[Set[str]] = None self._exclude_types: Optional[Set[str]] = None self._include_from_textclassifier = True def getEntityTypes(self) -> Optional[List[str]]: if self._include_types: return list(self._include_types) return None # ═══════════════════════════════════════════════════════════════ # TextClassifier # ═══════════════════════════════════════════════════════════════ class TextClassifier(Stub): """TextClassifier — 文本分类器""" TYPE_UNKNOWN = "unknown" TYPE_ADDRESS = "address" TYPE_DATE = "date" TYPE_DATE_TIME = "datetime" TYPE_DURATION = "duration" TYPE_EMAIL = "email" TYPE_FLIGHT_NUMBER = "flight" TYPE_IDENTIFIER = "identifier" TYPE_LINK = "link" TYPE_LIST = "list" TYPE_LOCATION = "location" TYPE_MEASUREMENT = "measurement" TYPE_MONEY = "money" TYPE_OTHER = "other" TYPE_PERIODIC = "periodic" TYPE_PHONE = "phone" TYPE_PRODUCT = "product" TYPE_RECIPE = "recipe" TYPE_TRACK_AIRLINE = "track_airline" TYPE_TRACK_FLIGHT = "track_flight" TYPE_TRACK_FOOD = "track_food" TYPE_TRACK_SPORT = "track_sport" TYPE_TRACK_WEATHER = "track_weather" TYPE_URL = "url" TYPE_VEHICLE = "vehicle" WIDGET_TYPE_CLIPBOARD = "clipboard" WIDGET_TYPE_CUT_COPY = "cutcopy" WIDGET_TYPE_EDIT_TEXT = "edittext" WIDGET_TYPE_LINKIFY = "linkify" WIDGET_TYPE_NOTIFICATION = "notification" WIDGET_TYPE_OTHER = "other" WIDGET_TYPE_SELECTION = "selection" WIDGET_TYPE_TEXT = "text" WIDGET_TYPE_UNSELECTED_TEXT = "unselected_text" # ═══════════════════════════════════════════════════════════ # Request # ═══════════════════════════════════════════════════════════ class Request(Stub): """TextClassifier.Request — 分类请求""" def __init__(self): super().__init__() self._calling_package_name: Optional[str] = None self._text: str = "" self._start_index: int = 0 self._end_index: int = 0 self._extras: Any = None self._default_locales: Any = None self._dark_launch_allowed = False def getCallingPackageName(self) -> Optional[str]: return self._calling_package_name def getText(self) -> str: return self._text def getStartIndex(self) -> int: return self._start_index def getEndIndex(self) -> int: return self._end_index def getExtras(self) -> Any: return self._extras def getDefaultLocales(self) -> Any: return self._default_locales def isDarkLaunchAllowed(self) -> bool: return self._dark_launch_allowed def __init__(self): super().__init__() def classifyText(self, request: Request) -> "TextClassification": text = request.getText() start = request.getStartIndex() end = request.getEndIndex() if end > len(text): end = len(text) selected = text[start:end] if start < end else text entity_type = TextClassifier.TYPE_UNKNOWN confidence = 0.0 # Basic regex-based classification if re.match(r'^https?://', selected): entity_type = TextClassifier.TYPE_URL confidence = 0.95 elif re.match(r'^[\w.+-]+@[\w-]+\.[\w.-]+$', selected): entity_type = TextClassifier.TYPE_EMAIL confidence = 0.95 elif re.match(r'^\+?[\d\s\-\(\)]{7,15}$', selected): entity_type = TextClassifier.TYPE_PHONE confidence = 0.85 elif re.match(r'^\d{1,4}[-/]\d{1,2}[-/]\d{1,4}$', selected): entity_type = TextClassifier.TYPE_DATE confidence = 0.80 elif re.match(r'^\d{1,2}:\d{2}(\s?[AP]M)?$', selected, re.IGNORECASE): entity_type = TextClassifier.TYPE_DATE_TIME confidence = 0.80 tc = TextClassification() tc._text = selected tc._entity_type = entity_type tc._confidence_score = confidence tc._entity_count = 1 return tc def suggestConversationActions(self, request: Request) -> List["ConversationAction"]: return [] def detectLanguage(self, text: str) -> "TextClassification": tc = TextClassification() tc._text = text tc._entity_type = TextClassifier.TYPE_UNKNOWN return tc def onSelectionEvent(self, event: Any): pass def onTextChanged(self, text: Any): pass def onTextSelectionAction(self, action: Any): pass # ═══════════════════════════════════════════════════════════════ # TextClassification # ═══════════════════════════════════════════════════════════════ class TextClassification(Stub): """TextClassification — 文本分类结果""" def __init__(self): super().__init__() self._text: str = "" self._entity_type: str = TextClassifier.TYPE_UNKNOWN self._confidence_score: float = 0.0 self._entity_count: int = 0 self._icon: Any = None self._label: str = "" self._actions: List[Any] = [] self._extras: Any = None self._id: Optional[str] = None def getText(self) -> str: return self._text def getEntityCount(self) -> int: return self._entity_count def getEntity(self, index: int) -> Optional[str]: if index == 0: return self._entity_type return None def getEntityType(self) -> str: return self._entity_type def getConfidenceScore(self, entityType: str) -> float: if entityType == self._entity_type: return self._confidence_score return 0.0 def getIcon(self) -> Any: return self._icon def getLabel(self) -> str: return self._label def getActions(self) -> List[Any]: return self._actions def getExtras(self) -> Any: return self._extras def getId(self) -> Optional[str]: return self._id def toString(self) -> str: return f"TextClassification(type={self._entity_type}," \ f" confidence={self._confidence_score:.2f})" # ═══════════════════════════════════════════════════════════════ # TextLinks # ═══════════════════════════════════════════════════════════════ class TextLinks(Stub): """TextLinks — 文本链接""" def __init__(self): super().__init__() self._links: List[Any] = [] self._extras: Any = None def getLinks(self) -> List[Any]: return self._links def getEntityCount(self) -> int: return len(self._links) def getEntity(self, index: int) -> Optional[str]: if 0 <= index < len(self._links): return self._links[index] return None def getEntityType(self) -> str: return TextClassifier.TYPE_LINK def getConfidenceScore(self, entityType: str) -> float: return 0.0 def getExtras(self) -> Any: return self._extras # ═══════════════════════════════════════════════════════════════ # TextSelection # ═══════════════════════════════════════════════════════════════ class TextSelection(Stub): """TextSelection — 文本选择结果""" def __init__(self): super().__init__() self._start_index: int = 0 self._end_index: int = 0 self._entity_type: str = TextClassifier.TYPE_UNKNOWN self._text: str = "" self._entity_count: int = 0 self._confidence_score: float = 0.0 self._extras: Any = None self._id: Optional[str] = None def getSelectionStartIndex(self) -> int: return self._start_index def getSelectionEndIndex(self) -> int: return self._end_index def getEntityType(self) -> str: return self._entity_type def getText(self) -> str: return self._text def getEntityCount(self) -> int: return self._entity_count def getEntity(self, index: int) -> Optional[str]: if index == 0: return self._entity_type return None def getConfidenceScore(self, entityType: str) -> float: if entityType == self._entity_type: return self._confidence_score return 0.0 def getExtras(self) -> Any: return self._extras def getId(self) -> Optional[str]: return self._id # ═══════════════════════════════════════════════════════════════ # ConversationAction # ═══════════════════════════════════════════════════════════════ class ConversationAction(Stub): """ConversationAction — 对话操作""" TYPE_CALL = "call" TYPE_CREATE_REMINDER = "create_reminder" TYPE_OPEN_URL = "open_url" TYPE_SEND_EMAIL = "send_email" TYPE_SEND_SMS = "send_sms" TYPE_SHARE_LOCATION = "share_location" TYPE_TEXT_REPLY = "text_reply" TYPE_VIEW_CALENDAR = "view_calendar" TYPE_VIEW_MAP = "view_map" def __init__(self, text: str = "", confidenceScore: float = 0.0, action: str = "", extras: Any = None, icon: Any = None, label: str = ""): super().__init__() self._text = text self._confidence_score = confidenceScore self._action = action self._extras = extras self._icon = icon self._label = label def getText(self) -> str: return self._text def getConfidenceScore(self) -> float: return self._confidence_score def getAction(self) -> str: return self._action def getExtras(self) -> Any: return self._extras def getIcon(self) -> Any: return self._icon def getLabel(self) -> str: return self._label # ═══════════════════════════════════════════════════════════════ # TextClassificationContext # ═══════════════════════════════════════════════════════════════ class TextClassificationContext(Stub): """TextClassificationContext — 文本分类上下文""" def __init__(self, packageName: str = "", widgetType: str = "", widgetVersion: str = ""): super().__init__() self._package_name = packageName self._widget_type = widgetType self._widget_version = widgetVersion def getPackageName(self) -> str: return self._package_name def getWidgetType(self) -> str: return self._widget_type def getWidgetVersion(self) -> str: return self._widget_version # ═══════════════════════════════════════════════════════════════ # __all__ # ═══════════════════════════════════════════════════════════════ __all__ = [ "TextClassifier", "TextClassification", "TextLinks", "TextSelection", "ConversationAction", "TextClassificationContext", "EntityConfig", ]