@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.
- package/dist/components/AiChipLabel.d.ts +12 -0
- package/dist/components/AiChipLabel.d.ts.map +1 -1
- package/dist/components/AiChipLabel.js +129 -1
- package/dist/components/AiContextButton.d.ts +18 -0
- package/dist/components/AiContextButton.d.ts.map +1 -0
- package/dist/components/AiContextButton.js +339 -0
- package/dist/components/AiImageButton.d.ts +12 -3
- package/dist/components/AiImageButton.d.ts.map +1 -1
- package/dist/components/AiImageButton.js +218 -8
- package/dist/components/AiStatusButton.d.ts.map +1 -1
- package/dist/components/AiStatusButton.js +1 -1
- package/dist/components/UsageToast.d.ts.map +1 -1
- package/dist/components/UsageToast.js +5 -3
- package/dist/examples/AiChipInputExample.d.ts +2 -0
- package/dist/examples/AiChipInputExample.d.ts.map +1 -0
- package/dist/examples/AiChipInputExample.js +14 -0
- package/dist/examples/AiContextButtonExample.d.ts +2 -0
- package/dist/examples/AiContextButtonExample.d.ts.map +1 -0
- package/dist/examples/AiContextButtonExample.js +88 -0
- package/dist/examples/AiImageButtonExample.d.ts +2 -0
- package/dist/examples/AiImageButtonExample.d.ts.map +1 -0
- package/dist/examples/AiImageButtonExample.js +26 -0
- package/dist/hooks/useAiCallImage.d.ts.map +1 -1
- package/dist/hooks/useAiCallImage.js +107 -1
- package/dist/hooks/useAiCallText.d.ts.map +1 -1
- package/dist/hooks/useAiCallText.js +25 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/styles/inline.d.ts.map +1 -1
- package/dist/styles/inline.js +3 -1
- package/package.json +2 -2
- package/src/components/AiChipLabel.tsx +218 -1
- package/src/components/AiContextButton.tsx +553 -0
- package/src/components/AiImageButton.tsx +386 -38
- package/src/components/AiStatusButton.tsx +7 -3
- package/src/components/UsageToast.tsx +5 -3
- package/src/examples/AiChipInputExample.tsx +81 -0
- package/src/examples/AiContextButtonExample.tsx +338 -0
- package/src/examples/AiImageButtonExample.tsx +72 -0
- package/src/hooks/useAiCallImage.ts +149 -1
- package/src/hooks/useAiCallText.ts +30 -1
- package/src/index.ts +4 -0
- 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
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/styles/inline.js
CHANGED
|
@@ -242,7 +242,9 @@ export const aiStyles = {
|
|
|
242
242
|
lineHeight: "1.5",
|
|
243
243
|
color: themeVars.text,
|
|
244
244
|
background: themeVars.bg,
|
|
245
|
-
|
|
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.
|
|
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.
|
|
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
|
+
}
|