@lastbrain/ai-ui-react 1.0.3
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/README.md +84 -0
- package/dist/components/AiChipLabel.d.ts +8 -0
- package/dist/components/AiChipLabel.d.ts.map +1 -0
- package/dist/components/AiChipLabel.js +39 -0
- package/dist/components/AiImageButton.d.ts +8 -0
- package/dist/components/AiImageButton.d.ts.map +1 -0
- package/dist/components/AiImageButton.js +36 -0
- package/dist/components/AiInput.d.ts +7 -0
- package/dist/components/AiInput.d.ts.map +1 -0
- package/dist/components/AiInput.js +77 -0
- package/dist/components/AiModelSelect.d.ts +10 -0
- package/dist/components/AiModelSelect.d.ts.map +1 -0
- package/dist/components/AiModelSelect.js +5 -0
- package/dist/components/AiPromptPanel.d.ts +22 -0
- package/dist/components/AiPromptPanel.d.ts.map +1 -0
- package/dist/components/AiPromptPanel.js +30 -0
- package/dist/components/AiSelect.d.ts +8 -0
- package/dist/components/AiSelect.d.ts.map +1 -0
- package/dist/components/AiSelect.js +38 -0
- package/dist/components/AiSettingsButton.d.ts +11 -0
- package/dist/components/AiSettingsButton.d.ts.map +1 -0
- package/dist/components/AiSettingsButton.js +16 -0
- package/dist/components/AiTextarea.d.ts +7 -0
- package/dist/components/AiTextarea.d.ts.map +1 -0
- package/dist/components/AiTextarea.js +79 -0
- package/dist/context/AiProvider.d.ts +18 -0
- package/dist/context/AiProvider.d.ts.map +1 -0
- package/dist/context/AiProvider.js +20 -0
- package/dist/hooks/useAiCallImage.d.ts +12 -0
- package/dist/hooks/useAiCallImage.d.ts.map +1 -0
- package/dist/hooks/useAiCallImage.js +29 -0
- package/dist/hooks/useAiCallText.d.ts +12 -0
- package/dist/hooks/useAiCallText.d.ts.map +1 -0
- package/dist/hooks/useAiCallText.js +29 -0
- package/dist/hooks/useAiClient.d.ts +12 -0
- package/dist/hooks/useAiClient.d.ts.map +1 -0
- package/dist/hooks/useAiClient.js +13 -0
- package/dist/hooks/useAiModels.d.ts +13 -0
- package/dist/hooks/useAiModels.d.ts.map +1 -0
- package/dist/hooks/useAiModels.js +32 -0
- package/dist/hooks/useAiStatus.d.ts +13 -0
- package/dist/hooks/useAiStatus.d.ts.map +1 -0
- package/dist/hooks/useAiStatus.js +32 -0
- package/dist/hooks/usePrompts.d.ts +35 -0
- package/dist/hooks/usePrompts.d.ts.map +1 -0
- package/dist/hooks/usePrompts.js +125 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/types.d.ts +20 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/package.json +60 -0
- package/src/components/AiChipLabel.tsx +88 -0
- package/src/components/AiImageButton.tsx +87 -0
- package/src/components/AiInput.tsx +150 -0
- package/src/components/AiModelSelect.tsx +37 -0
- package/src/components/AiPromptPanel.tsx +120 -0
- package/src/components/AiSelect.tsx +91 -0
- package/src/components/AiSettingsButton.tsx +111 -0
- package/src/components/AiTextarea.tsx +152 -0
- package/src/context/AiProvider.tsx +44 -0
- package/src/hooks/useAiCallImage.ts +49 -0
- package/src/hooks/useAiCallText.ts +49 -0
- package/src/hooks/useAiClient.ts +23 -0
- package/src/hooks/useAiModels.ts +50 -0
- package/src/hooks/useAiStatus.ts +50 -0
- package/src/hooks/usePrompts.ts +187 -0
- package/src/index.ts +23 -0
- package/src/types.ts +20 -0
package/README.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# @lastbrain/ai-ui-react
|
|
2
|
+
|
|
3
|
+
Headless React components for LastBrain AI UI Kit.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Headless components (no UI library dependency)
|
|
8
|
+
- React hooks for AI operations
|
|
9
|
+
- Context provider for configuration
|
|
10
|
+
- TypeScript support
|
|
11
|
+
- SSR safe
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @lastbrain/ai-ui-react @lastbrain/ai-ui-core
|
|
17
|
+
# or
|
|
18
|
+
pnpm add @lastbrain/ai-ui-react @lastbrain/ai-ui-core
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
### With Provider (Recommended)
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
import { AiProvider, AiInput, AiSettingsButton } from "@lastbrain/ai-ui-react";
|
|
27
|
+
|
|
28
|
+
function App() {
|
|
29
|
+
return (
|
|
30
|
+
<AiProvider baseUrl="https://api.lastbrain.com" apiKeyId="your-key">
|
|
31
|
+
<div>
|
|
32
|
+
<AiInput
|
|
33
|
+
model="openai/gpt-4o-mini"
|
|
34
|
+
prompt="Improve this text"
|
|
35
|
+
onValue={(text) => console.log(text)}
|
|
36
|
+
onToast={(toast) => alert(toast.message)}
|
|
37
|
+
/>
|
|
38
|
+
<AiSettingsButton />
|
|
39
|
+
</div>
|
|
40
|
+
</AiProvider>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Without Provider
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
import { AiInput } from "@lastbrain/ai-ui-react";
|
|
49
|
+
|
|
50
|
+
function MyComponent() {
|
|
51
|
+
return (
|
|
52
|
+
<AiInput
|
|
53
|
+
baseUrl="https://api.lastbrain.com"
|
|
54
|
+
apiKeyId="your-key"
|
|
55
|
+
model="openai/gpt-4o-mini"
|
|
56
|
+
prompt="Improve this text"
|
|
57
|
+
onValue={(text) => console.log(text)}
|
|
58
|
+
/>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Components
|
|
64
|
+
|
|
65
|
+
- `AiInput` - Text input with AI assistance
|
|
66
|
+
- `AiTextarea` - Textarea with AI assistance
|
|
67
|
+
- `AiSelect` - Select dropdown with AI assistance
|
|
68
|
+
- `AiChipLabel` - Chip/label with AI assistance
|
|
69
|
+
- `AiImageButton` - Button for AI image generation
|
|
70
|
+
- `AiSettingsButton` - Settings button with status display
|
|
71
|
+
- `AiPromptPanel` - Modal/drawer for model and prompt selection
|
|
72
|
+
- `AiModelSelect` - Model selection dropdown
|
|
73
|
+
|
|
74
|
+
## Hooks
|
|
75
|
+
|
|
76
|
+
- `useAiClient` - Access AI client instance
|
|
77
|
+
- `useAiModels` - Fetch available models
|
|
78
|
+
- `useAiStatus` - Fetch user status (tokens, wallet, storage)
|
|
79
|
+
- `useAiCallText` - Generate text
|
|
80
|
+
- `useAiCallImage` - Generate images
|
|
81
|
+
|
|
82
|
+
## API Reference
|
|
83
|
+
|
|
84
|
+
See the [full documentation](https://docs.lastbrain.com/ai-ui-kit/react) for detailed API reference.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type HTMLAttributes } from "react";
|
|
2
|
+
import type { BaseAiProps } from "../types";
|
|
3
|
+
export interface AiChipLabelProps extends Omit<BaseAiProps, "type">, HTMLAttributes<HTMLDivElement> {
|
|
4
|
+
label?: string;
|
|
5
|
+
uiMode?: "modal" | "drawer";
|
|
6
|
+
}
|
|
7
|
+
export declare function AiChipLabel({ baseUrl, apiKeyId, uiMode, context, model, prompt, onValue, onToast, disabled, className, label, ...divProps }: AiChipLabelProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
//# sourceMappingURL=AiChipLabel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AiChipLabel.d.ts","sourceRoot":"","sources":["../../src/components/AiChipLabel.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAY,KAAK,cAAc,EAAE,MAAM,OAAO,CAAC;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAK5C,MAAM,WAAW,gBACf,SAAQ,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE,cAAc,CAAC,cAAc,CAAC;IACjE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;CAC7B;AAED,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,QAAQ,EACR,MAAgB,EAChB,OAAO,EACP,KAAK,EACL,MAAM,EACN,OAAO,EACP,OAAO,EACP,QAAQ,EACR,SAAS,EACT,KAAK,EACL,GAAG,QAAQ,EACZ,EAAE,gBAAgB,2CA4DlB"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { useAiCallText } from "../hooks/useAiCallText";
|
|
5
|
+
import { useAiModels } from "../hooks/useAiModels";
|
|
6
|
+
import { AiPromptPanel } from "./AiPromptPanel";
|
|
7
|
+
export function AiChipLabel({ baseUrl, apiKeyId, uiMode = "modal", context, model, prompt, onValue, onToast, disabled, className, label, ...divProps }) {
|
|
8
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
9
|
+
const [chipLabel, setChipLabel] = useState(label || "");
|
|
10
|
+
const { models } = useAiModels({ baseUrl, apiKeyId });
|
|
11
|
+
const { generateText, loading } = useAiCallText({ baseUrl, apiKeyId });
|
|
12
|
+
const handleOpenPanel = () => {
|
|
13
|
+
setIsOpen(true);
|
|
14
|
+
};
|
|
15
|
+
const handleClosePanel = () => {
|
|
16
|
+
setIsOpen(false);
|
|
17
|
+
};
|
|
18
|
+
const handleSubmit = async (selectedModel, selectedPrompt) => {
|
|
19
|
+
try {
|
|
20
|
+
const result = await generateText({
|
|
21
|
+
model: selectedModel,
|
|
22
|
+
prompt: selectedPrompt,
|
|
23
|
+
context: context || chipLabel || undefined,
|
|
24
|
+
});
|
|
25
|
+
if (result.text) {
|
|
26
|
+
setChipLabel(result.text);
|
|
27
|
+
onValue?.(result.text);
|
|
28
|
+
onToast?.({ type: "success", message: "Label generated successfully" });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
onToast?.({ type: "error", message: "Failed to generate label" });
|
|
33
|
+
}
|
|
34
|
+
finally {
|
|
35
|
+
setIsOpen(false);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
return (_jsxs("div", { "data-ai-chip-wrapper": true, className: className, ...divProps, children: [_jsx("div", { "data-ai-chip-label": true, children: chipLabel || "Generate label" }), _jsx("button", { onClick: handleOpenPanel, disabled: disabled || loading, "data-ai-chip-button": true, type: "button", children: loading ? "..." : "✨" }), isOpen && (_jsx(AiPromptPanel, { isOpen: isOpen, onClose: handleClosePanel, onSubmit: handleSubmit, uiMode: uiMode, models: models || [] }))] }));
|
|
39
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type ButtonHTMLAttributes } from "react";
|
|
2
|
+
import type { BaseAiProps } from "../types";
|
|
3
|
+
export interface AiImageButtonProps extends Omit<BaseAiProps, "onValue" | "type">, ButtonHTMLAttributes<HTMLButtonElement> {
|
|
4
|
+
onImage?: (imageUrl: string) => void;
|
|
5
|
+
uiMode?: "modal" | "drawer";
|
|
6
|
+
}
|
|
7
|
+
export declare function AiImageButton({ baseUrl, apiKeyId, uiMode, context, model, prompt, onImage, onToast, disabled, className, children, ...buttonProps }: AiImageButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
//# sourceMappingURL=AiImageButton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AiImageButton.d.ts","sourceRoot":"","sources":["../../src/components/AiImageButton.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAY,KAAK,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAK5C,MAAM,WAAW,kBACf,SACE,IAAI,CAAC,WAAW,EAAE,SAAS,GAAG,MAAM,CAAC,EACrC,oBAAoB,CAAC,iBAAiB,CAAC;IACzC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;CAC7B;AAED,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EACP,QAAQ,EACR,MAAgB,EAChB,OAAO,EACP,KAAK,EACL,MAAM,EACN,OAAO,EACP,OAAO,EACP,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,GAAG,WAAW,EACf,EAAE,kBAAkB,2CAyDpB"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { useAiCallImage } from "../hooks/useAiCallImage";
|
|
5
|
+
import { useAiModels } from "../hooks/useAiModels";
|
|
6
|
+
import { AiPromptPanel } from "./AiPromptPanel";
|
|
7
|
+
export function AiImageButton({ baseUrl, apiKeyId, uiMode = "modal", context, model, prompt, onImage, onToast, disabled, className, children, ...buttonProps }) {
|
|
8
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
9
|
+
const { models } = useAiModels({ baseUrl, apiKeyId });
|
|
10
|
+
const { generateImage, loading } = useAiCallImage({ baseUrl, apiKeyId });
|
|
11
|
+
const handleOpenPanel = () => {
|
|
12
|
+
setIsOpen(true);
|
|
13
|
+
};
|
|
14
|
+
const handleClosePanel = () => {
|
|
15
|
+
setIsOpen(false);
|
|
16
|
+
};
|
|
17
|
+
const handleSubmit = async (selectedModel, selectedPrompt) => {
|
|
18
|
+
try {
|
|
19
|
+
const result = await generateImage({
|
|
20
|
+
model: selectedModel,
|
|
21
|
+
prompt: selectedPrompt,
|
|
22
|
+
});
|
|
23
|
+
if (result.url) {
|
|
24
|
+
onImage?.(result.url);
|
|
25
|
+
onToast?.({ type: "success", message: "Image generated successfully" });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
onToast?.({ type: "error", message: "Failed to generate image" });
|
|
30
|
+
}
|
|
31
|
+
finally {
|
|
32
|
+
setIsOpen(false);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
return (_jsxs(_Fragment, { children: [_jsx("button", { ...buttonProps, onClick: handleOpenPanel, disabled: disabled || loading, className: className, "data-ai-image-button": true, children: loading ? "Generating..." : children || "Generate Image" }), isOpen && (_jsx(AiPromptPanel, { isOpen: isOpen, onClose: handleClosePanel, onSubmit: handleSubmit, uiMode: uiMode, models: models?.filter((m) => m.type === "image") || [] }))] }));
|
|
36
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type InputHTMLAttributes } from "react";
|
|
2
|
+
import type { BaseAiProps } from "../types";
|
|
3
|
+
export interface AiInputProps extends Omit<BaseAiProps, "type">, Omit<InputHTMLAttributes<HTMLInputElement>, "onValue"> {
|
|
4
|
+
uiMode?: "modal" | "drawer";
|
|
5
|
+
}
|
|
6
|
+
export declare function AiInput({ baseUrl, apiKeyId, uiMode, context, model, prompt, editMode, onValue, onToast, disabled, className, ...inputProps }: AiInputProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
//# sourceMappingURL=AiInput.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AiInput.d.ts","sourceRoot":"","sources":["../../src/components/AiInput.tsx"],"names":[],"mappings":"AAEA,OAAc,EAAoB,KAAK,mBAAmB,EAAE,MAAM,OAAO,CAAC;AAC1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAK5C,MAAM,WAAW,YACf,SACE,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,EACzB,IAAI,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAAE,SAAS,CAAC;IACxD,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;CAC7B;AAED,wBAAgB,OAAO,CAAC,EACtB,OAAO,EACP,QAAQ,EACR,MAAgB,EAChB,OAAO,EACP,KAAK,EACL,MAAM,EACN,QAAgB,EAChB,OAAO,EACP,OAAO,EACP,QAAQ,EACR,SAAS,EACT,GAAG,UAAU,EACd,EAAE,YAAY,2CAyHd"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState, useRef } from "react";
|
|
4
|
+
import { useAiCallText } from "../hooks/useAiCallText";
|
|
5
|
+
import { useAiModels } from "../hooks/useAiModels";
|
|
6
|
+
import { AiPromptPanel } from "./AiPromptPanel";
|
|
7
|
+
export function AiInput({ baseUrl, apiKeyId, uiMode = "modal", context, model, prompt, editMode = false, onValue, onToast, disabled, className, ...inputProps }) {
|
|
8
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
9
|
+
const [inputValue, setInputValue] = useState(inputProps.value?.toString() || inputProps.defaultValue?.toString() || "");
|
|
10
|
+
const inputRef = useRef(null);
|
|
11
|
+
const { models } = useAiModels({ baseUrl, apiKeyId });
|
|
12
|
+
const { generateText, loading } = useAiCallText({ baseUrl, apiKeyId });
|
|
13
|
+
const hasConfiguration = Boolean(model && prompt);
|
|
14
|
+
const handleOpenPanel = () => {
|
|
15
|
+
setIsOpen(true);
|
|
16
|
+
};
|
|
17
|
+
const handleClosePanel = () => {
|
|
18
|
+
setIsOpen(false);
|
|
19
|
+
};
|
|
20
|
+
const handleSubmit = async (selectedModel, selectedPrompt) => {
|
|
21
|
+
try {
|
|
22
|
+
const result = await generateText({
|
|
23
|
+
model: selectedModel,
|
|
24
|
+
prompt: selectedPrompt,
|
|
25
|
+
context: context || inputValue || undefined,
|
|
26
|
+
actionType: "autocomplete",
|
|
27
|
+
});
|
|
28
|
+
if (result.text) {
|
|
29
|
+
if (editMode) {
|
|
30
|
+
setInputValue(result.text);
|
|
31
|
+
if (inputRef.current) {
|
|
32
|
+
inputRef.current.value = result.text;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
onValue?.(result.text);
|
|
36
|
+
onToast?.({ type: "success", message: "AI generation successful" });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
onToast?.({ type: "error", message: "Failed to generate text" });
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
setIsOpen(false);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
const handleQuickGenerate = async () => {
|
|
47
|
+
if (!model || !prompt)
|
|
48
|
+
return;
|
|
49
|
+
try {
|
|
50
|
+
const result = await generateText({
|
|
51
|
+
model,
|
|
52
|
+
prompt,
|
|
53
|
+
context: context || inputValue || undefined,
|
|
54
|
+
actionType: "autocomplete",
|
|
55
|
+
});
|
|
56
|
+
if (result.text) {
|
|
57
|
+
if (editMode) {
|
|
58
|
+
setInputValue(result.text);
|
|
59
|
+
if (inputRef.current) {
|
|
60
|
+
inputRef.current.value = result.text;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
onValue?.(result.text);
|
|
64
|
+
onToast?.({ type: "success", message: "AI generation successful" });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
onToast?.({ type: "error", message: "Failed to generate text" });
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
const handleInputChange = (e) => {
|
|
72
|
+
const newValue = e.target.value;
|
|
73
|
+
setInputValue(newValue);
|
|
74
|
+
inputProps.onChange?.(e);
|
|
75
|
+
};
|
|
76
|
+
return (_jsxs("div", { "data-ai-input-wrapper": true, className: className, children: [_jsx("input", { ref: inputRef, ...inputProps, value: inputValue, onChange: handleInputChange, disabled: disabled || loading, "data-ai-input": true }), hasConfiguration ? (_jsx("button", { onClick: handleQuickGenerate, disabled: disabled || loading, "data-ai-generate-button": true, type: "button", children: loading ? "Generating..." : "AI" })) : (_jsx("button", { onClick: handleOpenPanel, disabled: disabled || loading, "data-ai-setup-button": true, type: "button", children: "Setup AI" })), isOpen && (_jsx(AiPromptPanel, { isOpen: isOpen, onClose: handleClosePanel, onSubmit: handleSubmit, uiMode: uiMode, models: models || [] }))] }));
|
|
77
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ModelRef } from "@lastbrain/ai-ui-core";
|
|
2
|
+
export interface AiModelSelectProps {
|
|
3
|
+
models: ModelRef[];
|
|
4
|
+
value: string;
|
|
5
|
+
onChange: (value: string) => void;
|
|
6
|
+
className?: string;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function AiModelSelect({ models, value, onChange, className, disabled, }: AiModelSelectProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
//# sourceMappingURL=AiModelSelect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AiModelSelect.d.ts","sourceRoot":"","sources":["../../src/components/AiModelSelect.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEtD,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,aAAa,CAAC,EAC5B,MAAM,EACN,KAAK,EACL,QAAQ,EACR,SAAS,EACT,QAAQ,GACT,EAAE,kBAAkB,2CAiBpB"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
export function AiModelSelect({ models, value, onChange, className, disabled, }) {
|
|
4
|
+
return (_jsxs("select", { value: value, onChange: (e) => onChange(e.target.value), className: className, disabled: disabled, "data-ai-model-select": true, children: [_jsx("option", { value: "", children: "Select a model" }), models.map((model) => (_jsx("option", { value: model.id, children: model.name }, model.id)))] }));
|
|
5
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { ModelRef } from "@lastbrain/ai-ui-core";
|
|
3
|
+
import type { UiMode } from "../types";
|
|
4
|
+
export interface AiPromptPanelProps {
|
|
5
|
+
isOpen: boolean;
|
|
6
|
+
onClose: () => void;
|
|
7
|
+
onSubmit: (model: string, prompt: string) => void;
|
|
8
|
+
uiMode?: UiMode;
|
|
9
|
+
models?: ModelRef[];
|
|
10
|
+
children?: (props: AiPromptPanelRenderProps) => ReactNode;
|
|
11
|
+
}
|
|
12
|
+
export interface AiPromptPanelRenderProps {
|
|
13
|
+
models?: ModelRef[];
|
|
14
|
+
selectedModel: string;
|
|
15
|
+
setSelectedModel: (model: string) => void;
|
|
16
|
+
prompt: string;
|
|
17
|
+
setPrompt: (prompt: string) => void;
|
|
18
|
+
handleSubmit: () => void;
|
|
19
|
+
handleClose: () => void;
|
|
20
|
+
}
|
|
21
|
+
export declare function AiPromptPanel({ isOpen, onClose, onSubmit, uiMode, models, children, }: AiPromptPanelProps): import("react/jsx-runtime").JSX.Element | null;
|
|
22
|
+
//# sourceMappingURL=AiPromptPanel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AiPromptPanel.d.ts","sourceRoot":"","sources":["../../src/components/AiPromptPanel.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACjD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAClD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC;IACpB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,wBAAwB,KAAK,SAAS,CAAC;CAC3D;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,IAAI,CAAC;CACzB;AAED,wBAAgB,aAAa,CAAC,EAC5B,MAAM,EACN,OAAO,EACP,QAAQ,EACR,MAAgB,EAChB,MAAW,EACX,QAAQ,GACT,EAAE,kBAAkB,kDAuFpB"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
export function AiPromptPanel({ isOpen, onClose, onSubmit, uiMode = "modal", models = [], children, }) {
|
|
5
|
+
const [selectedModel, setSelectedModel] = useState(models[0]?.id || "");
|
|
6
|
+
const [prompt, setPrompt] = useState("");
|
|
7
|
+
if (!isOpen)
|
|
8
|
+
return null;
|
|
9
|
+
const handleSubmit = () => {
|
|
10
|
+
onSubmit(selectedModel, prompt);
|
|
11
|
+
setPrompt("");
|
|
12
|
+
};
|
|
13
|
+
const handleClose = () => {
|
|
14
|
+
onClose();
|
|
15
|
+
setPrompt("");
|
|
16
|
+
};
|
|
17
|
+
const renderProps = {
|
|
18
|
+
models,
|
|
19
|
+
selectedModel,
|
|
20
|
+
setSelectedModel,
|
|
21
|
+
prompt,
|
|
22
|
+
setPrompt,
|
|
23
|
+
handleSubmit,
|
|
24
|
+
handleClose,
|
|
25
|
+
};
|
|
26
|
+
if (children) {
|
|
27
|
+
return (_jsx("div", { "data-ai-prompt-panel": true, "data-type": uiMode, children: children(renderProps) }));
|
|
28
|
+
}
|
|
29
|
+
return (_jsxs("div", { "data-ai-prompt-panel": true, "data-type": uiMode, children: [_jsx("div", { "data-ai-prompt-panel-overlay": true, onClick: handleClose }), _jsxs("div", { "data-ai-prompt-panel-content": true, children: [_jsxs("div", { "data-ai-prompt-panel-header": true, children: [_jsx("h2", { children: "AI Prompt" }), _jsx("button", { onClick: handleClose, "data-ai-close-button": true, children: "\u00D7" })] }), _jsxs("div", { "data-ai-prompt-panel-body": true, children: [_jsxs("div", { "data-ai-model-select-wrapper": true, children: [_jsx("label", { htmlFor: "model-select", children: "Model" }), _jsx("select", { id: "model-select", value: selectedModel, onChange: (e) => setSelectedModel(e.target.value), "data-ai-model-select": true, children: models.map((model) => (_jsx("option", { value: model.id, children: model.name }, model.id))) })] }), _jsxs("div", { "data-ai-prompt-wrapper": true, children: [_jsx("label", { htmlFor: "prompt-input", children: "Prompt" }), _jsx("textarea", { id: "prompt-input", value: prompt, onChange: (e) => setPrompt(e.target.value), placeholder: "Enter your prompt...", rows: 5, "data-ai-prompt-input": true })] })] }), _jsxs("div", { "data-ai-prompt-panel-footer": true, children: [_jsx("button", { onClick: handleClose, "data-ai-cancel-button": true, children: "Cancel" }), _jsx("button", { onClick: handleSubmit, disabled: !selectedModel || !prompt, "data-ai-submit-button": true, children: "Generate" })] })] })] }));
|
|
30
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React, { type SelectHTMLAttributes } from "react";
|
|
2
|
+
import type { BaseAiProps } from "../types";
|
|
3
|
+
export interface AiSelectProps extends Omit<BaseAiProps, "type">, Omit<SelectHTMLAttributes<HTMLSelectElement>, "onValue"> {
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
uiMode?: "modal" | "drawer";
|
|
6
|
+
}
|
|
7
|
+
export declare function AiSelect({ baseUrl, apiKeyId, uiMode, context, model, prompt, onValue, onToast, disabled, className, children, ...selectProps }: AiSelectProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
//# sourceMappingURL=AiSelect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AiSelect.d.ts","sourceRoot":"","sources":["../../src/components/AiSelect.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAY,KAAK,oBAAoB,EAAE,MAAM,OAAO,CAAC;AACnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAK5C,MAAM,WAAW,aACf,SACE,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,EACzB,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,SAAS,CAAC;IAC1D,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;CAC7B;AAED,wBAAgB,QAAQ,CAAC,EACvB,OAAO,EACP,QAAQ,EACR,MAAgB,EAChB,OAAO,EACP,KAAK,EACL,MAAM,EACN,OAAO,EACP,OAAO,EACP,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,GAAG,WAAW,EACf,EAAE,aAAa,2CA6Df"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { useAiCallText } from "../hooks/useAiCallText";
|
|
5
|
+
import { useAiModels } from "../hooks/useAiModels";
|
|
6
|
+
import { AiPromptPanel } from "./AiPromptPanel";
|
|
7
|
+
export function AiSelect({ baseUrl, apiKeyId, uiMode = "modal", context, model, prompt, onValue, onToast, disabled, className, children, ...selectProps }) {
|
|
8
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
9
|
+
const { models } = useAiModels({ baseUrl, apiKeyId });
|
|
10
|
+
const { generateText, loading } = useAiCallText({ baseUrl, apiKeyId });
|
|
11
|
+
const handleOpenPanel = () => {
|
|
12
|
+
setIsOpen(true);
|
|
13
|
+
};
|
|
14
|
+
const handleClosePanel = () => {
|
|
15
|
+
setIsOpen(false);
|
|
16
|
+
};
|
|
17
|
+
const handleSubmit = async (selectedModel, selectedPrompt) => {
|
|
18
|
+
try {
|
|
19
|
+
const result = await generateText({
|
|
20
|
+
model: selectedModel,
|
|
21
|
+
prompt: selectedPrompt,
|
|
22
|
+
context: context || undefined,
|
|
23
|
+
actionType: "autocomplete",
|
|
24
|
+
});
|
|
25
|
+
if (result.text) {
|
|
26
|
+
onValue?.(result.text);
|
|
27
|
+
onToast?.({ type: "success", message: "AI suggestion ready" });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
onToast?.({ type: "error", message: "Failed to generate suggestion" });
|
|
32
|
+
}
|
|
33
|
+
finally {
|
|
34
|
+
setIsOpen(false);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
return (_jsxs("div", { "data-ai-select-wrapper": true, className: className, children: [_jsx("select", { ...selectProps, disabled: disabled || loading, "data-ai-select": true, children: children }), _jsx("button", { onClick: handleOpenPanel, disabled: disabled || loading, "data-ai-assist-button": true, type: "button", children: "AI Assist" }), isOpen && (_jsx(AiPromptPanel, { isOpen: isOpen, onClose: handleClosePanel, onSubmit: handleSubmit, uiMode: uiMode, models: models || [] }))] }));
|
|
38
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type ButtonHTMLAttributes } from "react";
|
|
2
|
+
export interface AiSettingsButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
3
|
+
baseUrl?: string;
|
|
4
|
+
apiKeyId?: string;
|
|
5
|
+
onAddTokens?: () => void;
|
|
6
|
+
onAddStorage?: () => void;
|
|
7
|
+
onDashboard?: () => void;
|
|
8
|
+
onDocumentation?: () => void;
|
|
9
|
+
}
|
|
10
|
+
export declare function AiSettingsButton({ baseUrl, apiKeyId, onAddTokens, onAddStorage, onDashboard, onDocumentation, className, children, ...buttonProps }: AiSettingsButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
//# sourceMappingURL=AiSettingsButton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AiSettingsButton.d.ts","sourceRoot":"","sources":["../../src/components/AiSettingsButton.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAY,KAAK,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAG5D,MAAM,WAAW,qBAAsB,SAAQ,oBAAoB,CAAC,iBAAiB,CAAC;IACpF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;CAC9B;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,OAAO,EACP,QAAQ,EACR,WAAW,EACX,YAAY,EACZ,WAAW,EACX,eAAe,EACf,SAAS,EACT,QAAQ,EACR,GAAG,WAAW,EACf,EAAE,qBAAqB,2CAsFvB"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { useAiStatus } from "../hooks/useAiStatus";
|
|
5
|
+
export function AiSettingsButton({ baseUrl, apiKeyId, onAddTokens, onAddStorage, onDashboard, onDocumentation, className, children, ...buttonProps }) {
|
|
6
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
7
|
+
const { status, loading } = useAiStatus({ baseUrl, apiKeyId });
|
|
8
|
+
const handleToggle = () => {
|
|
9
|
+
setIsOpen(!isOpen);
|
|
10
|
+
};
|
|
11
|
+
const handleClose = () => {
|
|
12
|
+
setIsOpen(false);
|
|
13
|
+
};
|
|
14
|
+
const hasApiKey = Boolean(apiKeyId);
|
|
15
|
+
return (_jsxs("div", { "data-ai-settings-wrapper": true, children: [_jsx("button", { ...buttonProps, onClick: handleToggle, className: className, "data-ai-settings-button": true, disabled: loading, children: children || "AI Settings" }), isOpen && (_jsxs("div", { "data-ai-settings-panel": true, children: [_jsx("div", { "data-ai-settings-overlay": true, onClick: handleClose }), _jsxs("div", { "data-ai-settings-content": true, children: [_jsxs("div", { "data-ai-settings-header": true, children: [_jsx("h3", { children: "AI Settings" }), _jsx("button", { onClick: handleClose, "data-ai-close-button": true, children: "\u00D7" })] }), _jsx("div", { "data-ai-settings-body": true, children: hasApiKey ? (_jsxs(_Fragment, { children: [status && (_jsxs("div", { "data-ai-status-section": true, children: [_jsxs("div", { "data-ai-status-item": true, children: [_jsx("span", { children: "Tokens:" }), _jsx("span", { children: status.balance?.total || 0 })] }), status.storage?.total_mb !== undefined && (_jsxs("div", { "data-ai-status-item": true, children: [_jsx("span", { children: "Storage:" }), _jsxs("span", { children: [status.storage.total_mb.toFixed(2), " MB"] })] }))] })), _jsxs("div", { "data-ai-actions-section": true, children: [onDashboard && (_jsx("button", { onClick: onDashboard, "data-ai-action-button": true, children: "Dashboard" })), onAddTokens && (_jsx("button", { onClick: onAddTokens, "data-ai-action-button": true, children: "Add Tokens" })), onAddStorage && (_jsx("button", { onClick: onAddStorage, "data-ai-action-button": true, children: "Add Storage" }))] })] })) : (_jsxs("div", { "data-ai-no-key-section": true, children: [_jsx("p", { children: "No API key configured" }), onDocumentation && (_jsx("button", { onClick: onDocumentation, "data-ai-action-button": true, children: "View Documentation" }))] })) })] })] }))] }));
|
|
16
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type TextareaHTMLAttributes } from "react";
|
|
2
|
+
import type { BaseAiProps } from "../types";
|
|
3
|
+
export interface AiTextareaProps extends Omit<BaseAiProps, "type">, Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, "onValue"> {
|
|
4
|
+
uiMode?: "modal" | "drawer";
|
|
5
|
+
}
|
|
6
|
+
export declare function AiTextarea({ baseUrl, apiKeyId, uiMode, context, model, prompt, editMode, onValue, onToast, disabled, className, ...textareaProps }: AiTextareaProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
//# sourceMappingURL=AiTextarea.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AiTextarea.d.ts","sourceRoot":"","sources":["../../src/components/AiTextarea.tsx"],"names":[],"mappings":"AAEA,OAAc,EAAoB,KAAK,sBAAsB,EAAE,MAAM,OAAO,CAAC;AAC7E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAK5C,MAAM,WAAW,eACf,SACE,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,EACzB,IAAI,CAAC,sBAAsB,CAAC,mBAAmB,CAAC,EAAE,SAAS,CAAC;IAC9D,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;CAC7B;AAED,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,QAAQ,EACR,MAAgB,EAChB,OAAO,EACP,KAAK,EACL,MAAM,EACN,QAAgB,EAChB,OAAO,EACP,OAAO,EACP,QAAQ,EACR,SAAS,EACT,GAAG,aAAa,EACjB,EAAE,eAAe,2CA2HjB"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState, useRef } from "react";
|
|
4
|
+
import { useAiCallText } from "../hooks/useAiCallText";
|
|
5
|
+
import { useAiModels } from "../hooks/useAiModels";
|
|
6
|
+
import { AiPromptPanel } from "./AiPromptPanel";
|
|
7
|
+
export function AiTextarea({ baseUrl, apiKeyId, uiMode = "modal", context, model, prompt, editMode = false, onValue, onToast, disabled, className, ...textareaProps }) {
|
|
8
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
9
|
+
const [textValue, setTextValue] = useState(textareaProps.value?.toString() ||
|
|
10
|
+
textareaProps.defaultValue?.toString() ||
|
|
11
|
+
"");
|
|
12
|
+
const textareaRef = useRef(null);
|
|
13
|
+
const { models } = useAiModels({ baseUrl, apiKeyId });
|
|
14
|
+
const { generateText, loading } = useAiCallText({ baseUrl, apiKeyId });
|
|
15
|
+
const hasConfiguration = Boolean(model && prompt);
|
|
16
|
+
const handleOpenPanel = () => {
|
|
17
|
+
setIsOpen(true);
|
|
18
|
+
};
|
|
19
|
+
const handleClosePanel = () => {
|
|
20
|
+
setIsOpen(false);
|
|
21
|
+
};
|
|
22
|
+
const handleSubmit = async (selectedModel, selectedPrompt) => {
|
|
23
|
+
try {
|
|
24
|
+
const result = await generateText({
|
|
25
|
+
model: selectedModel,
|
|
26
|
+
prompt: selectedPrompt,
|
|
27
|
+
context: context || textValue || undefined,
|
|
28
|
+
actionType: "autocomplete",
|
|
29
|
+
});
|
|
30
|
+
if (result.text) {
|
|
31
|
+
if (editMode) {
|
|
32
|
+
setTextValue(result.text);
|
|
33
|
+
if (textareaRef.current) {
|
|
34
|
+
textareaRef.current.value = result.text;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
onValue?.(result.text);
|
|
38
|
+
onToast?.({ type: "success", message: "AI generation successful" });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
onToast?.({ type: "error", message: "Failed to generate text" });
|
|
43
|
+
}
|
|
44
|
+
finally {
|
|
45
|
+
setIsOpen(false);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
const handleQuickGenerate = async () => {
|
|
49
|
+
if (!model || !prompt)
|
|
50
|
+
return;
|
|
51
|
+
try {
|
|
52
|
+
const result = await generateText({
|
|
53
|
+
model,
|
|
54
|
+
prompt,
|
|
55
|
+
context: context || textValue || undefined,
|
|
56
|
+
actionType: "autocomplete",
|
|
57
|
+
});
|
|
58
|
+
if (result.text) {
|
|
59
|
+
if (editMode) {
|
|
60
|
+
setTextValue(result.text);
|
|
61
|
+
if (textareaRef.current) {
|
|
62
|
+
textareaRef.current.value = result.text;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
onValue?.(result.text);
|
|
66
|
+
onToast?.({ type: "success", message: "AI generation successful" });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
onToast?.({ type: "error", message: "Failed to generate text" });
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
const handleTextareaChange = (e) => {
|
|
74
|
+
const newValue = e.target.value;
|
|
75
|
+
setTextValue(newValue);
|
|
76
|
+
textareaProps.onChange?.(e);
|
|
77
|
+
};
|
|
78
|
+
return (_jsxs("div", { "data-ai-textarea-wrapper": true, className: className, children: [_jsx("textarea", { ref: textareaRef, ...textareaProps, value: textValue, onChange: handleTextareaChange, disabled: disabled || loading, "data-ai-textarea": true }), hasConfiguration ? (_jsx("button", { onClick: handleQuickGenerate, disabled: disabled || loading, "data-ai-generate-button": true, type: "button", children: loading ? "Generating..." : "AI" })) : (_jsx("button", { onClick: handleOpenPanel, disabled: disabled || loading, "data-ai-setup-button": true, type: "button", children: "Setup AI" })), isOpen && (_jsx(AiPromptPanel, { isOpen: isOpen, onClose: handleClosePanel, onSubmit: handleSubmit, uiMode: uiMode, models: models || [] }))] }));
|
|
79
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { UiMode } from "../types";
|
|
3
|
+
export interface AiContextValue {
|
|
4
|
+
baseUrl: string;
|
|
5
|
+
apiKeyId: string;
|
|
6
|
+
uiMode: UiMode;
|
|
7
|
+
}
|
|
8
|
+
declare const AiContext: import("react").Context<AiContextValue | undefined>;
|
|
9
|
+
export interface AiProviderProps {
|
|
10
|
+
baseUrl: string;
|
|
11
|
+
apiKeyId: string;
|
|
12
|
+
uiMode?: UiMode;
|
|
13
|
+
children: ReactNode;
|
|
14
|
+
}
|
|
15
|
+
export declare function AiProvider({ baseUrl, apiKeyId, uiMode, children, }: AiProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
export declare function useAiContext(): AiContextValue;
|
|
17
|
+
export { AiContext };
|
|
18
|
+
//# sourceMappingURL=AiProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AiProvider.d.ts","sourceRoot":"","sources":["../../src/context/AiProvider.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA6B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAClE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,QAAA,MAAM,SAAS,qDAAuD,CAAC;AAEvE,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,QAAQ,EACR,MAAgB,EAChB,QAAQ,GACT,EAAE,eAAe,2CAQjB;AAED,wBAAgB,YAAY,IAAI,cAAc,CAM7C;AAED,OAAO,EAAE,SAAS,EAAE,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, useContext } from "react";
|
|
4
|
+
const AiContext = createContext(undefined);
|
|
5
|
+
export function AiProvider({ baseUrl, apiKeyId, uiMode = "modal", children, }) {
|
|
6
|
+
const value = {
|
|
7
|
+
baseUrl,
|
|
8
|
+
apiKeyId,
|
|
9
|
+
uiMode,
|
|
10
|
+
};
|
|
11
|
+
return _jsx(AiContext.Provider, { value: value, children: children });
|
|
12
|
+
}
|
|
13
|
+
export function useAiContext() {
|
|
14
|
+
const context = useContext(AiContext);
|
|
15
|
+
if (!context) {
|
|
16
|
+
throw new Error("useAiContext must be used within AiProvider");
|
|
17
|
+
}
|
|
18
|
+
return context;
|
|
19
|
+
}
|
|
20
|
+
export { AiContext };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AiImageRequest, AiImageResponse } from "@lastbrain/ai-ui-core";
|
|
2
|
+
export interface UseAiCallImageOptions {
|
|
3
|
+
baseUrl?: string;
|
|
4
|
+
apiKeyId?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface UseAiCallImageResult {
|
|
7
|
+
generateImage: (request: AiImageRequest) => Promise<AiImageResponse>;
|
|
8
|
+
loading: boolean;
|
|
9
|
+
error: Error | null;
|
|
10
|
+
}
|
|
11
|
+
export declare function useAiCallImage(options?: UseAiCallImageOptions): UseAiCallImageResult;
|
|
12
|
+
//# sourceMappingURL=useAiCallImage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAiCallImage.d.ts","sourceRoot":"","sources":["../../src/hooks/useAiCallImage.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAG7E,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,aAAa,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;IACrE,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB;AAED,wBAAgB,cAAc,CAC5B,OAAO,CAAC,EAAE,qBAAqB,GAC9B,oBAAoB,CA6BtB"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useState, useCallback } from "react";
|
|
3
|
+
import { useAiClient } from "./useAiClient";
|
|
4
|
+
export function useAiCallImage(options) {
|
|
5
|
+
const client = useAiClient(options);
|
|
6
|
+
const [loading, setLoading] = useState(false);
|
|
7
|
+
const [error, setError] = useState(null);
|
|
8
|
+
const generateImage = useCallback(async (request) => {
|
|
9
|
+
setLoading(true);
|
|
10
|
+
setError(null);
|
|
11
|
+
try {
|
|
12
|
+
const result = await client.generateImage(request);
|
|
13
|
+
return result;
|
|
14
|
+
}
|
|
15
|
+
catch (err) {
|
|
16
|
+
const error = err instanceof Error ? err : new Error("Failed to generate image");
|
|
17
|
+
setError(error);
|
|
18
|
+
throw error;
|
|
19
|
+
}
|
|
20
|
+
finally {
|
|
21
|
+
setLoading(false);
|
|
22
|
+
}
|
|
23
|
+
}, [client]);
|
|
24
|
+
return {
|
|
25
|
+
generateImage,
|
|
26
|
+
loading,
|
|
27
|
+
error,
|
|
28
|
+
};
|
|
29
|
+
}
|