Multi model support in thought

This commit is contained in:
2025-11-16 02:45:02 +08:00
parent a9fd75cc45
commit 9a75228e38
7 changed files with 780 additions and 24 deletions

View File

@@ -71,6 +71,7 @@ sealed class StreamThinkingRequest with _$StreamThinkingRequest {
@Default([]) List<String> accpetProposals,
List<String>? attachedPosts,
List<Map<String, dynamic>>? attachedMessages,
@JsonKey(name: 'service_id') String? serviceId,
}) = _StreamThinkingRequest;
factory StreamThinkingRequest.fromJson(Map<String, dynamic> json) =>
@@ -175,3 +176,26 @@ sealed class SnThinkingThought with _$SnThinkingThought {
factory SnThinkingThought.fromJson(Map<String, dynamic> json) =>
_$SnThinkingThoughtFromJson(json);
}
@freezed
sealed class ThoughtService with _$ThoughtService {
const factory ThoughtService({
@JsonKey(name: 'service_id') required String serviceId,
required double billingMultiplier,
required int perkLevel,
}) = _ThoughtService;
factory ThoughtService.fromJson(Map<String, dynamic> json) =>
_$ThoughtServiceFromJson(json);
}
@freezed
sealed class ThoughtServicesResponse with _$ThoughtServicesResponse {
const factory ThoughtServicesResponse({
@JsonKey(name: 'default_service') required String defaultService,
required List<ThoughtService> services,
}) = _ThoughtServicesResponse;
factory ThoughtServicesResponse.fromJson(Map<String, dynamic> json) =>
_$ThoughtServicesResponseFromJson(json);
}

View File

