@baishuyun/chat-sdk 0.0.10 → 0.0.12
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/CHANGELOG.md +16 -0
- package/package.json +4 -4
- package/src/chat.tsx +20 -1
- package/src/components/biz-comp/FieldChecker.tsx +23 -2
- package/src/components/biz-comp/FieldCheckerListMsg.tsx +30 -5
- package/src/components/biz-comp/FieldValueChecker.tsx +27 -1
- package/src/components/biz-comp/SubformFieldsValueChecker.tsx +22 -1
- package/src/components/biz-comp/chat-client.tsx +13 -6
- package/src/components/biz-comp/field-icon.tsx +1 -1
- package/src/components/biz-comp/multi-modal-input/index.tsx +31 -34
- package/src/components/biz-comp/multi-modal-input/prompt-input.tsx +1 -4
- package/src/components/biz-comp/opening-lines.tsx +1 -1
- package/src/components/biz-comp/preview-message-wrapper.tsx +8 -1
- package/src/components/biz-comp/preview-message.tsx +17 -1
- package/src/components/bs-ui/attachments-previewer.tsx +124 -32
- package/src/components/bs-ui/bot-avatar-name.tsx +1 -1
- package/src/components/bs-ui/bs-icons.tsx +15 -1
- package/src/components/bs-ui/card.tsx +1 -1
- package/src/components/bs-ui/chat-area-header.tsx +12 -2
- package/src/components/bs-ui/collapsible-txt-msg.tsx +1 -1
- package/src/components/bs-ui/fields-previewer.tsx +5 -0
- package/src/components/bs-ui/form-info-editor.tsx +2 -3
- package/src/components/bs-ui/icon-btn.tsx +11 -4
- package/src/components/bs-ui/line-checker.tsx +31 -14
- package/src/components/bs-ui/previewer-header.tsx +33 -6
- package/src/components/bs-ui/primary-confirm-btn.tsx +10 -5
- package/src/components/bs-ui/primary-entry-btn.tsx +1 -1
- package/src/components/bs-ui/square-checker.tsx +62 -0
- package/src/components/bs-ui/tab-radio-group.tsx +12 -3
- package/src/components/bs-ui/tooltip.tsx +37 -2
- package/src/components/ui/tooltip.tsx +37 -18
- package/src/const/index.ts +7 -1
- package/src/index.tsx +1 -1
- package/src/plugins/{mcp-form-builder-plugin → form-builder-plugin}/components/create-form-confirm.tsx +3 -2
- package/src/plugins/form-builder-plugin/components/entry-btn.tsx +44 -0
- package/src/plugins/{mcp-form-builder-plugin → form-builder-plugin}/components/msg-part.tsx +44 -27
- package/src/plugins/{mcp-form-builder-plugin → form-builder-plugin}/index.ts +19 -5
- package/src/plugins/form-filling-plugin/components/FormFillingOpeningLines.tsx +2 -1
- package/src/plugins/form-filling-plugin/components/avatar.tsx +9 -3
- package/src/plugins/form-filling-plugin/components/mode-select.tsx +10 -2
- package/src/plugins/form-filling-plugin/components/msg-part.tsx +26 -1
- package/src/plugins/form-filling-plugin/const.ts +1 -1
- package/src/plugins/form-filling-plugin/index.ts +18 -0
- package/src/plugins/report-query-plugin/components/query-msg-part.tsx +1 -0
- package/src/plugins/report-query-plugin/components/query-opening-lines.tsx +30 -0
- package/src/plugins/report-query-plugin/components/result-cards/DataTableCard.tsx +0 -1
- package/src/plugins/report-query-plugin/index.ts +11 -0
- package/src/plugins/report-query-plugin/utils/build-dash-component.ts +122 -0
- package/src/plugins/report-query-plugin/utils/create-default-dash-styles.ts +29 -0
- package/src/plugins/report-query-plugin/utils/create-default-widget-attr-list.ts +59 -0
- package/src/plugins/report-query-plugin/utils/field-enhance.ts +62 -0
- package/src/plugins/report-query-plugin/utils/index.tsx +109 -0
- package/src/stories/AttachmentsPreviewer.stories.tsx +118 -0
- package/src/stories/PrimaryConfirmBtn.stories.tsx +7 -0
- package/src/stories/SquareChecker.stories.tsx +96 -0
- package/src/style.css +24 -0
- package/dist/chat-sdk.js +0 -58300
- package/dist/chat-sdk.js.map +0 -1
- package/dist/chat-sdk.umd.cjs +0 -663
- package/dist/chat-sdk.umd.cjs.map +0 -1
- package/dist/index.css +0 -1
- package/src/plugins/mcp-form-builder-plugin/components/entry-btn.tsx +0 -9
- package/src/plugins/report-query-plugin/utils.tsx +0 -379
- /package/src/plugins/{mcp-form-builder-plugin → form-builder-plugin}/components/follow-up.tsx +0 -0
- /package/src/plugins/{mcp-form-builder-plugin → form-builder-plugin}/const/index.ts +0 -0
- /package/src/plugins/{mcp-form-builder-plugin → form-builder-plugin}/hooks/index.ts +0 -0
- /package/src/plugins/{mcp-form-builder-plugin → form-builder-plugin}/hooks/use-fields-confirmed.ts +0 -0
- /package/src/plugins/{mcp-form-builder-plugin → form-builder-plugin}/types.ts +0 -0
- /package/src/plugins/{mcp-form-builder-plugin → form-builder-plugin}/utils/index.ts +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @baishuyun/chat-sdk
|
|
2
2
|
|
|
3
|
+
## 0.0.12
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- udpate style
|
|
8
|
+
- Updated dependencies
|
|
9
|
+
- @baishuyun/agents@0.0.12
|
|
10
|
+
|
|
11
|
+
## 0.0.11
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- style update
|
|
16
|
+
- Updated dependencies
|
|
17
|
+
- @baishuyun/agents@0.0.11
|
|
18
|
+
|
|
3
19
|
## 0.0.10
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@baishuyun/chat-sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.12",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "src/index.jsx",
|
|
6
6
|
"module": "dist/chat-sdk.js",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"tw-animate-css": "^1.4.0",
|
|
36
36
|
"use-stick-to-bottom": "^1.1.1",
|
|
37
37
|
"zustand": "^5.0.8",
|
|
38
|
-
"@baishuyun/agents": "0.0.
|
|
38
|
+
"@baishuyun/agents": "0.0.12"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@storybook/react-vite": "^10.1.11",
|
|
@@ -51,8 +51,8 @@
|
|
|
51
51
|
"tailwindcss": "^4.1.17",
|
|
52
52
|
"vite": "^5.1.4",
|
|
53
53
|
"vite-plugin-dts": "^4.5.4",
|
|
54
|
-
"@baishuyun/types": "1.0.
|
|
55
|
-
"@baishuyun/typescript-config": "0.0.
|
|
54
|
+
"@baishuyun/types": "1.0.12",
|
|
55
|
+
"@baishuyun/typescript-config": "0.0.12"
|
|
56
56
|
},
|
|
57
57
|
"exports": {
|
|
58
58
|
".": {
|
package/src/chat.tsx
CHANGED
|
@@ -2,7 +2,7 @@ import { DefaultChatTransport } from 'ai';
|
|
|
2
2
|
import { useEffect, useMemo, useState } from 'react';
|
|
3
3
|
import { ChatFrame } from '@/components/biz-comp/chat-frame';
|
|
4
4
|
import { Messages } from '@/components/biz-comp/messages';
|
|
5
|
-
import { Attachment, ChatMessage } from '@baishuyun/types';
|
|
5
|
+
import { Attachment, ChatMessage, IGhostMsgEventDetail } from '@baishuyun/types';
|
|
6
6
|
import { ChatSDK } from '@/.';
|
|
7
7
|
import { MultimodalInput } from './components/biz-comp/multi-modal-input';
|
|
8
8
|
import { useDefaultPluginCustomComponent } from './hooks/use-plugin-custom-components';
|
|
@@ -10,10 +10,14 @@ import { useMergedChat } from './hooks/use-merged-chat';
|
|
|
10
10
|
import { useChatPreference } from './hooks/use-chat-preference';
|
|
11
11
|
import { useMsgStatusBroadcast } from './hooks/use-msg-status-broadcast';
|
|
12
12
|
import { useChatStatus } from './hooks/use-frame-mode';
|
|
13
|
+
import { usePluginLifeCycleChainRunner } from './hooks/use-plugin-life-cycle-chain-runner';
|
|
14
|
+
import { useEvt } from './hooks/use-evt';
|
|
13
15
|
|
|
14
16
|
export const Chat = ({ client }: { client: ChatSDK }) => {
|
|
15
17
|
const preference = useChatPreference(client);
|
|
16
18
|
|
|
19
|
+
const { exec: onAfterChatHide = () => {} } = usePluginLifeCycleChainRunner('onAfterChatAreaHide');
|
|
20
|
+
|
|
17
21
|
const transport = useMemo(() => {
|
|
18
22
|
return new DefaultChatTransport({
|
|
19
23
|
api: client?.options?.chatApiEndpoint,
|
|
@@ -29,11 +33,26 @@ export const Chat = ({ client }: { client: ChatSDK }) => {
|
|
|
29
33
|
enableMerge: preference?.enableMessageMerge,
|
|
30
34
|
});
|
|
31
35
|
|
|
36
|
+
useEvt('send-ghost-msg', (detail) => {
|
|
37
|
+
const { text, options } = detail as IGhostMsgEventDetail;
|
|
38
|
+
sendMessage(
|
|
39
|
+
{
|
|
40
|
+
text,
|
|
41
|
+
},
|
|
42
|
+
options
|
|
43
|
+
);
|
|
44
|
+
});
|
|
45
|
+
|
|
32
46
|
const { isHide } = useChatStatus();
|
|
33
47
|
|
|
34
48
|
useEffect(() => {
|
|
35
49
|
if (isHide) {
|
|
36
50
|
stop();
|
|
51
|
+
onAfterChatHide({
|
|
52
|
+
clearMsgs: () => {
|
|
53
|
+
setMessages(() => []);
|
|
54
|
+
},
|
|
55
|
+
});
|
|
37
56
|
}
|
|
38
57
|
}, [isHide, stop]);
|
|
39
58
|
|
|
@@ -16,11 +16,23 @@ export interface FieldCheckerProps {
|
|
|
16
16
|
icon?: React.ReactNode;
|
|
17
17
|
onChange?: (checked: boolean, field: Field, parentFieldName?: string, index?: number) => void;
|
|
18
18
|
value?: unknown;
|
|
19
|
+
streaming?: boolean;
|
|
20
|
+
confirmed?: boolean;
|
|
19
21
|
onLoaded?: (field: Field) => void;
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
export const FieldChecker = memo(
|
|
23
|
-
({
|
|
25
|
+
({
|
|
26
|
+
field,
|
|
27
|
+
disabled,
|
|
28
|
+
isSubField,
|
|
29
|
+
onChange,
|
|
30
|
+
onLoaded,
|
|
31
|
+
icon,
|
|
32
|
+
value,
|
|
33
|
+
streaming,
|
|
34
|
+
confirmed,
|
|
35
|
+
}: FieldCheckerProps) => {
|
|
24
36
|
const { widget, label } = field;
|
|
25
37
|
if (!widget) {
|
|
26
38
|
return null;
|
|
@@ -68,6 +80,8 @@ export const FieldChecker = memo(
|
|
|
68
80
|
return (
|
|
69
81
|
<>
|
|
70
82
|
<LineChecker
|
|
83
|
+
streaming={streaming}
|
|
84
|
+
confirmed={confirmed}
|
|
71
85
|
title={label}
|
|
72
86
|
disabled={disabled}
|
|
73
87
|
defaultChecked={true}
|
|
@@ -90,6 +104,8 @@ export const FieldChecker = memo(
|
|
|
90
104
|
{isSubForm
|
|
91
105
|
? widget.items.map((subField: Field, index: number) => (
|
|
92
106
|
<FieldChecker
|
|
107
|
+
confirmed={confirmed}
|
|
108
|
+
streaming={streaming}
|
|
93
109
|
key={subField.label}
|
|
94
110
|
isSubField={true}
|
|
95
111
|
disabled={disabled}
|
|
@@ -106,6 +122,11 @@ export const FieldChecker = memo(
|
|
|
106
122
|
);
|
|
107
123
|
},
|
|
108
124
|
(p1, p2) => {
|
|
109
|
-
return
|
|
125
|
+
return (
|
|
126
|
+
p1.field?.label === p2.field?.label &&
|
|
127
|
+
p1.disabled === p2.disabled &&
|
|
128
|
+
p1.confirmed === p2.confirmed &&
|
|
129
|
+
p1.streaming === p2.streaming
|
|
130
|
+
);
|
|
110
131
|
}
|
|
111
132
|
);
|
|
@@ -5,27 +5,52 @@ import { EditIcon, LetterAIcon } from '../bs-ui/bs-icons';
|
|
|
5
5
|
import { FieldValueChecker, FieldValueCheckerProps } from './FieldValueChecker';
|
|
6
6
|
|
|
7
7
|
export const FieldCheckerListMsg = memo(
|
|
8
|
-
({
|
|
8
|
+
({
|
|
9
|
+
fields,
|
|
10
|
+
children,
|
|
11
|
+
streaming,
|
|
12
|
+
confirmed,
|
|
13
|
+
}: {
|
|
14
|
+
fields: Array<FieldCheckerProps>;
|
|
15
|
+
children?: ReactNode;
|
|
16
|
+
streaming: boolean;
|
|
17
|
+
confirmed?: boolean;
|
|
18
|
+
}) => {
|
|
9
19
|
return (
|
|
10
20
|
<CollapsibleTxtMsg title="字段生成" icon={<LetterAIcon />} defaultOpen>
|
|
11
21
|
{fields.map((f) => (
|
|
12
|
-
<FieldChecker {...f} />
|
|
22
|
+
<FieldChecker {...f} streaming={streaming} confirmed={confirmed} />
|
|
13
23
|
))}
|
|
14
24
|
{children}
|
|
15
25
|
</CollapsibleTxtMsg>
|
|
16
26
|
);
|
|
17
27
|
},
|
|
18
28
|
(p1, p2) => {
|
|
19
|
-
return
|
|
29
|
+
return (
|
|
30
|
+
p1.fields.length === p2.fields.length &&
|
|
31
|
+
p1.streaming === p2.streaming &&
|
|
32
|
+
p1.confirmed === p2.confirmed &&
|
|
33
|
+
p1.children === p2.children
|
|
34
|
+
);
|
|
20
35
|
}
|
|
21
36
|
);
|
|
22
37
|
|
|
23
38
|
export const FieldValueCheckerListMsg = memo(
|
|
24
|
-
({
|
|
39
|
+
({
|
|
40
|
+
props,
|
|
41
|
+
readonly,
|
|
42
|
+
children,
|
|
43
|
+
streaming,
|
|
44
|
+
}: {
|
|
45
|
+
props: Array<FieldValueCheckerProps>;
|
|
46
|
+
children?: ReactNode;
|
|
47
|
+
readonly?: boolean;
|
|
48
|
+
streaming?: boolean;
|
|
49
|
+
}) => {
|
|
25
50
|
return (
|
|
26
51
|
<CollapsibleTxtMsg title="字段填写" icon={<EditIcon />} defaultOpen>
|
|
27
52
|
{props.map((f) => (
|
|
28
|
-
<FieldValueChecker {...f} />
|
|
53
|
+
<FieldValueChecker {...f} readonly={readonly} streaming={streaming} />
|
|
29
54
|
))}
|
|
30
55
|
{children}
|
|
31
56
|
</CollapsibleTxtMsg>
|
|
@@ -14,12 +14,22 @@ export interface FieldValueCheckerProps {
|
|
|
14
14
|
field: ValueOf<Pick<ToolUIPart<FieldsTools>, 'output'>>;
|
|
15
15
|
isSubField?: boolean;
|
|
16
16
|
disabled?: boolean;
|
|
17
|
+
readonly?: boolean;
|
|
17
18
|
onChange?: (checked: boolean, field: Field, parentFieldName?: string, index?: number) => void;
|
|
18
19
|
onLoaded?: (field: Field) => void;
|
|
20
|
+
streaming?: boolean;
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
export const FieldValueChecker = memo(
|
|
22
|
-
({
|
|
24
|
+
({
|
|
25
|
+
field,
|
|
26
|
+
disabled,
|
|
27
|
+
isSubField,
|
|
28
|
+
readonly,
|
|
29
|
+
streaming,
|
|
30
|
+
onChange,
|
|
31
|
+
onLoaded,
|
|
32
|
+
}: FieldValueCheckerProps) => {
|
|
23
33
|
const { widget, label } = field;
|
|
24
34
|
if (!widget) {
|
|
25
35
|
return null;
|
|
@@ -52,20 +62,24 @@ export const FieldValueChecker = memo(
|
|
|
52
62
|
return (
|
|
53
63
|
<>
|
|
54
64
|
<LineChecker
|
|
65
|
+
streaming={streaming}
|
|
55
66
|
title={label}
|
|
56
67
|
disabled={disabled}
|
|
57
68
|
defaultChecked={true}
|
|
58
69
|
onCheckedChange={handleCheck}
|
|
59
70
|
className={extraPadding}
|
|
71
|
+
readonly={readonly}
|
|
60
72
|
shortDesc={isSubForm ? '' : (value as string)}
|
|
61
73
|
// extra={typeDesc}
|
|
62
74
|
/>
|
|
63
75
|
{isSubForm && (
|
|
64
76
|
<SubformFieldsValueChecker
|
|
77
|
+
readonly={readonly}
|
|
65
78
|
subformField={field}
|
|
66
79
|
onChange={(detail) => {
|
|
67
80
|
onChange?.(detail.checked, detail.field, detail.parentFieldName, detail.row);
|
|
68
81
|
}}
|
|
82
|
+
streaming={streaming}
|
|
69
83
|
/>
|
|
70
84
|
)}
|
|
71
85
|
</>
|
|
@@ -90,6 +104,18 @@ export const FieldValueChecker = memo(
|
|
|
90
104
|
return false;
|
|
91
105
|
}
|
|
92
106
|
|
|
107
|
+
// 只读状态一致
|
|
108
|
+
const isReadonlyEqual = p1.readonly === p2.readonly;
|
|
109
|
+
if (!isReadonlyEqual) {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// 流式状态一致
|
|
114
|
+
const isStreamingEqual = p1.streaming === p2.streaming;
|
|
115
|
+
if (!isStreamingEqual) {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
|
|
93
119
|
// 进一步比较子表单下的字段
|
|
94
120
|
return isSubformFieldEqual(p1?.field, p2?.field);
|
|
95
121
|
}
|
|
@@ -13,6 +13,8 @@ const Checker = ({
|
|
|
13
13
|
|
|
14
14
|
label,
|
|
15
15
|
val,
|
|
16
|
+
streaming,
|
|
17
|
+
readonly,
|
|
16
18
|
// desc,
|
|
17
19
|
}: {
|
|
18
20
|
label: string;
|
|
@@ -20,9 +22,13 @@ const Checker = ({
|
|
|
20
22
|
onCheckedChange: (v: boolean) => void;
|
|
21
23
|
disabled?: boolean;
|
|
22
24
|
desc: string;
|
|
25
|
+
readonly?: boolean;
|
|
26
|
+
streaming?: boolean;
|
|
23
27
|
}) => {
|
|
24
28
|
return (
|
|
25
29
|
<LineChecker
|
|
30
|
+
streaming={streaming}
|
|
31
|
+
readonly={readonly}
|
|
26
32
|
title={label}
|
|
27
33
|
disabled={disabled}
|
|
28
34
|
defaultChecked={true}
|
|
@@ -37,12 +43,16 @@ const Checker = ({
|
|
|
37
43
|
const SubFieldChecker = memo(
|
|
38
44
|
({
|
|
39
45
|
field,
|
|
46
|
+
readonly,
|
|
40
47
|
onCheckedChange,
|
|
48
|
+
streaming,
|
|
41
49
|
}: {
|
|
42
50
|
onCheckedChange: (
|
|
43
51
|
checked: boolean,
|
|
44
52
|
field: ValueOf<Pick<ToolUIPart<FieldsTools>, 'output'>>
|
|
45
53
|
) => void;
|
|
54
|
+
readonly?: boolean;
|
|
55
|
+
streaming?: boolean;
|
|
46
56
|
field: ValueOf<Pick<ToolUIPart<FieldsTools>, 'output'>>;
|
|
47
57
|
}) => {
|
|
48
58
|
const { widget, label } = field;
|
|
@@ -74,6 +84,8 @@ const SubFieldChecker = memo(
|
|
|
74
84
|
|
|
75
85
|
return (
|
|
76
86
|
<Checker
|
|
87
|
+
streaming={streaming}
|
|
88
|
+
readonly={readonly}
|
|
77
89
|
desc={typeDesc}
|
|
78
90
|
label={label}
|
|
79
91
|
val={value as string}
|
|
@@ -82,7 +94,10 @@ const SubFieldChecker = memo(
|
|
|
82
94
|
);
|
|
83
95
|
},
|
|
84
96
|
(p1, p2) => {
|
|
85
|
-
const isNameEqual =
|
|
97
|
+
const isNameEqual =
|
|
98
|
+
p1.field.widget?.widgetName === p2.field.widget?.widgetName &&
|
|
99
|
+
p1.readonly === p2.readonly &&
|
|
100
|
+
p1.streaming === p2.streaming;
|
|
86
101
|
return isNameEqual;
|
|
87
102
|
}
|
|
88
103
|
);
|
|
@@ -110,9 +125,13 @@ type onSubformFieldChangeParam = {
|
|
|
110
125
|
export const SubformFieldsValueChecker = ({
|
|
111
126
|
subformField,
|
|
112
127
|
onChange,
|
|
128
|
+
streaming,
|
|
129
|
+
readonly,
|
|
113
130
|
}: {
|
|
114
131
|
onChange: (p: onSubformFieldChangeParam) => void;
|
|
115
132
|
subformField: ValueOf<Pick<ToolUIPart<FieldsTools>, 'output'>>;
|
|
133
|
+
streaming?: boolean;
|
|
134
|
+
readonly?: boolean;
|
|
116
135
|
}) => {
|
|
117
136
|
if (!subformField.widget.value || !subformField.widget.value.length) {
|
|
118
137
|
return null;
|
|
@@ -135,6 +154,8 @@ export const SubformFieldsValueChecker = ({
|
|
|
135
154
|
{rowData.map((fData: generatedField, col: number) => {
|
|
136
155
|
return (
|
|
137
156
|
<SubFieldChecker
|
|
157
|
+
readonly={readonly}
|
|
158
|
+
streaming={streaming}
|
|
138
159
|
field={{
|
|
139
160
|
label: fData.label,
|
|
140
161
|
widget: {
|
|
@@ -14,6 +14,7 @@ import { useDefaultPluginCustomComponent } from '@/hooks/use-plugin-custom-compo
|
|
|
14
14
|
import { BotAvatarAndName } from '../bs-ui/bot-avatar-name';
|
|
15
15
|
import { ChatEntryButtonConfig } from '@baishuyun/types';
|
|
16
16
|
import { useDraggable } from '@/hooks/use-draggable';
|
|
17
|
+
import { TooltipProvider } from '../ui/tooltip';
|
|
17
18
|
|
|
18
19
|
const ChatSlot = ({ client }: { client?: ChatSDK }) => {
|
|
19
20
|
const { setStatus, isVisible, isFloat, isDock } = useChatStatus();
|
|
@@ -105,7 +106,7 @@ const ChatContent: React.FC<{ client?: ChatSDK }> = ({ client }): ReactPortal |
|
|
|
105
106
|
return createPortal(<ChatSlot client={client} />, chatContentEl) as ReactPortal;
|
|
106
107
|
};
|
|
107
108
|
|
|
108
|
-
export const ChatEntryBtn = ({ client }: { client
|
|
109
|
+
export const ChatEntryBtn = ({ client }: { client: ChatSDK }) => {
|
|
109
110
|
const { bottom = 10, right = 10 } = client?.options?.btnOffset || {};
|
|
110
111
|
|
|
111
112
|
const { entryVisible, entryWrapper, setStatus, isVisible, entryVariant } = useChatStore(
|
|
@@ -137,6 +138,7 @@ export const ChatEntryBtn = ({ client }: { client?: ChatSDK }) => {
|
|
|
137
138
|
|
|
138
139
|
const EntryJsx = EntryCom ? (
|
|
139
140
|
<EntryCom
|
|
141
|
+
client={client}
|
|
140
142
|
variant={entryVariant}
|
|
141
143
|
chatVisible={isVisible}
|
|
142
144
|
style={entryStyle}
|
|
@@ -186,7 +188,7 @@ const MultiEntryButtonItem = ({
|
|
|
186
188
|
client,
|
|
187
189
|
config,
|
|
188
190
|
}: {
|
|
189
|
-
client
|
|
191
|
+
client: ChatSDK;
|
|
190
192
|
config: ChatEntryButtonConfig;
|
|
191
193
|
}) => {
|
|
192
194
|
const { setStatus, isVisible } = useChatStore((store) => ({
|
|
@@ -213,6 +215,7 @@ const MultiEntryButtonItem = ({
|
|
|
213
215
|
|
|
214
216
|
const EntryJsx = EntryCom ? (
|
|
215
217
|
<EntryCom
|
|
218
|
+
client={client}
|
|
216
219
|
variant={config.variant}
|
|
217
220
|
chatVisible={isVisible}
|
|
218
221
|
style={entryStyle}
|
|
@@ -249,7 +252,7 @@ const MultiEntryButtonItem = ({
|
|
|
249
252
|
};
|
|
250
253
|
|
|
251
254
|
/** Renders all multi-entry buttons from chatEntryButtons Map */
|
|
252
|
-
const MultiEntryButtons = ({ client }: { client
|
|
255
|
+
const MultiEntryButtons = ({ client }: { client: ChatSDK }) => {
|
|
253
256
|
const chatEntryButtons = useChatStore((store) => store.chatEntryButtons);
|
|
254
257
|
|
|
255
258
|
const buttons = Array.from(chatEntryButtons.values());
|
|
@@ -267,7 +270,7 @@ const MultiEntryButtons = ({ client }: { client?: ChatSDK }) => {
|
|
|
267
270
|
);
|
|
268
271
|
};
|
|
269
272
|
|
|
270
|
-
export const ChatWidgets = ({ client }: { client
|
|
273
|
+
export const ChatWidgets = ({ client }: { client: ChatSDK }) => {
|
|
271
274
|
return (
|
|
272
275
|
<>
|
|
273
276
|
<ChatContent client={client} />
|
|
@@ -277,10 +280,14 @@ export const ChatWidgets = ({ client }: { client?: ChatSDK }) => {
|
|
|
277
280
|
);
|
|
278
281
|
};
|
|
279
282
|
|
|
280
|
-
export const ChatClient = ({ store, client }: { client
|
|
283
|
+
export const ChatClient = ({ store, client }: { client: ChatSDK; store: ChatStore }) => {
|
|
281
284
|
return (
|
|
282
285
|
<ChatStoreProvider store={store}>
|
|
283
|
-
<
|
|
286
|
+
<TooltipProvider
|
|
287
|
+
zIndex={client?.options?.safeZIndex != null ? client.options.safeZIndex + 1 : 50}
|
|
288
|
+
>
|
|
289
|
+
<ChatWidgets client={client} />
|
|
290
|
+
</TooltipProvider>
|
|
284
291
|
</ChatStoreProvider>
|
|
285
292
|
);
|
|
286
293
|
};
|
|
@@ -3,7 +3,7 @@ import { FieldType } from '@baishuyun/types';
|
|
|
3
3
|
import { FontIcon } from '../bs-ui/font-icon';
|
|
4
4
|
import { FormulasIcon } from '../bs-ui/bs-icons';
|
|
5
5
|
|
|
6
|
-
export const FieldIcon = ({ type }: { type: FieldType
|
|
6
|
+
export const FieldIcon = ({ type }: { type: FieldType }) => {
|
|
7
7
|
const code = FIELD_ICON_CODE_MAP[type] || 'unknown';
|
|
8
8
|
if (type === 'formula') {
|
|
9
9
|
return <FormulasIcon />;
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
PromptInputToolbar,
|
|
20
20
|
PromptInputTools,
|
|
21
21
|
} from './prompt-input';
|
|
22
|
-
import {
|
|
22
|
+
import { AttachmentsPreviewer } from '@/components/bs-ui/attachments-previewer';
|
|
23
23
|
import { ChatMessage, Attachment } from '@baishuyun/types';
|
|
24
24
|
import { Button } from '@/components/ui/button';
|
|
25
25
|
import { usePluginLifeCycleChainRunner } from '@/hooks/use-plugin-life-cycle-chain-runner';
|
|
@@ -221,6 +221,9 @@ function PureMultimodalInput({
|
|
|
221
221
|
[setAttachments, uploadFile]
|
|
222
222
|
);
|
|
223
223
|
|
|
224
|
+
const accept = useChatPreference()?.acceptAttachmentFileType?.join(',');
|
|
225
|
+
const hasAcceptableFileType = !!accept;
|
|
226
|
+
|
|
224
227
|
// Add paste event listener to textarea
|
|
225
228
|
useEffect(() => {
|
|
226
229
|
const textarea = textareaRef.current;
|
|
@@ -241,7 +244,7 @@ function PureMultimodalInput({
|
|
|
241
244
|
ref={fileInputRef}
|
|
242
245
|
tabIndex={-1}
|
|
243
246
|
type="file"
|
|
244
|
-
|
|
247
|
+
accept={accept}
|
|
245
248
|
/>
|
|
246
249
|
|
|
247
250
|
<PromptInput
|
|
@@ -257,37 +260,29 @@ function PureMultimodalInput({
|
|
|
257
260
|
}}
|
|
258
261
|
>
|
|
259
262
|
{(attachments.length > 0 || uploadQueue.length > 0) && (
|
|
260
|
-
<
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
name: filename,
|
|
284
|
-
contentType: '',
|
|
285
|
-
}}
|
|
286
|
-
isUploading={true}
|
|
287
|
-
key={filename}
|
|
288
|
-
/>
|
|
289
|
-
))}
|
|
290
|
-
</div>
|
|
263
|
+
<AttachmentsPreviewer
|
|
264
|
+
attachments={[
|
|
265
|
+
...attachments.map((a) => ({
|
|
266
|
+
id: a.url,
|
|
267
|
+
url: a.url,
|
|
268
|
+
alt: a.name,
|
|
269
|
+
contentType: a.contentType,
|
|
270
|
+
})),
|
|
271
|
+
...uploadQueue.map((filename) => ({
|
|
272
|
+
id: `uploading-${filename}`,
|
|
273
|
+
url: '',
|
|
274
|
+
alt: filename,
|
|
275
|
+
isLoading: true,
|
|
276
|
+
})),
|
|
277
|
+
]}
|
|
278
|
+
onImageRemove={(item) => {
|
|
279
|
+
if (item.id.startsWith('uploading-')) return;
|
|
280
|
+
setAttachments((cur) => cur.filter((a) => a.url !== item.id));
|
|
281
|
+
if (fileInputRef.current) {
|
|
282
|
+
fileInputRef.current.value = '';
|
|
283
|
+
}
|
|
284
|
+
}}
|
|
285
|
+
/>
|
|
291
286
|
)}
|
|
292
287
|
<div className="flex flex-row items-start gap-1 sm:gap-2">
|
|
293
288
|
<PromptInputTextarea
|
|
@@ -306,7 +301,9 @@ function PureMultimodalInput({
|
|
|
306
301
|
<PromptInputToolbar className="border-top-0! border-t-0! p-0 shadow-none dark:border-0 dark:border-transparent!">
|
|
307
302
|
<div></div>
|
|
308
303
|
<PromptInputTools className="gap-2.5">
|
|
309
|
-
|
|
304
|
+
{hasAcceptableFileType ? (
|
|
305
|
+
<AttachmentsButton fileInputRef={fileInputRef} status={status} />
|
|
306
|
+
) : null}
|
|
310
307
|
<ClearBtn setMessages={setMessages} status={status} />
|
|
311
308
|
<DividerIcon />
|
|
312
309
|
{status === 'submitted' || status === 'streaming' ? (
|
|
@@ -104,10 +104,7 @@ export const PromptInputToolbar = ({ className, ...props }: PromptInputToolbarPr
|
|
|
104
104
|
export type PromptInputToolsProps = HTMLAttributes<HTMLDivElement>;
|
|
105
105
|
|
|
106
106
|
export const PromptInputTools = ({ className, ...props }: PromptInputToolsProps) => (
|
|
107
|
-
<div
|
|
108
|
-
className={cn('flex items-center gap-1', '[&_button:first-child]:rounded-bl-xl', className)}
|
|
109
|
-
{...props}
|
|
110
|
-
/>
|
|
107
|
+
<div className={cn('flex items-center gap-1', className)} {...props} />
|
|
111
108
|
);
|
|
112
109
|
|
|
113
110
|
export type PromptInputButtonProps = ComponentProps<typeof Button>;
|
|
@@ -53,13 +53,20 @@ export const PreviewMessageWrapper = ({
|
|
|
53
53
|
pointerEventsCls
|
|
54
54
|
)}
|
|
55
55
|
>
|
|
56
|
-
<IconBtn
|
|
56
|
+
<IconBtn
|
|
57
|
+
tooltip="复制"
|
|
58
|
+
icon={<CopyIcon />}
|
|
59
|
+
onClick={onCopy}
|
|
60
|
+
className="!hover:bg-[#eff0f6]"
|
|
61
|
+
/>
|
|
57
62
|
{onGenerate ? (
|
|
58
63
|
<IconBtn
|
|
64
|
+
tooltip="重新生成"
|
|
59
65
|
icon={<RefreshIcon />}
|
|
60
66
|
onClick={() => {
|
|
61
67
|
onGenerate && onGenerate();
|
|
62
68
|
}}
|
|
69
|
+
className="!hover:bg-[#eff0f6]"
|
|
63
70
|
/>
|
|
64
71
|
) : null}
|
|
65
72
|
</div>
|
|
@@ -20,6 +20,8 @@ import { WarningMessage } from '../bs-ui/warning-msg';
|
|
|
20
20
|
import { GenerateAnimation } from '../bs-ui/generate-animation';
|
|
21
21
|
import { AttachmentPartGroup } from '../bs-ui/attachment-part-group';
|
|
22
22
|
import { AttachmentPart } from '../bs-ui/attachment-part';
|
|
23
|
+
import { useChatStatus } from '@/hooks/use-frame-mode';
|
|
24
|
+
import { useEvtBus } from '@/hooks/use-evt-bus';
|
|
23
25
|
|
|
24
26
|
const PurePreviewMessage = ({
|
|
25
27
|
message,
|
|
@@ -45,6 +47,8 @@ const PurePreviewMessage = ({
|
|
|
45
47
|
(p: { type: string; text?: string }) => p.type === 'text' && p.text?.trim()
|
|
46
48
|
);
|
|
47
49
|
|
|
50
|
+
const chatStatus = useChatStatus();
|
|
51
|
+
|
|
48
52
|
const hasFileType = message.parts?.some((p: any) => {
|
|
49
53
|
if (Array.isArray(p)) {
|
|
50
54
|
return p.some((subP) => subP?.type === 'file');
|
|
@@ -66,6 +70,8 @@ const PurePreviewMessage = ({
|
|
|
66
70
|
|
|
67
71
|
const parts = onBeforePartsRender(fileGroupedParts);
|
|
68
72
|
|
|
73
|
+
const evtBus = useEvtBus();
|
|
74
|
+
|
|
69
75
|
const { exec: onBeforeSendMsg } = usePluginLifeCycleChainRunner('onBeforeMessageSend');
|
|
70
76
|
|
|
71
77
|
const handleCopy = () => {
|
|
@@ -75,7 +81,13 @@ const PurePreviewMessage = ({
|
|
|
75
81
|
.join('\n');
|
|
76
82
|
|
|
77
83
|
if (textParts) {
|
|
78
|
-
|
|
84
|
+
try {
|
|
85
|
+
navigator.clipboard.writeText(textParts);
|
|
86
|
+
evtBus.emit('chat-msg-copied', {
|
|
87
|
+
messageId: message.id,
|
|
88
|
+
content: textParts,
|
|
89
|
+
});
|
|
90
|
+
} catch (err) {}
|
|
79
91
|
}
|
|
80
92
|
};
|
|
81
93
|
|
|
@@ -87,6 +99,10 @@ const PurePreviewMessage = ({
|
|
|
87
99
|
});
|
|
88
100
|
};
|
|
89
101
|
|
|
102
|
+
if (chatStatus.isHide) {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
|
|
90
106
|
return (
|
|
91
107
|
<PreviewMessageWrapper
|
|
92
108
|
role={message.role}
|