@lastbrain/ai-ui-react 1.0.24 → 1.0.26

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.
Files changed (44) hide show
  1. package/dist/components/AiChipLabel.d.ts +12 -0
  2. package/dist/components/AiChipLabel.d.ts.map +1 -1
  3. package/dist/components/AiChipLabel.js +129 -1
  4. package/dist/components/AiContextButton.d.ts +18 -0
  5. package/dist/components/AiContextButton.d.ts.map +1 -0
  6. package/dist/components/AiContextButton.js +339 -0
  7. package/dist/components/AiImageButton.d.ts +12 -3
  8. package/dist/components/AiImageButton.d.ts.map +1 -1
  9. package/dist/components/AiImageButton.js +218 -8
  10. package/dist/components/AiStatusButton.d.ts.map +1 -1
  11. package/dist/components/AiStatusButton.js +1 -1
  12. package/dist/components/UsageToast.d.ts.map +1 -1
  13. package/dist/components/UsageToast.js +5 -3
  14. package/dist/examples/AiChipInputExample.d.ts +2 -0
  15. package/dist/examples/AiChipInputExample.d.ts.map +1 -0
  16. package/dist/examples/AiChipInputExample.js +14 -0
  17. package/dist/examples/AiContextButtonExample.d.ts +2 -0
  18. package/dist/examples/AiContextButtonExample.d.ts.map +1 -0
  19. package/dist/examples/AiContextButtonExample.js +88 -0
  20. package/dist/examples/AiImageButtonExample.d.ts +2 -0
  21. package/dist/examples/AiImageButtonExample.d.ts.map +1 -0
  22. package/dist/examples/AiImageButtonExample.js +26 -0
  23. package/dist/hooks/useAiCallImage.d.ts.map +1 -1
  24. package/dist/hooks/useAiCallImage.js +107 -1
  25. package/dist/hooks/useAiCallText.d.ts.map +1 -1
  26. package/dist/hooks/useAiCallText.js +25 -1
  27. package/dist/index.d.ts +4 -0
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +4 -0
  30. package/dist/styles/inline.d.ts.map +1 -1
  31. package/dist/styles/inline.js +3 -1
  32. package/package.json +2 -2
  33. package/src/components/AiChipLabel.tsx +218 -1
  34. package/src/components/AiContextButton.tsx +553 -0
  35. package/src/components/AiImageButton.tsx +386 -38
  36. package/src/components/AiStatusButton.tsx +7 -3
  37. package/src/components/UsageToast.tsx +5 -3
  38. package/src/examples/AiChipInputExample.tsx +81 -0
  39. package/src/examples/AiContextButtonExample.tsx +338 -0
  40. package/src/examples/AiImageButtonExample.tsx +72 -0
  41. package/src/hooks/useAiCallImage.ts +149 -1
  42. package/src/hooks/useAiCallText.ts +30 -1
  43. package/src/index.ts +4 -0
  44. package/src/styles/inline.ts +3 -1