@@ -15,7 +15,7 @@ T _$identity<T>(T value) => value;
/// @nodoc
mixin _$StreamThinkingRequest {
String get userMessage; String? get sequenceId; List<String> get accpetProposals; List<String>? get attachedPosts; List<Map<String, dynamic>>? get attachedMessages;
String get userMessage; String? get sequenceId; List<String> get accpetProposals; List<String>? get attachedPosts; List<Map<String, dynamic>>? get attachedMessages;@JsonKey(name: 'service_id') String? get serviceId;
/// Create a copy of StreamThinkingRequest
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@@ -28,16 +28,16 @@ $StreamThinkingRequestCopyWith<StreamThinkingRequest> get copyWith => _$StreamTh
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is StreamThinkingRequest&&(identical(other.userMessage, userMessage) || other.userMessage == userMessage)&&(identical(other.sequenceId, sequenceId) || other.sequenceId == sequenceId)&&const DeepCollectionEquality().equals(other.accpetProposals, accpetProposals)&&const DeepCollectionEquality().equals(other.attachedPosts, attachedPosts)&&const DeepCollectionEquality().equals(other.attachedMessages, attachedMessages));
return identical(this, other) || (other.runtimeType == runtimeType&&other is StreamThinkingRequest&&(identical(other.userMessage, userMessage) || other.userMessage == userMessage)&&(identical(other.sequenceId, sequenceId) || other.sequenceId == sequenceId)&&const DeepCollectionEquality().equals(other.accpetProposals, accpetProposals)&&const DeepCollectionEquality().equals(other.attachedPosts, attachedPosts)&&const DeepCollectionEquality().equals(other.attachedMessages, attachedMessages)&&(identical(other.serviceId, serviceId) || other.serviceId == serviceId));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,userMessage,sequenceId,const DeepCollectionEquality().hash(accpetProposals),const DeepCollectionEquality().hash(attachedPosts),const DeepCollectionEquality().hash(attachedMessages));
int get hashCode => Object.hash(runtimeType,userMessage,sequenceId,const DeepCollectionEquality().hash(accpetProposals),const DeepCollectionEquality().hash(attachedPosts),const DeepCollectionEquality().hash(attachedMessages),serviceId);
@override
String toString() {
return 'StreamThinkingRequest(userMessage: $userMessage, sequenceId: $sequenceId, accpetProposals: $accpetProposals, attachedPosts: $attachedPosts, attachedMessages: $attachedMessages)';
return 'StreamThinkingRequest(userMessage: $userMessage, sequenceId: $sequenceId, accpetProposals: $accpetProposals, attachedPosts: $attachedPosts, attachedMessages: $attachedMessages, serviceId: $serviceId)';
}
@@ -48,7 +48,7 @@ abstract mixin class $StreamThinkingRequestCopyWith<$Res> {
factory $StreamThinkingRequestCopyWith(StreamThinkingRequest value, $Res Function(StreamThinkingRequest) _then) = _$StreamThinkingRequestCopyWithImpl;
@useResult
$Res call({
String userMessage, String? sequenceId, List<String> accpetProposals, List<String>? attachedPosts, List<Map<String, dynamic>>? attachedMessages
String userMessage, String? sequenceId, List<String> accpetProposals, List<String>? attachedPosts, List<Map<String, dynamic>>? attachedMessages,@JsonKey(name: 'service_id') String? serviceId
});
@@ -65,14 +65,15 @@ class _$StreamThinkingRequestCopyWithImpl<$Res>
/// Create a copy of StreamThinkingRequest
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? userMessage = null,Object? sequenceId = freezed,Object? accpetProposals = null,Object? attachedPosts = freezed,Object? attachedMessages = freezed,}) {
@pragma('vm:prefer-inline') @override $Res call({Object? userMessage = null,Object? sequenceId = freezed,Object? accpetProposals = null,Object? attachedPosts = freezed,Object? attachedMessages = freezed,Object? serviceId = freezed,}) {
return _then(_self.copyWith(
userMessage: null == userMessage ? _self.userMessage : userMessage // ignore: cast_nullable_to_non_nullable
as String,sequenceId: freezed == sequenceId ? _self.sequenceId : sequenceId // ignore: cast_nullable_to_non_nullable
as String?,accpetProposals: null == accpetProposals ? _self.accpetProposals : accpetProposals // ignore: cast_nullable_to_non_nullable
as List<String>,attachedPosts: freezed == attachedPosts ? _self.attachedPosts : attachedPosts // ignore: cast_nullable_to_non_nullable
as List<String>?,attachedMessages: freezed == attachedMessages ? _self.attachedMessages : attachedMessages // ignore: cast_nullable_to_non_nullable
as List<Map<String, dynamic>>?,
as List<Map<String, dynamic>>?,serviceId: freezed == serviceId ? _self.serviceId : serviceId // ignore: cast_nullable_to_non_nullable
as String?,
));
}
@@ -154,10 +155,10 @@ return $default(_that);case _:
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String userMessage, String? sequenceId, List<String> accpetProposals, List<String>? attachedPosts, List<Map<String, dynamic>>? attachedMessages)? $default,{required TResult orElse(),}) {final _that = this;
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String userMessage, String? sequenceId, List<String> accpetProposals, List<String>? attachedPosts, List<Map<String, dynamic>>? attachedMessages, @JsonKey(name: 'service_id') String? serviceId)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _StreamThinkingRequest() when $default != null:
return $default(_that.userMessage,_that.sequenceId,_that.accpetProposals,_that.attachedPosts,_that.attachedMessages);case _:
return $default(_that.userMessage,_that.sequenceId,_that.accpetProposals,_that.attachedPosts,_that.attachedMessages,_that.serviceId);case _:
return orElse();
}
@@ -175,10 +176,10 @@ return $default(_that.userMessage,_that.sequenceId,_that.accpetProposals,_that.a
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String userMessage, String? sequenceId, List<String> accpetProposals, List<String>? attachedPosts, List<Map<String, dynamic>>? attachedMessages) $default,) {final _that = this;
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String userMessage, String? sequenceId, List<String> accpetProposals, List<String>? attachedPosts, List<Map<String, dynamic>>? attachedMessages, @JsonKey(name: 'service_id') String? serviceId) $default,) {final _that = this;
switch (_that) {
case _StreamThinkingRequest():
return $default(_that.userMessage,_that.sequenceId,_that.accpetProposals,_that.attachedPosts,_that.attachedMessages);}
return $default(_that.userMessage,_that.sequenceId,_that.accpetProposals,_that.attachedPosts,_that.attachedMessages,_that.serviceId);}
}
/// A variant of `when` that fallback to returning `null`
///
@@ -192,10 +193,10 @@ return $default(_that.userMessage,_that.sequenceId,_that.accpetProposals,_that.a
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String userMessage, String? sequenceId, List<String> accpetProposals, List<String>? attachedPosts, List<Map<String, dynamic>>? attachedMessages)? $default,) {final _that = this;
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String userMessage, String? sequenceId, List<String> accpetProposals, List<String>? attachedPosts, List<Map<String, dynamic>>? attachedMessages, @JsonKey(name: 'service_id') String? serviceId)? $default,) {final _that = this;
switch (_that) {
case _StreamThinkingRequest() when $default != null:
return $default(_that.userMessage,_that.sequenceId,_that.accpetProposals,_that.attachedPosts,_that.attachedMessages);case _:
return $default(_that.userMessage,_that.sequenceId,_that.accpetProposals,_that.attachedPosts,_that.attachedMessages,_that.serviceId);case _:
return null;
}
@@ -207,7 +208,7 @@ return $default(_that.userMessage,_that.sequenceId,_that.accpetProposals,_that.a
@JsonSerializable()
class _StreamThinkingRequest implements StreamThinkingRequest {
const _StreamThinkingRequest({required this.userMessage, this.sequenceId, final List<String> accpetProposals = const [], final List<String>? attachedPosts, final List<Map<String, dynamic>>? attachedMessages}): _accpetProposals = accpetProposals,_attachedPosts = attachedPosts,_attachedMessages = attachedMessages;
const _StreamThinkingRequest({required this.userMessage, this.sequenceId, final List<String> accpetProposals = const [], final List<String>? attachedPosts, final List<Map<String, dynamic>>? attachedMessages, @JsonKey(name: 'service_id') this.serviceId}): _accpetProposals = accpetProposals,_attachedPosts = attachedPosts,_attachedMessages = attachedMessages;
factory _StreamThinkingRequest.fromJson(Map<String, dynamic> json) => _$StreamThinkingRequestFromJson(json);
@override final String userMessage;
@@ -237,6 +238,7 @@ class _StreamThinkingRequest implements StreamThinkingRequest {
return EqualUnmodifiableListView(value);
}
@override@JsonKey(name: 'service_id') final String? serviceId;
/// Create a copy of StreamThinkingRequest
/// with the given fields replaced by the non-null parameter values.
@@ -251,16 +253,16 @@ Map<String, dynamic> toJson() {
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _StreamThinkingRequest&&(identical(other.userMessage, userMessage) || other.userMessage == userMessage)&&(identical(other.sequenceId, sequenceId) || other.sequenceId == sequenceId)&&const DeepCollectionEquality().equals(other._accpetProposals, _accpetProposals)&&const DeepCollectionEquality().equals(other._attachedPosts, _attachedPosts)&&const DeepCollectionEquality().equals(other._attachedMessages, _attachedMessages));
return identical(this, other) || (other.runtimeType == runtimeType&&other is _StreamThinkingRequest&&(identical(other.userMessage, userMessage) || other.userMessage == userMessage)&&(identical(other.sequenceId, sequenceId) || other.sequenceId == sequenceId)&&const DeepCollectionEquality().equals(other._accpetProposals, _accpetProposals)&&const DeepCollectionEquality().equals(other._attachedPosts, _attachedPosts)&&const DeepCollectionEquality().equals(other._attachedMessages, _attachedMessages)&&(identical(other.serviceId, serviceId) || other.serviceId == serviceId));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,userMessage,sequenceId,const DeepCollectionEquality().hash(_accpetProposals),const DeepCollectionEquality().hash(_attachedPosts),const DeepCollectionEquality().hash(_attachedMessages));
int get hashCode => Object.hash(runtimeType,userMessage,sequenceId,const DeepCollectionEquality().hash(_accpetProposals),const DeepCollectionEquality().hash(_attachedPosts),const DeepCollectionEquality().hash(_attachedMessages),serviceId);
@override
String toString() {
return 'StreamThinkingRequest(userMessage: $userMessage, sequenceId: $sequenceId, accpetProposals: $accpetProposals, attachedPosts: $attachedPosts, attachedMessages: $attachedMessages)';
return 'StreamThinkingRequest(userMessage: $userMessage, sequenceId: $sequenceId, accpetProposals: $accpetProposals, attachedPosts: $attachedPosts, attachedMessages: $attachedMessages, serviceId: $serviceId)';
}
@@ -271,7 +273,7 @@ abstract mixin class _$StreamThinkingRequestCopyWith<$Res> implements $StreamThi
factory _$StreamThinkingRequestCopyWith(_StreamThinkingRequest value, $Res Function(_StreamThinkingRequest) _then) = __$StreamThinkingRequestCopyWithImpl;
@override @useResult
$Res call({
String userMessage, String? sequenceId, List<String> accpetProposals, List<String>? attachedPosts, List<Map<String, dynamic>>? attachedMessages
String userMessage, String? sequenceId, List<String> accpetProposals, List<String>? attachedPosts, List<Map<String, dynamic>>? attachedMessages,@JsonKey(name: 'service_id') String? serviceId
});
@@ -288,14 +290,15 @@ class __$StreamThinkingRequestCopyWithImpl<$Res>
/// Create a copy of StreamThinkingRequest
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? userMessage = null,Object? sequenceId = freezed,Object? accpetProposals = null,Object? attachedPosts = freezed,Object? attachedMessages = freezed,}) {
@override @pragma('vm:prefer-inline') $Res call({Object? userMessage = null,Object? sequenceId = freezed,Object? accpetProposals = null,Object? attachedPosts = freezed,Object? attachedMessages = freezed,Object? serviceId = freezed,}) {
return _then(_StreamThinkingRequest(
userMessage: null == userMessage ? _self.userMessage : userMessage // ignore: cast_nullable_to_non_nullable
as String,sequenceId: freezed == sequenceId ? _self.sequenceId : sequenceId // ignore: cast_nullable_to_non_nullable
as String?,accpetProposals: null == accpetProposals ? _self._accpetProposals : accpetProposals // ignore: cast_nullable_to_non_nullable
as List<String>,attachedPosts: freezed == attachedPosts ? _self._attachedPosts : attachedPosts // ignore: cast_nullable_to_non_nullable
as List<String>?,attachedMessages: freezed == attachedMessages ? _self._attachedMessages : attachedMessages // ignore: cast_nullable_to_non_nullable
as List<Map<String, dynamic>>?,
as List<Map<String, dynamic>>?,serviceId: freezed == serviceId ? _self.serviceId : serviceId // ignore: cast_nullable_to_non_nullable
as String?,
));
}
@@ -2011,4 +2014,533 @@ $SnThinkingSequenceCopyWith<$Res>? get sequence {
}
}
/// @nodoc
mixin _$ThoughtService {
@JsonKey(name: 'service_id') String get serviceId; double get billingMultiplier; int get perkLevel;
/// Create a copy of ThoughtService
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$ThoughtServiceCopyWith<ThoughtService> get copyWith => _$ThoughtServiceCopyWithImpl<ThoughtService>(this as ThoughtService, _$identity);
/// Serializes this ThoughtService to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is ThoughtService&&(identical(other.serviceId, serviceId) || other.serviceId == serviceId)&&(identical(other.billingMultiplier, billingMultiplier) || other.billingMultiplier == billingMultiplier)&&(identical(other.perkLevel, perkLevel) || other.perkLevel == perkLevel));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,serviceId,billingMultiplier,perkLevel);
@override
String toString() {
return 'ThoughtService(serviceId: $serviceId, billingMultiplier: $billingMultiplier, perkLevel: $perkLevel)';
}
}
/// @nodoc
abstract mixin class $ThoughtServiceCopyWith<$Res> {
factory $ThoughtServiceCopyWith(ThoughtService value, $Res Function(ThoughtService) _then) = _$ThoughtServiceCopyWithImpl;
@useResult
$Res call({
@JsonKey(name: 'service_id') String serviceId, double billingMultiplier, int perkLevel
});
}
/// @nodoc
class _$ThoughtServiceCopyWithImpl<$Res>
implements $ThoughtServiceCopyWith<$Res> {
_$ThoughtServiceCopyWithImpl(this._self, this._then);
final ThoughtService _self;
final $Res Function(ThoughtService) _then;
/// Create a copy of ThoughtService
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? serviceId = null,Object? billingMultiplier = null,Object? perkLevel = null,}) {
return _then(_self.copyWith(
serviceId: null == serviceId ? _self.serviceId : serviceId // ignore: cast_nullable_to_non_nullable
as String,billingMultiplier: null == billingMultiplier ? _self.billingMultiplier : billingMultiplier // ignore: cast_nullable_to_non_nullable
as double,perkLevel: null == perkLevel ? _self.perkLevel : perkLevel // ignore: cast_nullable_to_non_nullable
as int,
));
}
}
/// Adds pattern-matching-related methods to [ThoughtService].
extension ThoughtServicePatterns on ThoughtService {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _ThoughtService value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _ThoughtService() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _ThoughtService value) $default,){
final _that = this;
switch (_that) {
case _ThoughtService():
return $default(_that);}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _ThoughtService value)? $default,){
final _that = this;
switch (_that) {
case _ThoughtService() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function(@JsonKey(name: 'service_id') String serviceId, double billingMultiplier, int perkLevel)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _ThoughtService() when $default != null:
return $default(_that.serviceId,_that.billingMultiplier,_that.perkLevel);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function(@JsonKey(name: 'service_id') String serviceId, double billingMultiplier, int perkLevel) $default,) {final _that = this;
switch (_that) {
case _ThoughtService():
return $default(_that.serviceId,_that.billingMultiplier,_that.perkLevel);}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function(@JsonKey(name: 'service_id') String serviceId, double billingMultiplier, int perkLevel)? $default,) {final _that = this;
switch (_that) {
case _ThoughtService() when $default != null:
return $default(_that.serviceId,_that.billingMultiplier,_that.perkLevel);case _:
return null;
}
}
}
/// @nodoc
@JsonSerializable()
class _ThoughtService implements ThoughtService {
const _ThoughtService({@JsonKey(name: 'service_id') required this.serviceId, required this.billingMultiplier, required this.perkLevel});
factory _ThoughtService.fromJson(Map<String, dynamic> json) => _$ThoughtServiceFromJson(json);
@override@JsonKey(name: 'service_id') final String serviceId;
@override final double billingMultiplier;
@override final int perkLevel;
/// Create a copy of ThoughtService
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$ThoughtServiceCopyWith<_ThoughtService> get copyWith => __$ThoughtServiceCopyWithImpl<_ThoughtService>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$ThoughtServiceToJson(this, );
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _ThoughtService&&(identical(other.serviceId, serviceId) || other.serviceId == serviceId)&&(identical(other.billingMultiplier, billingMultiplier) || other.billingMultiplier == billingMultiplier)&&(identical(other.perkLevel, perkLevel) || other.perkLevel == perkLevel));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,serviceId,billingMultiplier,perkLevel);
@override
String toString() {
return 'ThoughtService(serviceId: $serviceId, billingMultiplier: $billingMultiplier, perkLevel: $perkLevel)';
}
}
/// @nodoc
abstract mixin class _$ThoughtServiceCopyWith<$Res> implements $ThoughtServiceCopyWith<$Res> {
factory _$ThoughtServiceCopyWith(_ThoughtService value, $Res Function(_ThoughtService) _then) = __$ThoughtServiceCopyWithImpl;
@override @useResult
$Res call({
@JsonKey(name: 'service_id') String serviceId, double billingMultiplier, int perkLevel
});
}
/// @nodoc
class __$ThoughtServiceCopyWithImpl<$Res>
implements _$ThoughtServiceCopyWith<$Res> {
__$ThoughtServiceCopyWithImpl(this._self, this._then);
final _ThoughtService _self;
final $Res Function(_ThoughtService) _then;
/// Create a copy of ThoughtService
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? serviceId = null,Object? billingMultiplier = null,Object? perkLevel = null,}) {
return _then(_ThoughtService(
serviceId: null == serviceId ? _self.serviceId : serviceId // ignore: cast_nullable_to_non_nullable
as String,billingMultiplier: null == billingMultiplier ? _self.billingMultiplier : billingMultiplier // ignore: cast_nullable_to_non_nullable
as double,perkLevel: null == perkLevel ? _self.perkLevel : perkLevel // ignore: cast_nullable_to_non_nullable
as int,
));
}
}
/// @nodoc
mixin _$ThoughtServicesResponse {
@JsonKey(name: 'default_service') String get defaultService; List<ThoughtService> get services;
/// Create a copy of ThoughtServicesResponse
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$ThoughtServicesResponseCopyWith<ThoughtServicesResponse> get copyWith => _$ThoughtServicesResponseCopyWithImpl<ThoughtServicesResponse>(this as ThoughtServicesResponse, _$identity);
/// Serializes this ThoughtServicesResponse to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is ThoughtServicesResponse&&(identical(other.defaultService, defaultService) || other.defaultService == defaultService)&&const DeepCollectionEquality().equals(other.services, services));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,defaultService,const DeepCollectionEquality().hash(services));
@override
String toString() {
return 'ThoughtServicesResponse(defaultService: $defaultService, services: $services)';
}
}
/// @nodoc
abstract mixin class $ThoughtServicesResponseCopyWith<$Res> {
factory $ThoughtServicesResponseCopyWith(ThoughtServicesResponse value, $Res Function(ThoughtServicesResponse) _then) = _$ThoughtServicesResponseCopyWithImpl;
@useResult
$Res call({
@JsonKey(name: 'default_service') String defaultService, List<ThoughtService> services
});
}
/// @nodoc
class _$ThoughtServicesResponseCopyWithImpl<$Res>
implements $ThoughtServicesResponseCopyWith<$Res> {
_$ThoughtServicesResponseCopyWithImpl(this._self, this._then);
final ThoughtServicesResponse _self;
final $Res Function(ThoughtServicesResponse) _then;
/// Create a copy of ThoughtServicesResponse
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? defaultService = null,Object? services = null,}) {
return _then(_self.copyWith(
defaultService: null == defaultService ? _self.defaultService : defaultService // ignore: cast_nullable_to_non_nullable
as String,services: null == services ? _self.services : services // ignore: cast_nullable_to_non_nullable
as List<ThoughtService>,
));
}
}
/// Adds pattern-matching-related methods to [ThoughtServicesResponse].
extension ThoughtServicesResponsePatterns on ThoughtServicesResponse {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _ThoughtServicesResponse value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _ThoughtServicesResponse() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _ThoughtServicesResponse value) $default,){
final _that = this;
switch (_that) {
case _ThoughtServicesResponse():
return $default(_that);}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _ThoughtServicesResponse value)? $default,){
final _that = this;
switch (_that) {
case _ThoughtServicesResponse() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function(@JsonKey(name: 'default_service') String defaultService, List<ThoughtService> services)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _ThoughtServicesResponse() when $default != null:
return $default(_that.defaultService,_that.services);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function(@JsonKey(name: 'default_service') String defaultService, List<ThoughtService> services) $default,) {final _that = this;
switch (_that) {
case _ThoughtServicesResponse():
return $default(_that.defaultService,_that.services);}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function(@JsonKey(name: 'default_service') String defaultService, List<ThoughtService> services)? $default,) {final _that = this;
switch (_that) {
case _ThoughtServicesResponse() when $default != null:
return $default(_that.defaultService,_that.services);case _:
return null;
}
}
}
/// @nodoc
@JsonSerializable()
class _ThoughtServicesResponse implements ThoughtServicesResponse {
const _ThoughtServicesResponse({@JsonKey(name: 'default_service') required this.defaultService, required final List<ThoughtService> services}): _services = services;
factory _ThoughtServicesResponse.fromJson(Map<String, dynamic> json) => _$ThoughtServicesResponseFromJson(json);
@override@JsonKey(name: 'default_service') final String defaultService;
final List<ThoughtService> _services;
@override List<ThoughtService> get services {
if (_services is EqualUnmodifiableListView) return _services;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_services);
}
/// Create a copy of ThoughtServicesResponse
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$ThoughtServicesResponseCopyWith<_ThoughtServicesResponse> get copyWith => __$ThoughtServicesResponseCopyWithImpl<_ThoughtServicesResponse>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$ThoughtServicesResponseToJson(this, );
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _ThoughtServicesResponse&&(identical(other.defaultService, defaultService) || other.defaultService == defaultService)&&const DeepCollectionEquality().equals(other._services, _services));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,defaultService,const DeepCollectionEquality().hash(_services));
@override
String toString() {
return 'ThoughtServicesResponse(defaultService: $defaultService, services: $services)';
}
}
/// @nodoc
abstract mixin class _$ThoughtServicesResponseCopyWith<$Res> implements $ThoughtServicesResponseCopyWith<$Res> {
factory _$ThoughtServicesResponseCopyWith(_ThoughtServicesResponse value, $Res Function(_ThoughtServicesResponse) _then) = __$ThoughtServicesResponseCopyWithImpl;
@override @useResult
$Res call({
@JsonKey(name: 'default_service') String defaultService, List<ThoughtService> services
});
}
/// @nodoc
class __$ThoughtServicesResponseCopyWithImpl<$Res>
implements _$ThoughtServicesResponseCopyWith<$Res> {
__$ThoughtServicesResponseCopyWithImpl(this._self, this._then);
final _ThoughtServicesResponse _self;
final $Res Function(_ThoughtServicesResponse) _then;
/// Create a copy of ThoughtServicesResponse
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? defaultService = null,Object? services = null,}) {
return _then(_ThoughtServicesResponse(
defaultService: null == defaultService ? _self.defaultService : defaultService // ignore: cast_nullable_to_non_nullable
as String,services: null == services ? _self._services : services // ignore: cast_nullable_to_non_nullable
as List<ThoughtService>,
));
}
}
// dart format on

