From 07d4c2da37313dfec8af18f532b81d7e718b1af9 Mon Sep 17 00:00:00 2001 From: Wilielmus <88447902+WilliamKarolDiCioccio@users.noreply.github.com> Date: Wed, 18 Sep 2024 15:43:41 +0200 Subject: [PATCH] Add quick access to models settings in chat page --- app/lib/frontend/dialogs/model_settings.dart | 30 +++- app/lib/frontend/pages/dashboard/models.dart | 2 +- app/lib/frontend/widgets/chat_toolbar.dart | 147 ++++++++++--------- 3 files changed, 101 insertions(+), 78 deletions(-) diff --git a/app/lib/frontend/dialogs/model_settings.dart b/app/lib/frontend/dialogs/model_settings.dart index 4ee5cb3..e513f9b 100644 --- a/app/lib/frontend/dialogs/model_settings.dart +++ b/app/lib/frontend/dialogs/model_settings.dart @@ -6,23 +6,34 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart'; import 'package:gap/gap.dart'; import 'package:open_local_ui/backend/private/models/model.dart'; +import 'package:open_local_ui/backend/private/providers/model.dart'; import 'package:open_local_ui/backend/private/providers/model_settings.dart'; import 'package:provider/provider.dart'; import 'package:unicons/unicons.dart'; class ModelSettingsDialog extends StatefulWidget { - final Model model; + final String modelName; - const ModelSettingsDialog({super.key, required this.model}); + const ModelSettingsDialog({super.key, required this.modelName}); @override ModelSettingsDialogState createState() => ModelSettingsDialogState(); } class ModelSettingsDialogState extends State { + late Model _model; late ModelSettings _settings; final TextEditingController _controller = TextEditingController(); + @override + void initState() { + _model = context.read().models.firstWhere( + (model) => model.name == widget.modelName, + ); + + super.initState(); + } + @override void dispose() { _controller.dispose(); @@ -33,14 +44,14 @@ class ModelSettingsDialogState extends State { Widget build(BuildContext context) { late String modelName; - if (widget.model.name.length > 20) { - modelName = '${widget.model.name.substring(0, 20)}...'; + if (_model.name.length > 20) { + modelName = '${_model.name.substring(0, 20)}...'; } else { - modelName = widget.model.name; + modelName = _model.name; } return ChangeNotifierProvider( - create: (context) => ModelSettingsProvider(widget.model.name), + create: (context) => ModelSettingsProvider(_model.name), builder: (context, _) => AlertDialog( title: Text( AppLocalizations.of(context) @@ -346,11 +357,14 @@ class ModelSettingsDialogState extends State { } } -Future showModelSettingsDialog(Model model, BuildContext context) async { +Future showModelSettingsDialog( + String modelName, + BuildContext context, +) async { return showDialog( context: context, builder: (BuildContext context) { - return ModelSettingsDialog(model: model); + return ModelSettingsDialog(modelName: modelName); }, ); } diff --git a/app/lib/frontend/pages/dashboard/models.dart b/app/lib/frontend/pages/dashboard/models.dart index c4f7898..9e16ceb 100644 --- a/app/lib/frontend/pages/dashboard/models.dart +++ b/app/lib/frontend/pages/dashboard/models.dart @@ -491,7 +491,7 @@ class _ModelListTileState extends State { AppLocalizations.of(context).snackBarWarningTitle, AppLocalizations.of(context).enteringCriticalSectionSnackBar, SnackbarContentType.warning, - onTap: () => showModelSettingsDialog(widget.model, context), + onTap: () => showModelSettingsDialog(widget.model.name, context), ), ), const Gap(8), diff --git a/app/lib/frontend/widgets/chat_toolbar.dart b/app/lib/frontend/widgets/chat_toolbar.dart index 08886c7..db80b2e 100644 --- a/app/lib/frontend/widgets/chat_toolbar.dart +++ b/app/lib/frontend/widgets/chat_toolbar.dart @@ -6,6 +6,7 @@ import 'package:gap/gap.dart'; import 'package:open_local_ui/backend/private/providers/chat.dart'; import 'package:open_local_ui/backend/private/providers/model.dart'; import 'package:open_local_ui/core/snackbar.dart'; +import 'package:open_local_ui/frontend/dialogs/model_settings.dart'; import 'package:provider/provider.dart'; import 'package:unicons/unicons.dart'; @@ -43,35 +44,56 @@ class _ChatToolbarWidgetState extends State { } } - @override - Widget build(BuildContext context) { - return Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const ChatModelSelectionWidget(), - const Gap(16), - // const ChatOptionBarWidget(), - // const Gap(16), - ElevatedButton.icon( - label: Text( - AppLocalizations.of(context).chatToolbarNewSessionButton, - style: const TextStyle(fontSize: 18.0), + Widget _buildModelSelectionWidget(BuildContext context) { + final List modelsMenuEntries = []; + + for (final model in context.read().models) { + late String modelName; + + if (model.name.length > 20) { + modelName = '${model.name.substring(0, 20)}...'; + } else { + modelName = model.name; + } + + modelsMenuEntries.add( + DropdownMenuEntry( + value: model.name, + label: modelName, + ), + ); + } + + return DropdownMenu( + key: const Key('model_selector'), + enabled: context.watch().modelsCount > 0 && + !context.watch().isGenerating, + menuHeight: 128, + menuStyle: MenuStyle( + elevation: WidgetStateProperty.all( + 8.0, + ), + shape: WidgetStateProperty.all( + const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(16.0)), ), - icon: const Icon(UniconsLine.plus), - onPressed: !context.watch().isGenerating - ? () => _newSession() - : null, ), - ], + ), + inputDecorationTheme: InputDecorationTheme( + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(16.0), + ), + ), + enableSearch: true, + hintText: AppLocalizations.of(context).chatToolbarModelSelectorHint, + initialSelection: context.watch().modelName, + dropdownMenuEntries: modelsMenuEntries, + onSelected: (value) => context.read().setModel(value ?? ''), ); } -} - -class ChatOptionBarWidget extends StatelessWidget { - const ChatOptionBarWidget({super.key}); - @override - Widget build(BuildContext context) { + // ignore: unused_element + Widget _buildChatOptionBarWidget(BuildContext context) { return Container( decoration: BoxDecoration( border: Border.all( @@ -115,56 +137,43 @@ class ChatOptionBarWidget extends StatelessWidget { ), ); } -} - -class ChatModelSelectionWidget extends StatelessWidget { - const ChatModelSelectionWidget({super.key}); @override Widget build(BuildContext context) { - final List modelsMenuEntries = []; - - for (final model in context.read().models) { - late String modelName; - - if (model.name.length > 20) { - modelName = '${model.name.substring(0, 20)}...'; - } else { - modelName = model.name; - } - - modelsMenuEntries.add( - DropdownMenuEntry( - value: model.name, - label: modelName, - ), - ); - } - - return DropdownMenu( - enabled: context.watch().modelsCount > 0 && - !context.watch().isGenerating, - menuHeight: 128, - menuStyle: MenuStyle( - elevation: WidgetStateProperty.all( - 8.0, - ), - shape: WidgetStateProperty.all( - const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(16.0)), + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (context.read().modelName.isNotEmpty) + IconButton( + tooltip: AppLocalizations.of(context).modelsPageSettingsButton, + icon: const Icon(UniconsLine.setting), + onPressed: () => SnackBarHelpers.showSnackBar( + AppLocalizations.of(context).snackBarWarningTitle, + AppLocalizations.of(context).enteringCriticalSectionSnackBar, + SnackbarContentType.warning, + onTap: () => showModelSettingsDialog( + context.read().modelName, + context, + ), + ), ), + if (context.read().modelName.isNotEmpty) const Gap(16), + _buildModelSelectionWidget(context), + const Gap(16), + // _buildChatOptionBarWidget(context), + // const Gap(16), + ElevatedButton.icon( + key: const Key('new_session_button'), + label: Text( + AppLocalizations.of(context).chatToolbarNewSessionButton, + style: const TextStyle(fontSize: 18.0), + ), + icon: const Icon(UniconsLine.plus), + onPressed: !context.watch().isGenerating + ? () => _newSession() + : null, ), - ), - inputDecorationTheme: InputDecorationTheme( - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(16.0), - ), - ), - enableSearch: true, - hintText: AppLocalizations.of(context).chatToolbarModelSelectorHint, - initialSelection: context.watch().modelName, - dropdownMenuEntries: modelsMenuEntries, - onSelected: (value) => context.read().setModel(value ?? ''), + ], ); } }