@lastbrain/ai-ui-react 1.0.63 → 1.0.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/AiPromptPanel.js +19 -6
- package/dist/components/AiStatusButton.d.ts.map +1 -1
- package/dist/components/AiStatusButton.js +78 -11
- package/dist/context/LBAuthProvider.d.ts.map +1 -1
- package/dist/context/LBAuthProvider.js +129 -182
- package/dist/utils/modelManagement.d.ts.map +1 -1
- package/dist/utils/modelManagement.js +11 -5
- package/package.json +2 -2
- package/src/components/AiPromptPanel.tsx +25 -6
- package/src/components/AiStatusButton.tsx +122 -12
- package/src/context/LBAuthProvider.tsx +137 -209
- package/src/utils/modelManagement.ts +14 -5
|
@@ -4,7 +4,8 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
4
4
|
* Provider d'authentification LastBrain
|
|
5
5
|
* Gère l'état de connexion, la session et les appels IA
|
|
6
6
|
*/
|
|
7
|
-
import { createContext, useContext, useEffect, useCallback, useState, } from "react";
|
|
7
|
+
import { createContext, useContext, useEffect, useCallback, useMemo, useState, } from "react";
|
|
8
|
+
import { createLBClient } from "@lastbrain/ai-ui-core";
|
|
8
9
|
const LBContext = createContext(undefined);
|
|
9
10
|
export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", proxyUrl = "/api/lastbrain", onStatusChange, onAuthChange, }) {
|
|
10
11
|
const [state, setState] = useState({
|
|
@@ -18,61 +19,70 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
18
19
|
const [isLoadingStatus, setIsLoadingStatus] = useState(false);
|
|
19
20
|
const [isLoadingStorage, setIsLoadingStorage] = useState(false);
|
|
20
21
|
const [storageLastFetch, setStorageLastFetch] = useState(0);
|
|
22
|
+
const lbClient = useMemo(() => createLBClient({
|
|
23
|
+
baseUrl: proxyUrl,
|
|
24
|
+
mode: process.env.LB_API_KEY ? "env-key" : "auto",
|
|
25
|
+
selectedApiKeyId: state.selectedKey?.id,
|
|
26
|
+
}), [proxyUrl, state.selectedKey?.id]);
|
|
21
27
|
/**
|
|
22
28
|
* Vérifie si une session existe au chargement
|
|
23
29
|
*/
|
|
24
30
|
const checkSession = useCallback(async () => {
|
|
25
31
|
try {
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const statusData = await statusResponse.json();
|
|
38
|
-
setState({
|
|
39
|
-
status: "ready",
|
|
40
|
-
session,
|
|
41
|
-
user: {
|
|
42
|
-
id: session.userId,
|
|
43
|
-
email: statusData.user?.email || "",
|
|
44
|
-
},
|
|
45
|
-
});
|
|
32
|
+
const session = await lbClient.verifySession();
|
|
33
|
+
if (session) {
|
|
34
|
+
const userData = await lbClient.getUser().catch(() => null);
|
|
35
|
+
const activeKey = userData?.apiKeyActive
|
|
36
|
+
? {
|
|
37
|
+
id: userData.apiKeyActive.id,
|
|
38
|
+
name: userData.apiKeyActive.name,
|
|
39
|
+
keyPrefix: userData.apiKeyActive.prefix,
|
|
40
|
+
scopes: userData.apiKeyActive.scopes || [],
|
|
41
|
+
isActive: true,
|
|
42
|
+
createdAt: "",
|
|
46
43
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
44
|
+
: undefined;
|
|
45
|
+
setApiKeys(userData?.apiKeys || []);
|
|
46
|
+
setState({
|
|
47
|
+
status: "ready",
|
|
48
|
+
session,
|
|
49
|
+
user: {
|
|
50
|
+
id: session.userId,
|
|
51
|
+
email: userData?.user?.email || "",
|
|
52
|
+
},
|
|
53
|
+
selectedKey: activeKey,
|
|
54
|
+
});
|
|
55
|
+
onStatusChange?.("ready");
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
// Supabase session mode (no lb_session cookie): try user endpoint directly
|
|
59
|
+
const userData = await lbClient.getUser().catch(() => null);
|
|
60
|
+
if (userData?.user?.id) {
|
|
61
|
+
const activeKey = userData?.apiKeyActive
|
|
62
|
+
? {
|
|
63
|
+
id: userData.apiKeyActive.id,
|
|
64
|
+
name: userData.apiKeyActive.name,
|
|
65
|
+
keyPrefix: userData.apiKeyActive.prefix,
|
|
66
|
+
scopes: userData.apiKeyActive.scopes || [],
|
|
67
|
+
isActive: true,
|
|
68
|
+
createdAt: "",
|
|
69
|
+
}
|
|
70
|
+
: undefined;
|
|
71
|
+
setApiKeys(userData.apiKeys || []);
|
|
62
72
|
setState({
|
|
63
73
|
status: "ready",
|
|
64
|
-
session,
|
|
65
74
|
user: {
|
|
66
|
-
id:
|
|
67
|
-
email: "",
|
|
75
|
+
id: userData.user.id,
|
|
76
|
+
email: userData.user.email || "",
|
|
68
77
|
},
|
|
78
|
+
selectedKey: activeKey,
|
|
69
79
|
});
|
|
80
|
+
onStatusChange?.("ready");
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
setState({ status: "needs_auth" });
|
|
84
|
+
onStatusChange?.("needs_auth");
|
|
70
85
|
}
|
|
71
|
-
onStatusChange?.("ready");
|
|
72
|
-
}
|
|
73
|
-
else {
|
|
74
|
-
setState({ status: "needs_auth" });
|
|
75
|
-
onStatusChange?.("needs_auth");
|
|
76
86
|
}
|
|
77
87
|
}
|
|
78
88
|
catch (error) {
|
|
@@ -80,7 +90,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
80
90
|
setState({ status: "needs_auth" });
|
|
81
91
|
onStatusChange?.("needs_auth");
|
|
82
92
|
}
|
|
83
|
-
}, [
|
|
93
|
+
}, [lbClient, onStatusChange]);
|
|
84
94
|
useEffect(() => {
|
|
85
95
|
checkSession();
|
|
86
96
|
}, [checkSession]);
|
|
@@ -89,23 +99,8 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
89
99
|
*/
|
|
90
100
|
const fetchApiKeys = useCallback(async (token) => {
|
|
91
101
|
try {
|
|
92
|
-
|
|
93
|
-
const
|
|
94
|
-
headers: {
|
|
95
|
-
Authorization: `Bearer ${token}`,
|
|
96
|
-
"Content-Type": "application/json",
|
|
97
|
-
},
|
|
98
|
-
credentials: "include",
|
|
99
|
-
});
|
|
100
|
-
console.log("[LBProvider] API keys response status:", response.status);
|
|
101
|
-
if (!response.ok) {
|
|
102
|
-
const errorData = await response.json().catch(() => ({}));
|
|
103
|
-
console.error("[LBProvider] Failed to fetch API keys:", errorData);
|
|
104
|
-
throw new Error(errorData.message || "Failed to fetch API keys");
|
|
105
|
-
}
|
|
106
|
-
const data = await response.json();
|
|
107
|
-
console.log("[LBProvider] API keys received:", data);
|
|
108
|
-
const keys = data.apiKeys || data;
|
|
102
|
+
const data = await lbClient.getUser(token);
|
|
103
|
+
const keys = data.apiKeys || [];
|
|
109
104
|
setApiKeys(keys);
|
|
110
105
|
return keys;
|
|
111
106
|
}
|
|
@@ -113,7 +108,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
113
108
|
console.error("[LBProvider] Failed to fetch API keys:", error);
|
|
114
109
|
throw error;
|
|
115
110
|
}
|
|
116
|
-
}, [
|
|
111
|
+
}, [lbClient]);
|
|
117
112
|
/**
|
|
118
113
|
* Sélectionne une clé API et crée une session
|
|
119
114
|
*/
|
|
@@ -121,22 +116,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
121
116
|
try {
|
|
122
117
|
console.log("[LBProvider] Selecting API key:", apiKeyId);
|
|
123
118
|
setState((prev) => ({ ...prev, status: "loading" }));
|
|
124
|
-
const
|
|
125
|
-
method: "POST",
|
|
126
|
-
headers: {
|
|
127
|
-
"Content-Type": "application/json",
|
|
128
|
-
Authorization: `Bearer ${token}`,
|
|
129
|
-
},
|
|
130
|
-
body: JSON.stringify({ api_key_id: apiKeyId }),
|
|
131
|
-
credentials: "include",
|
|
132
|
-
});
|
|
133
|
-
console.log("[LBProvider] Session response status:", response.status);
|
|
134
|
-
if (!response.ok) {
|
|
135
|
-
const errorData = await response.json().catch(() => ({}));
|
|
136
|
-
console.error("[LBProvider] Failed to create session:", errorData);
|
|
137
|
-
throw new Error(errorData.message || "Failed to create session");
|
|
138
|
-
}
|
|
139
|
-
const sessionResult = await response.json();
|
|
119
|
+
const sessionResult = await lbClient.selectApiKey(apiKeyId, token);
|
|
140
120
|
console.log("[LBProvider] Session created successfully:", sessionResult);
|
|
141
121
|
setState({
|
|
142
122
|
status: "ready",
|
|
@@ -162,7 +142,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
162
142
|
});
|
|
163
143
|
throw error;
|
|
164
144
|
}
|
|
165
|
-
}, [
|
|
145
|
+
}, [lbClient, state.user, onStatusChange, onAuthChange]);
|
|
166
146
|
/**
|
|
167
147
|
* Connexion utilisateur (étape 1 : login)
|
|
168
148
|
* Retourne le token et les clés API sans créer de session
|
|
@@ -171,24 +151,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
171
151
|
try {
|
|
172
152
|
console.log("[LBProvider] Login attempt:", email);
|
|
173
153
|
setState((prev) => ({ ...prev, status: "loading" }));
|
|
174
|
-
const
|
|
175
|
-
method: "POST",
|
|
176
|
-
headers: { "Content-Type": "application/json" },
|
|
177
|
-
body: JSON.stringify({ email, password }),
|
|
178
|
-
credentials: "include",
|
|
179
|
-
});
|
|
180
|
-
console.log("[LBProvider] Login response status:", response.status);
|
|
181
|
-
if (!response.ok) {
|
|
182
|
-
const error = await response.json();
|
|
183
|
-
const errorMessage = error.message || "Login failed";
|
|
184
|
-
console.error("[LBProvider] Login failed:", errorMessage);
|
|
185
|
-
setState({
|
|
186
|
-
status: "needs_auth",
|
|
187
|
-
error: errorMessage,
|
|
188
|
-
});
|
|
189
|
-
return { success: false, error: errorMessage };
|
|
190
|
-
}
|
|
191
|
-
const result = await response.json();
|
|
154
|
+
const result = await lbClient.login(email, password);
|
|
192
155
|
console.log("[LBProvider] Login successful:", result.user?.email);
|
|
193
156
|
console.log("[LBProvider] Access token received:", result.accessToken ? "YES" : "NO");
|
|
194
157
|
console.log("[LBProvider] Token length:", result.accessToken?.length || 0);
|
|
@@ -259,7 +222,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
259
222
|
});
|
|
260
223
|
return { success: false, error: message };
|
|
261
224
|
}
|
|
262
|
-
}, [
|
|
225
|
+
}, [lbClient, fetchApiKeys, selectApiKey]);
|
|
263
226
|
/**
|
|
264
227
|
* Récupère le status API basique (balance, API key info) - RAPIDE
|
|
265
228
|
*/
|
|
@@ -271,22 +234,43 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
271
234
|
}
|
|
272
235
|
setIsLoadingStatus(true);
|
|
273
236
|
try {
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
if (response.ok) {
|
|
278
|
-
const data = await response.json();
|
|
279
|
-
setBasicStatus(data);
|
|
280
|
-
// Combiner avec le storage existant si disponible
|
|
281
|
-
const combinedStatus = {
|
|
282
|
-
...data,
|
|
283
|
-
storage: storageStatus?.storage || data.storage,
|
|
284
|
-
};
|
|
285
|
-
setApiStatus(combinedStatus);
|
|
237
|
+
let data;
|
|
238
|
+
try {
|
|
239
|
+
data = await lbClient.getStatus();
|
|
286
240
|
}
|
|
287
|
-
|
|
288
|
-
|
|
241
|
+
catch {
|
|
242
|
+
// Backward compatibility: older backends may not expose /auth/status
|
|
243
|
+
const userData = await lbClient.getUser();
|
|
244
|
+
data = {
|
|
245
|
+
authType: userData.authType,
|
|
246
|
+
user: userData.user,
|
|
247
|
+
apiKey: userData.apiKeyActive,
|
|
248
|
+
api_key: userData.apiKeyActive,
|
|
249
|
+
balance: {
|
|
250
|
+
used: 0,
|
|
251
|
+
total: userData.balance?.sellValueUsd || 0,
|
|
252
|
+
percentage: 0,
|
|
253
|
+
},
|
|
254
|
+
};
|
|
289
255
|
}
|
|
256
|
+
const normalizedStatus = {
|
|
257
|
+
...data,
|
|
258
|
+
authType: data?.authType,
|
|
259
|
+
user: data?.user,
|
|
260
|
+
apiKey: data?.apiKey || data?.api_key,
|
|
261
|
+
api_key: data?.api_key || data?.apiKey,
|
|
262
|
+
balance: data?.balance || {
|
|
263
|
+
used: 0,
|
|
264
|
+
total: 0,
|
|
265
|
+
percentage: 0,
|
|
266
|
+
},
|
|
267
|
+
};
|
|
268
|
+
setBasicStatus(normalizedStatus);
|
|
269
|
+
const combinedStatus = {
|
|
270
|
+
...normalizedStatus,
|
|
271
|
+
storage: storageStatus?.storage,
|
|
272
|
+
};
|
|
273
|
+
setApiStatus(combinedStatus);
|
|
290
274
|
}
|
|
291
275
|
catch (error) {
|
|
292
276
|
console.error("[LBProvider] Failed to fetch basic status:", error);
|
|
@@ -295,7 +279,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
295
279
|
finally {
|
|
296
280
|
setIsLoadingStatus(false);
|
|
297
281
|
}
|
|
298
|
-
}, [
|
|
282
|
+
}, [lbClient, state.status, storageStatus]);
|
|
299
283
|
/**
|
|
300
284
|
* Récupère le storage - LENT avec cache (5 minutes)
|
|
301
285
|
*/
|
|
@@ -315,35 +299,16 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
315
299
|
}
|
|
316
300
|
setIsLoadingStorage(true);
|
|
317
301
|
try {
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
//
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
}
|
|
329
|
-
if (response.ok) {
|
|
330
|
-
const data = await response.json();
|
|
331
|
-
// Si c'est la réponse complète (fallback), extraire juste le storage
|
|
332
|
-
const storageData = data.storage ? { storage: data.storage } : data;
|
|
333
|
-
setStorageStatus(storageData);
|
|
334
|
-
setStorageLastFetch(now);
|
|
335
|
-
// Combiner avec le basic status
|
|
336
|
-
const combinedStatus = {
|
|
337
|
-
...basicStatus,
|
|
338
|
-
storage: storageData.storage,
|
|
339
|
-
};
|
|
340
|
-
setApiStatus(combinedStatus);
|
|
341
|
-
}
|
|
342
|
-
else {
|
|
343
|
-
console.warn("[LBProvider] Failed to fetch storage status:", response.status);
|
|
344
|
-
// Arrêter les tentatives répétées si échec persistant
|
|
345
|
-
setStorageLastFetch(now); // Marquer comme essayé pour éviter la boucle
|
|
346
|
-
}
|
|
302
|
+
const data = await lbClient.getStorageStatus();
|
|
303
|
+
const storageData = data?.storage ? { storage: data.storage } : data;
|
|
304
|
+
setStorageStatus(storageData);
|
|
305
|
+
setStorageLastFetch(now);
|
|
306
|
+
// Combiner avec le basic status
|
|
307
|
+
const combinedStatus = {
|
|
308
|
+
...basicStatus,
|
|
309
|
+
storage: storageData?.storage,
|
|
310
|
+
};
|
|
311
|
+
setApiStatus(combinedStatus);
|
|
347
312
|
}
|
|
348
313
|
catch (error) {
|
|
349
314
|
console.error("[LBProvider] Failed to fetch storage status:", error);
|
|
@@ -353,7 +318,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
353
318
|
finally {
|
|
354
319
|
setIsLoadingStorage(false);
|
|
355
320
|
}
|
|
356
|
-
}, [
|
|
321
|
+
}, [lbClient, state.status, basicStatus, storageLastFetch]);
|
|
357
322
|
/**
|
|
358
323
|
* Sélectionne une clé API avec le token déjà stocké (après login)
|
|
359
324
|
*/
|
|
@@ -367,35 +332,26 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
367
332
|
* Change l'API key active - utilise la bonne méthode selon le contexte
|
|
368
333
|
*/
|
|
369
334
|
const switchApiKey = useCallback(async (apiKeyId) => {
|
|
370
|
-
if (state.status === "ready") {
|
|
371
|
-
|
|
372
|
-
const
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
if (!response.ok) {
|
|
379
|
-
const errorData = await response.json().catch(() => ({}));
|
|
380
|
-
throw new Error(errorData.error || "Failed to switch API key");
|
|
335
|
+
if (state.status === "ready" || accessToken) {
|
|
336
|
+
await lbClient.selectApiKey(apiKeyId, accessToken);
|
|
337
|
+
const selectedKey = apiKeys.find((key) => key.id === apiKeyId);
|
|
338
|
+
if (selectedKey) {
|
|
339
|
+
setState((prev) => ({
|
|
340
|
+
...prev,
|
|
341
|
+
selectedKey,
|
|
342
|
+
}));
|
|
381
343
|
}
|
|
382
|
-
// Refresh le status après le changement
|
|
383
344
|
await refreshBasicStatus();
|
|
384
|
-
// Refresh storage en arrière-plan
|
|
385
345
|
setTimeout(() => refreshStorageStatus(), 100);
|
|
386
346
|
}
|
|
387
|
-
else if (accessToken) {
|
|
388
|
-
// Utiliser la méthode avec access token
|
|
389
|
-
await selectApiKey(accessToken, apiKeyId);
|
|
390
|
-
}
|
|
391
347
|
else {
|
|
392
348
|
throw new Error("No valid authentication method available");
|
|
393
349
|
}
|
|
394
350
|
}, [
|
|
395
351
|
state.status,
|
|
396
|
-
proxyUrl,
|
|
397
352
|
accessToken,
|
|
398
|
-
|
|
353
|
+
apiKeys,
|
|
354
|
+
lbClient,
|
|
399
355
|
refreshBasicStatus,
|
|
400
356
|
refreshStorageStatus,
|
|
401
357
|
]);
|
|
@@ -404,10 +360,7 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
404
360
|
*/
|
|
405
361
|
const logout = useCallback(async () => {
|
|
406
362
|
try {
|
|
407
|
-
await
|
|
408
|
-
method: "POST",
|
|
409
|
-
credentials: "include",
|
|
410
|
-
});
|
|
363
|
+
await lbClient.logout();
|
|
411
364
|
}
|
|
412
365
|
catch (error) {
|
|
413
366
|
console.error("[LBProvider] Logout failed:", error);
|
|
@@ -416,10 +369,15 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
416
369
|
setState({ status: "needs_auth" });
|
|
417
370
|
setApiKeys([]);
|
|
418
371
|
setAccessToken(undefined);
|
|
372
|
+
// Reset tous les statuts après logout
|
|
373
|
+
setApiStatus(null);
|
|
374
|
+
setBasicStatus(null);
|
|
375
|
+
setStorageStatus(null);
|
|
376
|
+
setStorageLastFetch(0);
|
|
419
377
|
onStatusChange?.("needs_auth");
|
|
420
378
|
onAuthChange?.(); // Refresh provider after logout
|
|
421
379
|
}
|
|
422
|
-
}, [
|
|
380
|
+
}, [lbClient, onStatusChange, onAuthChange]);
|
|
423
381
|
/**
|
|
424
382
|
* Recharge la session
|
|
425
383
|
*/
|
|
@@ -435,25 +393,14 @@ export function LBProvider({ children, baseUrl: _baseUrl = "/api/lastbrain", pro
|
|
|
435
393
|
return;
|
|
436
394
|
}
|
|
437
395
|
try {
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
credentials: "include",
|
|
441
|
-
});
|
|
442
|
-
if (response.ok) {
|
|
443
|
-
const data = await response.json();
|
|
444
|
-
console.log("[LBProvider] API keys received:", data);
|
|
445
|
-
setApiKeys(data.apiKeys || []);
|
|
446
|
-
}
|
|
447
|
-
else {
|
|
448
|
-
console.warn("[LBProvider] Failed to fetch API keys:", response.status);
|
|
449
|
-
setApiKeys([]);
|
|
450
|
-
}
|
|
396
|
+
const data = await lbClient.getUser();
|
|
397
|
+
setApiKeys(data.apiKeys || []);
|
|
451
398
|
}
|
|
452
399
|
catch (error) {
|
|
453
400
|
console.error("[LBProvider] Failed to fetch API keys:", error);
|
|
454
401
|
setApiKeys([]);
|
|
455
402
|
}
|
|
456
|
-
}, [
|
|
403
|
+
}, [lbClient, state.status]);
|
|
457
404
|
// Refresh status quand la session devient ready
|
|
458
405
|
useEffect(() => {
|
|
459
406
|
if (state.status === "ready") {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modelManagement.d.ts","sourceRoot":"","sources":["../../src/utils/modelManagement.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,OAAO,EACjB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,IAAI,CAAC,CAqCf;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CACR,KAAK,CAAC;IACJ,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;IAC/C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC,CACH,
|
|
1
|
+
{"version":3,"file":"modelManagement.d.ts","sourceRoot":"","sources":["../../src/utils/modelManagement.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,OAAO,EACjB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,IAAI,CAAC,CAqCf;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CACR,KAAK,CAAC;IACJ,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;IAC/C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC,CACH,CAsDA;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,MAAM,EAAE,CAAC,CAkDnB"}
|
|
@@ -45,12 +45,12 @@ export async function getAvailableModels(options = {}) {
|
|
|
45
45
|
const isExternalProxy = baseUrl && baseUrl.includes("/api/lastbrain");
|
|
46
46
|
const isPublicApi = baseUrl && baseUrl.includes("/api/public/v1");
|
|
47
47
|
const endpoint = isExternalProxy
|
|
48
|
-
? `${baseUrl}/
|
|
48
|
+
? `${baseUrl}/auth/models` // Proxy routes to /api/ai/auth/models
|
|
49
49
|
: isPublicApi
|
|
50
|
-
? `${baseUrl}/
|
|
50
|
+
? `${baseUrl}/gateway-models` // → /api/public/v1/gateway-models
|
|
51
51
|
: baseUrl
|
|
52
|
-
? `${baseUrl}/auth/
|
|
53
|
-
: `/api/ai/auth/
|
|
52
|
+
? `${baseUrl}/auth/models` // → /api/ai/auth/models
|
|
53
|
+
: `/api/ai/auth/models`; // fallback
|
|
54
54
|
console.log("[getAvailableModels] isExternalProxy:", isExternalProxy, "isPublicApi:", isPublicApi, "endpoint:", endpoint);
|
|
55
55
|
const headers = {};
|
|
56
56
|
// Ajouter la clé API pour les appels publics directs
|
|
@@ -66,7 +66,13 @@ export async function getAvailableModels(options = {}) {
|
|
|
66
66
|
throw new Error(`Erreur lors de la récupération des modèles: ${response.status}`);
|
|
67
67
|
}
|
|
68
68
|
const data = await response.json();
|
|
69
|
-
|
|
69
|
+
if (Array.isArray(data?.models)) {
|
|
70
|
+
return data.models;
|
|
71
|
+
}
|
|
72
|
+
if (Array.isArray(data?.providers)) {
|
|
73
|
+
return data.providers.flatMap((provider) => Array.isArray(provider.models) ? provider.models : []);
|
|
74
|
+
}
|
|
75
|
+
return [];
|
|
70
76
|
}
|
|
71
77
|
/**
|
|
72
78
|
* Récupère les modèles activés par l'utilisateur avec API key
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lastbrain/ai-ui-react",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.64",
|
|
4
4
|
"description": "Headless React components for LastBrain AI UI Kit",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"lucide-react": "^0.257.0",
|
|
51
|
-
"@lastbrain/ai-ui-core": "1.0.
|
|
51
|
+
"@lastbrain/ai-ui-core": "1.0.48"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@types/react": "^19.2.0",
|
|
@@ -182,11 +182,16 @@ function AiPromptPanelInternal({
|
|
|
182
182
|
|
|
183
183
|
if (showAllModels) {
|
|
184
184
|
return categoryModels;
|
|
185
|
-
} else {
|
|
186
|
-
return categoryModels.filter((m) => effectiveUserModels.includes(m.id));
|
|
187
185
|
}
|
|
186
|
+
|
|
187
|
+
const enabledModels = categoryModels.filter((m) =>
|
|
188
|
+
effectiveUserModels.includes(m.id)
|
|
189
|
+
);
|
|
190
|
+
return enabledModels.length > 0 ? enabledModels : categoryModels;
|
|
188
191
|
};
|
|
189
192
|
|
|
193
|
+
const modelOptions = getFilteredModels();
|
|
194
|
+
|
|
190
195
|
// Fetch prompts when modal opens
|
|
191
196
|
useEffect(() => {
|
|
192
197
|
if (isOpen && (models.length > 0 || enableModelManagement)) {
|
|
@@ -209,7 +214,7 @@ function AiPromptPanelInternal({
|
|
|
209
214
|
]);
|
|
210
215
|
|
|
211
216
|
const handleSubmit = async () => {
|
|
212
|
-
const activeModelId = selectedModel ||
|
|
217
|
+
const activeModelId = selectedModel || modelOptions[0]?.id;
|
|
213
218
|
if (!activeModelId || !prompt.trim()) return;
|
|
214
219
|
setIsGenerating(true);
|
|
215
220
|
try {
|
|
@@ -249,6 +254,20 @@ function AiPromptPanelInternal({
|
|
|
249
254
|
};
|
|
250
255
|
}, []);
|
|
251
256
|
|
|
257
|
+
useEffect(() => {
|
|
258
|
+
if (!isOpen) {
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
if (modelOptions.length === 0) {
|
|
262
|
+
setSelectedModel("");
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
const hasSelected = modelOptions.some((model) => model.id === selectedModel);
|
|
266
|
+
if (!hasSelected) {
|
|
267
|
+
setSelectedModel(modelOptions[0].id);
|
|
268
|
+
}
|
|
269
|
+
}, [isOpen, modelOptions, selectedModel]);
|
|
270
|
+
|
|
252
271
|
const handleKeyDown = (e: React.KeyboardEvent) => {
|
|
253
272
|
if (e.key === "Escape") {
|
|
254
273
|
handleClose();
|
|
@@ -284,7 +303,7 @@ function AiPromptPanelInternal({
|
|
|
284
303
|
|
|
285
304
|
if (!isOpen) return null;
|
|
286
305
|
|
|
287
|
-
const activeModelId = selectedModel ||
|
|
306
|
+
const activeModelId = selectedModel || modelOptions[0]?.id || "";
|
|
288
307
|
const currentModelType = models.find((m) => m.id === activeModelId)?.type;
|
|
289
308
|
const filteredPrompts = prompts.filter((p: Prompt | PublicPrompt) => {
|
|
290
309
|
const matchesType =
|
|
@@ -562,10 +581,10 @@ function AiPromptPanelInternal({
|
|
|
562
581
|
...(modelFocused && aiStyles.selectFocus),
|
|
563
582
|
}}
|
|
564
583
|
>
|
|
565
|
-
{
|
|
584
|
+
{modelOptions.length === 0 && (
|
|
566
585
|
<option value="">Loading models...</option>
|
|
567
586
|
)}
|
|
568
|
-
{
|
|
587
|
+
{modelOptions.map((model) => {
|
|
569
588
|
const isActive = effectiveUserModels.includes(model.id);
|
|
570
589
|
return (
|
|
571
590
|
<option
|