/// EMAI 助手的一条对话消息。 class EmaiMessage { EmaiMessage({ required this.isUser, required this.text, this.isFinal = false, this.isError = false, this.fromEarphone = false, DateTime? at, }) : at = at ?? DateTime.now(); final bool isUser; String text; /// 流式内容是否已经收完(用户侧看 SpeechEnded,助手侧看 RespondingEnded) bool isFinal; /// 错误提示气泡(用红色系展示,不参与对话上下文) final bool isError; /// 这一轮是不是耳机按键唤醒时发生的。 /// 手机页面照样要展示它——用户要求「不管在哪聊的,打开界面都能看到」—— /// 只是给个耳机小标记,免得看不懂这些内容是哪来的。 final bool fromEarphone; final DateTime at; Map toJson() => { 'u': isUser, 't': text, 'f': isFinal, 'e': isError, 'h': fromEarphone, 'at': at.millisecondsSinceEpoch, }; factory EmaiMessage.fromJson(Map json) => EmaiMessage( isUser: json['u'] == true, text: (json['t'] ?? '').toString(), isFinal: json['f'] == true, isError: json['e'] == true, fromEarphone: json['h'] == true, at: DateTime.fromMillisecondsSinceEpoch( (json['at'] as num?)?.toInt() ?? 0), ); }