From 613bf4fb421141521d2db78ce643508cee2972ea Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Sun, 26 Oct 2025 22:04:34 +0800 Subject: [PATCH] :lipstick: Optimize UX in AI thought --- lib/models/thought.dart | 4 ++ lib/models/thought.freezed.dart | 92 +++++++++++++++++++-------------- lib/models/thought.g.dart | 8 +++ lib/screens/thought/think.dart | 52 ++++++++++++++++++- 4 files changed, 115 insertions(+), 41 deletions(-) diff --git a/lib/models/thought.dart b/lib/models/thought.dart index 7236c30d..c702e044 100644 --- a/lib/models/thought.dart +++ b/lib/models/thought.dart @@ -80,6 +80,8 @@ sealed class SnThinkingSequence with _$SnThinkingSequence { const factory SnThinkingSequence({ required String id, String? topic, + @Default(0) int totalToken, + @Default(0) int paidToken, required String accountId, required DateTime createdAt, required DateTime updatedAt, @@ -98,6 +100,8 @@ sealed class SnThinkingThought with _$SnThinkingThought { @Default([]) List files, @Default([]) List chunks, @ThinkingThoughtRoleConverter() required ThinkingThoughtRole role, + int? tokenCount, + String? modelName, required String sequenceId, SnThinkingSequence? sequence, required DateTime createdAt, diff --git a/lib/models/thought.freezed.dart b/lib/models/thought.freezed.dart index f1f58a21..2d568fde 100644 --- a/lib/models/thought.freezed.dart +++ b/lib/models/thought.freezed.dart @@ -552,7 +552,7 @@ as Map?, /// @nodoc mixin _$SnThinkingSequence { - String get id; String? get topic; String get accountId; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; + String get id; String? get topic; int get totalToken; int get paidToken; String get accountId; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; /// Create a copy of SnThinkingSequence /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) @@ -565,16 +565,16 @@ $SnThinkingSequenceCopyWith get copyWith => _$SnThinkingSequ @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is SnThinkingSequence&&(identical(other.id, id) || other.id == id)&&(identical(other.topic, topic) || other.topic == topic)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is SnThinkingSequence&&(identical(other.id, id) || other.id == id)&&(identical(other.topic, topic) || other.topic == topic)&&(identical(other.totalToken, totalToken) || other.totalToken == totalToken)&&(identical(other.paidToken, paidToken) || other.paidToken == paidToken)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); } @JsonKey(includeFromJson: false, includeToJson: false) @override -int get hashCode => Object.hash(runtimeType,id,topic,accountId,createdAt,updatedAt,deletedAt); +int get hashCode => Object.hash(runtimeType,id,topic,totalToken,paidToken,accountId,createdAt,updatedAt,deletedAt); @override String toString() { - return 'SnThinkingSequence(id: $id, topic: $topic, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; + return 'SnThinkingSequence(id: $id, topic: $topic, totalToken: $totalToken, paidToken: $paidToken, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; } @@ -585,7 +585,7 @@ abstract mixin class $SnThinkingSequenceCopyWith<$Res> { factory $SnThinkingSequenceCopyWith(SnThinkingSequence value, $Res Function(SnThinkingSequence) _then) = _$SnThinkingSequenceCopyWithImpl; @useResult $Res call({ - String id, String? topic, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt + String id, String? topic, int totalToken, int paidToken, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt }); @@ -602,11 +602,13 @@ class _$SnThinkingSequenceCopyWithImpl<$Res> /// Create a copy of SnThinkingSequence /// with the given fields replaced by the non-null parameter values. -@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? topic = freezed,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { +@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? topic = freezed,Object? totalToken = null,Object? paidToken = null,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { return _then(_self.copyWith( id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable as String,topic: freezed == topic ? _self.topic : topic // ignore: cast_nullable_to_non_nullable -as String?,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable +as String?,totalToken: null == totalToken ? _self.totalToken : totalToken // ignore: cast_nullable_to_non_nullable +as int,paidToken: null == paidToken ? _self.paidToken : paidToken // ignore: cast_nullable_to_non_nullable +as int,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable as String,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable @@ -692,10 +694,10 @@ return $default(_that);case _: /// } /// ``` -@optionalTypeArgs TResult maybeWhen(TResult Function( String id, String? topic, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this; +@optionalTypeArgs TResult maybeWhen(TResult Function( String id, String? topic, int totalToken, int paidToken, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this; switch (_that) { case _SnThinkingSequence() when $default != null: -return $default(_that.id,_that.topic,_that.accountId,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: +return $default(_that.id,_that.topic,_that.totalToken,_that.paidToken,_that.accountId,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: return orElse(); } @@ -713,10 +715,10 @@ return $default(_that.id,_that.topic,_that.accountId,_that.createdAt,_that.updat /// } /// ``` -@optionalTypeArgs TResult when(TResult Function( String id, String? topic, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt) $default,) {final _that = this; +@optionalTypeArgs TResult when(TResult Function( String id, String? topic, int totalToken, int paidToken, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt) $default,) {final _that = this; switch (_that) { case _SnThinkingSequence(): -return $default(_that.id,_that.topic,_that.accountId,_that.createdAt,_that.updatedAt,_that.deletedAt);} +return $default(_that.id,_that.topic,_that.totalToken,_that.paidToken,_that.accountId,_that.createdAt,_that.updatedAt,_that.deletedAt);} } /// A variant of `when` that fallback to returning `null` /// @@ -730,10 +732,10 @@ return $default(_that.id,_that.topic,_that.accountId,_that.createdAt,_that.updat /// } /// ``` -@optionalTypeArgs TResult? whenOrNull(TResult? Function( String id, String? topic, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,) {final _that = this; +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String id, String? topic, int totalToken, int paidToken, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,) {final _that = this; switch (_that) { case _SnThinkingSequence() when $default != null: -return $default(_that.id,_that.topic,_that.accountId,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: +return $default(_that.id,_that.topic,_that.totalToken,_that.paidToken,_that.accountId,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: return null; } @@ -745,11 +747,13 @@ return $default(_that.id,_that.topic,_that.accountId,_that.createdAt,_that.updat @JsonSerializable() class _SnThinkingSequence implements SnThinkingSequence { - const _SnThinkingSequence({required this.id, this.topic, required this.accountId, required this.createdAt, required this.updatedAt, this.deletedAt}); + const _SnThinkingSequence({required this.id, this.topic, this.totalToken = 0, this.paidToken = 0, required this.accountId, required this.createdAt, required this.updatedAt, this.deletedAt}); factory _SnThinkingSequence.fromJson(Map json) => _$SnThinkingSequenceFromJson(json); @override final String id; @override final String? topic; +@override@JsonKey() final int totalToken; +@override@JsonKey() final int paidToken; @override final String accountId; @override final DateTime createdAt; @override final DateTime updatedAt; @@ -768,16 +772,16 @@ Map toJson() { @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnThinkingSequence&&(identical(other.id, id) || other.id == id)&&(identical(other.topic, topic) || other.topic == topic)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnThinkingSequence&&(identical(other.id, id) || other.id == id)&&(identical(other.topic, topic) || other.topic == topic)&&(identical(other.totalToken, totalToken) || other.totalToken == totalToken)&&(identical(other.paidToken, paidToken) || other.paidToken == paidToken)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); } @JsonKey(includeFromJson: false, includeToJson: false) @override -int get hashCode => Object.hash(runtimeType,id,topic,accountId,createdAt,updatedAt,deletedAt); +int get hashCode => Object.hash(runtimeType,id,topic,totalToken,paidToken,accountId,createdAt,updatedAt,deletedAt); @override String toString() { - return 'SnThinkingSequence(id: $id, topic: $topic, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; + return 'SnThinkingSequence(id: $id, topic: $topic, totalToken: $totalToken, paidToken: $paidToken, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; } @@ -788,7 +792,7 @@ abstract mixin class _$SnThinkingSequenceCopyWith<$Res> implements $SnThinkingSe factory _$SnThinkingSequenceCopyWith(_SnThinkingSequence value, $Res Function(_SnThinkingSequence) _then) = __$SnThinkingSequenceCopyWithImpl; @override @useResult $Res call({ - String id, String? topic, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt + String id, String? topic, int totalToken, int paidToken, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt }); @@ -805,11 +809,13 @@ class __$SnThinkingSequenceCopyWithImpl<$Res> /// Create a copy of SnThinkingSequence /// with the given fields replaced by the non-null parameter values. -@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? topic = freezed,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { +@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? topic = freezed,Object? totalToken = null,Object? paidToken = null,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { return _then(_SnThinkingSequence( id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable as String,topic: freezed == topic ? _self.topic : topic // ignore: cast_nullable_to_non_nullable -as String?,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable +as String?,totalToken: null == totalToken ? _self.totalToken : totalToken // ignore: cast_nullable_to_non_nullable +as int,paidToken: null == paidToken ? _self.paidToken : paidToken // ignore: cast_nullable_to_non_nullable +as int,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable as String,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable @@ -824,7 +830,7 @@ as DateTime?, /// @nodoc mixin _$SnThinkingThought { - String get id; String? get content; List get files; List get chunks;@ThinkingThoughtRoleConverter() ThinkingThoughtRole get role; String get sequenceId; SnThinkingSequence? get sequence; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; + String get id; String? get content; List get files; List get chunks;@ThinkingThoughtRoleConverter() ThinkingThoughtRole get role; int? get tokenCount; String? get modelName; String get sequenceId; SnThinkingSequence? get sequence; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; /// Create a copy of SnThinkingThought /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) @@ -837,16 +843,16 @@ $SnThinkingThoughtCopyWith get copyWith => _$SnThinkingThough @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is SnThinkingThought&&(identical(other.id, id) || other.id == id)&&(identical(other.content, content) || other.content == content)&&const DeepCollectionEquality().equals(other.files, files)&&const DeepCollectionEquality().equals(other.chunks, chunks)&&(identical(other.role, role) || other.role == role)&&(identical(other.sequenceId, sequenceId) || other.sequenceId == sequenceId)&&(identical(other.sequence, sequence) || other.sequence == sequence)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is SnThinkingThought&&(identical(other.id, id) || other.id == id)&&(identical(other.content, content) || other.content == content)&&const DeepCollectionEquality().equals(other.files, files)&&const DeepCollectionEquality().equals(other.chunks, chunks)&&(identical(other.role, role) || other.role == role)&&(identical(other.tokenCount, tokenCount) || other.tokenCount == tokenCount)&&(identical(other.modelName, modelName) || other.modelName == modelName)&&(identical(other.sequenceId, sequenceId) || other.sequenceId == sequenceId)&&(identical(other.sequence, sequence) || other.sequence == sequence)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); } @JsonKey(includeFromJson: false, includeToJson: false) @override -int get hashCode => Object.hash(runtimeType,id,content,const DeepCollectionEquality().hash(files),const DeepCollectionEquality().hash(chunks),role,sequenceId,sequence,createdAt,updatedAt,deletedAt); +int get hashCode => Object.hash(runtimeType,id,content,const DeepCollectionEquality().hash(files),const DeepCollectionEquality().hash(chunks),role,tokenCount,modelName,sequenceId,sequence,createdAt,updatedAt,deletedAt); @override String toString() { - return 'SnThinkingThought(id: $id, content: $content, files: $files, chunks: $chunks, role: $role, sequenceId: $sequenceId, sequence: $sequence, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; + return 'SnThinkingThought(id: $id, content: $content, files: $files, chunks: $chunks, role: $role, tokenCount: $tokenCount, modelName: $modelName, sequenceId: $sequenceId, sequence: $sequence, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; } @@ -857,7 +863,7 @@ abstract mixin class $SnThinkingThoughtCopyWith<$Res> { factory $SnThinkingThoughtCopyWith(SnThinkingThought value, $Res Function(SnThinkingThought) _then) = _$SnThinkingThoughtCopyWithImpl; @useResult $Res call({ - String id, String? content, List files, List chunks,@ThinkingThoughtRoleConverter() ThinkingThoughtRole role, String sequenceId, SnThinkingSequence? sequence, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt + String id, String? content, List files, List chunks,@ThinkingThoughtRoleConverter() ThinkingThoughtRole role, int? tokenCount, String? modelName, String sequenceId, SnThinkingSequence? sequence, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt }); @@ -874,14 +880,16 @@ class _$SnThinkingThoughtCopyWithImpl<$Res> /// Create a copy of SnThinkingThought /// with the given fields replaced by the non-null parameter values. -@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? content = freezed,Object? files = null,Object? chunks = null,Object? role = null,Object? sequenceId = null,Object? sequence = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { +@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? content = freezed,Object? files = null,Object? chunks = null,Object? role = null,Object? tokenCount = freezed,Object? modelName = freezed,Object? sequenceId = null,Object? sequence = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { return _then(_self.copyWith( id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable as String,content: freezed == content ? _self.content : content // ignore: cast_nullable_to_non_nullable as String?,files: null == files ? _self.files : files // ignore: cast_nullable_to_non_nullable as List,chunks: null == chunks ? _self.chunks : chunks // ignore: cast_nullable_to_non_nullable as List,role: null == role ? _self.role : role // ignore: cast_nullable_to_non_nullable -as ThinkingThoughtRole,sequenceId: null == sequenceId ? _self.sequenceId : sequenceId // ignore: cast_nullable_to_non_nullable +as ThinkingThoughtRole,tokenCount: freezed == tokenCount ? _self.tokenCount : tokenCount // ignore: cast_nullable_to_non_nullable +as int?,modelName: freezed == modelName ? _self.modelName : modelName // ignore: cast_nullable_to_non_nullable +as String?,sequenceId: null == sequenceId ? _self.sequenceId : sequenceId // ignore: cast_nullable_to_non_nullable as String,sequence: freezed == sequence ? _self.sequence : sequence // ignore: cast_nullable_to_non_nullable as SnThinkingSequence?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable @@ -980,10 +988,10 @@ return $default(_that);case _: /// } /// ``` -@optionalTypeArgs TResult maybeWhen(TResult Function( String id, String? content, List files, List chunks, @ThinkingThoughtRoleConverter() ThinkingThoughtRole role, String sequenceId, SnThinkingSequence? sequence, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this; +@optionalTypeArgs TResult maybeWhen(TResult Function( String id, String? content, List files, List chunks, @ThinkingThoughtRoleConverter() ThinkingThoughtRole role, int? tokenCount, String? modelName, String sequenceId, SnThinkingSequence? sequence, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this; switch (_that) { case _SnThinkingThought() when $default != null: -return $default(_that.id,_that.content,_that.files,_that.chunks,_that.role,_that.sequenceId,_that.sequence,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: +return $default(_that.id,_that.content,_that.files,_that.chunks,_that.role,_that.tokenCount,_that.modelName,_that.sequenceId,_that.sequence,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: return orElse(); } @@ -1001,10 +1009,10 @@ return $default(_that.id,_that.content,_that.files,_that.chunks,_that.role,_that /// } /// ``` -@optionalTypeArgs TResult when(TResult Function( String id, String? content, List files, List chunks, @ThinkingThoughtRoleConverter() ThinkingThoughtRole role, String sequenceId, SnThinkingSequence? sequence, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt) $default,) {final _that = this; +@optionalTypeArgs TResult when(TResult Function( String id, String? content, List files, List chunks, @ThinkingThoughtRoleConverter() ThinkingThoughtRole role, int? tokenCount, String? modelName, String sequenceId, SnThinkingSequence? sequence, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt) $default,) {final _that = this; switch (_that) { case _SnThinkingThought(): -return $default(_that.id,_that.content,_that.files,_that.chunks,_that.role,_that.sequenceId,_that.sequence,_that.createdAt,_that.updatedAt,_that.deletedAt);} +return $default(_that.id,_that.content,_that.files,_that.chunks,_that.role,_that.tokenCount,_that.modelName,_that.sequenceId,_that.sequence,_that.createdAt,_that.updatedAt,_that.deletedAt);} } /// A variant of `when` that fallback to returning `null` /// @@ -1018,10 +1026,10 @@ return $default(_that.id,_that.content,_that.files,_that.chunks,_that.role,_that /// } /// ``` -@optionalTypeArgs TResult? whenOrNull(TResult? Function( String id, String? content, List files, List chunks, @ThinkingThoughtRoleConverter() ThinkingThoughtRole role, String sequenceId, SnThinkingSequence? sequence, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,) {final _that = this; +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String id, String? content, List files, List chunks, @ThinkingThoughtRoleConverter() ThinkingThoughtRole role, int? tokenCount, String? modelName, String sequenceId, SnThinkingSequence? sequence, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,) {final _that = this; switch (_that) { case _SnThinkingThought() when $default != null: -return $default(_that.id,_that.content,_that.files,_that.chunks,_that.role,_that.sequenceId,_that.sequence,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: +return $default(_that.id,_that.content,_that.files,_that.chunks,_that.role,_that.tokenCount,_that.modelName,_that.sequenceId,_that.sequence,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: return null; } @@ -1033,7 +1041,7 @@ return $default(_that.id,_that.content,_that.files,_that.chunks,_that.role,_that @JsonSerializable() class _SnThinkingThought implements SnThinkingThought { - const _SnThinkingThought({required this.id, this.content, final List files = const [], final List chunks = const [], @ThinkingThoughtRoleConverter() required this.role, required this.sequenceId, this.sequence, required this.createdAt, required this.updatedAt, this.deletedAt}): _files = files,_chunks = chunks; + const _SnThinkingThought({required this.id, this.content, final List files = const [], final List chunks = const [], @ThinkingThoughtRoleConverter() required this.role, this.tokenCount, this.modelName, required this.sequenceId, this.sequence, required this.createdAt, required this.updatedAt, this.deletedAt}): _files = files,_chunks = chunks; factory _SnThinkingThought.fromJson(Map json) => _$SnThinkingThoughtFromJson(json); @override final String id; @@ -1053,6 +1061,8 @@ class _SnThinkingThought implements SnThinkingThought { } @override@ThinkingThoughtRoleConverter() final ThinkingThoughtRole role; +@override final int? tokenCount; +@override final String? modelName; @override final String sequenceId; @override final SnThinkingSequence? sequence; @override final DateTime createdAt; @@ -1072,16 +1082,16 @@ Map toJson() { @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnThinkingThought&&(identical(other.id, id) || other.id == id)&&(identical(other.content, content) || other.content == content)&&const DeepCollectionEquality().equals(other._files, _files)&&const DeepCollectionEquality().equals(other._chunks, _chunks)&&(identical(other.role, role) || other.role == role)&&(identical(other.sequenceId, sequenceId) || other.sequenceId == sequenceId)&&(identical(other.sequence, sequence) || other.sequence == sequence)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnThinkingThought&&(identical(other.id, id) || other.id == id)&&(identical(other.content, content) || other.content == content)&&const DeepCollectionEquality().equals(other._files, _files)&&const DeepCollectionEquality().equals(other._chunks, _chunks)&&(identical(other.role, role) || other.role == role)&&(identical(other.tokenCount, tokenCount) || other.tokenCount == tokenCount)&&(identical(other.modelName, modelName) || other.modelName == modelName)&&(identical(other.sequenceId, sequenceId) || other.sequenceId == sequenceId)&&(identical(other.sequence, sequence) || other.sequence == sequence)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); } @JsonKey(includeFromJson: false, includeToJson: false) @override -int get hashCode => Object.hash(runtimeType,id,content,const DeepCollectionEquality().hash(_files),const DeepCollectionEquality().hash(_chunks),role,sequenceId,sequence,createdAt,updatedAt,deletedAt); +int get hashCode => Object.hash(runtimeType,id,content,const DeepCollectionEquality().hash(_files),const DeepCollectionEquality().hash(_chunks),role,tokenCount,modelName,sequenceId,sequence,createdAt,updatedAt,deletedAt); @override String toString() { - return 'SnThinkingThought(id: $id, content: $content, files: $files, chunks: $chunks, role: $role, sequenceId: $sequenceId, sequence: $sequence, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; + return 'SnThinkingThought(id: $id, content: $content, files: $files, chunks: $chunks, role: $role, tokenCount: $tokenCount, modelName: $modelName, sequenceId: $sequenceId, sequence: $sequence, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; } @@ -1092,7 +1102,7 @@ abstract mixin class _$SnThinkingThoughtCopyWith<$Res> implements $SnThinkingTho factory _$SnThinkingThoughtCopyWith(_SnThinkingThought value, $Res Function(_SnThinkingThought) _then) = __$SnThinkingThoughtCopyWithImpl; @override @useResult $Res call({ - String id, String? content, List files, List chunks,@ThinkingThoughtRoleConverter() ThinkingThoughtRole role, String sequenceId, SnThinkingSequence? sequence, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt + String id, String? content, List files, List chunks,@ThinkingThoughtRoleConverter() ThinkingThoughtRole role, int? tokenCount, String? modelName, String sequenceId, SnThinkingSequence? sequence, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt }); @@ -1109,14 +1119,16 @@ class __$SnThinkingThoughtCopyWithImpl<$Res> /// Create a copy of SnThinkingThought /// with the given fields replaced by the non-null parameter values. -@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? content = freezed,Object? files = null,Object? chunks = null,Object? role = null,Object? sequenceId = null,Object? sequence = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { +@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? content = freezed,Object? files = null,Object? chunks = null,Object? role = null,Object? tokenCount = freezed,Object? modelName = freezed,Object? sequenceId = null,Object? sequence = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { return _then(_SnThinkingThought( id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable as String,content: freezed == content ? _self.content : content // ignore: cast_nullable_to_non_nullable as String?,files: null == files ? _self._files : files // ignore: cast_nullable_to_non_nullable as List,chunks: null == chunks ? _self._chunks : chunks // ignore: cast_nullable_to_non_nullable as List,role: null == role ? _self.role : role // ignore: cast_nullable_to_non_nullable -as ThinkingThoughtRole,sequenceId: null == sequenceId ? _self.sequenceId : sequenceId // ignore: cast_nullable_to_non_nullable +as ThinkingThoughtRole,tokenCount: freezed == tokenCount ? _self.tokenCount : tokenCount // ignore: cast_nullable_to_non_nullable +as int?,modelName: freezed == modelName ? _self.modelName : modelName // ignore: cast_nullable_to_non_nullable +as String?,sequenceId: null == sequenceId ? _self.sequenceId : sequenceId // ignore: cast_nullable_to_non_nullable as String,sequence: freezed == sequence ? _self.sequence : sequence // ignore: cast_nullable_to_non_nullable as SnThinkingSequence?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable diff --git a/lib/models/thought.g.dart b/lib/models/thought.g.dart index 257dc0b0..5dce045d 100644 --- a/lib/models/thought.g.dart +++ b/lib/models/thought.g.dart @@ -44,6 +44,8 @@ _SnThinkingSequence _$SnThinkingSequenceFromJson(Map json) => _SnThinkingSequence( id: json['id'] as String, topic: json['topic'] as String?, + totalToken: (json['total_token'] as num?)?.toInt() ?? 0, + paidToken: (json['paid_token'] as num?)?.toInt() ?? 0, accountId: json['account_id'] as String, createdAt: DateTime.parse(json['created_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String), @@ -57,6 +59,8 @@ Map _$SnThinkingSequenceToJson(_SnThinkingSequence instance) => { 'id': instance.id, 'topic': instance.topic, + 'total_token': instance.totalToken, + 'paid_token': instance.paidToken, 'account_id': instance.accountId, 'created_at': instance.createdAt.toIso8601String(), 'updated_at': instance.updatedAt.toIso8601String(), @@ -80,6 +84,8 @@ _SnThinkingThought _$SnThinkingThoughtFromJson(Map json) => role: const ThinkingThoughtRoleConverter().fromJson( (json['role'] as num).toInt(), ), + tokenCount: (json['token_count'] as num?)?.toInt(), + modelName: json['model_name'] as String?, sequenceId: json['sequence_id'] as String, sequence: json['sequence'] == null @@ -102,6 +108,8 @@ Map _$SnThinkingThoughtToJson(_SnThinkingThought instance) => 'files': instance.files.map((e) => e.toJson()).toList(), 'chunks': instance.chunks.map((e) => e.toJson()).toList(), 'role': const ThinkingThoughtRoleConverter().toJson(instance.role), + 'token_count': instance.tokenCount, + 'model_name': instance.modelName, 'sequence_id': instance.sequenceId, 'sequence': instance.sequence?.toJson(), 'created_at': instance.createdAt.toIso8601String(), diff --git a/lib/screens/thought/think.dart b/lib/screens/thought/think.dart index b4e5dcc3..574b4e11 100644 --- a/lib/screens/thought/think.dart +++ b/lib/screens/thought/think.dart @@ -2,6 +2,7 @@ import "dart:convert"; import "package:dio/dio.dart"; import "package:easy_localization/easy_localization.dart"; import "package:flutter/material.dart"; +import "package:flutter/services.dart"; import "package:flutter_hooks/flutter_hooks.dart"; import "package:gap/gap.dart"; import "package:google_fonts/google_fonts.dart"; @@ -382,9 +383,28 @@ class ThoughtScreen extends HookConsumerWidget { ], ), ), + if (thought.role == ThinkingThoughtRole.assistant) + SizedBox( + height: 20, + width: 20, + child: IconButton( + visualDensity: VisualDensity( + horizontal: -4, + vertical: -4, + ), + padding: EdgeInsets.zero, + iconSize: 16, + icon: Icon(Symbols.content_copy), + onPressed: () { + Clipboard.setData( + ClipboardData(text: thought.content ?? ''), + ); + showSnackBar('copiedToClipboard'.tr()); + }, + ), + ), ], ), - const Gap(8), if (thought.chunks.isNotEmpty) ...[ buildChunkTiles(thought.chunks), const Gap(8), @@ -405,6 +425,36 @@ class ThoughtScreen extends HookConsumerWidget { ), ], ), + if (thought.role == ThinkingThoughtRole.assistant && + (thought.tokenCount != null || thought.modelName != null)) ...[ + const Gap(8), + Row( + children: [ + if (thought.modelName != null) ...[ + const Icon(Symbols.neurology, size: 16), + const Gap(4), + Text( + '${thought.modelName}', + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ), + const Gap(16), + ], + if (thought.tokenCount != null) + ...([ + const Icon(Symbols.token, size: 16), + const Gap(4), + Text( + '${thought.tokenCount} tokens', + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ), + ]), + ], + ), + ], if (proposals.isNotEmpty && thought.role == ThinkingThoughtRole.assistant) ...[ const Gap(12),