From 9d50e3f09c514c07b8c2eb3cfe972d8017c1720b Mon Sep 17 00:00:00 2001 From: Ankit Mahato Date: Fri, 29 Aug 2025 01:27:32 +0530 Subject: [PATCH] Add default AI model selection to settings Replaces the previous placeholder for default LLM selection with a working default AI model selector in settings. Updates SettingsModel and related providers to support storing and updating the default AI model as a JSON object. Integrates the selector UI and ensures new AI requests use the default model if set. --- lib/models/settings_model.dart | 40 +++++-------------- lib/providers/collection_providers.dart | 5 ++- lib/providers/settings_providers.dart | 6 +-- .../ai/ai_model_selector_dialog.dart | 4 ++ lib/screens/common_widgets/code_pane.dart | 3 +- lib/screens/settings_page.dart | 31 ++++++++------ 6 files changed, 41 insertions(+), 48 deletions(-) diff --git a/lib/models/settings_model.dart b/lib/models/settings_model.dart index 47382f6e..71a58ebb 100644 --- a/lib/models/settings_model.dart +++ b/lib/models/settings_model.dart @@ -18,8 +18,7 @@ class SettingsModel { this.workspaceFolderPath, this.isSSLDisabled = false, this.isDashBotEnabled = true, - // TODO: Fix it - // this.defaultLLMSaveObject, + this.defaultAIModel, }); final bool isDark; @@ -35,8 +34,7 @@ class SettingsModel { final String? workspaceFolderPath; final bool isSSLDisabled; final bool isDashBotEnabled; - // TODO: Fix it - // final LLMSaveObject? defaultLLMSaveObject; + final Map? defaultAIModel; SettingsModel copyWith({ bool? isDark, @@ -52,9 +50,7 @@ class SettingsModel { String? workspaceFolderPath, bool? isSSLDisabled, bool? isDashBotEnabled, - // TODO: Fix it - // LLMSaveObject? def, - // LLMSaveObject? defaultLLMSaveObject, + Map? defaultAIModel, }) { return SettingsModel( isDark: isDark ?? this.isDark, @@ -72,8 +68,7 @@ class SettingsModel { workspaceFolderPath: workspaceFolderPath ?? this.workspaceFolderPath, isSSLDisabled: isSSLDisabled ?? this.isSSLDisabled, isDashBotEnabled: isDashBotEnabled ?? this.isDashBotEnabled, - // TODO: Fix it - // defaultLLMSaveObject: defaultLLMSaveObject ?? this.defaultLLMSaveObject, + defaultAIModel: defaultAIModel ?? this.defaultAIModel, ); } @@ -94,8 +89,7 @@ class SettingsModel { workspaceFolderPath: workspaceFolderPath, isSSLDisabled: isSSLDisabled, isDashBotEnabled: isDashBotEnabled, - // TODO: Fix it - // defaultLLMSaveObject: defaultLLMSaveObject, + defaultAIModel: defaultAIModel, ); } @@ -151,14 +145,7 @@ class SettingsModel { final workspaceFolderPath = data["workspaceFolderPath"] as String?; final isSSLDisabled = data["isSSLDisabled"] as bool?; final isDashBotEnabled = data["isDashBotEnabled"] as bool?; - - // TODO: Fix it - // LLMSaveObject? defaultLLMSaveObject; - // if (data["defaultLLMSaveObject"] != null) { - // defaultLLMSaveObject = - // LLMSaveObject.fromJSON(data["defaultLLMSaveObject"]); - // } - + final defaultAIModel = data["defaultAIModel"] as Map?; const sm = SettingsModel(); return sm.copyWith( @@ -176,8 +163,7 @@ class SettingsModel { workspaceFolderPath: workspaceFolderPath, isSSLDisabled: isSSLDisabled, isDashBotEnabled: isDashBotEnabled, - // TODO: Fix it - // defaultLLMSaveObject: defaultLLMSaveObject, + defaultAIModel: defaultAIModel, ); } @@ -198,8 +184,7 @@ class SettingsModel { "workspaceFolderPath": workspaceFolderPath, "isSSLDisabled": isSSLDisabled, "isDashBotEnabled": isDashBotEnabled, - // TODO: Fix it - // 'defaultLLMSaveObject': defaultLLMSaveObject?.toJSON(), + 'defaultLLMSaveObject': defaultAIModel, }; } @@ -225,10 +210,8 @@ class SettingsModel { other.historyRetentionPeriod == historyRetentionPeriod && other.workspaceFolderPath == workspaceFolderPath && other.isSSLDisabled == isSSLDisabled && - other.isDashBotEnabled == isDashBotEnabled; - // TODO: Fix it - // && - // other.defaultLLMSaveObject == defaultLLMSaveObject; + other.isDashBotEnabled == isDashBotEnabled && + other.defaultAIModel == defaultAIModel; } @override @@ -248,8 +231,7 @@ class SettingsModel { workspaceFolderPath, isSSLDisabled, isDashBotEnabled, - // TODO: Fix it - // defaultLLMSaveObject, + defaultAIModel, ); } } diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index 3d9f91f0..c6e9db55 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -245,6 +245,7 @@ class CollectionStateNotifier RequestModel newModel; if (apiType != null && currentModel.apiType != apiType) { + final defaultModel = ref.read(settingsProvider).defaultAIModel; newModel = switch (apiType) { APIType.rest || APIType.graphql => currentModel.copyWith( apiType: apiType, @@ -257,7 +258,9 @@ class CollectionStateNotifier name: name ?? currentModel.name, description: description ?? currentModel.description, httpRequestModel: null, - aiRequestModel: const AIRequestModel()), + aiRequestModel: defaultModel == null + ? const AIRequestModel() + : AIRequestModel.fromJson(defaultModel)), }; } else { newModel = currentModel.copyWith( diff --git a/lib/providers/settings_providers.dart b/lib/providers/settings_providers.dart index f4493abb..be09cc6e 100644 --- a/lib/providers/settings_providers.dart +++ b/lib/providers/settings_providers.dart @@ -34,8 +34,7 @@ class ThemeStateNotifier extends StateNotifier { String? workspaceFolderPath, bool? isSSLDisabled, bool? isDashBotEnabled, - // TODO: Fix it - // LLMSaveObject? defaultLLMSaveObject, + Map? defaultAIModel, }) async { state = state.copyWith( isDark: isDark, @@ -51,8 +50,7 @@ class ThemeStateNotifier extends StateNotifier { workspaceFolderPath: workspaceFolderPath, isSSLDisabled: isSSLDisabled, isDashBotEnabled: isDashBotEnabled, - // TODO: Fix it - // defaultLLMSaveObject: defaultLLMSaveObject, + defaultAIModel: defaultAIModel, ); await setSettingsToSharedPrefs(state); } diff --git a/lib/screens/common_widgets/ai/ai_model_selector_dialog.dart b/lib/screens/common_widgets/ai/ai_model_selector_dialog.dart index 9b6b53cb..be6f7e73 100644 --- a/lib/screens/common_widgets/ai/ai_model_selector_dialog.dart +++ b/lib/screens/common_widgets/ai/ai_model_selector_dialog.dart @@ -22,6 +22,10 @@ class _AIModelSelectorDialogState extends ConsumerState { @override void initState() { super.initState(); + selectedProvider = widget.aiRequestModel?.modelApiProvider; + if (selectedProvider != null && widget.aiRequestModel?.model != null) { + newAIRequestModel = widget.aiRequestModel?.copyWith(); + } aM = ModelManager.fetchAvailableModels(); } diff --git a/lib/screens/common_widgets/code_pane.dart b/lib/screens/common_widgets/code_pane.dart index c4031fae..5c08cc69 100644 --- a/lib/screens/common_widgets/code_pane.dart +++ b/lib/screens/common_widgets/code_pane.dart @@ -29,7 +29,8 @@ class CodePane extends ConsumerWidget { ? getRequestModelFromHistoryModel(selectedHistoryRequestModel!) : ref.watch(selectedRequestModelProvider); - if (selectedRequestModel!.apiType == APIType.ai) { + // TODO: Add AI Request Codegen + if (selectedRequestModel?.apiType == APIType.ai) { return const ErrorMessage( message: "Code generation for AI Requests is currently not available.", ); diff --git a/lib/screens/settings_page.dart b/lib/screens/settings_page.dart index 8131aadd..4da2a48f 100644 --- a/lib/screens/settings_page.dart +++ b/lib/screens/settings_page.dart @@ -1,3 +1,4 @@ +import 'package:apidash_core/apidash_core.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -7,6 +8,7 @@ import '../services/services.dart'; import '../utils/utils.dart'; import '../widgets/widgets.dart'; import '../consts.dart'; +import 'common_widgets/common_widgets.dart'; class SettingsPage extends ConsumerWidget { const SettingsPage({super.key}); @@ -114,19 +116,22 @@ class SettingsPage extends ConsumerWidget { }, ), ), - // TODO: Fix it - // ListTile( - // hoverColor: kColorTransparent, - // title: const Text('Default Large Language Model (LLM)'), - // trailing: DefaultLLMSelectorButton( - // defaultLLM: settings.defaultLLMSaveObject, - // onDefaultLLMUpdated: (d) { - // ref - // .read(settingsProvider.notifier) - // .update(defaultLLMSaveObject: d); - // }, - // ), - // ), + ListTile( + hoverColor: kColorTransparent, + title: const Text('Default Large Language Model (LLM)'), + trailing: AIModelSelectorButton( + aiRequestModel: + AIRequestModel.fromJson(settings.defaultAIModel ?? {}), + onModelUpdated: (d) { + ref.read(settingsProvider.notifier).update( + defaultAIModel: d.copyWith( + modelConfigs: [], + stream: null, + systemPrompt: '', + userPrompt: '').toJson()); + }, + ), + ), CheckboxListTile( title: const Text("Save Responses"), subtitle: