AI 接入 V0.1
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
import 'json_util.dart';
|
||||
|
||||
/// 会话列表项(不含消息)
|
||||
class ChatSessionItem {
|
||||
final int id;
|
||||
final String title;
|
||||
final String updateTime;
|
||||
|
||||
const ChatSessionItem({
|
||||
required this.id,
|
||||
required this.title,
|
||||
required this.updateTime,
|
||||
});
|
||||
|
||||
factory ChatSessionItem.fromJson(Map<String, dynamic> json) {
|
||||
return ChatSessionItem(
|
||||
id: asInt(json['id']),
|
||||
title: asNonEmpty(json['title'], '新对话'),
|
||||
updateTime: formatDateTime(json['updateTime']),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 会话里的一条消息。工具调用的中间过程后端不入库,所以只有 user / assistant
|
||||
class ChatMessageItem {
|
||||
final int id;
|
||||
final String role;
|
||||
final String content;
|
||||
|
||||
const ChatMessageItem({
|
||||
required this.id,
|
||||
required this.role,
|
||||
required this.content,
|
||||
});
|
||||
|
||||
bool get isUser => role == 'user';
|
||||
|
||||
factory ChatMessageItem.fromJson(Map<String, dynamic> json) {
|
||||
return ChatMessageItem(
|
||||
id: asInt(json['id']),
|
||||
role: asString(json['role'], fallback: 'assistant'),
|
||||
content: asString(json['content']),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 页面上的一个气泡。
|
||||
///
|
||||
/// 和 [ChatMessageItem] 的区别:这个没有 id、带 streaming 标记,
|
||||
/// 因为正在生成的那条回答还没落库。
|
||||
class ChatBubble {
|
||||
final String role;
|
||||
final String content;
|
||||
|
||||
/// 正在生成中(末尾会显示光标 / 工具提示)
|
||||
final bool streaming;
|
||||
|
||||
const ChatBubble({
|
||||
required this.role,
|
||||
required this.content,
|
||||
this.streaming = false,
|
||||
});
|
||||
|
||||
const ChatBubble.user(String content) : this(role: 'user', content: content);
|
||||
|
||||
const ChatBubble.assistant(String content, {bool streaming = false})
|
||||
: this(role: 'assistant', content: content, streaming: streaming);
|
||||
|
||||
bool get isUser => role == 'user';
|
||||
|
||||
ChatBubble copyWith({String? content, bool? streaming}) {
|
||||
return ChatBubble(
|
||||
role: role,
|
||||
content: content ?? this.content,
|
||||
streaming: streaming ?? this.streaming,
|
||||
);
|
||||
}
|
||||
|
||||
factory ChatBubble.fromItem(ChatMessageItem item) =>
|
||||
ChatBubble(role: item.role, content: item.content);
|
||||
}
|
||||
|
||||
/// SSE 事件类型
|
||||
enum AiEventType { delta, tool, done, error }
|
||||
|
||||
/// 一次 SSE 事件。后端只会发这四种,见 AiChatService。
|
||||
class AiEvent {
|
||||
final AiEventType type;
|
||||
|
||||
/// delta:本次新增的文本
|
||||
final String? content;
|
||||
|
||||
/// tool:正在调用的工具名
|
||||
final String? toolName;
|
||||
|
||||
/// done:会话 ID(新会话时后端才刚创建,App 要靠它接着聊)
|
||||
final int? sessionId;
|
||||
|
||||
/// error:错误提示
|
||||
final String? message;
|
||||
|
||||
const AiEvent._(this.type, {this.content, this.toolName, this.sessionId, this.message});
|
||||
|
||||
const AiEvent.delta(String content) : this._(AiEventType.delta, content: content);
|
||||
|
||||
const AiEvent.tool(String name) : this._(AiEventType.tool, toolName: name);
|
||||
|
||||
const AiEvent.done(int? sessionId) : this._(AiEventType.done, sessionId: sessionId);
|
||||
|
||||
const AiEvent.error(String message) : this._(AiEventType.error, message: message);
|
||||
}
|
||||
Reference in New Issue
Block a user