diff --git a/lib/screens/history/history_widgets/his_request_pane.dart b/lib/screens/history/history_widgets/his_request_pane.dart index 6766ad1b..73f61927 100644 --- a/lib/screens/history/history_widgets/his_request_pane.dart +++ b/lib/screens/history/history_widgets/his_request_pane.dart @@ -127,6 +127,7 @@ class HistoryRequestPane extends ConsumerWidget { const HistoryScriptsTab(), ], ), + APIType.ai => FlutterLogo(), _ => kSizedBoxEmpty, }; } @@ -204,6 +205,7 @@ class HisRequestBody extends ConsumerWidget { readOnly: true, ), ), + APIType.ai => FlutterLogo(), _ => kSizedBoxEmpty, }; } diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/ai_request/aireq_authorization.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/ai_request/aireq_authorization.dart new file mode 100644 index 00000000..cd5e0221 --- /dev/null +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/ai_request/aireq_authorization.dart @@ -0,0 +1,43 @@ +import 'package:apidash/providers/collection_providers.dart'; +import 'package:apidash/widgets/editor.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class AIRequestAuthorizationSection extends ConsumerWidget { + const AIRequestAuthorizationSection({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final selectedId = ref.watch(selectedIdStateProvider); + final reqM = ref.read(collectionStateNotifierProvider)![selectedId]!; + final aiReqM = reqM.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("$selectedId-aireq-authvalue-body"), + fieldKey: "$selectedId-aireq-authvalue-body", + initialValue: cred, + onChanged: (String value) { + payload.credential = value; + ref + .read(collectionStateNotifierProvider.notifier) + .update(aiRequestModel: aiReqM.updatePayload(payload)); + }, + hintText: 'Enter API key or Authorization Credentials', + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/ai_request/aireq_configs.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/ai_request/aireq_configs.dart new file mode 100644 index 00000000..b7b3d1ab --- /dev/null +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/ai_request/aireq_configs.dart @@ -0,0 +1,153 @@ +import 'package:apidash/providers/collection_providers.dart'; +import 'package:apidash/widgets/editor.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/genai.dart'; + +class AIRequestConfigSection extends ConsumerStatefulWidget { + const AIRequestConfigSection({super.key}); + + @override + ConsumerState createState() => + _AIRequestConfigSectionState(); +} + +class _AIRequestConfigSectionState + extends ConsumerState { + @override + Widget build(BuildContext context) { + final selectedId = ref.watch(selectedIdStateProvider); + final reqM = ref.read(collectionStateNotifierProvider)![selectedId]!; + final aiReqM = reqM.aiRequestModel!; + final payload = aiReqM.payload; + + return SingleChildScrollView( + padding: EdgeInsets.symmetric(vertical: 20), + child: Column( + key: ValueKey(selectedId), + children: [ + ...payload.configMap.values.map( + (el) => ListTile( + title: Text(el.configName), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + el.configDescription, + style: TextStyle(color: Colors.white30), + ), + SizedBox(height: 5), + if (el.configType == LLMModelConfigurationType.boolean) ...[ + Switch( + value: el.configValue.value as bool, + onChanged: (x) { + el.configValue.value = x; + payload.configMap[el.configId] = el; + ref + .read(collectionStateNotifierProvider.notifier) + .update( + aiRequestModel: aiReqM.updatePayload(payload), + ); + setState(() {}); + }, + ) + ] else if (el.configType == + LLMModelConfigurationType.numeric) ...[ + ADOutlinedTextField( + initialValue: el.configValue.value.toString(), + onChanged: (x) { + if (x.isEmpty) x = '0'; + if (num.tryParse(x) == null) return; + el.configValue.value = num.parse(x); + + payload.configMap[el.configId] = el; + ref + .read(collectionStateNotifierProvider.notifier) + .update( + aiRequestModel: aiReqM.updatePayload(payload), + ); + + setState(() {}); + }, + ) + ] else if (el.configType == + LLMModelConfigurationType.text) ...[ + ADOutlinedTextField( + initialValue: el.configValue.value.toString(), + onChanged: (x) { + el.configValue.value = x; + + payload.configMap[el.configId] = el; + ref + .read(collectionStateNotifierProvider.notifier) + .update( + aiRequestModel: aiReqM.updatePayload(payload), + ); + + setState(() {}); + }, + ) + ] else if (el.configType == + LLMModelConfigurationType.slider) ...[ + Row( + children: [ + Expanded( + child: Slider( + min: (el.configValue.value as ( + double, + double, + double + )) + .$1, + value: (el.configValue.value as ( + double, + double, + double + )) + .$2, + max: (el.configValue.value as ( + double, + double, + double + )) + .$3, + onChanged: (x) { + final z = el.configValue.value as ( + double, + double, + double + ); + el.configValue.value = (z.$1, x, z.$3); + + payload.configMap[el.configId] = el; + ref + .read( + collectionStateNotifierProvider.notifier) + .update( + aiRequestModel: + aiReqM.updatePayload(payload), + ); + + setState(() {}); + }, + ), + ), + Text((el.configValue.value as (double, double, double)) + .$2 + .toStringAsFixed(2)), + ], + ) + ], + SizedBox(height: 10), + // Divider(color: Colors.white10), + // SizedBox(height: 10), + ], + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/ai_request/aireq_prompt.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/ai_request/aireq_prompt.dart new file mode 100644 index 00000000..f090ca6e --- /dev/null +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/ai_request/aireq_prompt.dart @@ -0,0 +1,80 @@ +import 'package:apidash/providers/collection_providers.dart'; +import 'package:apidash/widgets/editor.dart'; +import 'package:apidash_design_system/tokens/measurements.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +class AIRequestPromptSection extends ConsumerWidget { + const AIRequestPromptSection({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final selectedId = ref.watch(selectedIdStateProvider); + final reqM = ref.read(collectionStateNotifierProvider)![selectedId]!; + final aiReqM = reqM.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', + style: TextStyle(color: Colors.white54), + ), + ), + kVSpacer10, + Expanded( + child: Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: TextFieldEditor( + key: Key("$selectedId-aireq-sysprompt-body"), + fieldKey: "$selectedId-aireq-sysprompt-body", + initialValue: systemPrompt, + onChanged: (String value) { + payload.systemPrompt = value; + ref + .read(collectionStateNotifierProvider.notifier) + .update(aiRequestModel: aiReqM.updatePayload(payload)); + }, + hintText: 'Enter System Prompt', + ), + ), + ), + SizedBox(height: 10), + Padding( + padding: const EdgeInsets.only(left: 25.0), + child: Text( + 'User Prompt / Input', + style: TextStyle(color: Colors.white54), + ), + ), + kVSpacer10, + Expanded( + child: Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: TextFieldEditor( + key: Key("$selectedId-aireq-userprompt-body"), + fieldKey: "$selectedId-aireq-userprompt-body", + initialValue: userPrompt, + onChanged: (String value) { + payload.userPrompt = value; + ref + .read(collectionStateNotifierProvider.notifier) + .update(aiRequestModel: aiReqM.updatePayload(payload)); + }, + hintText: 'Enter User Prompt', + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/ai_request/request_pane_ai.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/ai_request/request_pane_ai.dart new file mode 100644 index 00000000..5d219717 --- /dev/null +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/ai_request/request_pane_ai.dart @@ -0,0 +1,49 @@ +import 'package:apidash/screens/home_page/editor_pane/details_card/request_pane/ai_request/aireq_authorization.dart'; +import 'package:apidash/screens/home_page/editor_pane/details_card/request_pane/ai_request/aireq_configs.dart'; +import 'package:apidash/screens/home_page/editor_pane/details_card/request_pane/ai_request/aireq_prompt.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:apidash/providers/providers.dart'; +import 'package:apidash/widgets/widgets.dart'; + +class EditAIRequestPane extends ConsumerWidget { + const EditAIRequestPane({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final selectedId = ref.watch(selectedIdStateProvider); + final codePaneVisible = ref.watch(codePaneVisibleStateProvider); + final tabIndex = ref.watch( + selectedRequestModelProvider.select((value) => value?.requestTabIndex)); + + return RequestPane( + selectedId: selectedId, + codePaneVisible: false, + tabIndex: tabIndex, + onPressedCodeButton: () { + ref.read(codePaneVisibleStateProvider.notifier).state = + !codePaneVisible; + }, + onTapTabBar: (index) { + ref + .read(collectionStateNotifierProvider.notifier) + .update(requestTabIndex: index); + }, + showIndicators: [ + false, + false, + false, + ], + tabLabels: const [ + "Prompt", + "Authorization", + "Configurations", + ], + children: const [ + AIRequestPromptSection(), + AIRequestAuthorizationSection(), + AIRequestConfigSection(), + ], + ); + } +} diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart index e192f26e..91d80e41 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart @@ -92,6 +92,7 @@ class EditRequestBody extends ConsumerWidget { ), ), ), + APIType.ai => FlutterLogo(), _ => kSizedBoxEmpty, } ], diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane.dart index 9c852c71..40216103 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane.dart @@ -1,3 +1,4 @@ +import 'package:apidash/screens/home_page/editor_pane/details_card/request_pane/ai_request/request_pane_ai.dart'; import 'package:apidash_core/apidash_core.dart'; import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:flutter/material.dart'; @@ -17,6 +18,7 @@ class EditRequestPane extends ConsumerWidget { return switch (apiType) { APIType.rest => const EditRestRequestPane(), APIType.graphql => const EditGraphQLRequestPane(), + APIType.ai => const EditAIRequestPane(), _ => kSizedBoxEmpty, }; }