@@ -9,6 +9,30 @@ export function useAiCallText(options) {
9
9
  setLoading(true);
10
10
  setError(null);
11
11
  try {
12
+ // Vérifier si on est en mode dev (API key contient "dev")
13
+ if (options?.apiKeyId?.includes("dev")) {
14
+ // Simulation pour l'environnement dev
15
+ await new Promise((resolve) => setTimeout(resolve, 1000)); // Délai pour simuler l'API
16
+ let simulatedResult = "";
17
+ // Si le prompt contient des mots-clés pour les chips
18
+ if (request.prompt.toLowerCase().includes("tags") ||
19
+ request.prompt.toLowerCase().includes("chip") ||
20
+ request.prompt.toLowerCase().includes("virgule")) {
21
+ simulatedResult =
22
+ "react, typescript, javascript, frontend, backend, api, development, web, mobile, database";
23
+ }
24
+ else {
25
+ // Lorem ipsum pour les autres cas
26
+ simulatedResult =
27
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.";
28
+ }
29
+ return {
30
+ requestId: `dev-${Date.now()}`,
31
+ text: simulatedResult,
32
+ debitTokens: 150,
33
+ };
34
+ }
35
+ // Mode production : appel API normal
12
36
  const result = await client.generateText(request);
13
37
  return result;
14
38
  }
@@ -20,7 +44,7 @@ export function useAiCallText(options) {
20
44
  finally {
21
45
  setLoading(false);
22
46
  }
23
- }, [client]);
47
+ }, [client, options?.apiKeyId]);
24
48
  return {
25
49
  generateText,
26
50
  loading,
package/dist/index.d.ts CHANGED
@@ -14,10 +14,14 @@ export * from "./components/AiTextarea";
14
14
  export * from "./components/AiSelect";
15
15
  export * from "./components/AiChipLabel";
16
16
  export * from "./components/AiImageButton";
17
+ export * from "./components/AiContextButton";
17
18
  export * from "./components/AiSettingsButton";
18
19
  export * from "./components/AiStatusButton";
19
20
  export * from "./utils/modelManagement";
20
21
  export * from "./utils/cache";
21
22
  export * from "./examples/AiImageGenerator";
22
23
  export * from "./examples/AiPromptPanelAdvanced";
24
+ export * from "./examples/AiChipInputExample";
25
+ export * from "./examples/AiImageButtonExample";
26
+ export * from "./examples/AiContextButtonExample";
23
27
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,SAAS,CAAC;AAGxB,cAAc,sBAAsB,CAAC;AAGrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,oBAAoB,CAAC;AACnC,cAAc,4BAA4B,CAAC;AAG3C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC;AAG5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,eAAe,CAAC;AAG9B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,kCAAkC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,SAAS,CAAC;AAGxB,cAAc,sBAAsB,CAAC;AAGrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,oBAAoB,CAAC;AACnC,cAAc,4BAA4B,CAAC;AAG3C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC;AAG5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,eAAe,CAAC;AAG9B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,kCAAkC,CAAC;AACjD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,iCAAiC,CAAC;AAChD,cAAc,mCAAmC,CAAC"}
package/dist/index.js CHANGED
@@ -18,6 +18,7 @@ export * from "./components/AiTextarea";
18
18
  export * from "./components/AiSelect";
19
19
  export * from "./components/AiChipLabel";
20
20
  export * from "./components/AiImageButton";
21
+ export * from "./components/AiContextButton";
21
22
  export * from "./components/AiSettingsButton";
22
23
  export * from "./components/AiStatusButton";
23
24
  // Utils
@@ -26,3 +27,6 @@ export * from "./utils/cache";
26
27
  // Examples
27
28
  export * from "./examples/AiImageGenerator";
28
29
  export * from "./examples/AiPromptPanelAdvanced";
30
+ export * from "./examples/AiChipInputExample";
31
+ export * from "./examples/AiImageButtonExample";
32
+ export * from "./examples/AiContextButtonExample";
@@ -1 +1 @@
1
- {"version":3,"file":"inline.d.ts","sourceRoot":"","sources":["../../src/styles/inline.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA6HH,eAAO,MAAM,QAAQ;WAgBd,KAAK,CAAC,aAAa;gBAKnB,KAAK,CAAC,aAAa;gBAInB,KAAK,CAAC,aAAa;;;;;mBAyBnB,KAAK,CAAC,aAAa;wBAMnB,KAAK,CAAC,aAAa;cAmBnB,KAAK,CAAC,aAAa;mBAKnB,KAAK,CAAC,aAAa;;;;;sBAwBnB,KAAK,CAAC,aAAa;2BAMnB,KAAK,CAAC,aAAa;YAoBnB,KAAK,CAAC,aAAa;iBAMnB,KAAK,CAAC,aAAa;oBAMnB,KAAK,CAAC,aAAa;YAyBnB,KAAK,CAAC,aAAa;iBAKnB,KAAK,CAAC,aAAa;kBAgBnB,KAAK,CAAC,aAAa;uBAMnB,KAAK,CAAC,aAAa;0BAKnB,KAAK,CAAC,aAAa;aAgBnB,KAAK,CAAC,aAAa;mBASnB,KAAK,CAAC,aAAa;oBAKnB,KAAK,CAAC,aAAa;yBAKnB,KAAK,CAAC,aAAa;qBASnB,KAAK,CAAC,aAAa;gBAQnB,KAAK,CAAC,aAAa;kBAKnB,KAAK,CAAC,aAAa;kBAQnB,KAAK,CAAC,aAAa;sBAKnB,KAAK,CAAC,aAAa;yBAKnB,KAAK,CAAC,aAAa;yBAKnB,KAAK,CAAC,aAAa;oBASnB,KAAK,CAAC,aAAa;iBAcnB,KAAK,CAAC,aAAa;sBAKnB,KAAK,CAAC,aAAa;UAcnB,KAAK,CAAC,aAAa;WAenB,KAAK,CAAC,aAAa;kBAWnB,KAAK,CAAC,aAAa;kBAanB,KAAK,CAAC,aAAa;iBAQnB,KAAK,CAAC,aAAa;gBAOnB,KAAK,CAAC,aAAa;sBAiBnB,KAAK,CAAC,aAAa;2BAKnB,KAAK,CAAC,aAAa;eAMnB,KAAK,CAAC,aAAa;iBAQnB,KAAK,CAAC,aAAa;gBAQnB,KAAK,CAAC,aAAa;qBAInB,KAAK,CAAC,aAAa;qBAOnB,KAAK,CAAC,aAAa;0BAKnB,KAAK,CAAC,aAAa;aAUnB,KAAK,CAAC,aAAa;CACzB,CAAC;AA+BF,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,OAAO,EACnB,YAAY,GAAE,MAAY,EAC1B,aAAa,GAAE,MAAY,GAC1B;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAoDlE"}
1
+ {"version":3,"file":"inline.d.ts","sourceRoot":"","sources":["../../src/styles/inline.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA6HH,eAAO,MAAM,QAAQ;WAgBd,KAAK,CAAC,aAAa;gBAKnB,KAAK,CAAC,aAAa;gBAInB,KAAK,CAAC,aAAa;;;;;mBAyBnB,KAAK,CAAC,aAAa;wBAMnB,KAAK,CAAC,aAAa;cAmBnB,KAAK,CAAC,aAAa;mBAKnB,KAAK,CAAC,aAAa;;;;;sBAwBnB,KAAK,CAAC,aAAa;2BAMnB,KAAK,CAAC,aAAa;YAoBnB,KAAK,CAAC,aAAa;iBAMnB,KAAK,CAAC,aAAa;oBAMnB,KAAK,CAAC,aAAa;YA2BnB,KAAK,CAAC,aAAa;iBAKnB,KAAK,CAAC,aAAa;kBAgBnB,KAAK,CAAC,aAAa;uBAMnB,KAAK,CAAC,aAAa;0BAKnB,KAAK,CAAC,aAAa;aAgBnB,KAAK,CAAC,aAAa;mBASnB,KAAK,CAAC,aAAa;oBAKnB,KAAK,CAAC,aAAa;yBAKnB,KAAK,CAAC,aAAa;qBASnB,KAAK,CAAC,aAAa;gBAQnB,KAAK,CAAC,aAAa;kBAKnB,KAAK,CAAC,aAAa;kBAQnB,KAAK,CAAC,aAAa;sBAKnB,KAAK,CAAC,aAAa;yBAKnB,KAAK,CAAC,aAAa;yBAKnB,KAAK,CAAC,aAAa;oBASnB,KAAK,CAAC,aAAa;iBAcnB,KAAK,CAAC,aAAa;sBAKnB,KAAK,CAAC,aAAa;UAcnB,KAAK,CAAC,aAAa;WAenB,KAAK,CAAC,aAAa;kBAWnB,KAAK,CAAC,aAAa;kBAanB,KAAK,CAAC,aAAa;iBAQnB,KAAK,CAAC,aAAa;gBAOnB,KAAK,CAAC,aAAa;sBAiBnB,KAAK,CAAC,aAAa;2BAKnB,KAAK,CAAC,aAAa;eAMnB,KAAK,CAAC,aAAa;iBAQnB,KAAK,CAAC,aAAa;gBAQnB,KAAK,CAAC,aAAa;qBAInB,KAAK,CAAC,aAAa;qBAOnB,KAAK,CAAC,aAAa;0BAKnB,KAAK,CAAC,aAAa;aAUnB,KAAK,CAAC,aAAa;CACzB,CAAC;AA+BF,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,OAAO,EACnB,YAAY,GAAE,MAAY,EAC1B,aAAa,GAAE,MAAY,GAC1B;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAoDlE"}
@@ -242,7 +242,9 @@ export const aiStyles = {
242
242
  lineHeight: "1.5",
243
243
  color: themeVars.text,
244
244
  background: themeVars.bg,
245
- border: `1px solid ${themeVars.border}`,
245
+ borderWidth: "1px",
246
+ borderStyle: "solid",
247
+ borderColor: themeVars.border,
246
248
  borderRadius: "8px",
247
249
  outline: "none",
248
250
  transition: "all 0.2s",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lastbrain/ai-ui-react",
3
- "version": "1.0.24",
3
+ "version": "1.0.26",
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.16"
51
+ "@lastbrain/ai-ui-core": "1.0.18"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@types/react": "^19.2.0",
@@ -1,7 +1,12 @@
1
1
  "use client";
2
2
 
3
- import React from "react";
3
+ import React, { useState, useRef, KeyboardEvent } from "react";
4
+ import { X, Sparkles } from "lucide-react";
4
5
  import { aiStyles } from "../styles/inline";
6
+ import { AiPromptPanel } from "./AiPromptPanel";
7
+ import { useAiCallText } from "../hooks/useAiCallText";
8
+ import { useAiModels } from "../hooks/useAiModels";
9
+ import { useAiContext } from "../context/AiProvider";
5
10
 
6
11
  export interface AiChipLabelProps {
7
12
  children: React.ReactNode;
@@ -48,3 +53,215 @@ export function AiChipLabel({
48
53
  </span>
49
54
  );
50
55
  }
56
+
57
+ export interface AiChipInputProps {
58
+ value?: string[];
59
+ onChange?: (chips: string[]) => void;
60
+ placeholder?: string;
61
+ context?: string;
62
+ maxChips?: number;
63
+ allowDuplicates?: boolean;
64
+ className?: string;
65
+ // Props optionnelles pour override du contexte (si nécessaire)
66
+ baseUrl?: string;
67
+ apiKeyId?: string;
68
+ }
69
+
70
+ export function AiChipInput({
71
+ value = [],
72
+ onChange,
73
+ placeholder = "Tapez et appuyez sur Entrée pour ajouter des tags...",
74
+ context,
75
+ maxChips,
76
+ allowDuplicates = false,
77
+ className,
78
+ baseUrl: propBaseUrl,
79
+ apiKeyId: propApiKeyId,
80
+ }: AiChipInputProps) {
81
+ const [inputValue, setInputValue] = useState("");
82
+ const [showPromptPanel, setShowPromptPanel] = useState(false);
83
+ const inputRef = useRef<HTMLInputElement>(null);
84
+
85
+ // Récupérer le contexte AiProvider avec fallback sur les props
86
+ const aiContext = useAiContext();
87
+ const baseUrl = propBaseUrl ?? aiContext.baseUrl;
88
+ const apiKeyId = propApiKeyId ?? aiContext.apiKeyId;
89
+
90
+ // Hooks pour l'IA avec les valeurs du contexte
91
+ const { models } = useAiModels({ baseUrl, apiKeyId });
92
+ const { generateText } = useAiCallText({ baseUrl, apiKeyId });
93
+
94
+ const addChip = (text: string) => {
95
+ if (!text.trim()) return;
96
+
97
+ const newChips = text
98
+ .split(/[,;]/)
99
+ .map((chip: string) => chip.trim())
100
+ .filter(Boolean);
101
+ const updatedChips = [...value];
102
+
103
+ newChips.forEach((chip: string) => {
104
+ if (maxChips && updatedChips.length >= maxChips) return;
105
+ if (!allowDuplicates && updatedChips.includes(chip)) return;
106
+ updatedChips.push(chip);
107
+ });
108
+
109
+ onChange?.(updatedChips);
110
+ setInputValue("");
111
+ };
112
+
113
+ const removeChip = (index: number) => {
114
+ const updatedChips = value.filter((_, i) => i !== index);
115
+ onChange?.(updatedChips);
116
+ };
117
+
118
+ const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {
119
+ if (e.key === "Enter") {
120
+ e.preventDefault();
121
+ addChip(inputValue);
122
+ } else if (e.key === "Backspace" && !inputValue && value.length > 0) {
123
+ removeChip(value.length - 1);
124
+ }
125
+ };
126
+
127
+ const handleGenerateChips = () => {
128
+ setShowPromptPanel(true);
129
+ };
130
+
131
+ const handlePromptSubmit = async (model: string, prompt: string) => {
132
+ try {
133
+ // Construire le prompt avec l'instruction spécifique
134
+ const instruction = `${prompt}${context ? `\n\nContexte: ${context}` : ""}
135
+
136
+ IMPORTANT: Réponds UNIQUEMENT avec une liste de tags séparés par des virgules, sans explication ni formatage.
137
+ Exemple de réponse attendue: javascript, react, frontend, api, development`;
138
+
139
+ const response = await generateText({
140
+ model,
141
+ prompt: instruction,
142
+ });
143
+
144
+ const chips = parseChipsFromResponse(response.text);
145
+
146
+ // Fermer le modal immédiatement
147
+ setShowPromptPanel(false);
148
+
149
+ // Ajouter directement toutes les chips générées
150
+ addGeneratedChips(chips);
151
+ } catch (error) {
152
+ console.error("Erreur lors de la génération des chips:", error);
153
+ setShowPromptPanel(false);
154
+ }
155
+ };
156
+
157
+ const parseChipsFromResponse = (response: string): string[] => {
158
+ return response
159
+ .split(/[,;]/)
160
+ .map((chip) => chip.trim())
161
+ .filter(Boolean)
162
+ .slice(0, 10); // Limiter à 10 tags
163
+ };
164
+
165
+ const addGeneratedChips = (chips: string[]) => {
166
+ const updatedChips = [...value];
167
+
168
+ chips.forEach((chip) => {
169
+ if (maxChips && updatedChips.length >= maxChips) return;
170
+ if (!allowDuplicates && updatedChips.includes(chip)) return;
171
+ updatedChips.push(chip);
172
+ });
173
+
174
+ onChange?.(updatedChips);
175
+ };
176
+
177
+ console.log("AiChipInput render - value:", value, "length:", value.length);
178
+
179
+ return (
180
+ <div className={className}>
181
+ {/* Input avec bouton génération */}
182
+ <div style={{ position: "relative", marginBottom: "8px" }}>
183
+ <input
184
+ ref={inputRef}
185
+ type="text"
186
+ value={inputValue}
187
+ onChange={(e) => setInputValue(e.target.value)}
188
+ onKeyDown={handleKeyDown}
189
+ placeholder={placeholder}
190
+ style={{
191
+ ...aiStyles.input,
192
+ paddingRight: "40px", // Space for button
193
+ }}
194
+ />
195
+ <button
196
+ onClick={handleGenerateChips}
197
+ style={{
198
+ position: "absolute",
199
+ right: "8px",
200
+ top: "50%",
201
+ transform: "translateY(-50%)",
202
+ background: "none",
203
+ border: "none",
204
+ cursor: "pointer",
205
+ padding: "4px",
206
+ borderRadius: "4px",
207
+ display: "flex",
208
+ alignItems: "center",
209
+ color: "#6366f1",
210
+ }}
211
+ title="Générer des tags avec l'IA"
212
+ >
213
+ <Sparkles size={16} />
214
+ </button>
215
+ </div>
216
+
217
+ {/* Chips affichées */}
218
+ {value.length > 0 && (
219
+ <div style={{ display: "flex", flexWrap: "wrap", gap: "6px" }}>
220
+ {value.map((chip, index) => {
221
+ console.log("Rendering chip:", chip, "at index:", index);
222
+ return (
223
+ <div
224
+ key={index}
225
+ style={{
226
+ ...aiStyles.chip,
227
+ display: "flex",
228
+ alignItems: "center",
229
+ gap: "6px",
230
+ paddingRight: "6px",
231
+ }}
232
+ >
233
+ <span>{chip}</span>
234
+ <button
235
+ onClick={() => removeChip(index)}
236
+ style={{
237
+ background: "none",
238
+ border: "none",
239
+ cursor: "pointer",
240
+ padding: "0",
241
+ display: "flex",
242
+ alignItems: "center",
243
+ color: "currentColor",
244
+ opacity: 0.7,
245
+ }}
246
+ title="Supprimer"
247
+ >
248
+ <X size={14} />
249
+ </button>
250
+ </div>
251
+ );
252
+ })}
253
+ </div>
254
+ )}
255
+
256
+ {/* AiPromptPanel pour la génération */}
257
+ <AiPromptPanel
258
+ isOpen={showPromptPanel}
259
+ onClose={() => setShowPromptPanel(false)}
260
+ onSubmit={handlePromptSubmit}
261
+ models={models || undefined}
262
+ baseUrl={baseUrl}
263
+ sourceText={context ? `Contexte: ${context}` : undefined}
264
+ />
265
+ </div>
266
+ );
267
+ }