suggested questions endpoint backed by Gemini

This commit is contained in:
Mohamad Mahdi Jebeli 2026-06-27 16:00:57 +03:30
parent e20120056a
commit e30b01a3bb
5 changed files with 62 additions and 30 deletions

View File

@ -129,19 +129,49 @@ class UserProvider extends CoreProvier {
Future<String?> 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;
}
}

View File

@ -303,6 +303,6 @@ class RequestHelper {
}
static String aiSuggestedQuestions() {
return '$baseUrl/ai/aiquestion';
return '$newApiBaseUrl/ai/aiquestion';
}
}

View File

@ -147,27 +147,22 @@ class _AiChatPageState extends State<AiChatPage> with TickerProviderStateMixin {
final bots = context.read<HistoryAiChatState>().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<AiChatPage> 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;
});

View File

@ -164,6 +164,7 @@ class AiChatState extends CoreProvier {
Future<void> 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;

View File

@ -794,7 +794,8 @@ class _AiMessageBarState extends State<AiMessageBar> {
openAttach = false;
state.update();
await state.postMessage(
widget.bot, widget.assistantsName != null);
widget.bot, widget.assistantsName != null,
webSearch: widget.isSearchMode);
},
),
),