AI助手优化-头像和对话功能

This commit is contained in:
2026-09-29 09:45:02 +08:00
parent 80222099ff
commit f4ad2f8612
15 changed files with 990 additions and 37 deletions
+17
View File
@@ -6,10 +6,24 @@ class ChatSessionItem {
final String title;
final String updateTime;
/// 本会话绑定的人设 id。null = 内置默认人设。
///
/// 会话的人设在**新建时确定、之后不可改** —— 一次对话从头到尾是同一个人。
final int? personaId;
/// 人设显示名。人设被删了会回落成「默认人设」,历史会话不会因此打不开
final String personaName;
/// 人设头像相对路径。null = 用默认头像
final String? personaAvatar;
const ChatSessionItem({
required this.id,
required this.title,
required this.updateTime,
this.personaId,
this.personaName = '默认人设',
this.personaAvatar,
});
factory ChatSessionItem.fromJson(Map<String, dynamic> json) {
@@ -17,6 +31,9 @@ class ChatSessionItem {
id: asInt(json['id']),
title: asNonEmpty(json['title'], '新对话'),
updateTime: formatDateTime(json['updateTime']),
personaId: asNullableInt(json['personaId']),
personaName: asNonEmpty(json['personaName'], '默认人设'),
personaAvatar: asNonEmpty(json['personaAvatar'], ''),
);
}
}
+6
View File
@@ -17,6 +17,7 @@ class AiPersonaItem {
required this.isDefault,
required this.editable,
required this.defaultPrompt,
this.avatar,
});
/// null = 虚拟的「默认」项(内容是服务端代码内置的)
@@ -42,6 +43,10 @@ class AiPersonaItem {
/// 以后改了默认人设,App 不用跟着改版本。
final String? defaultPrompt;
/// 头像**相对路径**(如 `persona/2026/09/29/xxx.jpg`)。
/// 用 [Avatar] 组件显示,它会自己拼 host。null = 用默认头像。
final String? avatar;
/// 用于「显示已选中的是哪一项」的稳定标识。
///
/// 默认项没有 id,用 -1 代替 —— 不能直接用 null 当 map key 去比较。
@@ -58,6 +63,7 @@ class AiPersonaItem {
// 用户项上这个字段是 null —— 不能直接用 asNonEmpty(它要 fallback 参数,
// 而我们恰恰需要保留「null = 没有」这个语义,供「恢复默认」按钮判断)
defaultPrompt: _nullableNonEmpty(json['defaultPrompt']),
avatar: _nullableNonEmpty(json['avatar']),
);
}
+26 -3
View File
@@ -3,12 +3,21 @@ class AuthResponse {
final String? username;
final String? nickname;
const AuthResponse({required this.token, this.username, this.nickname});
/// 头像相对路径。null = 用默认头像
final String? avatar;
const AuthResponse({
required this.token,
this.username,
this.nickname,
this.avatar,
});
factory AuthResponse.fromJson(Map<String, dynamic> json) => AuthResponse(
token: json['token']?.toString() ?? '',
username: json['username']?.toString(),
nickname: json['nickname']?.toString(),
avatar: json['avatar']?.toString(),
);
}
@@ -17,13 +26,27 @@ class UserInfo {
final String username;
final String nickname;
const UserInfo({this.id, required this.username, required this.nickname});
/// 头像相对路径。null = 用默认头像
final String? avatar;
Map<String, dynamic> toJson() => {'id': id, 'username': username, 'nickname': nickname};
const UserInfo({
this.id,
required this.username,
required this.nickname,
this.avatar,
});
Map<String, dynamic> toJson() => {
'id': id,
'username': username,
'nickname': nickname,
'avatar': avatar,
};
factory UserInfo.fromJson(Map<String, dynamic> json) => UserInfo(
id: json['id']?.toString(),
username: json['username']?.toString() ?? '',
nickname: json['nickname']?.toString() ?? '',
avatar: json['avatar']?.toString(),
);
}