@nethru/kit 1.1.3 → 1.1.5
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/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 +81 -0
- package/dist/components/chat/content/MarkdownContent.js +2 -0
- package/dist/components/chat/contexts/ChatContext.js +25 -2
- package/dist/components/chat/mock.js +23 -10
- package/package.json +6 -2
|
@@ -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,81 @@
|
|
|
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
|
+
return /*#__PURE__*/_jsx(_Fragment, {
|
|
21
|
+
children: providers.length > 0 && /*#__PURE__*/_jsx(Select, {
|
|
22
|
+
variant: "standard",
|
|
23
|
+
value: model,
|
|
24
|
+
onChange: onChange,
|
|
25
|
+
disableUnderline: true,
|
|
26
|
+
sx: styles.select,
|
|
27
|
+
renderValue: value => findModel(providers, value)?.name,
|
|
28
|
+
children: makeOptions(providers)
|
|
29
|
+
})
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
function makeOptions(providers) {
|
|
33
|
+
const jsx = [];
|
|
34
|
+
providers.forEach((provider, index) => {
|
|
35
|
+
if (index > 0) jsx.push(/*#__PURE__*/_jsx(Divider, {}, index));
|
|
36
|
+
provider.models.forEach(model => {
|
|
37
|
+
jsx.push(/*#__PURE__*/_jsx(MenuItem, {
|
|
38
|
+
value: model.id,
|
|
39
|
+
children: /*#__PURE__*/_jsxs(Box, {
|
|
40
|
+
children: [/*#__PURE__*/_jsx(Box, {
|
|
41
|
+
sx: styles.name,
|
|
42
|
+
children: model.name
|
|
43
|
+
}), /*#__PURE__*/_jsx(Box, {
|
|
44
|
+
sx: styles.desc,
|
|
45
|
+
children: model.description
|
|
46
|
+
})]
|
|
47
|
+
})
|
|
48
|
+
}, model.id));
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
return jsx;
|
|
52
|
+
}
|
|
53
|
+
function findProvider(providers, value) {
|
|
54
|
+
for (const provider of providers) {
|
|
55
|
+
for (const model of provider.models) {
|
|
56
|
+
if (model.id === value) return provider;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function findModel(providers, value) {
|
|
61
|
+
for (const provider of providers) {
|
|
62
|
+
for (const model of provider.models) {
|
|
63
|
+
if (model.id === value) return model;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const styles = {
|
|
68
|
+
select: {
|
|
69
|
+
color: '#666',
|
|
70
|
+
fontSize: '13px',
|
|
71
|
+
fontWeight: 400
|
|
72
|
+
},
|
|
73
|
+
name: {
|
|
74
|
+
fontWeight: 400,
|
|
75
|
+
fontSize: '13px'
|
|
76
|
+
},
|
|
77
|
+
desc: {
|
|
78
|
+
fontSize: '11px',
|
|
79
|
+
fontWeight: 200
|
|
80
|
+
}
|
|
81
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import ReactMarkdown from 'react-markdown';
|
|
2
|
+
import remarkGfm from 'remark-gfm';
|
|
2
3
|
import './MarkdownContent.css';
|
|
3
4
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
4
5
|
function MarkdownContent({
|
|
@@ -7,6 +8,7 @@ function MarkdownContent({
|
|
|
7
8
|
return /*#__PURE__*/_jsx("div", {
|
|
8
9
|
className: "markdown-content",
|
|
9
10
|
children: /*#__PURE__*/_jsx(ReactMarkdown, {
|
|
11
|
+
remarkPlugins: [remarkGfm],
|
|
10
12
|
children: content
|
|
11
13
|
})
|
|
12
14
|
});
|
|
@@ -10,10 +10,14 @@ export function ChatProvider({
|
|
|
10
10
|
const [inputValue, setInputValue] = useState('');
|
|
11
11
|
const [isLoading, setIsLoading] = useState(false);
|
|
12
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');
|
|
13
16
|
const [tools, setTools] = useState([]);
|
|
14
17
|
const chatContainerRef = useRef(null);
|
|
15
18
|
useEffect(() => {
|
|
16
|
-
|
|
19
|
+
loadModels();
|
|
20
|
+
// loadTools();
|
|
17
21
|
}, []);
|
|
18
22
|
useEffect(() => {
|
|
19
23
|
scrollToBottom();
|
|
@@ -23,6 +27,18 @@ export function ChatProvider({
|
|
|
23
27
|
chatContainerRef.current.scrollTop = chatContainerRef.current.scrollHeight;
|
|
24
28
|
}
|
|
25
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
|
+
};
|
|
26
42
|
const loadTools = async () => {
|
|
27
43
|
const {
|
|
28
44
|
apiUrl
|
|
@@ -59,7 +75,9 @@ export function ChatProvider({
|
|
|
59
75
|
},
|
|
60
76
|
body: JSON.stringify({
|
|
61
77
|
message: message,
|
|
62
|
-
conversationId: conversationId
|
|
78
|
+
conversationId: conversationId,
|
|
79
|
+
provider: provider,
|
|
80
|
+
model: model
|
|
63
81
|
})
|
|
64
82
|
});
|
|
65
83
|
const data = await response.json();
|
|
@@ -92,6 +110,11 @@ export function ChatProvider({
|
|
|
92
110
|
inputValue,
|
|
93
111
|
setInputValue,
|
|
94
112
|
isLoading,
|
|
113
|
+
providers,
|
|
114
|
+
provider,
|
|
115
|
+
setProvider,
|
|
116
|
+
model,
|
|
117
|
+
setModel,
|
|
95
118
|
tools,
|
|
96
119
|
chatContainerRef,
|
|
97
120
|
sendMessage,
|
|
@@ -721,16 +721,29 @@ 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
|
+
{
|
|
741
|
+
"type": "text",
|
|
742
|
+
"value": "현재 등록된 컨테이너 목록은 아래와 같습니다 👇 \n\n| ID | 유형 | 이름 | URL | 활성화 여부 |\n|----|------|------|------|--------------|\n| 00001 | WEB | 와이즈컬렉터3 | [https://wc.nethru.co.kr](https://wc.nethru.co.kr) | ✅ 활성 |\n| 00003 | WEB | 넷스루 홈페이지 | [http://www.nethru.co.kr](http://www.nethru.co.kr) | ✅ 활성 |\n| 00004 | WEB | WC몰 | [https://wcmall.nethru.co.kr](https://wcmall.nethru.co.kr) | ✅ 활성 |\n| 00005 | WEB | Google Arts & Culture | [https://artsandculture.google.com](https://artsandculture.google.com) | ✅ 활성 |\n| 00006 | MOBILE | OmniNotes | [https://www.omnintes.com](https://www.omnintes.com) | ✅ 활성 |\n| 00007 | MOBILE | Plaid | [https://www.plaid.com](https://www.plaid.com) | ✅ 활성 |\n| 00008 | MOBILE | 안드로이드 샘플앱 | [http://www.androidtest.com](http://www.androidtest.com) | ✅ 활성 |\n| 00009 | MOBILE | 엄니노트 | [https://www.omnintes.com](https://www.omnintes.com) | ✅ 활성 |\n| 00026 | WEB | 신수민티스토리 | [https://nethoomru.tistory.com](https://nethoomru.tistory.com) | ✅ 활성 |\n| 00710 | WEB | solmin_test2 | [https://wc-solmin.tistory.com](https://wc-solmin.tistory.com) | ✅ 활성 |\n| 00711 | MOBILE | KB Pay | [https://kbpay.kbcard.com](https://kbpay.kbcard.com) | ✅ 활성 |\n| 00712 | MOBILE | OmniNotes2 | [https://www.omnintes.com](https://www.omnintes.com) | ✅ 활성 |\n| 00715 | WEB | test2 | [https://wc-solmin.tistory.com](https://wc-solmin.tistory.com) | ❌ 비활성 |\n| 00718 | MOBILE | iOS 샘플앱 | [http://www.iostest.com](http://www.iostest.com) | ✅ 활성 |\n| 00742 | MOBILE | 모바일 샘플앱 250903 (iOS 테스트 임시) | [http://www.androidtest.com](http://www.androidtest.com) | ✅ 활성 |\n| 00743 | MOBILE | 요기요 | [https://www.yogiyo.co.kr](https://www.yogiyo.co.kr) | ✅ 활성 |\n| 00744 | MOBILE | 사내 TFT 예제 - KBPay | [https://www.tftex1.co.kr](https://www.tftex1.co.kr) | ✅ 활성 |\n| 00745 | MOBILE | OmniNotes-soomsoom | [https://www.omnintes.com](https://www.omnintes.com) | ✅ 활성 |\n| 00746 | MOBILE | 믿고걸_뉴스 | [http://www.worthskippingnews.com](http://www.worthskippingnews.com) | ✅ 활성 |\n| 00747 | WEB | KB 은행 | [https://www.kbstar.com](https://www.kbstar.com) | ✅ 활성 |\n| 00748 | MOBILE | test251127 | [http://www.test251127.com](http://www.test251127.com) | ❌ 비활성 |\n| 00764 | MOBILE | test749 | [http://w.a.com](http://w.a.com) | ❌ 비활성 |\n| 00765 | MOBILE | test750 | [http://www.test.com](http://www.test.com) | ❌ 비활성 |\n\n총 **24개 컨테이너**가 등록되어 있으며, 이 중 **18개는 활성화**, **6개는 비활성화** 상태입니다. \n\n특정 컨테이너(예: “KB Pay”나 “와이즈컬렉터3”)의 **태스크 목록이나 설정 세부 정보**를 보고 싶으신가요?"
|
|
743
|
+
}, {
|
|
744
|
+
type: "text",
|
|
745
|
+
value: "# Hello\n" + "https://example.org\n" + "```sh\n" + "# Code block\n" + "const func = () => {};\n" + "```\n" + "\n" + "\n" + "~~strike~~ this\n" + "\n" + "[MIT](license) © [Titus Wormer](https://wooorm.com)\n" + "## TODO\n" + "\n" + "* [ ] This\n" + "* [ ] That\n" + "* [x] The other\n" + "\n" + "|Fahrenheit|Celsius|Kelvin|\n" + "|---:|---:|---:|\n" + "|-459.67|-273.15|0|\n" + "|-40|-40|233.15|\n" + "|32|0|273.15|\n" + "|212|100|373.15|\n"
|
|
746
|
+
}, {
|
|
734
747
|
type: 'text',
|
|
735
748
|
value: '안녕하세요! 저는 회사 내부 정보와 다양한 기능에 접근할 수 있는 AI 어시스턴트입니다.\n무엇을 도와드릴까요?'
|
|
736
749
|
}]
|
package/package.json
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nethru/kit",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.5",
|
|
4
4
|
"description": "A React component library by Nethru",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"homepage": ".",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public"
|
|
9
|
+
},
|
|
7
10
|
"files": [
|
|
8
11
|
"/dist"
|
|
9
12
|
],
|
|
@@ -47,7 +50,8 @@
|
|
|
47
50
|
"@nethru/ui": "^2.1.45",
|
|
48
51
|
"highcharts": "^11.3.0",
|
|
49
52
|
"highcharts-react-official": "^3.2.1",
|
|
50
|
-
"react-markdown": "^10.1.0"
|
|
53
|
+
"react-markdown": "^10.1.0",
|
|
54
|
+
"remark-gfm": "^4.0.1"
|
|
51
55
|
},
|
|
52
56
|
"browserslist": {
|
|
53
57
|
"production": [
|