AI Request History & Duplication Feature

This commit is contained in:
Manas Hejmadi
2025-06-08 22:34:26 +05:30
parent 97d4a7a45b
commit 452020f720
11 changed files with 331 additions and 37 deletions

View File

@@ -1,4 +1,5 @@
import 'package:apidash_core/apidash_core.dart'; import 'package:apidash_core/apidash_core.dart';
import 'package:genai/genai.dart';
import 'models.dart'; import 'models.dart';
part 'history_request_model.freezed.dart'; part 'history_request_model.freezed.dart';
@@ -14,7 +15,8 @@ class HistoryRequestModel with _$HistoryRequestModel {
const factory HistoryRequestModel({ const factory HistoryRequestModel({
required String historyId, required String historyId,
required HistoryMetaModel metaData, required HistoryMetaModel metaData,
required HttpRequestModel httpRequestModel, HttpRequestModel? httpRequestModel,
AIRequestModel? aiRequestModel,
required HttpResponseModel httpResponseModel, required HttpResponseModel httpResponseModel,
String? preRequestScript, String? preRequestScript,
String? postRequestScript, String? postRequestScript,

View File

@@ -22,7 +22,8 @@ HistoryRequestModel _$HistoryRequestModelFromJson(Map<String, dynamic> json) {
mixin _$HistoryRequestModel { mixin _$HistoryRequestModel {
String get historyId => throw _privateConstructorUsedError; String get historyId => throw _privateConstructorUsedError;
HistoryMetaModel get metaData => throw _privateConstructorUsedError; HistoryMetaModel get metaData => throw _privateConstructorUsedError;
HttpRequestModel get httpRequestModel => throw _privateConstructorUsedError; HttpRequestModel? get httpRequestModel => throw _privateConstructorUsedError;
AIRequestModel? get aiRequestModel => throw _privateConstructorUsedError;
HttpResponseModel get httpResponseModel => throw _privateConstructorUsedError; HttpResponseModel get httpResponseModel => throw _privateConstructorUsedError;
String? get preRequestScript => throw _privateConstructorUsedError; String? get preRequestScript => throw _privateConstructorUsedError;
String? get postRequestScript => throw _privateConstructorUsedError; String? get postRequestScript => throw _privateConstructorUsedError;
@@ -47,14 +48,16 @@ abstract class $HistoryRequestModelCopyWith<$Res> {
$Res call( $Res call(
{String historyId, {String historyId,
HistoryMetaModel metaData, HistoryMetaModel metaData,
HttpRequestModel httpRequestModel, HttpRequestModel? httpRequestModel,
AIRequestModel? aiRequestModel,
HttpResponseModel httpResponseModel, HttpResponseModel httpResponseModel,
String? preRequestScript, String? preRequestScript,
String? postRequestScript, String? postRequestScript,
AuthModel? authModel}); AuthModel? authModel});
$HistoryMetaModelCopyWith<$Res> get metaData; $HistoryMetaModelCopyWith<$Res> get metaData;
$HttpRequestModelCopyWith<$Res> get httpRequestModel; $HttpRequestModelCopyWith<$Res>? get httpRequestModel;
$AIRequestModelCopyWith<$Res>? get aiRequestModel;
$HttpResponseModelCopyWith<$Res> get httpResponseModel; $HttpResponseModelCopyWith<$Res> get httpResponseModel;
$AuthModelCopyWith<$Res>? get authModel; $AuthModelCopyWith<$Res>? get authModel;
} }
@@ -76,7 +79,8 @@ class _$HistoryRequestModelCopyWithImpl<$Res, $Val extends HistoryRequestModel>
$Res call({ $Res call({
Object? historyId = null, Object? historyId = null,
Object? metaData = null, Object? metaData = null,
Object? httpRequestModel = null, Object? httpRequestModel = freezed,
Object? aiRequestModel = freezed,
Object? httpResponseModel = null, Object? httpResponseModel = null,
Object? preRequestScript = freezed, Object? preRequestScript = freezed,
Object? postRequestScript = freezed, Object? postRequestScript = freezed,
@@ -91,10 +95,14 @@ class _$HistoryRequestModelCopyWithImpl<$Res, $Val extends HistoryRequestModel>
? _value.metaData ? _value.metaData
: metaData // ignore: cast_nullable_to_non_nullable : metaData // ignore: cast_nullable_to_non_nullable
as HistoryMetaModel, as HistoryMetaModel,
httpRequestModel: null == httpRequestModel httpRequestModel: freezed == httpRequestModel
? _value.httpRequestModel ? _value.httpRequestModel
: httpRequestModel // ignore: cast_nullable_to_non_nullable : httpRequestModel // ignore: cast_nullable_to_non_nullable
as HttpRequestModel, as HttpRequestModel?,
aiRequestModel: freezed == aiRequestModel
? _value.aiRequestModel
: aiRequestModel // ignore: cast_nullable_to_non_nullable
as AIRequestModel?,
httpResponseModel: null == httpResponseModel httpResponseModel: null == httpResponseModel
? _value.httpResponseModel ? _value.httpResponseModel
: httpResponseModel // ignore: cast_nullable_to_non_nullable : httpResponseModel // ignore: cast_nullable_to_non_nullable
@@ -128,12 +136,30 @@ class _$HistoryRequestModelCopyWithImpl<$Res, $Val extends HistoryRequestModel>
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@override @override
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
$HttpRequestModelCopyWith<$Res> get httpRequestModel { $HttpRequestModelCopyWith<$Res>? get httpRequestModel {
return $HttpRequestModelCopyWith<$Res>(_value.httpRequestModel, (value) { if (_value.httpRequestModel == null) {
return null;
}
return $HttpRequestModelCopyWith<$Res>(_value.httpRequestModel!, (value) {
return _then(_value.copyWith(httpRequestModel: value) as $Val); return _then(_value.copyWith(httpRequestModel: value) as $Val);
}); });
} }
/// Create a copy of HistoryRequestModel
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$AIRequestModelCopyWith<$Res>? get aiRequestModel {
if (_value.aiRequestModel == null) {
return null;
}
return $AIRequestModelCopyWith<$Res>(_value.aiRequestModel!, (value) {
return _then(_value.copyWith(aiRequestModel: value) as $Val);
});
}
/// Create a copy of HistoryRequestModel /// Create a copy of HistoryRequestModel
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@override @override
@@ -170,7 +196,8 @@ abstract class _$$HistoryRequestModelImplCopyWith<$Res>
$Res call( $Res call(
{String historyId, {String historyId,
HistoryMetaModel metaData, HistoryMetaModel metaData,
HttpRequestModel httpRequestModel, HttpRequestModel? httpRequestModel,
AIRequestModel? aiRequestModel,
HttpResponseModel httpResponseModel, HttpResponseModel httpResponseModel,
String? preRequestScript, String? preRequestScript,
String? postRequestScript, String? postRequestScript,
@@ -179,7 +206,9 @@ abstract class _$$HistoryRequestModelImplCopyWith<$Res>
@override @override
$HistoryMetaModelCopyWith<$Res> get metaData; $HistoryMetaModelCopyWith<$Res> get metaData;
@override @override
$HttpRequestModelCopyWith<$Res> get httpRequestModel; $HttpRequestModelCopyWith<$Res>? get httpRequestModel;
@override
$AIRequestModelCopyWith<$Res>? get aiRequestModel;
@override @override
$HttpResponseModelCopyWith<$Res> get httpResponseModel; $HttpResponseModelCopyWith<$Res> get httpResponseModel;
@override @override
@@ -201,7 +230,8 @@ class __$$HistoryRequestModelImplCopyWithImpl<$Res>
$Res call({ $Res call({
Object? historyId = null, Object? historyId = null,
Object? metaData = null, Object? metaData = null,
Object? httpRequestModel = null, Object? httpRequestModel = freezed,
Object? aiRequestModel = freezed,
Object? httpResponseModel = null, Object? httpResponseModel = null,
Object? preRequestScript = freezed, Object? preRequestScript = freezed,
Object? postRequestScript = freezed, Object? postRequestScript = freezed,
@@ -216,10 +246,14 @@ class __$$HistoryRequestModelImplCopyWithImpl<$Res>
? _value.metaData ? _value.metaData
: metaData // ignore: cast_nullable_to_non_nullable : metaData // ignore: cast_nullable_to_non_nullable
as HistoryMetaModel, as HistoryMetaModel,
httpRequestModel: null == httpRequestModel httpRequestModel: freezed == httpRequestModel
? _value.httpRequestModel ? _value.httpRequestModel
: httpRequestModel // ignore: cast_nullable_to_non_nullable : httpRequestModel // ignore: cast_nullable_to_non_nullable
as HttpRequestModel, as HttpRequestModel?,
aiRequestModel: freezed == aiRequestModel
? _value.aiRequestModel
: aiRequestModel // ignore: cast_nullable_to_non_nullable
as AIRequestModel?,
httpResponseModel: null == httpResponseModel httpResponseModel: null == httpResponseModel
? _value.httpResponseModel ? _value.httpResponseModel
: httpResponseModel // ignore: cast_nullable_to_non_nullable : httpResponseModel // ignore: cast_nullable_to_non_nullable
@@ -247,7 +281,8 @@ class _$HistoryRequestModelImpl implements _HistoryRequestModel {
const _$HistoryRequestModelImpl( const _$HistoryRequestModelImpl(
{required this.historyId, {required this.historyId,
required this.metaData, required this.metaData,
required this.httpRequestModel, this.httpRequestModel,
this.aiRequestModel,
required this.httpResponseModel, required this.httpResponseModel,
this.preRequestScript, this.preRequestScript,
this.postRequestScript, this.postRequestScript,
@@ -261,7 +296,9 @@ class _$HistoryRequestModelImpl implements _HistoryRequestModel {
@override @override
final HistoryMetaModel metaData; final HistoryMetaModel metaData;
@override @override
final HttpRequestModel httpRequestModel; final HttpRequestModel? httpRequestModel;
@override
final AIRequestModel? aiRequestModel;
@override @override
final HttpResponseModel httpResponseModel; final HttpResponseModel httpResponseModel;
@override @override
@@ -273,7 +310,7 @@ class _$HistoryRequestModelImpl implements _HistoryRequestModel {
@override @override
String toString() { String toString() {
return 'HistoryRequestModel(historyId: $historyId, metaData: $metaData, httpRequestModel: $httpRequestModel, httpResponseModel: $httpResponseModel, preRequestScript: $preRequestScript, postRequestScript: $postRequestScript, authModel: $authModel)'; return 'HistoryRequestModel(historyId: $historyId, metaData: $metaData, httpRequestModel: $httpRequestModel, aiRequestModel: $aiRequestModel, httpResponseModel: $httpResponseModel, preRequestScript: $preRequestScript, postRequestScript: $postRequestScript, authModel: $authModel)';
} }
@override @override
@@ -287,6 +324,8 @@ class _$HistoryRequestModelImpl implements _HistoryRequestModel {
other.metaData == metaData) && other.metaData == metaData) &&
(identical(other.httpRequestModel, httpRequestModel) || (identical(other.httpRequestModel, httpRequestModel) ||
other.httpRequestModel == httpRequestModel) && other.httpRequestModel == httpRequestModel) &&
(identical(other.aiRequestModel, aiRequestModel) ||
other.aiRequestModel == aiRequestModel) &&
(identical(other.httpResponseModel, httpResponseModel) || (identical(other.httpResponseModel, httpResponseModel) ||
other.httpResponseModel == httpResponseModel) && other.httpResponseModel == httpResponseModel) &&
(identical(other.preRequestScript, preRequestScript) || (identical(other.preRequestScript, preRequestScript) ||
@@ -304,6 +343,7 @@ class _$HistoryRequestModelImpl implements _HistoryRequestModel {
historyId, historyId,
metaData, metaData,
httpRequestModel, httpRequestModel,
aiRequestModel,
httpResponseModel, httpResponseModel,
preRequestScript, preRequestScript,
postRequestScript, postRequestScript,
@@ -330,7 +370,8 @@ abstract class _HistoryRequestModel implements HistoryRequestModel {
const factory _HistoryRequestModel( const factory _HistoryRequestModel(
{required final String historyId, {required final String historyId,
required final HistoryMetaModel metaData, required final HistoryMetaModel metaData,
required final HttpRequestModel httpRequestModel, final HttpRequestModel? httpRequestModel,
final AIRequestModel? aiRequestModel,
required final HttpResponseModel httpResponseModel, required final HttpResponseModel httpResponseModel,
final String? preRequestScript, final String? preRequestScript,
final String? postRequestScript, final String? postRequestScript,
@@ -344,7 +385,9 @@ abstract class _HistoryRequestModel implements HistoryRequestModel {
@override @override
HistoryMetaModel get metaData; HistoryMetaModel get metaData;
@override @override
HttpRequestModel get httpRequestModel; HttpRequestModel? get httpRequestModel;
@override
AIRequestModel? get aiRequestModel;
@override @override
HttpResponseModel get httpResponseModel; HttpResponseModel get httpResponseModel;
@override @override

View File

@@ -11,8 +11,14 @@ _$HistoryRequestModelImpl _$$HistoryRequestModelImplFromJson(Map json) =>
historyId: json['historyId'] as String, historyId: json['historyId'] as String,
metaData: HistoryMetaModel.fromJson( metaData: HistoryMetaModel.fromJson(
Map<String, Object?>.from(json['metaData'] as Map)), Map<String, Object?>.from(json['metaData'] as Map)),
httpRequestModel: HttpRequestModel.fromJson( httpRequestModel: json['httpRequestModel'] == null
? null
: HttpRequestModel.fromJson(
Map<String, Object?>.from(json['httpRequestModel'] as Map)), Map<String, Object?>.from(json['httpRequestModel'] as Map)),
aiRequestModel: json['aiRequestModel'] == null
? null
: AIRequestModel.fromJson(
Map<String, Object?>.from(json['aiRequestModel'] as Map)),
httpResponseModel: HttpResponseModel.fromJson( httpResponseModel: HttpResponseModel.fromJson(
Map<String, Object?>.from(json['httpResponseModel'] as Map)), Map<String, Object?>.from(json['httpResponseModel'] as Map)),
preRequestScript: json['preRequestScript'] as String?, preRequestScript: json['preRequestScript'] as String?,
@@ -28,7 +34,8 @@ Map<String, dynamic> _$$HistoryRequestModelImplToJson(
<String, dynamic>{ <String, dynamic>{
'historyId': instance.historyId, 'historyId': instance.historyId,
'metaData': instance.metaData.toJson(), 'metaData': instance.metaData.toJson(),
'httpRequestModel': instance.httpRequestModel.toJson(), 'httpRequestModel': instance.httpRequestModel?.toJson(),
'aiRequestModel': instance.aiRequestModel?.toJson(),
'httpResponseModel': instance.httpResponseModel.toJson(), 'httpResponseModel': instance.httpResponseModel.toJson(),
'preRequestScript': instance.preRequestScript, 'preRequestScript': instance.preRequestScript,
'postRequestScript': instance.postRequestScript, 'postRequestScript': instance.postRequestScript,

View File

@@ -187,10 +187,15 @@ class CollectionStateNotifier
var itemIds = ref.read(requestSequenceProvider); var itemIds = ref.read(requestSequenceProvider);
var currentModel = historyRequestModel; var currentModel = historyRequestModel;
final aT = currentModel.aiRequestModel != null ? APIType.ai : APIType.rest;
final newModel = RequestModel( final newModel = RequestModel(
apiType: aT,
id: newId, id: newId,
name: "${currentModel.metaData.name} (history)", name: "${currentModel.metaData.name} (history)",
httpRequestModel: currentModel.httpRequestModel, aiRequestModel: currentModel.aiRequestModel,
httpRequestModel: currentModel.httpRequestModel ?? HttpRequestModel(),
responseStatus: currentModel.metaData.responseStatus, responseStatus: currentModel.metaData.responseStatus,
message: kResponseCodeReasons[currentModel.metaData.responseStatus], message: kResponseCodeReasons[currentModel.metaData.responseStatus],
httpResponseModel: currentModel.httpResponseModel, httpResponseModel: currentModel.httpResponseModel,
@@ -461,6 +466,7 @@ class CollectionStateNotifier
timeStamp: DateTime.now(), timeStamp: DateTime.now(),
), ),
httpRequestModel: substitutedHttpRequestModel, httpRequestModel: substitutedHttpRequestModel,
aiRequestModel: aiRequestModel,
httpResponseModel: httpResponseModel!, httpResponseModel: httpResponseModel!,
preRequestScript: requestModel.preRequestScript, preRequestScript: requestModel.preRequestScript,
postRequestScript: requestModel.postRequestScript, postRequestScript: requestModel.postRequestScript,

View File

@@ -28,6 +28,13 @@ class CodePane extends ConsumerWidget {
final selectedRequestModel = isHistoryRequest final selectedRequestModel = isHistoryRequest
? getRequestModelFromHistoryModel(selectedHistoryRequestModel!) ? getRequestModelFromHistoryModel(selectedHistoryRequestModel!)
: ref.watch(selectedRequestModelProvider); : ref.watch(selectedRequestModelProvider);
if (selectedRequestModel!.apiType == APIType.ai) {
return const ErrorMessage(
message: "Code generation for AI Requests is currently not available.",
);
}
final defaultUriScheme = final defaultUriScheme =
ref.watch(settingsProvider.select((value) => value.defaultUriScheme)); ref.watch(settingsProvider.select((value) => value.defaultUriScheme));

View File

@@ -0,0 +1,178 @@
import 'package:apidash/providers/collection_providers.dart';
import 'package:apidash/providers/history_providers.dart';
import 'package:apidash/widgets/editor.dart';
import 'package:apidash_design_system/tokens/measurements.dart';
import 'package:apidash_design_system/widgets/textfield_outlined.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:genai/llm_config.dart';
import 'package:genai/widgets/ai_config_widgets.dart';
class HisAIRequestPromptSection extends ConsumerWidget {
const HisAIRequestPromptSection({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final selectedHistoryModel =
ref.watch(selectedHistoryRequestModelProvider)!;
final aiReqM = selectedHistoryModel.aiRequestModel!;
final payload = aiReqM.payload;
final systemPrompt = payload.systemPrompt;
final userPrompt = payload.userPrompt;
return Container(
padding: EdgeInsets.symmetric(vertical: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(left: 25.0),
child: Text(
'System Prompt',
),
),
kVSpacer10,
Expanded(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 20),
child: TextFieldEditor(
key: Key(
"${selectedHistoryModel.historyId}-aireq-sysprompt-body"),
fieldKey:
"${selectedHistoryModel.historyId}-aireq-sysprompt-body",
initialValue: systemPrompt,
readOnly: true,
),
),
),
SizedBox(height: 10),
Padding(
padding: const EdgeInsets.only(left: 25.0),
child: Text(
'User Prompt / Input',
),
),
kVSpacer10,
Expanded(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 20),
child: TextFieldEditor(
key: Key(
"${selectedHistoryModel.historyId}-aireq-userprompt-body"),
fieldKey:
"${selectedHistoryModel.historyId}-aireq-userprompt-body",
initialValue: userPrompt,
readOnly: true,
),
),
),
],
),
);
}
}
class HisAIRequestAuthorizationSection extends ConsumerWidget {
const HisAIRequestAuthorizationSection({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final selectedHistoryModel =
ref.watch(selectedHistoryRequestModelProvider)!;
final aiReqM = selectedHistoryModel.aiRequestModel!;
final payload = aiReqM.payload;
final cred = payload.credential;
return Container(
padding: EdgeInsets.symmetric(vertical: 20),
child: Column(
children: [
Expanded(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 20),
child: TextFieldEditor(
key: Key(
"${selectedHistoryModel.historyId}-aireq-authvalue-body"),
fieldKey:
"${selectedHistoryModel.historyId}-aireq-authvalue-body",
initialValue: cred,
readOnly: true,
),
),
),
],
),
);
}
}
class HisAIRequestConfigSection extends ConsumerWidget {
const HisAIRequestConfigSection({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final selectedHistoryModel =
ref.watch(selectedHistoryRequestModelProvider)!;
final aiReqM = selectedHistoryModel.aiRequestModel!;
final payload = aiReqM.payload;
return SingleChildScrollView(
padding: EdgeInsets.symmetric(vertical: 20),
child: Column(
key: ValueKey(selectedHistoryModel.historyId),
children: [
...payload.configMap.values.map(
(el) => ListTile(
title: Text(el.configName),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
el.configDescription,
),
SizedBox(height: 5),
if (el.configType == LLMModelConfigurationType.boolean) ...[
BooleanAIConfig(
readonly: true,
configuration: el,
onConfigUpdated: (x) {},
),
] else if (el.configType ==
LLMModelConfigurationType.numeric) ...[
WritableAIConfig(
configuration: el,
onConfigUpdated: (x) {},
readonly: true,
numeric: true,
),
] else if (el.configType ==
LLMModelConfigurationType.text) ...[
WritableAIConfig(
configuration: el,
onConfigUpdated: (x) {},
readonly: true,
),
] else if (el.configType ==
LLMModelConfigurationType.slider) ...[
SliderAIConfig(
configuration: el,
onSliderUpdated: (x) {},
readonly: true,
),
],
SizedBox(height: 10),
],
),
),
),
],
),
);
}
}

View File

@@ -1,3 +1,4 @@
import 'package:apidash/screens/history/history_widgets/ai_history_page.dart';
import 'package:apidash_core/apidash_core.dart'; import 'package:apidash_core/apidash_core.dart';
import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:apidash_design_system/apidash_design_system.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@@ -22,22 +23,38 @@ class HistoryRequestPane extends ConsumerWidget {
final codePaneVisible = ref.watch(historyCodePaneVisibleStateProvider); final codePaneVisible = ref.watch(historyCodePaneVisibleStateProvider);
final apiType = ref.watch(selectedHistoryRequestModelProvider final apiType = ref.watch(selectedHistoryRequestModelProvider
.select((value) => value?.metaData.apiType)); .select((value) => value?.metaData.apiType));
final headersMap = ref.watch(selectedHistoryRequestModelProvider
.select((value) => value?.httpRequestModel.headersMap)) ?? final headersMap = ref.watch(selectedHistoryRequestModelProvider.select(
(value) {
if (apiType == APIType.ai) return <String, String>{};
return value?.httpRequestModel!.headersMap;
},
)) ??
{}; {};
final headerLength = headersMap.length; final headerLength = headersMap.length;
final paramsMap = ref.watch(selectedHistoryRequestModelProvider final paramsMap = ref.watch(selectedHistoryRequestModelProvider.select(
.select((value) => value?.httpRequestModel.paramsMap)) ?? (value) {
if (apiType == APIType.ai) return <String, String>{};
return value?.httpRequestModel!.paramsMap;
},
)) ??
{}; {};
final paramLength = paramsMap.length; final paramLength = paramsMap.length;
final hasBody = ref.watch(selectedHistoryRequestModelProvider final hasBody = ref.watch(selectedHistoryRequestModelProvider.select(
.select((value) => value?.httpRequestModel.hasBody)) ?? (value) {
if (apiType == APIType.ai) return false;
return value?.httpRequestModel!.hasBody;
},
)) ??
false; false;
final hasQuery = ref.watch(selectedHistoryRequestModelProvider final hasQuery =
.select((value) => value?.httpRequestModel.hasQuery)) ?? ref.watch(selectedHistoryRequestModelProvider.select((value) {
if (apiType == APIType.ai) return false;
return value?.httpRequestModel!.hasQuery;
})) ??
false; false;
final scriptsLength = ref.watch(selectedHistoryRequestModelProvider final scriptsLength = ref.watch(selectedHistoryRequestModelProvider
@@ -127,7 +144,27 @@ class HistoryRequestPane extends ConsumerWidget {
const HistoryScriptsTab(), const HistoryScriptsTab(),
], ],
), ),
APIType.ai => FlutterLogo(), APIType.ai => RequestPane(
key: const Key("history-request-pane-ai"),
selectedId: selectedId,
codePaneVisible: codePaneVisible,
onPressedCodeButton: () {
ref.read(historyCodePaneVisibleStateProvider.notifier).state =
!codePaneVisible;
},
showViewCodeButton: !isCompact,
showIndicators: [
false,
false,
false,
],
tabLabels: const ["Prompts", "Authorization", "Configuration"],
children: [
const HisAIRequestPromptSection(),
const HisAIRequestAuthorizationSection(),
const HisAIRequestConfigSection(),
],
),
_ => kSizedBoxEmpty, _ => kSizedBoxEmpty,
}; };
} }

View File

@@ -13,16 +13,20 @@ class HistoryResponsePane extends ConsumerWidget {
final selectedId = ref.watch(selectedHistoryIdStateProvider); final selectedId = ref.watch(selectedHistoryIdStateProvider);
final selectedHistoryRequest = final selectedHistoryRequest =
ref.watch(selectedHistoryRequestModelProvider); ref.watch(selectedHistoryRequestModelProvider);
final historyHttpResponseModel = selectedHistoryRequest?.httpResponseModel; final historyHttpResponseModel = selectedHistoryRequest?.httpResponseModel;
if (selectedId != null) { if (selectedId != null) {
final requestModel = final requestModel =
getRequestModelFromHistoryModel(selectedHistoryRequest!); getRequestModelFromHistoryModel(selectedHistoryRequest!);
final statusCode = historyHttpResponseModel?.statusCode;
return Column( return Column(
children: [ children: [
ResponsePaneHeader( ResponsePaneHeader(
responseStatus: historyHttpResponseModel?.statusCode, responseStatus: statusCode,
message: kResponseCodeReasons[historyHttpResponseModel?.statusCode], message: kResponseCodeReasons[statusCode],
time: historyHttpResponseModel?.time, time: historyHttpResponseModel?.time,
), ),
Expanded( Expanded(

View File

@@ -13,6 +13,7 @@ RequestModel getRequestModelFromHistoryModel(HistoryRequestModel model) {
name: model.metaData.name, name: model.metaData.name,
responseStatus: model.httpResponseModel.statusCode, responseStatus: model.httpResponseModel.statusCode,
message: kResponseCodeReasons[model.httpResponseModel.statusCode], message: kResponseCodeReasons[model.httpResponseModel.statusCode],
aiRequestModel: model.aiRequestModel,
httpRequestModel: model.httpRequestModel, httpRequestModel: model.httpRequestModel,
httpResponseModel: model.httpResponseModel, httpResponseModel: model.httpResponseModel,
); );

View File

@@ -4,10 +4,12 @@ import 'package:genai/llm_config.dart';
class SliderAIConfig extends StatelessWidget { class SliderAIConfig extends StatelessWidget {
final LLMModelConfiguration configuration; final LLMModelConfiguration configuration;
final Function(LLMModelConfiguration) onSliderUpdated; final Function(LLMModelConfiguration) onSliderUpdated;
final bool readonly;
const SliderAIConfig({ const SliderAIConfig({
super.key, super.key,
required this.configuration, required this.configuration,
required this.onSliderUpdated, required this.onSliderUpdated,
this.readonly = false,
}); });
@override @override
@@ -23,6 +25,7 @@ class SliderAIConfig extends StatelessWidget {
max: (configuration.configValue.value as (double, double, double)) max: (configuration.configValue.value as (double, double, double))
.$3, .$3,
onChanged: (x) { onChanged: (x) {
if (readonly) return;
final z = final z =
configuration.configValue.value as (double, double, double); configuration.configValue.value as (double, double, double);
configuration.configValue.value = (z.$1, x, z.$3); configuration.configValue.value = (z.$1, x, z.$3);
@@ -43,11 +46,13 @@ class WritableAIConfig extends StatelessWidget {
final bool numeric; final bool numeric;
final LLMModelConfiguration configuration; final LLMModelConfiguration configuration;
final Function(LLMModelConfiguration) onConfigUpdated; final Function(LLMModelConfiguration) onConfigUpdated;
final bool readonly;
const WritableAIConfig({ const WritableAIConfig({
super.key, super.key,
this.numeric = false, this.numeric = false,
required this.configuration, required this.configuration,
required this.onConfigUpdated, required this.onConfigUpdated,
this.readonly = false,
}); });
@override @override
@@ -55,6 +60,7 @@ class WritableAIConfig extends StatelessWidget {
return TextFormField( return TextFormField(
initialValue: configuration.configValue.value.toString(), initialValue: configuration.configValue.value.toString(),
onChanged: (x) { onChanged: (x) {
if (readonly) return;
if (numeric) { if (numeric) {
if (x.isEmpty) x = '0'; if (x.isEmpty) x = '0';
if (num.tryParse(x) == null) return; if (num.tryParse(x) == null) return;
@@ -71,10 +77,12 @@ class WritableAIConfig extends StatelessWidget {
class BooleanAIConfig extends StatelessWidget { class BooleanAIConfig extends StatelessWidget {
final LLMModelConfiguration configuration; final LLMModelConfiguration configuration;
final Function(LLMModelConfiguration) onConfigUpdated; final Function(LLMModelConfiguration) onConfigUpdated;
final bool readonly;
const BooleanAIConfig({ const BooleanAIConfig({
super.key, super.key,
required this.configuration, required this.configuration,
required this.onConfigUpdated, required this.onConfigUpdated,
this.readonly = false,
}); });
@override @override
@@ -82,6 +90,7 @@ class BooleanAIConfig extends StatelessWidget {
return Switch( return Switch(
value: configuration.configValue.value as bool, value: configuration.configValue.value as bool,
onChanged: (x) { onChanged: (x) {
if (readonly) return;
configuration.configValue.value = x; configuration.configValue.value = x;
onConfigUpdated(configuration); onConfigUpdated(configuration);
}, },

View File

@@ -31,7 +31,7 @@ void main() {
expect( expect(
find.text( find.text(
historyRequestModel.httpRequestModel.method.name.toUpperCase()), historyRequestModel.httpRequestModel!.method.name.toUpperCase()),
findsOneWidget); findsOneWidget);
}); });
@@ -45,7 +45,7 @@ void main() {
); );
expect( expect(
find.text(historyRequestModel.httpRequestModel.url), findsOneWidget); find.text(historyRequestModel.httpRequestModel!.url), findsOneWidget);
}); });
}); });
} }