View File

@@ -24,6 +24,7 @@ _StreamThinkingRequest _$StreamThinkingRequestFromJson(
(json['attached_messages'] as List<dynamic>?)
?.map((e) => e as Map<String, dynamic>)
.toList(),
serviceId: json['service_id'] as String?,
);
Map<String, dynamic> _$StreamThinkingRequestToJson(
@@ -34,6 +35,7 @@ Map<String, dynamic> _$StreamThinkingRequestToJson(
'accpet_proposals': instance.accpetProposals,
'attached_posts': instance.attachedPosts,
'attached_messages': instance.attachedMessages,
'service_id': instance.serviceId,
};
_SnThinkingChunk _$SnThinkingChunkFromJson(Map<String, dynamic> json) =>
@@ -185,3 +187,34 @@ Map<String, dynamic> _$SnThinkingThoughtToJson(_SnThinkingThought instance) =>
'updated_at': instance.updatedAt.toIso8601String(),
'deleted_at': instance.deletedAt?.toIso8601String(),
};
_ThoughtService _$ThoughtServiceFromJson(Map<String, dynamic> json) =>
_ThoughtService(
serviceId: json['service_id'] as String,
billingMultiplier: (json['billing_multiplier'] as num).toDouble(),
perkLevel: (json['perk_level'] as num).toInt(),
);
Map<String, dynamic> _$ThoughtServiceToJson(_ThoughtService instance) =>
<String, dynamic>{
'service_id': instance.serviceId,
'billing_multiplier': instance.billingMultiplier,
'perk_level': instance.perkLevel,
};
_ThoughtServicesResponse _$ThoughtServicesResponseFromJson(
Map<String, dynamic> json,
) => _ThoughtServicesResponse(
defaultService: json['default_service'] as String,
services:
(json['services'] as List<dynamic>)
.map((e) => ThoughtService.fromJson(e as Map<String, dynamic>))
.toList(),
);
Map<String, dynamic> _$ThoughtServicesResponseToJson(
_ThoughtServicesResponse instance,
) => <String, dynamic>{
'default_service': instance.defaultService,
'services': instance.services.map((e) => e.toJson()).toList(),
};

