From e30b01a3bb682719efe14c15d23b0d082bc4e155 Mon Sep 17 00:00:00 2001 From: "Mr.Jebelli" Date: Sat, 27 Jun 2026 16:00:57 +0330 Subject: [PATCH] suggested questions endpoint backed by Gemini --- lib/providers/user.dart | 42 ++++++++++++++++++---- lib/services/network/request_helper.dart | 2 +- lib/views/ai/ai_chat_page.dart | 44 ++++++++++++------------ lib/views/ai/ai_chat_state.dart | 1 + lib/views/ai/widgets/ai_message_bar.dart | 3 +- 5 files changed, 62 insertions(+), 30 deletions(-) diff --git a/lib/providers/user.dart b/lib/providers/user.dart index 70f243a..e0255f2 100644 --- a/lib/providers/user.dart +++ b/lib/providers/user.dart @@ -129,19 +129,49 @@ class UserProvider extends CoreProvier { Future setAndGetToken({String? newToken}) async { try { if (newToken == null) { - final cached = TokenStorage.accessToken; - if (cached != null && cached.isNotEmpty) { - RequestService.token = cached; - return cached; + // اگر access token معتبر است، همان را برمی‌گردانیم. + if (TokenStorage.isAccessTokenValid) { + final cached = TokenStorage.accessToken; + if (cached != null && cached.isNotEmpty) { + RequestService.token = cached; + return cached; + } } + // access token منقضی است؛ اگر refresh token داریم، تلاش به + // refresh قبل از ادامه. اگر refresh هم fail شد، session را پاک + // می‌کنیم تا splash کاربر را به login بفرستد. + if (TokenStorage.refreshToken != null && + TokenStorage.refreshToken!.isNotEmpty) { + final ok = await KeycloakAuthService.instance.refresh(); + if (ok) { + final fresh = TokenStorage.accessToken; + if (fresh != null && fresh.isNotEmpty) { + RequestService.token = fresh; + await StorageService.setValue(key: 'token', value: fresh); + return fresh; + } + } + // refresh fail کرد → session تمام شده، کاربر باید مجدد login کند. + print( + '🔐 setAndGetToken: refresh failed, clearing session for re-login'); + await TokenStorage.clear(); + await StorageService.delete(key: 'token'); + RequestService.token = null; + return null; + } + // نه access معتبر داریم نه refresh — هیچ session فعالی نیست. final token = await StorageService.getValue(key: 'token'); - if (token != null) RequestService.token = token; - return token; + if (token != null && token.isNotEmpty) { + RequestService.token = token; + return token; + } + return null; } RequestService.token = newToken; await StorageService.setValue(key: 'token', value: newToken); return null; } catch (e) { + print('🔐 setAndGetToken error: $e'); return null; } } diff --git a/lib/services/network/request_helper.dart b/lib/services/network/request_helper.dart index 31b543f..9779d37 100644 --- a/lib/services/network/request_helper.dart +++ b/lib/services/network/request_helper.dart @@ -303,6 +303,6 @@ class RequestHelper { } static String aiSuggestedQuestions() { - return '$baseUrl/ai/aiquestion'; + return '$newApiBaseUrl/ai/aiquestion'; } } diff --git a/lib/views/ai/ai_chat_page.dart b/lib/views/ai/ai_chat_page.dart index f20556e..2e3e5cc 100644 --- a/lib/views/ai/ai_chat_page.dart +++ b/lib/views/ai/ai_chat_page.dart @@ -147,27 +147,22 @@ class _AiChatPageState extends State with TickerProviderStateMixin { final bots = context.read().bots; if (mounted) { setState(() { - _searchBot = bots.firstWhere((b) => b.id == 36); + // قبلاً _geminiBot از bot id=35 با name=gemini دنبال می‌شد + // (الگوی legacy multi-model). در ساختار جدید Gemini یک bot + // مستقل با id=36 است. try { - _geminiBot = bots.firstWhere((b) => - b.id == 35 && - (b.name?.toLowerCase().contains('gemini') ?? false)); + _searchBot = bots.firstWhere((b) => b.id == 36); + } catch (_) { + _searchBot = null; + } + try { + _geminiBot = bots.firstWhere( + (b) => (b.name?.toLowerCase().contains('gemini') ?? false)); } catch (e) { _geminiBot = BotsModel( - id: 35, - name: 'Gemini', + id: 36, + name: 'gemini', responseType: 'text', - attachmentType: [ - 'audio', - 'image', - 'pdf', - 'csv', - 'doc', - 'docx', - 'xls', - 'xlsx' - ], - attachment: 1, ); } try { @@ -883,15 +878,20 @@ class _AiChatPageState extends State with TickerProviderStateMixin { mainAxisSize: MainAxisSize.min, children: [ AiMessageBar( - bot: _isSearchMode && _searchBot != null - ? _searchBot! - : _getSelectedBot(), + // قبلاً وقتی search mode روشن می‌شد bot به Gemini سویچ + // می‌شد (legacy). الان وب‌جستجو به‌عنوان tool روی هر + // bot انتخاب‌شده اعمال می‌شود؛ پس همان bot فعلی را + // پاس می‌دهیم. + bot: _getSelectedBot(), attch: widget.args.attach, assistantsName: widget.args.assistantsName, - showSearchToggle: _currentBot.id == 35 && _searchBot != null, + // toggle همیشه برای GPT/Gemini در دسترس باشد — نیازی + // به _searchBot (= bot 36) نیست چون tool روی هر bot + // فعال است. + showSearchToggle: _currentBot.id == 35 || _currentBot.id == 36, isSearchMode: _isSearchMode, onSearchModeToggled: (bool isSearchOn) { - if (_searchBot == null) return; + print('[SEARCH_TOGGLE] tapped — new mode=$isSearchOn'); setState(() { _isSearchMode = isSearchOn; }); diff --git a/lib/views/ai/ai_chat_state.dart b/lib/views/ai/ai_chat_state.dart index bbb9bf4..7a71683 100644 --- a/lib/views/ai/ai_chat_state.dart +++ b/lib/views/ai/ai_chat_state.dart @@ -164,6 +164,7 @@ class AiChatState extends CoreProvier { Future postMessage(BotsModel bot, bool isAssistants, {bool webSearch = false}) async { + print('[POST_MSG] bot.id=${bot.id} bot.name=${bot.name} webSearch=$webSearch'); onResponsing = true; final uploadedFile = file; file = null; diff --git a/lib/views/ai/widgets/ai_message_bar.dart b/lib/views/ai/widgets/ai_message_bar.dart index 26e4a0b..74f6aea 100644 --- a/lib/views/ai/widgets/ai_message_bar.dart +++ b/lib/views/ai/widgets/ai_message_bar.dart @@ -794,7 +794,8 @@ class _AiMessageBarState extends State { openAttach = false; state.update(); await state.postMessage( - widget.bot, widget.assistantsName != null); + widget.bot, widget.assistantsName != null, + webSearch: widget.isSearchMode); }, ), ),