diff --git a/gai-frontend/lib/chat/chat.dart b/gai-frontend/lib/chat/chat.dart index 50238cd9d..561f465c3 100644 --- a/gai-frontend/lib/chat/chat.dart +++ b/gai-frontend/lib/chat/chat.dart @@ -58,14 +58,12 @@ class _ChatViewState extends State { _modelManager.getModelsOrDefault(_userSelectedModelIds); // Account - // This should be wrapped up in a provider. See WIP in vpn app. EthereumAddress? _funder; BigInt? _signerKey; AccountDetailPoller? _accountDetail; final _accountDetailNotifier = ValueNotifier(null); // Auth - // AuthTokenMethod _authTokenMethod = AuthTokenMethod.manual; String? _authToken; String? _inferenceUrl; String? _scriptURLParam; @@ -96,21 +94,12 @@ class _ChatViewState extends State { } void _initScripting() { - // final script = UserPreferencesScripts().userScript.get(); - // log('User script on start: $script'); - ChatScripting.init( // If a script URL is provided, it will be loaded. - // url: 'lib/extensions/filter_example.js', url: _scriptURLParam, - // If debugMode is true, the script will be re-loaded before each invocation - // debugMode: true, - - // Allow a provided script url param to override the stored script script: _scriptURLParam == null ? UserPreferencesScripts().userScript.get() : null, - providerManager: _providerManager, modelManager: _modelManager, getUserSelectedModels: () => _userSelectedModels, @@ -157,7 +146,6 @@ class _ChatViewState extends State { ); } - // This should be wrapped up in a provider. See WIP in vpn app. void _accountChanged() async { log("chat: accountChanged: $_account"); _accountDetail?.cancel(); @@ -247,7 +235,6 @@ class _ChatViewState extends State { _chatHistory.addMessage(message); }); scrollMessagesDown(); - // log('Chat history updated: ${_chatHistory.messages.length}, ${_chatHistory.messages}'); } void _updateSelectedModels(List modelIds) { @@ -272,7 +259,6 @@ class _ChatViewState extends State { initialInferenceUrl: _inferenceUrl, accountDetailNotifier: _accountDetailNotifier, onAccountChanged: (chain, funder, signerKey) { - // log('onAccountChanged: Account changed: $chain, $funder, $signerKey'); setState(() { _selectedChain = chain; _funder = funder; @@ -354,7 +340,6 @@ class _ChatViewState extends State { // Manage the prompt UI _promptTextController.clear(); - // FocusManager.instance.primaryFocus?.unfocus(); // ? // If we have a script selected allow it to handle the prompt if (ChatScripting.enabled) { @@ -390,7 +375,7 @@ class _ChatViewState extends State { if (chatResponse != null) { _handleChatResponseDefaultBehavior(chatResponse); } else { - // The provider connection should have logged the issue. Do nothing. + // The provider connection should have logged the issue. Do nothing. } } catch (e) { _addMessage( @@ -605,12 +590,16 @@ class _ChatViewState extends State { ).left(8), // Settings button - _buildSettingsButton(buttonHeight).left(8), + _buildSettingsButton( + buttonHeight, + authToken: _authToken ?? _providerManager.providerConnection?.inferenceClient?.authToken, + inferenceUrl: _inferenceUrl ?? _providerManager.providerConnection?.inferenceClient?.baseUrl, + ).left(8), ], ); } - SizedBox _buildSettingsButton(double buttonHeight) { + SizedBox _buildSettingsButton(double buttonHeight, {String? authToken, String? inferenceUrl}) { final settingsIconSize = buttonHeight * 1.5; return SizedBox( width: settingsIconSize, @@ -644,6 +633,8 @@ class _ChatViewState extends State { editUserScript: () { UserScriptDialog.show(context); }, + authToken: authToken, + inferenceUrl: inferenceUrl, ), ), ); diff --git a/gai-frontend/lib/chat/chat_settings_button.dart b/gai-frontend/lib/chat/chat_settings_button.dart index 15a3a76c5..ad9a1a5e2 100644 --- a/gai-frontend/lib/chat/chat_settings_button.dart +++ b/gai-frontend/lib/chat/chat_settings_button.dart @@ -1,3 +1,4 @@ +import 'package:flutter/services.dart'; import 'package:orchid/chat/identicon_options_menu_item.dart'; import 'package:orchid/chat/scripting/code_viewer/scripts_menu_item.dart'; import 'package:orchid/orchid/orchid.dart'; @@ -17,6 +18,8 @@ class ChatSettingsButton extends StatefulWidget { final VoidCallback onPartyModeChanged; final VoidCallback onClearChat; final VoidCallback editUserScript; + final String? authToken; + final String? inferenceUrl; const ChatSettingsButton({ Key? key, @@ -28,6 +31,8 @@ class ChatSettingsButton extends StatefulWidget { required this.onPartyModeChanged, required this.onClearChat, required this.editUserScript, + this.authToken, + this.inferenceUrl, }) : super(key: key); @override @@ -40,12 +45,68 @@ class _ChatSettingsButtonState extends State { final _textStyle = OrchidText.medium_16_025.copyWith(height: 2.0); bool _buttonSelected = false; + Future _copyToClipboard(String text, String label) async { + await Clipboard.setData(ClipboardData(text: text)); + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('$label copied to clipboard')), + ); + } + } + + List> _buildInferenceInfo() { + if (widget.authToken == null || widget.inferenceUrl == null) { + return []; + } + + return [ + const PopupMenuDivider(height: 1.0), + PopupMenuItem( + height: _height, + child: Theme( + data: Theme.of(context).copyWith(dividerColor: Colors.transparent), + child: ExpansionTile( + title: Text('Inference Connection', style: _textStyle), + children: [ + ListTile( + title: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text('Auth Token:', style: TextStyle(color: Colors.white)), + Text( + widget.authToken!, + style: const TextStyle(fontSize: 12, color: Colors.white70), + overflow: TextOverflow.ellipsis, + ), + TextButton( + onPressed: () => _copyToClipboard(widget.authToken!, 'Auth token'), + child: const Text('Copy Token', style: TextStyle(color: Colors.white)), + ), + const SizedBox(height: 8), + const Text('Inference URL:', style: TextStyle(color: Colors.white)), + Text( + widget.inferenceUrl!, + style: const TextStyle(fontSize: 12, color: Colors.white70), + overflow: TextOverflow.ellipsis, + ), + TextButton( + onPressed: () => _copyToClipboard(widget.inferenceUrl!, 'Inference URL'), + child: const Text('Copy URL', style: TextStyle(color: Colors.white)), + ), + ], + ), + ), + ], + ), + ), + ), + ]; + } + @override Widget build(BuildContext context) { - final buildCommit = - const String.fromEnvironment('build_commit', defaultValue: '...'); - final githubUrl = - 'https://github.com/OrchidTechnologies/orchid/tree/$buildCommit/web-ethereum/dapp2'; + final buildCommit = const String.fromEnvironment('build_commit', defaultValue: '...'); + final githubUrl = 'https://github.com/OrchidTechnologies/orchid/tree/$buildCommit/web-ethereum/dapp2'; return OrchidPopupMenuButton( width: 30, @@ -124,30 +185,6 @@ class _ChatSettingsButtonState extends State { ), div, - /* - // party mode - PopupMenuItem( - onTap: widget.onPartyModeChanged, - height: _height, - child: SizedBox( - width: _width, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text("Party Mode", style: _textStyle), - Icon( - widget.partyMode - ? Icons.check_box_outlined - : Icons.check_box_outline_blank, - color: Colors.white, - ), - ], - ), - ), - ), - div, - */ - // scripts SubmenuPopopMenuItemBuilder( builder: (bool expanded) => ScriptsMenuItem( @@ -156,7 +193,6 @@ class _ChatSettingsButtonState extends State { expanded: expanded, textStyle: _textStyle, editScript: () { - log('edit script'); Navigator.pop(context); widget.editUserScript(); }, @@ -171,6 +207,10 @@ class _ChatSettingsButtonState extends State { textStyle: _textStyle, ), ), + + // Inference connection info + ..._buildInferenceInfo(), + div, // build version @@ -198,71 +238,4 @@ class _ChatSettingsButtonState extends State { ), ); } - - /* - Future _openLicensePage(BuildContext context) { - // TODO: - return Future.delayed(millis(100), () async {}); - } - - Widget _buildLanguagePref(bool expanded) { - return UserPreferencesUI().languageOverride.builder((languageOverride) { - return ExpandingPopupMenuItem( - expanded: expanded, - title: s.language, - currentSelectionText: OrchidLanguage.languages[languageOverride] ?? '', - expandedContent: _languageOptions(languageOverride), - expandedHeight: 690, - textStyle: _textStyle, - ); - }); - } - */ - - Widget _languageOptions(String? selected) { - var items = OrchidLanguage.languages.keys - .map( - (key) => _listMenuItem( - selected: key == selected, - title: OrchidLanguage.languages[key]!, - onTap: () async { - await UserPreferencesUI().languageOverride.set(key); - }, - ), - ) - .toList() - .cast() - .separatedWith( - const PopupMenuDivider(height: 1.0), - ); - - items.insert( - 0, - _listMenuItem( - selected: selected == null, - title: s.systemDefault, - onTap: () async { - await UserPreferencesUI().languageOverride.set(null); - }, - )); - - return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: items, - ); - } - - PopupMenuItem _listMenuItem({ - required bool selected, - required String title, - required VoidCallback onTap, - }) { - return OrchidPopupMenuItemUtils.listMenuItem( - context: context, - selected: selected, - title: title, - onTap: onTap, - textStyle: _textStyle, - ); - } } diff --git a/gai-frontend/lib/chat/inference_client.dart b/gai-frontend/lib/chat/inference_client.dart index d6c2fe5e3..32016b810 100644 --- a/gai-frontend/lib/chat/inference_client.dart +++ b/gai-frontend/lib/chat/inference_client.dart @@ -82,6 +82,9 @@ class InferenceClient { final String baseUrl; String? _authToken; + // Add getter for auth token + String? get authToken => _authToken; + InferenceClient({required String baseUrl}) : baseUrl = _normalizeBaseUrl(baseUrl);