@nethru/kit 1.1.2 → 1.1.4
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/chat/AiChat.js +3 -4
- package/dist/components/chat/ChatInput.js +3 -18
- package/dist/components/chat/ChatMessage.js +2 -2
- package/dist/components/chat/ChatMessages.js +1 -1
- package/dist/components/chat/ModelSelect.js +82 -0
- package/dist/components/chat/{hooks/useChatApi.js → contexts/ChatContext.js} +55 -9
- package/dist/components/chat/mock.js +17 -10
- package/dist/index.js +1 -0
- package/package.json +4 -1
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Stack } from "@mui/material";
|
|
3
|
+
import { useChatContext } from './contexts/ChatContext';
|
|
3
4
|
import ChatMessages from './ChatMessages';
|
|
4
5
|
import ChatInput from './ChatInput';
|
|
5
|
-
import useChatApi from './hooks/useChatApi';
|
|
6
6
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
7
7
|
function AiChat({
|
|
8
|
-
defaultMessages,
|
|
9
8
|
sx
|
|
10
9
|
}) {
|
|
11
10
|
const {
|
|
@@ -15,7 +14,7 @@ function AiChat({
|
|
|
15
14
|
isLoading,
|
|
16
15
|
chatContainerRef,
|
|
17
16
|
sendMessage
|
|
18
|
-
} =
|
|
17
|
+
} = useChatContext();
|
|
19
18
|
return /*#__PURE__*/_jsxs(Stack, {
|
|
20
19
|
sx: {
|
|
21
20
|
...styles.container,
|
|
@@ -37,7 +36,7 @@ export default AiChat;
|
|
|
37
36
|
const styles = {
|
|
38
37
|
container: {
|
|
39
38
|
width: '100%',
|
|
40
|
-
height: '
|
|
39
|
+
height: '100%',
|
|
41
40
|
background: 'white',
|
|
42
41
|
display: 'flex',
|
|
43
42
|
flexDirection: 'column',
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { Box, FormControl, IconButton,
|
|
2
|
+
import { Box, FormControl, IconButton, Stack, TextField } from '@mui/material';
|
|
3
3
|
import { Send as SendIcon } from '@mui/icons-material';
|
|
4
|
+
import ModelSelect from "./ModelSelect";
|
|
4
5
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
5
6
|
const ChatInput = ({
|
|
6
7
|
inputValue,
|
|
@@ -8,7 +9,6 @@ const ChatInput = ({
|
|
|
8
9
|
onSend,
|
|
9
10
|
isLoading
|
|
10
11
|
}) => {
|
|
11
|
-
const [model, setModel] = React.useState('GPT_4_1_MINI');
|
|
12
12
|
const handleKeyPress = e => {
|
|
13
13
|
if (e.key === 'Enter' && !e.shiftKey) {
|
|
14
14
|
e.preventDefault();
|
|
@@ -41,22 +41,7 @@ const ChatInput = ({
|
|
|
41
41
|
alignItems: "center",
|
|
42
42
|
children: [/*#__PURE__*/_jsx(FormControl, {
|
|
43
43
|
variant: "standard",
|
|
44
|
-
children: /*#__PURE__*/
|
|
45
|
-
variant: "standard",
|
|
46
|
-
value: model,
|
|
47
|
-
onChange: e => setModel(e.target.value),
|
|
48
|
-
disableUnderline: true,
|
|
49
|
-
sx: {
|
|
50
|
-
fontSize: '13px'
|
|
51
|
-
},
|
|
52
|
-
children: [/*#__PURE__*/_jsx(MenuItem, {
|
|
53
|
-
value: "GPT_4_1_MINI",
|
|
54
|
-
children: "GPT-4.1 Mini"
|
|
55
|
-
}), /*#__PURE__*/_jsx(MenuItem, {
|
|
56
|
-
value: "CLAUDE_3",
|
|
57
|
-
children: "Claude 3"
|
|
58
|
-
})]
|
|
59
|
-
})
|
|
44
|
+
children: /*#__PURE__*/_jsx(ModelSelect, {})
|
|
60
45
|
}), /*#__PURE__*/_jsx(IconButton, {
|
|
61
46
|
onClick: onSend,
|
|
62
47
|
disabled: isLoading || !inputValue.trim(),
|
|
@@ -40,7 +40,7 @@ const styles = {
|
|
|
40
40
|
wordWrap: 'break-word',
|
|
41
41
|
fontSize: '13px',
|
|
42
42
|
animation: `${slideIn} 0.3s ease`,
|
|
43
|
-
color: '#
|
|
43
|
+
color: '#555',
|
|
44
44
|
background: '#ecedee',
|
|
45
45
|
alignSelf: 'flex-end',
|
|
46
46
|
marginLeft: 'auto',
|
|
@@ -64,7 +64,7 @@ const styles = {
|
|
|
64
64
|
wordWrap: 'break-word',
|
|
65
65
|
fontSize: '13px',
|
|
66
66
|
animation: `${slideIn} 0.3s ease`,
|
|
67
|
-
color: '#
|
|
67
|
+
color: '#555',
|
|
68
68
|
alignSelf: 'flex-start'
|
|
69
69
|
},
|
|
70
70
|
contentItem: {
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Box, Divider, MenuItem, Select } from "@mui/material";
|
|
3
|
+
import { useChatContext } from "./contexts/ChatContext";
|
|
4
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
5
|
+
export default function ModelSelect() {
|
|
6
|
+
const {
|
|
7
|
+
model,
|
|
8
|
+
setModel,
|
|
9
|
+
provider,
|
|
10
|
+
setProvider,
|
|
11
|
+
providers
|
|
12
|
+
} = useChatContext();
|
|
13
|
+
const onChange = event => {
|
|
14
|
+
const {
|
|
15
|
+
value
|
|
16
|
+
} = event.target;
|
|
17
|
+
setProvider(findProvider(providers, value)?.provider);
|
|
18
|
+
setModel(findModel(providers, value)?.id);
|
|
19
|
+
};
|
|
20
|
+
console.log(provider, model);
|
|
21
|
+
return /*#__PURE__*/_jsx(_Fragment, {
|
|
22
|
+
children: providers.length > 0 && /*#__PURE__*/_jsx(Select, {
|
|
23
|
+
variant: "standard",
|
|
24
|
+
value: model,
|
|
25
|
+
onChange: onChange,
|
|
26
|
+
disableUnderline: true,
|
|
27
|
+
sx: styles.select,
|
|
28
|
+
renderValue: value => findModel(providers, value)?.name,
|
|
29
|
+
children: makeOptions(providers)
|
|
30
|
+
})
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
function makeOptions(providers) {
|
|
34
|
+
const jsx = [];
|
|
35
|
+
providers.forEach((provider, index) => {
|
|
36
|
+
if (index > 0) jsx.push(/*#__PURE__*/_jsx(Divider, {}, index));
|
|
37
|
+
provider.models.forEach(model => {
|
|
38
|
+
jsx.push(/*#__PURE__*/_jsx(MenuItem, {
|
|
39
|
+
value: model.id,
|
|
40
|
+
children: /*#__PURE__*/_jsxs(Box, {
|
|
41
|
+
children: [/*#__PURE__*/_jsx(Box, {
|
|
42
|
+
sx: styles.name,
|
|
43
|
+
children: model.name
|
|
44
|
+
}), /*#__PURE__*/_jsx(Box, {
|
|
45
|
+
sx: styles.desc,
|
|
46
|
+
children: model.description
|
|
47
|
+
})]
|
|
48
|
+
})
|
|
49
|
+
}, model.id));
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
return jsx;
|
|
53
|
+
}
|
|
54
|
+
function findProvider(providers, value) {
|
|
55
|
+
for (const provider of providers) {
|
|
56
|
+
for (const model of provider.models) {
|
|
57
|
+
if (model.id === value) return provider;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function findModel(providers, value) {
|
|
62
|
+
for (const provider of providers) {
|
|
63
|
+
for (const model of provider.models) {
|
|
64
|
+
if (model.id === value) return model;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const styles = {
|
|
69
|
+
select: {
|
|
70
|
+
color: '#666',
|
|
71
|
+
fontSize: '13px',
|
|
72
|
+
fontWeight: 400
|
|
73
|
+
},
|
|
74
|
+
name: {
|
|
75
|
+
fontWeight: 400,
|
|
76
|
+
fontSize: '13px'
|
|
77
|
+
},
|
|
78
|
+
desc: {
|
|
79
|
+
fontSize: '11px',
|
|
80
|
+
fontWeight: 200
|
|
81
|
+
}
|
|
82
|
+
};
|
|
@@ -1,14 +1,23 @@
|
|
|
1
|
-
import { useEffect, useRef, useState } from 'react';
|
|
1
|
+
import React, { createContext, useContext, useEffect, useRef, useState } from 'react';
|
|
2
2
|
import { getConfig } from "../../../js/config";
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
4
|
+
const ChatContext = /*#__PURE__*/createContext();
|
|
5
|
+
export function ChatProvider({
|
|
6
|
+
children,
|
|
7
|
+
defaultMessages = []
|
|
8
|
+
}) {
|
|
9
|
+
const [messages, setMessages] = useState(defaultMessages);
|
|
5
10
|
const [inputValue, setInputValue] = useState('');
|
|
6
11
|
const [isLoading, setIsLoading] = useState(false);
|
|
7
12
|
const [conversationId, setConversationId] = useState(null);
|
|
13
|
+
const [provider, setProvider] = useState('OPENAI');
|
|
14
|
+
const [providers, setProviders] = useState([]);
|
|
15
|
+
const [model, setModel] = useState('gpt-4.1-mini');
|
|
8
16
|
const [tools, setTools] = useState([]);
|
|
9
17
|
const chatContainerRef = useRef(null);
|
|
10
18
|
useEffect(() => {
|
|
11
|
-
|
|
19
|
+
loadModels();
|
|
20
|
+
// loadTools();
|
|
12
21
|
}, []);
|
|
13
22
|
useEffect(() => {
|
|
14
23
|
scrollToBottom();
|
|
@@ -18,6 +27,18 @@ const useChatApi = defaultMessages => {
|
|
|
18
27
|
chatContainerRef.current.scrollTop = chatContainerRef.current.scrollHeight;
|
|
19
28
|
}
|
|
20
29
|
};
|
|
30
|
+
const loadModels = async () => {
|
|
31
|
+
const {
|
|
32
|
+
apiUrl
|
|
33
|
+
} = getConfig();
|
|
34
|
+
try {
|
|
35
|
+
const response = await fetch(`${apiUrl}/api/models/provider`);
|
|
36
|
+
const data = await response.json();
|
|
37
|
+
setProviders(data);
|
|
38
|
+
} catch (error) {
|
|
39
|
+
console.error('Error loading models:', error);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
21
42
|
const loadTools = async () => {
|
|
22
43
|
const {
|
|
23
44
|
apiUrl
|
|
@@ -54,7 +75,9 @@ const useChatApi = defaultMessages => {
|
|
|
54
75
|
},
|
|
55
76
|
body: JSON.stringify({
|
|
56
77
|
message: message,
|
|
57
|
-
conversationId: conversationId
|
|
78
|
+
conversationId: conversationId,
|
|
79
|
+
provider: provider,
|
|
80
|
+
model: model
|
|
58
81
|
})
|
|
59
82
|
});
|
|
60
83
|
const data = await response.json();
|
|
@@ -77,14 +100,37 @@ const useChatApi = defaultMessages => {
|
|
|
77
100
|
setIsLoading(false);
|
|
78
101
|
}
|
|
79
102
|
};
|
|
80
|
-
|
|
103
|
+
const clearChat = () => {
|
|
104
|
+
setMessages([]);
|
|
105
|
+
setConversationId(null);
|
|
106
|
+
setInputValue('');
|
|
107
|
+
};
|
|
108
|
+
const value = {
|
|
81
109
|
messages,
|
|
82
110
|
inputValue,
|
|
83
111
|
setInputValue,
|
|
84
112
|
isLoading,
|
|
113
|
+
providers,
|
|
114
|
+
provider,
|
|
115
|
+
setProvider,
|
|
116
|
+
model,
|
|
117
|
+
setModel,
|
|
85
118
|
tools,
|
|
86
119
|
chatContainerRef,
|
|
87
|
-
sendMessage
|
|
120
|
+
sendMessage,
|
|
121
|
+
clearChat,
|
|
122
|
+
conversationId
|
|
88
123
|
};
|
|
89
|
-
|
|
90
|
-
|
|
124
|
+
return /*#__PURE__*/_jsx(ChatContext.Provider, {
|
|
125
|
+
value: value,
|
|
126
|
+
children: children
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
export function useChatContext() {
|
|
130
|
+
const context = useContext(ChatContext);
|
|
131
|
+
if (!context) {
|
|
132
|
+
throw new Error('useChatContext must be used within a ChatProvider');
|
|
133
|
+
}
|
|
134
|
+
return context;
|
|
135
|
+
}
|
|
136
|
+
export default ChatContext;
|
|
@@ -721,16 +721,23 @@ const mockTrendConvert2 = {
|
|
|
721
721
|
export const defaultMessages = [{
|
|
722
722
|
role: 'assistant',
|
|
723
723
|
// kinds: [],
|
|
724
|
-
kinds: ['COMPARE'],
|
|
725
|
-
content: [
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
724
|
+
//kinds: ['COMPARE'],
|
|
725
|
+
content: [
|
|
726
|
+
// mockTrendConvert1,
|
|
727
|
+
// {
|
|
728
|
+
// ...mockTrendConvert1,
|
|
729
|
+
// "arguments": {
|
|
730
|
+
// "taskId": "wc_convert_2",
|
|
731
|
+
// "from": "20251210",
|
|
732
|
+
// "to": "20251210",
|
|
733
|
+
// "unit": "30"
|
|
734
|
+
// }
|
|
735
|
+
// },
|
|
736
|
+
// mockTrendConvert2,
|
|
737
|
+
// mockSummary1,
|
|
738
|
+
// mockSummary2,
|
|
739
|
+
// mockSearchTaskByKeyword,
|
|
740
|
+
{
|
|
734
741
|
type: 'text',
|
|
735
742
|
value: '안녕하세요! 저는 회사 내부 정보와 다양한 기능에 접근할 수 있는 AI 어시스턴트입니다.\n무엇을 도와드릴까요?'
|
|
736
743
|
}]
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { configure, getConfig } from './js/config';
|
|
2
2
|
export { default as AiChat } from './components/chat/AiChat';
|
|
3
|
+
export { ChatProvider, useChatContext } from './components/chat/contexts/ChatContext';
|
|
3
4
|
export { default as PieChart } from './components/charts/PieChart';
|
|
4
5
|
export { default as ColumnChart } from './components/charts/ColumnChart';
|
|
5
6
|
export { default as StackedAreaTrendChart } from './components/charts/StackedAreaTrendChart';
|
package/package.json
CHANGED