feat: 重构 memory 系统,支持 user memory 和 work memory 分离
This commit is contained in:
@@ -0,0 +1,951 @@
|
||||
class PersonMeta {
|
||||
final String? source;
|
||||
final double? confidence;
|
||||
final DateTime? lastUpdatedAt;
|
||||
|
||||
PersonMeta({this.source, this.confidence, this.lastUpdatedAt});
|
||||
|
||||
factory PersonMeta.fromJson(Map<String, dynamic>? json) {
|
||||
if (json == null) return PersonMeta();
|
||||
return PersonMeta(
|
||||
source: json['source'] as String?,
|
||||
confidence: (json['confidence'] as num?)?.toDouble(),
|
||||
lastUpdatedAt: json['last_updated_at'] != null
|
||||
? DateTime.parse(json['last_updated_at'] as String)
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'source': source,
|
||||
'confidence': confidence,
|
||||
'last_updated_at': lastUpdatedAt?.toIso8601String(),
|
||||
};
|
||||
}
|
||||
|
||||
class Person {
|
||||
final String name;
|
||||
final String? relationship;
|
||||
final String? role;
|
||||
final String? preferredContactChannel;
|
||||
final String? notes;
|
||||
final PersonMeta? meta;
|
||||
|
||||
Person({
|
||||
required this.name,
|
||||
this.relationship,
|
||||
this.role,
|
||||
this.preferredContactChannel,
|
||||
this.notes,
|
||||
this.meta,
|
||||
});
|
||||
|
||||
factory Person.fromJson(Map<String, dynamic> json) {
|
||||
return Person(
|
||||
name: json['name'] as String? ?? '',
|
||||
relationship: json['relationship'] as String?,
|
||||
role: json['role'] as String?,
|
||||
preferredContactChannel: json['preferred_contact_channel'] as String?,
|
||||
notes: json['notes'] as String?,
|
||||
meta: json['meta'] != null
|
||||
? PersonMeta.fromJson(json['meta'] as Map<String, dynamic>?)
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'name': name,
|
||||
'relationship': relationship,
|
||||
'role': role,
|
||||
'preferred_contact_channel': preferredContactChannel,
|
||||
'notes': notes,
|
||||
'meta': meta?.toJson(),
|
||||
};
|
||||
|
||||
Person copyWith({
|
||||
String? name,
|
||||
String? relationship,
|
||||
String? role,
|
||||
String? preferredContactChannel,
|
||||
String? notes,
|
||||
PersonMeta? meta,
|
||||
}) {
|
||||
return Person(
|
||||
name: name ?? this.name,
|
||||
relationship: relationship ?? this.relationship,
|
||||
role: role ?? this.role,
|
||||
preferredContactChannel:
|
||||
preferredContactChannel ?? this.preferredContactChannel,
|
||||
notes: notes ?? this.notes,
|
||||
meta: meta ?? this.meta,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PlaceMeta {
|
||||
final String? source;
|
||||
final double? confidence;
|
||||
final DateTime? lastUpdatedAt;
|
||||
|
||||
PlaceMeta({this.source, this.confidence, this.lastUpdatedAt});
|
||||
|
||||
factory PlaceMeta.fromJson(Map<String, dynamic>? json) {
|
||||
if (json == null) return PlaceMeta();
|
||||
return PlaceMeta(
|
||||
source: json['source'] as String?,
|
||||
confidence: (json['confidence'] as num?)?.toDouble(),
|
||||
lastUpdatedAt: json['last_updated_at'] != null
|
||||
? DateTime.parse(json['last_updated_at'] as String)
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'source': source,
|
||||
'confidence': confidence,
|
||||
'last_updated_at': lastUpdatedAt?.toIso8601String(),
|
||||
};
|
||||
}
|
||||
|
||||
class Place {
|
||||
final String name;
|
||||
final String? category;
|
||||
final String? address;
|
||||
final String? timezone;
|
||||
final int? commuteMinutes;
|
||||
final String? preference;
|
||||
final String? notes;
|
||||
final PlaceMeta? meta;
|
||||
|
||||
Place({
|
||||
required this.name,
|
||||
this.category,
|
||||
this.address,
|
||||
this.timezone,
|
||||
this.commuteMinutes,
|
||||
this.preference,
|
||||
this.notes,
|
||||
this.meta,
|
||||
});
|
||||
|
||||
factory Place.fromJson(Map<String, dynamic> json) {
|
||||
return Place(
|
||||
name: json['name'] as String? ?? '',
|
||||
category: json['category'] as String?,
|
||||
address: json['address'] as String?,
|
||||
timezone: json['timezone'] as String?,
|
||||
commuteMinutes: json['commute_minutes'] as int?,
|
||||
preference: json['preference'] as String?,
|
||||
notes: json['notes'] as String?,
|
||||
meta: json['meta'] != null
|
||||
? PlaceMeta.fromJson(json['meta'] as Map<String, dynamic>?)
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'name': name,
|
||||
'category': category,
|
||||
'address': address,
|
||||
'timezone': timezone,
|
||||
'commute_minutes': commuteMinutes,
|
||||
'preference': preference,
|
||||
'notes': notes,
|
||||
'meta': meta?.toJson(),
|
||||
};
|
||||
|
||||
Place copyWith({
|
||||
String? name,
|
||||
String? category,
|
||||
String? address,
|
||||
String? timezone,
|
||||
int? commuteMinutes,
|
||||
String? preference,
|
||||
String? notes,
|
||||
PlaceMeta? meta,
|
||||
}) {
|
||||
return Place(
|
||||
name: name ?? this.name,
|
||||
category: category ?? this.category,
|
||||
address: address ?? this.address,
|
||||
timezone: timezone ?? this.timezone,
|
||||
commuteMinutes: commuteMinutes ?? this.commuteMinutes,
|
||||
preference: preference ?? this.preference,
|
||||
notes: notes ?? this.notes,
|
||||
meta: meta ?? this.meta,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class UserPreferences {
|
||||
final String? communicationStyle;
|
||||
final List<String> languagePreference;
|
||||
final String? locationPreference;
|
||||
final String? workLifestyle;
|
||||
final List<String> notificationPreference;
|
||||
|
||||
UserPreferences({
|
||||
this.communicationStyle,
|
||||
this.languagePreference = const [],
|
||||
this.locationPreference,
|
||||
this.workLifestyle,
|
||||
this.notificationPreference = const [],
|
||||
});
|
||||
|
||||
factory UserPreferences.fromJson(Map<String, dynamic>? json) {
|
||||
if (json == null) return UserPreferences();
|
||||
return UserPreferences(
|
||||
communicationStyle: json['communication_style'] as String?,
|
||||
languagePreference:
|
||||
(json['language_preference'] as List<dynamic>?)?.cast<String>() ?? [],
|
||||
locationPreference: json['location_preference'] as String?,
|
||||
workLifestyle: json['work_lifestyle'] as String?,
|
||||
notificationPreference:
|
||||
(json['notification_preference'] as List<dynamic>?)?.cast<String>() ??
|
||||
[],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'communication_style': communicationStyle,
|
||||
'language_preference': languagePreference,
|
||||
'location_preference': locationPreference,
|
||||
'work_lifestyle': workLifestyle,
|
||||
'notification_preference': notificationPreference,
|
||||
};
|
||||
|
||||
UserPreferences copyWith({
|
||||
String? communicationStyle,
|
||||
List<String>? languagePreference,
|
||||
String? locationPreference,
|
||||
String? workLifestyle,
|
||||
List<String>? notificationPreference,
|
||||
}) {
|
||||
return UserPreferences(
|
||||
communicationStyle: communicationStyle ?? this.communicationStyle,
|
||||
languagePreference: languagePreference ?? this.languagePreference,
|
||||
locationPreference: locationPreference ?? this.locationPreference,
|
||||
workLifestyle: workLifestyle ?? this.workLifestyle,
|
||||
notificationPreference:
|
||||
notificationPreference ?? this.notificationPreference,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class TimeWindow {
|
||||
final List<String> weekdays;
|
||||
final String? start;
|
||||
final String? end;
|
||||
|
||||
TimeWindow({this.weekdays = const [], this.start, this.end});
|
||||
|
||||
factory TimeWindow.fromJson(Map<String, dynamic> json) {
|
||||
return TimeWindow(
|
||||
weekdays: (json['weekdays'] as List<dynamic>?)?.cast<String>() ?? [],
|
||||
start: json['start'] as String?,
|
||||
end: json['end'] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'weekdays': weekdays,
|
||||
'start': start,
|
||||
'end': end,
|
||||
};
|
||||
}
|
||||
|
||||
class SchedulingPreferences {
|
||||
final List<TimeWindow> productiveWindows;
|
||||
final List<TimeWindow> preferredMeetingWindows;
|
||||
final List<TimeWindow> noMeetingWindows;
|
||||
final List<TimeWindow> deepWorkWindows;
|
||||
final List<int> preferredMeetingDurationMinutes;
|
||||
final int? meetingBufferMinutes;
|
||||
final int? maxMeetingsPerDay;
|
||||
final String? notes;
|
||||
|
||||
SchedulingPreferences({
|
||||
this.productiveWindows = const [],
|
||||
this.preferredMeetingWindows = const [],
|
||||
this.noMeetingWindows = const [],
|
||||
this.deepWorkWindows = const [],
|
||||
this.preferredMeetingDurationMinutes = const [30, 60],
|
||||
this.meetingBufferMinutes,
|
||||
this.maxMeetingsPerDay,
|
||||
this.notes,
|
||||
});
|
||||
|
||||
factory SchedulingPreferences.fromJson(Map<String, dynamic>? json) {
|
||||
if (json == null) return SchedulingPreferences();
|
||||
return SchedulingPreferences(
|
||||
productiveWindows:
|
||||
(json['productive_windows'] as List<dynamic>?)
|
||||
?.map((e) => TimeWindow.fromJson(e as Map<String, dynamic>))
|
||||
.toList() ??
|
||||
[],
|
||||
preferredMeetingWindows:
|
||||
(json['preferred_meeting_windows'] as List<dynamic>?)
|
||||
?.map((e) => TimeWindow.fromJson(e as Map<String, dynamic>))
|
||||
.toList() ??
|
||||
[],
|
||||
noMeetingWindows:
|
||||
(json['no_meeting_windows'] as List<dynamic>?)
|
||||
?.map((e) => TimeWindow.fromJson(e as Map<String, dynamic>))
|
||||
.toList() ??
|
||||
[],
|
||||
deepWorkWindows:
|
||||
(json['deep_work_windows'] as List<dynamic>?)
|
||||
?.map((e) => TimeWindow.fromJson(e as Map<String, dynamic>))
|
||||
.toList() ??
|
||||
[],
|
||||
preferredMeetingDurationMinutes:
|
||||
(json['preferred_meeting_duration_minutes'] as List<dynamic>?)
|
||||
?.cast<int>() ??
|
||||
[30, 60],
|
||||
meetingBufferMinutes: json['meeting_buffer_minutes'] as int?,
|
||||
maxMeetingsPerDay: json['max_meetings_per_day'] as int?,
|
||||
notes: json['notes'] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'productive_windows': productiveWindows.map((e) => e.toJson()).toList(),
|
||||
'preferred_meeting_windows': preferredMeetingWindows
|
||||
.map((e) => e.toJson())
|
||||
.toList(),
|
||||
'no_meeting_windows': noMeetingWindows.map((e) => e.toJson()).toList(),
|
||||
'deep_work_windows': deepWorkWindows.map((e) => e.toJson()).toList(),
|
||||
'preferred_meeting_duration_minutes': preferredMeetingDurationMinutes,
|
||||
'meeting_buffer_minutes': meetingBufferMinutes,
|
||||
'max_meetings_per_day': maxMeetingsPerDay,
|
||||
'notes': notes,
|
||||
};
|
||||
|
||||
SchedulingPreferences copyWith({
|
||||
List<TimeWindow>? productiveWindows,
|
||||
List<TimeWindow>? preferredMeetingWindows,
|
||||
List<TimeWindow>? noMeetingWindows,
|
||||
List<TimeWindow>? deepWorkWindows,
|
||||
List<int>? preferredMeetingDurationMinutes,
|
||||
int? meetingBufferMinutes,
|
||||
int? maxMeetingsPerDay,
|
||||
String? notes,
|
||||
}) {
|
||||
return SchedulingPreferences(
|
||||
productiveWindows: productiveWindows ?? this.productiveWindows,
|
||||
preferredMeetingWindows:
|
||||
preferredMeetingWindows ?? this.preferredMeetingWindows,
|
||||
noMeetingWindows: noMeetingWindows ?? this.noMeetingWindows,
|
||||
deepWorkWindows: deepWorkWindows ?? this.deepWorkWindows,
|
||||
preferredMeetingDurationMinutes:
|
||||
preferredMeetingDurationMinutes ??
|
||||
this.preferredMeetingDurationMinutes,
|
||||
meetingBufferMinutes: meetingBufferMinutes ?? this.meetingBufferMinutes,
|
||||
maxMeetingsPerDay: maxMeetingsPerDay ?? this.maxMeetingsPerDay,
|
||||
notes: notes ?? this.notes,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class RecurringRoutineMeta {
|
||||
final String? source;
|
||||
final double? confidence;
|
||||
final DateTime? lastUpdatedAt;
|
||||
|
||||
RecurringRoutineMeta({this.source, this.confidence, this.lastUpdatedAt});
|
||||
|
||||
factory RecurringRoutineMeta.fromJson(Map<String, dynamic>? json) {
|
||||
if (json == null) return RecurringRoutineMeta();
|
||||
return RecurringRoutineMeta(
|
||||
source: json['source'] as String?,
|
||||
confidence: (json['confidence'] as num?)?.toDouble(),
|
||||
lastUpdatedAt: json['last_updated_at'] != null
|
||||
? DateTime.parse(json['last_updated_at'] as String)
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'source': source,
|
||||
'confidence': confidence,
|
||||
'last_updated_at': lastUpdatedAt?.toIso8601String(),
|
||||
};
|
||||
}
|
||||
|
||||
class RecurringRoutine {
|
||||
final String name;
|
||||
final String? description;
|
||||
final String? cadence;
|
||||
final List<TimeWindow> timeWindows;
|
||||
final String? importance;
|
||||
final RecurringRoutineMeta? meta;
|
||||
|
||||
RecurringRoutine({
|
||||
required this.name,
|
||||
this.description,
|
||||
this.cadence,
|
||||
this.timeWindows = const [],
|
||||
this.importance,
|
||||
this.meta,
|
||||
});
|
||||
|
||||
factory RecurringRoutine.fromJson(Map<String, dynamic> json) {
|
||||
return RecurringRoutine(
|
||||
name: json['name'] as String? ?? '',
|
||||
description: json['description'] as String?,
|
||||
cadence: json['cadence'] as String?,
|
||||
timeWindows:
|
||||
(json['time_windows'] as List<dynamic>?)
|
||||
?.map((e) => TimeWindow.fromJson(e as Map<String, dynamic>))
|
||||
.toList() ??
|
||||
[],
|
||||
importance: json['importance'] as String?,
|
||||
meta: json['meta'] != null
|
||||
? RecurringRoutineMeta.fromJson(json['meta'] as Map<String, dynamic>?)
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'name': name,
|
||||
'description': description,
|
||||
'cadence': cadence,
|
||||
'time_windows': timeWindows.map((e) => e.toJson()).toList(),
|
||||
'importance': importance,
|
||||
'meta': meta?.toJson(),
|
||||
};
|
||||
|
||||
RecurringRoutine copyWith({
|
||||
String? name,
|
||||
String? description,
|
||||
String? cadence,
|
||||
List<TimeWindow>? timeWindows,
|
||||
String? importance,
|
||||
RecurringRoutineMeta? meta,
|
||||
}) {
|
||||
return RecurringRoutine(
|
||||
name: name ?? this.name,
|
||||
description: description ?? this.description,
|
||||
cadence: cadence ?? this.cadence,
|
||||
timeWindows: timeWindows ?? this.timeWindows,
|
||||
importance: importance ?? this.importance,
|
||||
meta: meta ?? this.meta,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class UserMemoryContent {
|
||||
final String? occupation;
|
||||
final String? timezone;
|
||||
final String? primaryLanguage;
|
||||
final List<Person> people;
|
||||
final List<Place> places;
|
||||
final UserPreferences preferences;
|
||||
final SchedulingPreferences schedulingPreferences;
|
||||
final List<String> interests;
|
||||
final List<String> avoidTopics;
|
||||
final List<String> customRules;
|
||||
final List<RecurringRoutine> recurringRoutines;
|
||||
|
||||
UserMemoryContent({
|
||||
this.occupation,
|
||||
this.timezone,
|
||||
this.primaryLanguage,
|
||||
this.people = const [],
|
||||
this.places = const [],
|
||||
UserPreferences? preferences,
|
||||
SchedulingPreferences? schedulingPreferences,
|
||||
this.interests = const [],
|
||||
this.avoidTopics = const [],
|
||||
this.customRules = const [],
|
||||
this.recurringRoutines = const [],
|
||||
}) : preferences = preferences ?? UserPreferences(),
|
||||
schedulingPreferences = schedulingPreferences ?? SchedulingPreferences();
|
||||
|
||||
factory UserMemoryContent.fromJson(Map<String, dynamic>? json) {
|
||||
if (json == null) return UserMemoryContent();
|
||||
return UserMemoryContent(
|
||||
occupation: json['occupation'] as String?,
|
||||
timezone: json['timezone'] as String?,
|
||||
primaryLanguage: json['primary_language'] as String?,
|
||||
people:
|
||||
(json['people'] as List<dynamic>?)
|
||||
?.map((e) => Person.fromJson(e as Map<String, dynamic>))
|
||||
.toList() ??
|
||||
[],
|
||||
places:
|
||||
(json['places'] as List<dynamic>?)
|
||||
?.map((e) => Place.fromJson(e as Map<String, dynamic>))
|
||||
.toList() ??
|
||||
[],
|
||||
preferences: UserPreferences.fromJson(
|
||||
json['preferences'] as Map<String, dynamic>?,
|
||||
),
|
||||
schedulingPreferences: SchedulingPreferences.fromJson(
|
||||
json['scheduling_preferences'] as Map<String, dynamic>?,
|
||||
),
|
||||
interests: (json['interests'] as List<dynamic>?)?.cast<String>() ?? [],
|
||||
avoidTopics:
|
||||
(json['avoid_topics'] as List<dynamic>?)?.cast<String>() ?? [],
|
||||
customRules:
|
||||
(json['custom_rules'] as List<dynamic>?)?.cast<String>() ?? [],
|
||||
recurringRoutines:
|
||||
(json['recurring_routines'] as List<dynamic>?)
|
||||
?.map((e) => RecurringRoutine.fromJson(e as Map<String, dynamic>))
|
||||
.toList() ??
|
||||
[],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'occupation': occupation,
|
||||
'timezone': timezone,
|
||||
'primary_language': primaryLanguage,
|
||||
'people': people.map((e) => e.toJson()).toList(),
|
||||
'places': places.map((e) => e.toJson()).toList(),
|
||||
'preferences': preferences.toJson(),
|
||||
'scheduling_preferences': schedulingPreferences.toJson(),
|
||||
'interests': interests,
|
||||
'avoid_topics': avoidTopics,
|
||||
'custom_rules': customRules,
|
||||
'recurring_routines': recurringRoutines.map((e) => e.toJson()).toList(),
|
||||
};
|
||||
|
||||
UserMemoryContent copyWith({
|
||||
String? occupation,
|
||||
String? timezone,
|
||||
String? primaryLanguage,
|
||||
List<Person>? people,
|
||||
List<Place>? places,
|
||||
UserPreferences? preferences,
|
||||
SchedulingPreferences? schedulingPreferences,
|
||||
List<String>? interests,
|
||||
List<String>? avoidTopics,
|
||||
List<String>? customRules,
|
||||
List<RecurringRoutine>? recurringRoutines,
|
||||
}) {
|
||||
return UserMemoryContent(
|
||||
occupation: occupation ?? this.occupation,
|
||||
timezone: timezone ?? this.timezone,
|
||||
primaryLanguage: primaryLanguage ?? this.primaryLanguage,
|
||||
people: people ?? this.people,
|
||||
places: places ?? this.places,
|
||||
preferences: preferences ?? this.preferences,
|
||||
schedulingPreferences:
|
||||
schedulingPreferences ?? this.schedulingPreferences,
|
||||
interests: interests ?? this.interests,
|
||||
avoidTopics: avoidTopics ?? this.avoidTopics,
|
||||
customRules: customRules ?? this.customRules,
|
||||
recurringRoutines: recurringRoutines ?? this.recurringRoutines,
|
||||
);
|
||||
}
|
||||
|
||||
String get summary {
|
||||
final parts = <String>[];
|
||||
if (occupation != null && occupation!.isNotEmpty) {
|
||||
parts.add(occupation!);
|
||||
}
|
||||
if (people.isNotEmpty) {
|
||||
parts.add('${people.length} 位联系人');
|
||||
}
|
||||
if (places.isNotEmpty) {
|
||||
parts.add('${places.length} 个地点');
|
||||
}
|
||||
if (interests.isNotEmpty) {
|
||||
parts.add('${interests.length} 个兴趣');
|
||||
}
|
||||
return parts.isEmpty ? '暂无信息' : parts.join(' · ');
|
||||
}
|
||||
}
|
||||
|
||||
class KeyMilestone {
|
||||
final String name;
|
||||
final DateTime? dueDate;
|
||||
final String? status;
|
||||
final String? notes;
|
||||
|
||||
KeyMilestone({required this.name, this.dueDate, this.status, this.notes});
|
||||
|
||||
factory KeyMilestone.fromJson(Map<String, dynamic> json) {
|
||||
return KeyMilestone(
|
||||
name: json['name'] as String? ?? '',
|
||||
dueDate: json['due_date'] != null
|
||||
? DateTime.parse(json['due_date'] as String)
|
||||
: null,
|
||||
status: json['status'] as String?,
|
||||
notes: json['notes'] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'name': name,
|
||||
'due_date': dueDate?.toIso8601String().split('T').first,
|
||||
'status': status,
|
||||
'notes': notes,
|
||||
};
|
||||
}
|
||||
|
||||
class CurrentProject {
|
||||
final String name;
|
||||
final String? description;
|
||||
final String? status;
|
||||
final String? priority;
|
||||
final DateTime? deadline;
|
||||
final List<String> collaborators;
|
||||
final List<KeyMilestone> keyMilestones;
|
||||
final String? notes;
|
||||
|
||||
CurrentProject({
|
||||
required this.name,
|
||||
this.description,
|
||||
this.status,
|
||||
this.priority,
|
||||
this.deadline,
|
||||
this.collaborators = const [],
|
||||
this.keyMilestones = const [],
|
||||
this.notes,
|
||||
});
|
||||
|
||||
factory CurrentProject.fromJson(Map<String, dynamic> json) {
|
||||
return CurrentProject(
|
||||
name: json['name'] as String? ?? '',
|
||||
description: json['description'] as String?,
|
||||
status: json['status'] as String?,
|
||||
priority: json['priority'] as String?,
|
||||
deadline: json['deadline'] != null
|
||||
? DateTime.parse(json['deadline'] as String)
|
||||
: null,
|
||||
collaborators:
|
||||
(json['collaborators'] as List<dynamic>?)?.cast<String>() ?? [],
|
||||
keyMilestones:
|
||||
(json['key_milestones'] as List<dynamic>?)
|
||||
?.map((e) => KeyMilestone.fromJson(e as Map<String, dynamic>))
|
||||
.toList() ??
|
||||
[],
|
||||
notes: json['notes'] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'name': name,
|
||||
'description': description,
|
||||
'status': status,
|
||||
'priority': priority,
|
||||
'deadline': deadline?.toIso8601String().split('T').first,
|
||||
'collaborators': collaborators,
|
||||
'key_milestones': keyMilestones.map((e) => e.toJson()).toList(),
|
||||
'notes': notes,
|
||||
};
|
||||
|
||||
CurrentProject copyWith({
|
||||
String? name,
|
||||
String? description,
|
||||
String? status,
|
||||
String? priority,
|
||||
DateTime? deadline,
|
||||
List<String>? collaborators,
|
||||
List<KeyMilestone>? keyMilestones,
|
||||
String? notes,
|
||||
}) {
|
||||
return CurrentProject(
|
||||
name: name ?? this.name,
|
||||
description: description ?? this.description,
|
||||
status: status ?? this.status,
|
||||
priority: priority ?? this.priority,
|
||||
deadline: deadline ?? this.deadline,
|
||||
collaborators: collaborators ?? this.collaborators,
|
||||
keyMilestones: keyMilestones ?? this.keyMilestones,
|
||||
notes: notes ?? this.notes,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class WorkHabits {
|
||||
final List<TimeWindow> availableHours;
|
||||
final List<TimeWindow> deepWorkBlocks;
|
||||
final List<TimeWindow> preferredMeetingWindows;
|
||||
final List<TimeWindow> noMeetingWindows;
|
||||
final List<int> preferredMeetingDurationMinutes;
|
||||
final String? notificationChannel;
|
||||
final String? notes;
|
||||
|
||||
WorkHabits({
|
||||
this.availableHours = const [],
|
||||
this.deepWorkBlocks = const [],
|
||||
this.preferredMeetingWindows = const [],
|
||||
this.noMeetingWindows = const [],
|
||||
this.preferredMeetingDurationMinutes = const [30, 60],
|
||||
this.notificationChannel,
|
||||
this.notes,
|
||||
});
|
||||
|
||||
factory WorkHabits.fromJson(Map<String, dynamic>? json) {
|
||||
if (json == null) return WorkHabits();
|
||||
return WorkHabits(
|
||||
availableHours:
|
||||
(json['available_hours'] as List<dynamic>?)
|
||||
?.map((e) => TimeWindow.fromJson(e as Map<String, dynamic>))
|
||||
.toList() ??
|
||||
[],
|
||||
deepWorkBlocks:
|
||||
(json['deep_work_blocks'] as List<dynamic>?)
|
||||
?.map((e) => TimeWindow.fromJson(e as Map<String, dynamic>))
|
||||
.toList() ??
|
||||
[],
|
||||
preferredMeetingWindows:
|
||||
(json['preferred_meeting_windows'] as List<dynamic>?)
|
||||
?.map((e) => TimeWindow.fromJson(e as Map<String, dynamic>))
|
||||
.toList() ??
|
||||
[],
|
||||
noMeetingWindows:
|
||||
(json['no_meeting_windows'] as List<dynamic>?)
|
||||
?.map((e) => TimeWindow.fromJson(e as Map<String, dynamic>))
|
||||
.toList() ??
|
||||
[],
|
||||
preferredMeetingDurationMinutes:
|
||||
(json['preferred_meeting_duration_minutes'] as List<dynamic>?)
|
||||
?.cast<int>() ??
|
||||
[30, 60],
|
||||
notificationChannel: json['notification_channel'] as String?,
|
||||
notes: json['notes'] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'available_hours': availableHours.map((e) => e.toJson()).toList(),
|
||||
'deep_work_blocks': deepWorkBlocks.map((e) => e.toJson()).toList(),
|
||||
'preferred_meeting_windows': preferredMeetingWindows
|
||||
.map((e) => e.toJson())
|
||||
.toList(),
|
||||
'no_meeting_windows': noMeetingWindows.map((e) => e.toJson()).toList(),
|
||||
'preferred_meeting_duration_minutes': preferredMeetingDurationMinutes,
|
||||
'notification_channel': notificationChannel,
|
||||
'notes': notes,
|
||||
};
|
||||
|
||||
WorkHabits copyWith({
|
||||
List<TimeWindow>? availableHours,
|
||||
List<TimeWindow>? deepWorkBlocks,
|
||||
List<TimeWindow>? preferredMeetingWindows,
|
||||
List<TimeWindow>? noMeetingWindows,
|
||||
List<int>? preferredMeetingDurationMinutes,
|
||||
String? notificationChannel,
|
||||
String? notes,
|
||||
}) {
|
||||
return WorkHabits(
|
||||
availableHours: availableHours ?? this.availableHours,
|
||||
deepWorkBlocks: deepWorkBlocks ?? this.deepWorkBlocks,
|
||||
preferredMeetingWindows:
|
||||
preferredMeetingWindows ?? this.preferredMeetingWindows,
|
||||
noMeetingWindows: noMeetingWindows ?? this.noMeetingWindows,
|
||||
preferredMeetingDurationMinutes:
|
||||
preferredMeetingDurationMinutes ??
|
||||
this.preferredMeetingDurationMinutes,
|
||||
notificationChannel: notificationChannel ?? this.notificationChannel,
|
||||
notes: notes ?? this.notes,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class TeamMemberMeta {
|
||||
final String? source;
|
||||
final double? confidence;
|
||||
final DateTime? lastUpdatedAt;
|
||||
|
||||
TeamMemberMeta({this.source, this.confidence, this.lastUpdatedAt});
|
||||
|
||||
factory TeamMemberMeta.fromJson(Map<String, dynamic>? json) {
|
||||
if (json == null) return TeamMemberMeta();
|
||||
return TeamMemberMeta(
|
||||
source: json['source'] as String?,
|
||||
confidence: (json['confidence'] as num?)?.toDouble(),
|
||||
lastUpdatedAt: json['last_updated_at'] != null
|
||||
? DateTime.parse(json['last_updated_at'] as String)
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'source': source,
|
||||
'confidence': confidence,
|
||||
'last_updated_at': lastUpdatedAt?.toIso8601String(),
|
||||
};
|
||||
}
|
||||
|
||||
class TeamMember {
|
||||
final String name;
|
||||
final String? role;
|
||||
final String? relationship;
|
||||
final String? preferredContactChannel;
|
||||
final String? notes;
|
||||
final TeamMemberMeta? meta;
|
||||
|
||||
TeamMember({
|
||||
required this.name,
|
||||
this.role,
|
||||
this.relationship,
|
||||
this.preferredContactChannel,
|
||||
this.notes,
|
||||
this.meta,
|
||||
});
|
||||
|
||||
factory TeamMember.fromJson(Map<String, dynamic> json) {
|
||||
return TeamMember(
|
||||
name: json['name'] as String? ?? '',
|
||||
role: json['role'] as String?,
|
||||
relationship: json['relationship'] as String?,
|
||||
preferredContactChannel: json['preferred_contact_channel'] as String?,
|
||||
notes: json['notes'] as String?,
|
||||
meta: json['meta'] != null
|
||||
? TeamMemberMeta.fromJson(json['meta'] as Map<String, dynamic>?)
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'name': name,
|
||||
'role': role,
|
||||
'relationship': relationship,
|
||||
'preferred_contact_channel': preferredContactChannel,
|
||||
'notes': notes,
|
||||
'meta': meta?.toJson(),
|
||||
};
|
||||
|
||||
TeamMember copyWith({
|
||||
String? name,
|
||||
String? role,
|
||||
String? relationship,
|
||||
String? preferredContactChannel,
|
||||
String? notes,
|
||||
TeamMemberMeta? meta,
|
||||
}) {
|
||||
return TeamMember(
|
||||
name: name ?? this.name,
|
||||
role: role ?? this.role,
|
||||
relationship: relationship ?? this.relationship,
|
||||
preferredContactChannel:
|
||||
preferredContactChannel ?? this.preferredContactChannel,
|
||||
notes: notes ?? this.notes,
|
||||
meta: meta ?? this.meta,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class WorkProfileContent {
|
||||
final String? occupation;
|
||||
final List<String> expertise;
|
||||
final List<String> preferredTools;
|
||||
final List<CurrentProject> currentProjects;
|
||||
final WorkHabits workHabits;
|
||||
final List<TeamMember> teamMembers;
|
||||
final String? teamContext;
|
||||
final List<String> workRules;
|
||||
|
||||
WorkProfileContent({
|
||||
this.occupation,
|
||||
this.expertise = const [],
|
||||
this.preferredTools = const [],
|
||||
this.currentProjects = const [],
|
||||
WorkHabits? workHabits,
|
||||
this.teamMembers = const [],
|
||||
this.teamContext,
|
||||
this.workRules = const [],
|
||||
}) : workHabits = workHabits ?? WorkHabits();
|
||||
|
||||
factory WorkProfileContent.fromJson(Map<String, dynamic>? json) {
|
||||
if (json == null) return WorkProfileContent();
|
||||
return WorkProfileContent(
|
||||
occupation: json['occupation'] as String?,
|
||||
expertise: (json['expertise'] as List<dynamic>?)?.cast<String>() ?? [],
|
||||
preferredTools:
|
||||
(json['preferred_tools'] as List<dynamic>?)?.cast<String>() ?? [],
|
||||
currentProjects:
|
||||
(json['current_projects'] as List<dynamic>?)
|
||||
?.map((e) => CurrentProject.fromJson(e as Map<String, dynamic>))
|
||||
.toList() ??
|
||||
[],
|
||||
workHabits: WorkHabits.fromJson(
|
||||
json['work_habits'] as Map<String, dynamic>?,
|
||||
),
|
||||
teamMembers:
|
||||
(json['team_members'] as List<dynamic>?)
|
||||
?.map((e) => TeamMember.fromJson(e as Map<String, dynamic>))
|
||||
.toList() ??
|
||||
[],
|
||||
teamContext: json['team_context'] as String?,
|
||||
workRules: (json['work_rules'] as List<dynamic>?)?.cast<String>() ?? [],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'occupation': occupation,
|
||||
'expertise': expertise,
|
||||
'preferred_tools': preferredTools,
|
||||
'current_projects': currentProjects.map((e) => e.toJson()).toList(),
|
||||
'work_habits': workHabits.toJson(),
|
||||
'team_members': teamMembers.map((e) => e.toJson()).toList(),
|
||||
'team_context': teamContext,
|
||||
'work_rules': workRules,
|
||||
};
|
||||
|
||||
WorkProfileContent copyWith({
|
||||
String? occupation,
|
||||
List<String>? expertise,
|
||||
List<String>? preferredTools,
|
||||
List<CurrentProject>? currentProjects,
|
||||
WorkHabits? workHabits,
|
||||
List<TeamMember>? teamMembers,
|
||||
String? teamContext,
|
||||
List<String>? workRules,
|
||||
}) {
|
||||
return WorkProfileContent(
|
||||
occupation: occupation ?? this.occupation,
|
||||
expertise: expertise ?? this.expertise,
|
||||
preferredTools: preferredTools ?? this.preferredTools,
|
||||
currentProjects: currentProjects ?? this.currentProjects,
|
||||
workHabits: workHabits ?? this.workHabits,
|
||||
teamMembers: teamMembers ?? this.teamMembers,
|
||||
teamContext: teamContext ?? this.teamContext,
|
||||
workRules: workRules ?? this.workRules,
|
||||
);
|
||||
}
|
||||
|
||||
String get summary {
|
||||
final parts = <String>[];
|
||||
if (occupation != null && occupation!.isNotEmpty) {
|
||||
parts.add(occupation!);
|
||||
}
|
||||
if (expertise.isNotEmpty) {
|
||||
parts.add('${expertise.length} 项专长');
|
||||
}
|
||||
if (currentProjects.isNotEmpty) {
|
||||
parts.add('${currentProjects.length} 个项目');
|
||||
}
|
||||
if (teamMembers.isNotEmpty) {
|
||||
parts.add('${teamMembers.length} 位团队成员');
|
||||
}
|
||||
return parts.isEmpty ? '暂无信息' : parts.join(' · ');
|
||||
}
|
||||
}
|
||||
|
||||
class MemoryListResponse {
|
||||
final UserMemoryContent? userMemory;
|
||||
final WorkProfileContent? workMemory;
|
||||
|
||||
MemoryListResponse({this.userMemory, this.workMemory});
|
||||
|
||||
factory MemoryListResponse.fromJson(Map<String, dynamic> json) {
|
||||
return MemoryListResponse(
|
||||
userMemory: json['user_memory'] != null
|
||||
? UserMemoryContent.fromJson(
|
||||
json['user_memory'] as Map<String, dynamic>?,
|
||||
)
|
||||
: null,
|
||||
workMemory: json['work_memory'] != null
|
||||
? WorkProfileContent.fromJson(
|
||||
json['work_memory'] as Map<String, dynamic>?,
|
||||
)
|
||||
: null,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user