View File

@@ -36,6 +36,13 @@ Future<List<SnThinkingThought>> thoughtSequence(
.toList();
}
@riverpod
Future<ThoughtServicesResponse> thoughtServices(Ref ref) async {
final apiClient = ref.watch(apiClientProvider);
final response = await apiClient.get('/insight/thought/services');
return ThoughtServicesResponse.fromJson(response.data);
}
class ThoughtScreen extends HookConsumerWidget {
const ThoughtScreen({super.key});

View File

@@ -171,5 +171,25 @@ class _ThoughtSequenceProviderElement
String get sequenceId => (origin as ThoughtSequenceProvider).sequenceId;
}
String _$thoughtServicesHash() => r'0ddeaec713ecfcdc9786c197f3d4cb41d36c26a5';
/// See also [thoughtServices].
@ProviderFor(thoughtServices)
final thoughtServicesProvider =
AutoDisposeFutureProvider<ThoughtServicesResponse>.internal(
thoughtServices,
name: r'thoughtServicesProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$thoughtServicesHash,
dependencies: null,
allTransitiveDependencies: null,
);
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
typedef ThoughtServicesRef =
AutoDisposeFutureProviderRef<ThoughtServicesResponse>;
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package

View File

@@ -1,6 +1,7 @@
import 'dart:convert';
import 'dart:math' as math;
import 'package:dio/dio.dart';
import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
@@ -9,6 +10,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/thought.dart';
import 'package:island/pods/network.dart';
import 'package:island/pods/userinfo.dart';
import 'package:island/screens/thought/think.dart';
import 'package:island/screens/posts/compose.dart';
import 'package:island/talker.dart';
import 'package:island/widgets/alert.dart';
@@ -40,6 +42,8 @@ class ThoughtChatState {
final ValueNotifier<String?> sequenceId;
final ValueNotifier<List<SnThinkingThought>> localThoughts;
final ValueNotifier<String?> currentTopic;
final ValueNotifier<List<ThoughtService>> services;
final ValueNotifier<String> selectedServiceId;
final TextEditingController messageController;
final ScrollController scrollController;
final ValueNotifier<bool> isStreaming;
@@ -52,6 +56,8 @@ class ThoughtChatState {
required this.sequenceId,
required this.localThoughts,
required this.currentTopic,
required this.services,
required this.selectedServiceId,
required this.messageController,
required this.scrollController,
required this.isStreaming,
@@ -77,6 +83,25 @@ ThoughtChatState useThoughtChat(
);
final currentTopic = useState<String?>(initialTopic ?? 'aiThought'.tr());
// Watch the provider for services
final servicesAsync = ref.watch(thoughtServicesProvider);
// Initialize services and selected service from provider
final services = useState<List<ThoughtService>>([]);
final selectedServiceId = useState<String>('');
// Update state when provider data arrives
useEffect(() {
if (servicesAsync.hasValue) {
final response = servicesAsync.value!;
services.value = response.services;
if (selectedServiceId.value.isEmpty) {
selectedServiceId.value = response.defaultService;
}
}
return null;
}, [servicesAsync]);
final messageController = useTextEditingController();
final scrollController = useScrollController();
final isStreaming = useState(false);
@@ -151,6 +176,8 @@ ThoughtChatState useThoughtChat(
accpetProposals: ['post_create'],
attachedMessages: attachedMessages,
attachedPosts: attachedPosts,
serviceId:
selectedServiceId.value.isNotEmpty ? selectedServiceId.value : null,
);
try {
@@ -344,6 +371,8 @@ ThoughtChatState useThoughtChat(
sequenceId: sequenceId,
localThoughts: localThoughts,
currentTopic: currentTopic,
services: services,
selectedServiceId: selectedServiceId,
messageController: messageController,
scrollController: scrollController,
isStreaming: isStreaming,
@@ -469,6 +498,8 @@ class ThoughtChatInterface extends HookConsumerWidget {
attachedMessages: attachedMessages,
attachedPosts: attachedPosts,
isDisabled: isDisabled,
services: chatState.services.value,
selectedServiceId: chatState.selectedServiceId,
),
),
),
@@ -513,6 +544,8 @@ class ThoughtInput extends HookWidget {
final List<Map<String, dynamic>>? attachedMessages;
final List<String>? attachedPosts;
final bool isDisabled;
final List<ThoughtService> services;
final ValueNotifier<String> selectedServiceId;
const ThoughtInput({
super.key,
@@ -522,6 +555,8 @@ class ThoughtInput extends HookWidget {
this.attachedMessages,
this.attachedPosts,
this.isDisabled = false,
required this.services,
required this.selectedServiceId,
});
@override
@@ -605,6 +640,7 @@ class ThoughtInput extends HookWidget {
],
),
),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -644,6 +680,110 @@ class ThoughtInput extends HookWidget {
),
],
),
Padding(
padding: const EdgeInsets.fromLTRB(8, 4, 8, 4),
child: Row(
children: [
if (services.isNotEmpty)
DropdownButtonHideUnderline(
child: DropdownButton2<String>(
value:
selectedServiceId.value.isEmpty
? null
: selectedServiceId.value,
customButton: Container(
padding: EdgeInsets.all(4),
decoration: BoxDecoration(
border: BoxBorder.all(
color: Theme.of(context).colorScheme.outline,
width: 1,
),
borderRadius: const BorderRadius.all(
Radius.circular(16),
),
),
child: Row(
spacing: 8,
children: [
const Icon(
Symbols.network_intelligence,
size: 20,
),
Text(selectedServiceId.value),
const Icon(
Symbols.keyboard_arrow_down,
size: 14,
).padding(right: 4),
],
).padding(vertical: 2, horizontal: 6),
),
items:
services
.map(
(service) => DropdownMenuItem<String>(
value: service.serviceId,
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
service.serviceId,
style: DefaultTextStyle.of(
context,
).style.copyWith(
fontSize: 14,
fontWeight: FontWeight.w500,
),
),
Text(
'Rate: ${service.billingMultiplier}x, Level: P${service.perkLevel}',
style: DefaultTextStyle.of(
context,
).style.copyWith(
fontSize: 12,
color:
Theme.of(context)
.colorScheme
.onSurfaceVariant,
),
),
],
),
),
)
.toList(),
onChanged:
!isStreaming && !isDisabled
? (value) {
if (value != null) {
selectedServiceId.value = value;
}
}
: null,
hint: const Text('Select Service'),
isDense: true,
buttonStyleData: ButtonStyleData(
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(
Radius.circular(16),
),
),
),
menuItemStyleData: MenuItemStyleData(
selectedMenuItemBuilder: (context, child) {
return child;
},
height: 56,
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 8,
),
),
),
),
],
),
),
],
),
),