@orbe-agro/client-core 5.6.239 → 5.6.240
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/@ecme/assets/styles/app.css +116 -3
- package/dist/@ecme/assets/styles/tailwind/index.css +119 -3
- package/dist/@ecme/components/template/Footer.js +1 -1
- package/dist/@ecme/components/template/OrbeAiWidget/OrbeAiWidget.js +0 -2
- package/dist/@ecme/components/template/OrbeAiWidget/OrbeAiWidget.js.map +1 -1
- package/dist/@ecme/components/view/ChatBox/ChatBox.js +2 -0
- package/dist/@ecme/components/view/ChatBox/ChatBox.js.map +1 -1
- package/dist/@ecme/components/view/ChatBox/components/MessageList.js +2 -1
- package/dist/@ecme/components/view/ChatBox/components/MessageList.js.map +1 -1
- package/dist/@ecme/index.js +3 -4
- package/dist/@ecme/services/AiService.js +53 -24
- package/dist/@ecme/services/AiService.js.map +1 -1
- package/dist/@ecme/services/aiAuthHeaders.js +35 -0
- package/dist/@ecme/services/aiAuthHeaders.js.map +1 -0
- package/dist/@ecme/services/axios/AxiosRequestIntrceptorConfigCallback.js +4 -27
- package/dist/@ecme/services/axios/AxiosRequestIntrceptorConfigCallback.js.map +1 -1
- package/dist/@ecme/services/index.js +4 -5
- package/dist/@ecme/services/sseParser.js +42 -0
- package/dist/@ecme/services/sseParser.js.map +1 -0
- package/dist/@ecme/views/concepts/ai/Chat/components/AiErrorMessage.js +15 -0
- package/dist/@ecme/views/concepts/ai/Chat/components/AiErrorMessage.js.map +1 -0
- package/dist/@ecme/views/concepts/ai/Chat/components/ApprovalCard.js +73 -0
- package/dist/@ecme/views/concepts/ai/Chat/components/ApprovalCard.js.map +1 -0
- package/dist/@ecme/views/concepts/ai/Chat/components/ChatView.js +37 -10
- package/dist/@ecme/views/concepts/ai/Chat/components/ChatView.js.map +1 -1
- package/dist/@ecme/views/concepts/ai/Chat/components/ToolCallChip.js +153 -0
- package/dist/@ecme/views/concepts/ai/Chat/components/ToolCallChip.js.map +1 -0
- package/dist/@ecme/views/concepts/ai/Chat/components/toolPresentation.js +99 -0
- package/dist/@ecme/views/concepts/ai/Chat/components/toolPresentation.js.map +1 -0
- package/dist/@ecme/views/concepts/ai/Chat/hooks/useChatSend.js +111 -17
- package/dist/@ecme/views/concepts/ai/Chat/hooks/useChatSend.js.map +1 -1
- package/dist/@ecme/views/concepts/ai/Chat/store/generativeChatStore.js +29 -13
- package/dist/@ecme/views/concepts/ai/Chat/store/generativeChatStore.js.map +1 -1
- package/dist/@types/@ecme/components/template/OrbeAiWidget/OrbeAiWidget.d.ts.map +1 -1
- package/dist/@types/@ecme/components/view/ChatBox/ChatBox.d.ts.map +1 -1
- package/dist/@types/@ecme/components/view/ChatBox/components/MessageList.d.ts +2 -0
- package/dist/@types/@ecme/components/view/ChatBox/components/MessageList.d.ts.map +1 -1
- package/dist/@types/@ecme/services/AiService.d.ts +28 -15
- package/dist/@types/@ecme/services/AiService.d.ts.map +1 -1
- package/dist/@types/@ecme/services/aiAuthHeaders.d.ts +12 -0
- package/dist/@types/@ecme/services/aiAuthHeaders.d.ts.map +1 -0
- package/dist/@types/@ecme/services/axios/AxiosRequestIntrceptorConfigCallback.d.ts +6 -0
- package/dist/@types/@ecme/services/axios/AxiosRequestIntrceptorConfigCallback.d.ts.map +1 -1
- package/dist/@types/@ecme/services/sseParser.d.ts +20 -0
- package/dist/@types/@ecme/services/sseParser.d.ts.map +1 -0
- package/dist/@types/@ecme/views/concepts/ai/Chat/components/AiErrorMessage.d.ts +8 -0
- package/dist/@types/@ecme/views/concepts/ai/Chat/components/AiErrorMessage.d.ts.map +1 -0
- package/dist/@types/@ecme/views/concepts/ai/Chat/components/ApprovalCard.d.ts +15 -0
- package/dist/@types/@ecme/views/concepts/ai/Chat/components/ApprovalCard.d.ts.map +1 -0
- package/dist/@types/@ecme/views/concepts/ai/Chat/components/ChatView.d.ts.map +1 -1
- package/dist/@types/@ecme/views/concepts/ai/Chat/components/ToolCallChip.d.ts +7 -0
- package/dist/@types/@ecme/views/concepts/ai/Chat/components/ToolCallChip.d.ts.map +1 -0
- package/dist/@types/@ecme/views/concepts/ai/Chat/components/toolPresentation.d.ts +14 -0
- package/dist/@types/@ecme/views/concepts/ai/Chat/components/toolPresentation.d.ts.map +1 -0
- package/dist/@types/@ecme/views/concepts/ai/Chat/hooks/useChatSend.d.ts +2 -1
- package/dist/@types/@ecme/views/concepts/ai/Chat/hooks/useChatSend.d.ts.map +1 -1
- package/dist/@types/@ecme/views/concepts/ai/Chat/store/generativeChatStore.d.ts +1 -0
- package/dist/@types/@ecme/views/concepts/ai/Chat/store/generativeChatStore.d.ts.map +1 -1
- package/dist/@types/@ecme/views/concepts/ai/Chat/types.d.ts +96 -23
- package/dist/@types/@ecme/views/concepts/ai/Chat/types.d.ts.map +1 -1
- package/dist/base/assets/styles/init.css +128 -3
- package/lib/@ecme/components/template/OrbeAiWidget/OrbeAiWidget.tsx +0 -2
- package/lib/@ecme/components/view/ChatBox/ChatBox.tsx +2 -0
- package/lib/@ecme/components/view/ChatBox/components/MessageList.tsx +8 -4
- package/lib/@ecme/services/AiService.ts +89 -44
- package/lib/@ecme/services/aiAuthHeaders.ts +58 -0
- package/lib/@ecme/services/axios/AxiosRequestIntrceptorConfigCallback.ts +10 -39
- package/lib/@ecme/services/sseParser.ts +75 -0
- package/lib/@ecme/views/concepts/ai/Chat/components/AiErrorMessage.tsx +28 -0
- package/lib/@ecme/views/concepts/ai/Chat/components/ApprovalCard.tsx +103 -0
- package/lib/@ecme/views/concepts/ai/Chat/components/ChatView.tsx +74 -10
- package/lib/@ecme/views/concepts/ai/Chat/components/ToolCallChip.tsx +218 -0
- package/lib/@ecme/views/concepts/ai/Chat/components/toolPresentation.ts +137 -0
- package/lib/@ecme/views/concepts/ai/Chat/hooks/useChatSend.ts +175 -23
- package/lib/@ecme/views/concepts/ai/Chat/store/generativeChatStore.ts +41 -13
- package/lib/@ecme/views/concepts/ai/Chat/types.ts +82 -29
- package/package.json +1 -1
- package/dist/@ecme/views/concepts/ai/Chat/components/ModelSelect.js +0 -48
- package/dist/@ecme/views/concepts/ai/Chat/components/ModelSelect.js.map +0 -1
- package/dist/@ecme/views/concepts/ai/Chat/store/aiModelStore.js +0 -15
- package/dist/@ecme/views/concepts/ai/Chat/store/aiModelStore.js.map +0 -1
- package/dist/@types/@ecme/views/concepts/ai/Chat/components/ModelSelect.d.ts +0 -8
- package/dist/@types/@ecme/views/concepts/ai/Chat/components/ModelSelect.d.ts.map +0 -1
- package/dist/@types/@ecme/views/concepts/ai/Chat/store/aiModelStore.d.ts +0 -25
- package/dist/@types/@ecme/views/concepts/ai/Chat/store/aiModelStore.d.ts.map +0 -1
- package/lib/@ecme/views/concepts/ai/Chat/components/ModelSelect.tsx +0 -66
- package/lib/@ecme/views/concepts/ai/Chat/store/aiModelStore.ts +0 -23
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatBox.js","sources":["../../../../../lib/@ecme/components/view/ChatBox/ChatBox.tsx"],"sourcesContent":["import ChatContainer from './components/ChatContainer'\nimport MessageList from './components/MessageList'\nimport ChatInput from './components/ChatInput'\nimport type { MessageListProps } from './components/MessageList'\nimport type { ChatContainerProps } from './components/ChatContainer'\nimport type { ChatInputProps } from './components/ChatInput'\nimport type { ReactNode } from 'react'\nimport { forwardRef } from 'react'\nimport type { ScrollBarRef } from '@/components/ui/ScrollBar'\n\nexport type MessageList = MessageListProps['list']\n\nexport type ChatBoxProps = {\n messageList: MessageList\n header?: ChatContainerProps['header']\n showMessageList?: boolean\n children?: ReactNode\n containerClass?: string\n} & Omit<MessageListProps, 'list'> &\n ChatInputProps\n\nconst ChatBox = forwardRef<ScrollBarRef, ChatBoxProps>((props, ref) => {\n const {\n messageList,\n showMessageList = true,\n children,\n header,\n placeholder,\n onInputChange,\n showAvatar,\n avatarGap,\n customRenderer,\n customAction,\n bubbleClass,\n myBubbleClass,\n botBubbleClass,\n renderTyping,\n typing,\n messageListClass,\n containerClass,\n } = props\n\n return (\n <ChatContainer\n className={containerClass}\n header={header}\n input={\n <ChatInput\n placeholder={placeholder}\n onInputChange={onInputChange}\n />\n }\n >\n {showMessageList && (\n <MessageList\n ref={ref}\n list={messageList}\n showAvatar={showAvatar}\n avatarGap={avatarGap}\n customRenderer={customRenderer}\n customAction={customAction}\n typing={typing}\n messageListClass={messageListClass}\n bubbleClass={bubbleClass}\n myBubbleClass={myBubbleClass}\n botBubbleClass={botBubbleClass}\n renderTyping={renderTyping}\n /> )}\n {children}\n </ChatContainer>\n )\n})\n\nChatBox.displayName = 'ChatBox'\n\nexport default ChatBox\n"],"names":[],"mappings":";;;;;AAqBA,MAAM,UAAU,WAAuC,CAAC,OAAO,QAAQ;AACnE,QAAM;AAAA,IACF;AAAA,IACA,kBAAkB;AAAA,IAClB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,IACA;AAEJ,SACI;AAAA,IAAC;AAAA,IAAA;AAAA,MACG,WAAW;AAAA,MACX;AAAA,MACA,OACI;AAAA,QAAC;AAAA,QAAA;AAAA,UACG;AAAA,UACA;AAAA,QAAA;AAAA,MAAA;AAAA,MAIP,UAAA;AAAA,QAAA,mBACG;AAAA,UAAC;AAAA,UAAA;AAAA,YACG;AAAA,YACA,MAAM;AAAA,YACN;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UAAA;AAAA,QAAA;AAAA,QAEP;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGb,CAAC;AAED,QAAQ,cAAc;"}
|
|
1
|
+
{"version":3,"file":"ChatBox.js","sources":["../../../../../lib/@ecme/components/view/ChatBox/ChatBox.tsx"],"sourcesContent":["import ChatContainer from './components/ChatContainer'\nimport MessageList from './components/MessageList'\nimport ChatInput from './components/ChatInput'\nimport type { MessageListProps } from './components/MessageList'\nimport type { ChatContainerProps } from './components/ChatContainer'\nimport type { ChatInputProps } from './components/ChatInput'\nimport type { ReactNode } from 'react'\nimport { forwardRef } from 'react'\nimport type { ScrollBarRef } from '@/components/ui/ScrollBar'\n\nexport type MessageList = MessageListProps['list']\n\nexport type ChatBoxProps = {\n messageList: MessageList\n header?: ChatContainerProps['header']\n showMessageList?: boolean\n children?: ReactNode\n containerClass?: string\n} & Omit<MessageListProps, 'list'> &\n ChatInputProps\n\nconst ChatBox = forwardRef<ScrollBarRef, ChatBoxProps>((props, ref) => {\n const {\n messageList,\n showMessageList = true,\n children,\n header,\n placeholder,\n onInputChange,\n showAvatar,\n avatarGap,\n customRenderer,\n customAction,\n bubbleClass,\n myBubbleClass,\n botBubbleClass,\n errorBubbleClass,\n renderTyping,\n typing,\n messageListClass,\n containerClass,\n } = props\n\n return (\n <ChatContainer\n className={containerClass}\n header={header}\n input={\n <ChatInput\n placeholder={placeholder}\n onInputChange={onInputChange}\n />\n }\n >\n {showMessageList && (\n <MessageList\n ref={ref}\n list={messageList}\n showAvatar={showAvatar}\n avatarGap={avatarGap}\n customRenderer={customRenderer}\n customAction={customAction}\n typing={typing}\n messageListClass={messageListClass}\n bubbleClass={bubbleClass}\n myBubbleClass={myBubbleClass}\n botBubbleClass={botBubbleClass}\n errorBubbleClass={errorBubbleClass}\n renderTyping={renderTyping}\n /> )}\n {children}\n </ChatContainer>\n )\n})\n\nChatBox.displayName = 'ChatBox'\n\nexport default ChatBox\n"],"names":[],"mappings":";;;;;AAqBA,MAAM,UAAU,WAAuC,CAAC,OAAO,QAAQ;AACnE,QAAM;AAAA,IACF;AAAA,IACA,kBAAkB;AAAA,IAClB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,IACA;AAEJ,SACI;AAAA,IAAC;AAAA,IAAA;AAAA,MACG,WAAW;AAAA,MACX;AAAA,MACA,OACI;AAAA,QAAC;AAAA,QAAA;AAAA,UACG;AAAA,UACA;AAAA,QAAA;AAAA,MAAA;AAAA,MAIP,UAAA;AAAA,QAAA,mBACG;AAAA,UAAC;AAAA,UAAA;AAAA,YACG;AAAA,YACA,MAAM;AAAA,YACN;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UAAA;AAAA,QAAA;AAAA,QAEP;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGb,CAAC;AAED,QAAQ,cAAc;"}
|
|
@@ -16,6 +16,7 @@ const MessageList = forwardRef((props, ref) => {
|
|
|
16
16
|
bubbleClass,
|
|
17
17
|
myBubbleClass,
|
|
18
18
|
botBubbleClass,
|
|
19
|
+
errorBubbleClass,
|
|
19
20
|
renderTyping
|
|
20
21
|
} = props;
|
|
21
22
|
return /* @__PURE__ */ jsx("div", { className: classNames("relative", messageListClass), children: /* @__PURE__ */ jsxs("div", { className: "absolute top-0 left-0 h-full w-full py-4", children: [
|
|
@@ -33,7 +34,7 @@ const MessageList = forwardRef((props, ref) => {
|
|
|
33
34
|
{
|
|
34
35
|
showAvatar,
|
|
35
36
|
avatarGap,
|
|
36
|
-
bubbleClass: message.isMyMessage ? myBubbleClass ?? bubbleClass : botBubbleClass ?? bubbleClass,
|
|
37
|
+
bubbleClass: message.isError ? errorBubbleClass ?? bubbleClass : message.isMyMessage ? myBubbleClass ?? bubbleClass : botBubbleClass ?? bubbleClass,
|
|
37
38
|
...message,
|
|
38
39
|
...customRenderer ? {
|
|
39
40
|
customRenderer: () => customRenderer(message, index)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageList.js","sources":["../../../../../../lib/@ecme/components/view/ChatBox/components/MessageList.tsx"],"sourcesContent":["import ScrollBar from '@/components/ui/ScrollBar'\nimport Message from './Message'\nimport classNames from '@/utils/classNames'\nimport type { ReactNode } from 'react'\nimport { forwardRef } from 'react'\nimport type { ScrollBarRef } from '@/components/ui/ScrollBar'\nimport type { MessageProps } from './Message'\n\ntype List = MessageProps & { fresh?: boolean }\n\nexport type MessageListProps = {\n list: List[]\n showAvatar?: boolean\n avatarGap?: boolean\n typing?:\n | {\n id: string\n name: string\n avatarImageUrl?: string\n }\n | false\n customRenderer?: (message: List, index: number) => string | ReactNode\n customAction?: (message: List, index: number) => string | ReactNode\n bubbleClass?: string\n myBubbleClass?: string\n botBubbleClass?: string\n renderTyping?: () => ReactNode\n messageListClass?: string\n}\n\nconst MessageList = forwardRef<ScrollBarRef, MessageListProps>((props, ref) => { const {\n list = [],\n showAvatar = true,\n typing = false,\n avatarGap,\n customRenderer,\n customAction,\n messageListClass,\n bubbleClass,\n myBubbleClass,\n botBubbleClass,\n renderTyping,\n } = props\n\n return (\n <div className={classNames('relative', messageListClass)}>\n <div className=\"absolute top-0 left-0 h-full w-full py-4\"> <ScrollBar\n ref={ref}\n autoHide\n className=\"overflow-y-auto h-full max-w-full\"\n >\n <div className=\"flex flex-col gap-4 px-4\">\n {list.map((message, index) => (\n <Message\n key={message.id}\n showAvatar={showAvatar}\n avatarGap={avatarGap}\n bubbleClass={\n message.
|
|
1
|
+
{"version":3,"file":"MessageList.js","sources":["../../../../../../lib/@ecme/components/view/ChatBox/components/MessageList.tsx"],"sourcesContent":["import ScrollBar from '@/components/ui/ScrollBar'\nimport Message from './Message'\nimport classNames from '@/utils/classNames'\nimport type { ReactNode } from 'react'\nimport { forwardRef } from 'react'\nimport type { ScrollBarRef } from '@/components/ui/ScrollBar'\nimport type { MessageProps } from './Message'\n\ntype List = MessageProps & { fresh?: boolean; isError?: boolean }\n\nexport type MessageListProps = {\n list: List[]\n showAvatar?: boolean\n avatarGap?: boolean\n typing?:\n | {\n id: string\n name: string\n avatarImageUrl?: string\n }\n | false\n customRenderer?: (message: List, index: number) => string | ReactNode\n customAction?: (message: List, index: number) => string | ReactNode\n bubbleClass?: string\n myBubbleClass?: string\n botBubbleClass?: string\n errorBubbleClass?: string\n renderTyping?: () => ReactNode\n messageListClass?: string\n}\n\nconst MessageList = forwardRef<ScrollBarRef, MessageListProps>((props, ref) => { const {\n list = [],\n showAvatar = true,\n typing = false,\n avatarGap,\n customRenderer,\n customAction,\n messageListClass,\n bubbleClass,\n myBubbleClass,\n botBubbleClass,\n errorBubbleClass,\n renderTyping,\n } = props\n\n return (\n <div className={classNames('relative', messageListClass)}>\n <div className=\"absolute top-0 left-0 h-full w-full py-4\"> <ScrollBar\n ref={ref}\n autoHide\n className=\"overflow-y-auto h-full max-w-full\"\n >\n <div className=\"flex flex-col gap-4 px-4\">\n {list.map((message, index) => (\n <Message\n key={message.id}\n showAvatar={showAvatar}\n avatarGap={avatarGap}\n bubbleClass={\n message.isError\n ? errorBubbleClass ?? bubbleClass\n : message.isMyMessage\n ? myBubbleClass ?? bubbleClass\n : botBubbleClass ?? bubbleClass\n }\n {...message}\n {...(customRenderer\n ? {\n customRenderer: () =>\n customRenderer(message, index),\n }\n : {})}\n {...(customAction\n ? {\n customAction: () =>\n customAction(message, index),\n }\n : {})}\n />\n ))}\n {typing && (\n <Message\n id={typing.name + 'typing'}\n sender={typing}\n type=\"regular\"\n showAvatar={showAvatar}\n bubbleClass={botBubbleClass ?? bubbleClass}\n avatarGap={avatarGap}\n content={\n renderTyping ? (\n renderTyping()\n ) : (\n <span className=\"flex items-center gap-2\">\n <span className=\"size-1.5 rounded-full bg-gray-700 motion-safe:animate-[bounce_1s_ease-in-out_infinite] dark:bg-gray-300\"></span>\n <span className=\"size-1.5 rounded-full bg-gray-700 motion-safe:animate-[bounce_0.5s_ease-in-out_infinite] dark:bg-gray-300\"></span>\n <span className=\"size-1.5 rounded-full bg-gray-700 motion-safe:animate-[bounce_1s_ease-in-out_infinite] dark:bg-gray-300\"></span>\n </span>\n )\n }\n />\n )}\n </div> </ScrollBar>\n </div>\n </div>\n )\n})\n\nMessageList.displayName = 'MessageList'\n\nexport default MessageList\n"],"names":[],"mappings":";;;;;;AA+BA,MAAM,cAAc,WAA2C,CAAC,OAAO,QAAQ;AAAK,QAAM;AAAA,IAClF,OAAO,CAAA;AAAA,IACP,aAAa;AAAA,IACb,SAAS;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,IACA;AAEJ,SACI,oBAAC,OAAA,EAAI,WAAW,WAAW,YAAY,gBAAgB,GACnD,UAAA,qBAAC,OAAA,EAAI,WAAU,4CAA2C,UAAA;AAAA,IAAA;AAAA,IAAgB;AAAA,MAAC;AAAA,MAAA;AAAA,QACnE;AAAA,QACA,UAAQ;AAAA,QACR,WAAU;AAAA,QAEV,UAAA;AAAA,UAAA,qBAAC,OAAA,EAAI,WAAU,4BACV,UAAA;AAAA,YAAA,KAAK,IAAI,CAAC,SAAS,UAChB;AAAA,cAAC;AAAA,cAAA;AAAA,gBAEG;AAAA,gBACA;AAAA,gBACA,aACI,QAAQ,UACF,oBAAoB,cACpB,QAAQ,cACN,iBAAiB,cACjB,kBAAkB;AAAA,gBAE7B,GAAG;AAAA,gBACH,GAAI,iBACC;AAAA,kBACI,gBAAgB,MACZ,eAAe,SAAS,KAAK;AAAA,gBAAA,IAErC,CAAA;AAAA,gBACL,GAAI,eACC;AAAA,kBACI,cAAc,MACV,aAAa,SAAS,KAAK;AAAA,gBAAA,IAEnC,CAAA;AAAA,cAAC;AAAA,cAtBF,QAAQ;AAAA,YAAA,CAwBpB;AAAA,YACA,UACG;AAAA,cAAC;AAAA,cAAA;AAAA,gBACG,IAAI,OAAO,OAAO;AAAA,gBAClB,QAAQ;AAAA,gBACR,MAAK;AAAA,gBACL;AAAA,gBACA,aAAa,kBAAkB;AAAA,gBAC/B;AAAA,gBACA,SACI,eACI,iBAEA,qBAAC,QAAA,EAAK,WAAU,2BACZ,UAAA;AAAA,kBAAA,oBAAC,QAAA,EAAK,WAAU,0GAAA,CAA0G;AAAA,kBAC1H,oBAAC,QAAA,EAAK,WAAU,4GAAA,CAA4G;AAAA,kBAC5H,oBAAC,QAAA,EAAK,WAAU,0GAAA,CAA0G;AAAA,gBAAA,EAAA,CAC9H;AAAA,cAAA;AAAA,YAAA;AAAA,UAGZ,GAER;AAAA,UAAM;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAAgB,EAAA,CAC9B,EAAA,CACJ;AAER,CAAC;AAED,YAAY,cAAc;"}
|
package/dist/@ecme/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import "./auth/index.js";
|
|
|
10
10
|
import "./assets/index.js";
|
|
11
11
|
import "./locales/index.js";
|
|
12
12
|
import { ADMIN, USER } from "./constants/roles.constant.js";
|
|
13
|
-
import { AI_API_URL,
|
|
13
|
+
import { AI_API_URL, apiGetChatHistory, apiGetImages, apiPostImages, resumeChat, streamChat } from "./services/AiService.js";
|
|
14
14
|
import { APP_NAME, REDIRECT_URL_KEY } from "./constants/app.constant.js";
|
|
15
15
|
import { AUTH_PREFIX_PATH, CONCEPTS_PREFIX_PATH, DASHBOARDS_PREFIX_PATH, GUIDE_PREFIX_PATH, PAGES_PREFIX_PATH, ROOT, UI_COMPONENTS_PREFIX_PATH } from "./constants/route.constant.js";
|
|
16
16
|
import { default as default2 } from "./components/shared/AbbreviateNumber.js";
|
|
@@ -207,7 +207,6 @@ import { default as default137 } from "./utils/hoc/withHeaderItem.js";
|
|
|
207
207
|
export {
|
|
208
208
|
ADMIN,
|
|
209
209
|
AI_API_URL,
|
|
210
|
-
AI_MODEL_HEADER,
|
|
211
210
|
APP_NAME,
|
|
212
211
|
AUTH_PREFIX_PATH,
|
|
213
212
|
default2 as AbbreviateNumber,
|
|
@@ -376,7 +375,6 @@ export {
|
|
|
376
375
|
default103 as Views,
|
|
377
376
|
default104 as acronym,
|
|
378
377
|
apiForgotPassword,
|
|
379
|
-
apiGetAiModels,
|
|
380
378
|
apiGetAnalyticDashboard,
|
|
381
379
|
apiGetArticleList,
|
|
382
380
|
apiGetCalendar,
|
|
@@ -421,7 +419,6 @@ export {
|
|
|
421
419
|
apiGetSupportHubCategories,
|
|
422
420
|
apiGithubOauthSignIn,
|
|
423
421
|
apiGoogleOauthSignIn,
|
|
424
|
-
apiPostChat,
|
|
425
422
|
apiPostImages,
|
|
426
423
|
apiPostProject,
|
|
427
424
|
apiResetPassword,
|
|
@@ -449,7 +446,9 @@ export {
|
|
|
449
446
|
othersPlaceholder,
|
|
450
447
|
protectedRoutes,
|
|
451
448
|
publicRoutes,
|
|
449
|
+
resumeChat,
|
|
452
450
|
default114 as sharedDocs,
|
|
451
|
+
streamChat,
|
|
453
452
|
tailwindStyles,
|
|
454
453
|
templateStyles,
|
|
455
454
|
default115 as themeConfig,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { authHeaders } from "./aiAuthHeaders.js";
|
|
1
2
|
import ApiService from "./ApiService.js";
|
|
2
|
-
import {
|
|
3
|
-
const AI_MODEL_HEADER = "X-Ai-Model";
|
|
3
|
+
import { readSse } from "./sseParser.js";
|
|
4
4
|
const AI_DEV_URL = "http://localhost:8000";
|
|
5
5
|
const AI_BUILD_URL = "https://orbe-ai-homolog.apps.qas.orbeagro.com.br";
|
|
6
6
|
function getAiApiUrl() {
|
|
@@ -11,33 +11,63 @@ function getAiApiUrl() {
|
|
|
11
11
|
return AI_BUILD_URL;
|
|
12
12
|
}
|
|
13
13
|
const AI_API_URL = getAiApiUrl();
|
|
14
|
-
const aiModelHeader = () => {
|
|
15
|
-
const selectedModel = useAiModelStore.getState().selectedModel;
|
|
16
|
-
return selectedModel ? { [AI_MODEL_HEADER]: selectedModel } : void 0;
|
|
17
|
-
};
|
|
18
14
|
const aiRequest = (config) => ApiService.fetchDataWithAxios({
|
|
19
15
|
...config,
|
|
20
16
|
baseURL: AI_API_URL,
|
|
21
17
|
skipGlobalLoading: true
|
|
22
18
|
});
|
|
23
|
-
async function
|
|
24
|
-
return aiRequest({
|
|
25
|
-
url: "/ai/chat",
|
|
26
|
-
method: "post",
|
|
27
|
-
data,
|
|
28
|
-
headers: aiModelHeader()
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
async function apiGetChatHistory() {
|
|
19
|
+
async function apiGetChatHistory(conversationId) {
|
|
32
20
|
return aiRequest({
|
|
33
21
|
url: "/ai/chat/history",
|
|
34
|
-
method: "get"
|
|
22
|
+
method: "get",
|
|
23
|
+
params: conversationId ? { conversation_id: conversationId } : void 0
|
|
35
24
|
});
|
|
36
25
|
}
|
|
37
|
-
async function
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
26
|
+
async function streamChat({
|
|
27
|
+
prompt,
|
|
28
|
+
conversationId,
|
|
29
|
+
signal,
|
|
30
|
+
onEvent
|
|
31
|
+
}) {
|
|
32
|
+
await postarEConsumir(
|
|
33
|
+
"/ai/chat/stream",
|
|
34
|
+
{ prompt, conversation_id: conversationId },
|
|
35
|
+
onEvent,
|
|
36
|
+
signal
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
async function resumeChat({
|
|
40
|
+
approved,
|
|
41
|
+
conversationId,
|
|
42
|
+
signal,
|
|
43
|
+
onEvent
|
|
44
|
+
}) {
|
|
45
|
+
await postarEConsumir(
|
|
46
|
+
"/ai/chat/resume",
|
|
47
|
+
{ approved, conversation_id: conversationId },
|
|
48
|
+
onEvent,
|
|
49
|
+
signal
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
async function postarEConsumir(caminho, corpo, onEvent, signal) {
|
|
53
|
+
const resposta = await fetch(`${AI_API_URL}${caminho}`, {
|
|
54
|
+
method: "POST",
|
|
55
|
+
headers: {
|
|
56
|
+
...authHeaders(),
|
|
57
|
+
"Content-Type": "application/json"
|
|
58
|
+
},
|
|
59
|
+
body: JSON.stringify(corpo),
|
|
60
|
+
signal
|
|
61
|
+
});
|
|
62
|
+
if (!resposta.ok || !resposta.body) {
|
|
63
|
+
throw new Error(`Falha ao falar com a IA (HTTP ${resposta.status})`);
|
|
64
|
+
}
|
|
65
|
+
await readSse(resposta.body, ({ event, data }) => {
|
|
66
|
+
try {
|
|
67
|
+
onEvent({ type: event, data: JSON.parse(data) });
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.debug("Evento SSE ignorado:", event, error);
|
|
70
|
+
}
|
|
41
71
|
});
|
|
42
72
|
}
|
|
43
73
|
async function apiGetImages(params) {
|
|
@@ -56,11 +86,10 @@ async function apiPostImages(data) {
|
|
|
56
86
|
}
|
|
57
87
|
export {
|
|
58
88
|
AI_API_URL,
|
|
59
|
-
AI_MODEL_HEADER,
|
|
60
|
-
apiGetAiModels,
|
|
61
89
|
apiGetChatHistory,
|
|
62
90
|
apiGetImages,
|
|
63
|
-
|
|
64
|
-
|
|
91
|
+
apiPostImages,
|
|
92
|
+
resumeChat,
|
|
93
|
+
streamChat
|
|
65
94
|
};
|
|
66
95
|
//# sourceMappingURL=AiService.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiService.js","sources":["../../../lib/@ecme/services/AiService.ts"],"sourcesContent":["import ApiService from './ApiService'\nimport {
|
|
1
|
+
{"version":3,"file":"AiService.js","sources":["../../../lib/@ecme/services/AiService.ts"],"sourcesContent":["import { authHeaders } from './aiAuthHeaders'\nimport ApiService from './ApiService'\nimport { readSse } from './sseParser'\nimport type { ChatEvent } from '@/views/concepts/ai/Chat/types'\nimport type { AxiosRequestConfig } from 'axios'\n\nconst AI_DEV_URL = 'http://localhost:8000'\nconst AI_BUILD_URL = 'https://orbe-ai-homolog.apps.qas.orbeagro.com.br'\n\n/**\n * Host da API de IA.\n *\n * O /ai/* nao vive no gateway do resto da aplicacao, entao nao pode usar o\n * baseURL do AxiosBase (API_URL). A resolucao e por origin em runtime, e nao\n * por import.meta.env.MODE, porque o MODE e congelado na build da lib como\n * \"production\" e nao reflete o dev do MFE consumidor.\n */\nfunction getAiApiUrl() {\n const origin = globalThis?.location?.origin ?? ''\n\n if (origin.includes('localhost') || origin.includes('127.0.0.1')) {\n return AI_DEV_URL\n }\n\n // QAS e PRD compartilham a mesma URL por enquanto. Quando houver uma URL\n // de PRD, o split entra aqui: if (origin.includes('.prd.')) return AI_PRD_URL\n return AI_BUILD_URL\n}\n\nexport const AI_API_URL = getAiApiUrl()\n\n/**\n * Toda chamada de IA sai pelo AI_API_URL (o baseURL por requisicao vence o da\n * instancia do AxiosBase) e fica fora do loading global — o chat mostra o\n * proprio balaozinho de \"digitando\".\n */\nconst aiRequest = <T>(config: AxiosRequestConfig) =>\n ApiService.fetchDataWithAxios<T>({\n ...config,\n baseURL: AI_API_URL,\n skipGlobalLoading: true,\n })\n\nexport async function apiGetChatHistory<T>(conversationId?: string) {\n return aiRequest<T>({\n url: '/ai/chat/history',\n method: 'get',\n params: conversationId ? { conversation_id: conversationId } : undefined,\n })\n}\n\nexport type StreamChatParams = {\n prompt: string\n /** Identifica a conversa; o backend usa como thread da memoria. */\n conversationId?: string\n signal?: AbortSignal\n onEvent: (evento: ChatEvent) => void\n}\n\nexport type ResumeChatParams = {\n /** true = aprovar a operacao pendente, false = negar. */\n approved: boolean\n conversationId?: string\n signal?: AbortSignal\n onEvent: (evento: ChatEvent) => void\n}\n\n/**\n * Envia a mensagem e consome a resposta em streaming (SSE).\n *\n * Usa `fetch`, e nao o Axios, porque o Axios no browser so resolve a Promise\n * com a resposta inteira — nao ha como ler o corpo enquanto ele chega.\n */\nexport async function streamChat({\n prompt,\n conversationId,\n signal,\n onEvent,\n}: StreamChatParams): Promise<void> {\n await postarEConsumir(\n '/ai/chat/stream',\n { prompt, conversation_id: conversationId },\n onEvent,\n signal,\n )\n}\n\n/**\n * Retoma uma conversa parada num pedido de aprovacao.\n *\n * Devolve o mesmo tipo de stream do `streamChat`, e a resposta continua na\n * MESMA mensagem do chat — o backend so volta do ponto onde parou.\n */\nexport async function resumeChat({\n approved,\n conversationId,\n signal,\n onEvent,\n}: ResumeChatParams): Promise<void> {\n await postarEConsumir(\n '/ai/chat/resume',\n { approved, conversation_id: conversationId },\n onEvent,\n signal,\n )\n}\n\n/** POST + leitura do SSE, comum ao envio e a retomada. */\nasync function postarEConsumir(\n caminho: string,\n corpo: Record<string, unknown>,\n onEvent: (evento: ChatEvent) => void,\n signal?: AbortSignal,\n): Promise<void> {\n const resposta = await fetch(`${AI_API_URL}${caminho}`, {\n method: 'POST',\n headers: {\n ...authHeaders(),\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(corpo),\n signal,\n })\n\n if (!resposta.ok || !resposta.body) {\n throw new Error(`Falha ao falar com a IA (HTTP ${resposta.status})`)\n }\n\n await readSse(resposta.body, ({ event, data }) => {\n try {\n onEvent({ type: event, data: JSON.parse(data) } as ChatEvent)\n } catch (error) {\n // Evento malformado nao pode derrubar o stream inteiro.\n console.debug('Evento SSE ignorado:', event, error)\n }\n })\n}\n\nexport async function apiGetImages<T, U extends Record<string, unknown>>(\n params: U,\n) {\n return aiRequest<T>({\n url: '/ai/images',\n method: 'get',\n params,\n })\n}\n\nexport async function apiPostImages<T, U extends Record<string, unknown>>(\n data: U,\n) {\n return aiRequest<T>({\n url: '/ai/images',\n method: 'post',\n data,\n })\n}\n"],"names":[],"mappings":";;;AAMA,MAAM,aAAa;AACnB,MAAM,eAAe;AAUrB,SAAS,cAAc;AACnB,QAAM,SAAS,YAAY,UAAU,UAAU;AAE/C,MAAI,OAAO,SAAS,WAAW,KAAK,OAAO,SAAS,WAAW,GAAG;AAC9D,WAAO;AAAA,EACX;AAIA,SAAO;AACX;AAEO,MAAM,aAAa,YAAA;AAO1B,MAAM,YAAY,CAAI,WAClB,WAAW,mBAAsB;AAAA,EAC7B,GAAG;AAAA,EACH,SAAS;AAAA,EACT,mBAAmB;AACvB,CAAC;AAEL,eAAsB,kBAAqB,gBAAyB;AAChE,SAAO,UAAa;AAAA,IAChB,KAAK;AAAA,IACL,QAAQ;AAAA,IACR,QAAQ,iBAAiB,EAAE,iBAAiB,mBAAmB;AAAA,EAAA,CAClE;AACL;AAwBA,eAAsB,WAAW;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACJ,GAAoC;AAChC,QAAM;AAAA,IACF;AAAA,IACA,EAAE,QAAQ,iBAAiB,eAAA;AAAA,IAC3B;AAAA,IACA;AAAA,EAAA;AAER;AAQA,eAAsB,WAAW;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACJ,GAAoC;AAChC,QAAM;AAAA,IACF;AAAA,IACA,EAAE,UAAU,iBAAiB,eAAA;AAAA,IAC7B;AAAA,IACA;AAAA,EAAA;AAER;AAGA,eAAe,gBACX,SACA,OACA,SACA,QACa;AACb,QAAM,WAAW,MAAM,MAAM,GAAG,UAAU,GAAG,OAAO,IAAI;AAAA,IACpD,QAAQ;AAAA,IACR,SAAS;AAAA,MACL,GAAG,YAAA;AAAA,MACH,gBAAgB;AAAA,IAAA;AAAA,IAEpB,MAAM,KAAK,UAAU,KAAK;AAAA,IAC1B;AAAA,EAAA,CACH;AAED,MAAI,CAAC,SAAS,MAAM,CAAC,SAAS,MAAM;AAChC,UAAM,IAAI,MAAM,iCAAiC,SAAS,MAAM,GAAG;AAAA,EACvE;AAEA,QAAM,QAAQ,SAAS,MAAM,CAAC,EAAE,OAAO,WAAW;AAC9C,QAAI;AACA,cAAQ,EAAE,MAAM,OAAO,MAAM,KAAK,MAAM,IAAI,GAAgB;AAAA,IAChE,SAAS,OAAO;AAEZ,cAAQ,MAAM,wBAAwB,OAAO,KAAK;AAAA,IACtD;AAAA,EACJ,CAAC;AACL;AAEA,eAAsB,aAClB,QACF;AACE,SAAO,UAAa;AAAA,IAChB,KAAK;AAAA,IACL,QAAQ;AAAA,IACR;AAAA,EAAA,CACH;AACL;AAEA,eAAsB,cAClB,MACF;AACE,SAAO,UAAa;AAAA,IAChB,KAAK;AAAA,IACL,QAAQ;AAAA,IACR;AAAA,EAAA,CACH;AACL;"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import appConfig from "../configs/app.config.js";
|
|
2
|
+
import { TOKEN_NAME_IN_STORAGE, TOKEN_TYPE, REQUEST_HEADER_AUTH_KEY } from "../constants/api.constant.js";
|
|
3
|
+
const authHeaders = () => {
|
|
4
|
+
const storage = appConfig.accessTokenPersistStrategy;
|
|
5
|
+
const headers = {};
|
|
6
|
+
if (storage !== "localStorage" && storage !== "sessionStorage") {
|
|
7
|
+
return headers;
|
|
8
|
+
}
|
|
9
|
+
const source = storage === "localStorage" ? localStorage : sessionStorage;
|
|
10
|
+
const accessToken = source.getItem(TOKEN_NAME_IN_STORAGE) || "";
|
|
11
|
+
if (accessToken) {
|
|
12
|
+
headers[REQUEST_HEADER_AUTH_KEY] = `${TOKEN_TYPE}${accessToken}`;
|
|
13
|
+
}
|
|
14
|
+
const userId = readUserId();
|
|
15
|
+
if (userId) {
|
|
16
|
+
headers["X-User-Id"] = userId;
|
|
17
|
+
}
|
|
18
|
+
return headers;
|
|
19
|
+
};
|
|
20
|
+
const readUserId = () => {
|
|
21
|
+
try {
|
|
22
|
+
const raw = localStorage.getItem("SessionUserPageStore");
|
|
23
|
+
if (!raw) {
|
|
24
|
+
return void 0;
|
|
25
|
+
}
|
|
26
|
+
return JSON.parse(raw)?.state?.user?.userId;
|
|
27
|
+
} catch (error) {
|
|
28
|
+
console.debug("Could not read userId from session store:", error);
|
|
29
|
+
return void 0;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
export {
|
|
33
|
+
authHeaders
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=aiAuthHeaders.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aiAuthHeaders.js","sources":["../../../lib/@ecme/services/aiAuthHeaders.ts"],"sourcesContent":["import appConfig from '@/configs/app.config'\nimport {\n REQUEST_HEADER_AUTH_KEY,\n TOKEN_NAME_IN_STORAGE,\n TOKEN_TYPE,\n} from '@/constants/api.constant'\n\n/**\n * Headers de autenticacao lidos do storage.\n *\n * Existe porque o chat de IA usa `fetch` (o Axios nao faz streaming no\n * browser) e portanto nao passa pelo interceptor. Em vez de duplicar as regras\n * de onde mora o token, o interceptor e o fetch chamam esta funcao — uma\n * verdade so.\n *\n * Ver AxiosRequestIntrceptorConfigCallback, que a consome.\n */\nexport const authHeaders = (): Record<string, string> => {\n const storage = appConfig.accessTokenPersistStrategy\n const headers: Record<string, string> = {}\n\n if (storage !== 'localStorage' && storage !== 'sessionStorage') {\n return headers\n }\n\n const source = storage === 'localStorage' ? localStorage : sessionStorage\n const accessToken = source.getItem(TOKEN_NAME_IN_STORAGE) || ''\n\n if (accessToken) {\n headers[REQUEST_HEADER_AUTH_KEY] = `${TOKEN_TYPE}${accessToken}`\n }\n\n const userId = readUserId()\n if (userId) {\n headers['X-User-Id'] = userId\n }\n\n return headers\n}\n\n/**\n * userId da sessao persistida pelo zustand.\n *\n * Silencioso em caso de erro: um storage corrompido nao pode derrubar a\n * requisicao — sem o header, o backend apenas trata o usuario como desconhecido.\n */\nconst readUserId = (): string | undefined => {\n try {\n const raw = localStorage.getItem('SessionUserPageStore')\n if (!raw) {\n return undefined\n }\n return JSON.parse(raw)?.state?.user?.userId\n } catch (error) {\n console.debug('Could not read userId from session store:', error)\n return undefined\n }\n}\n"],"names":[],"mappings":";;AAiBO,MAAM,cAAc,MAA8B;AACrD,QAAM,UAAU,UAAU;AAC1B,QAAM,UAAkC,CAAA;AAExC,MAAI,YAAY,kBAAkB,YAAY,kBAAkB;AAC5D,WAAO;AAAA,EACX;AAEA,QAAM,SAAS,YAAY,iBAAiB,eAAe;AAC3D,QAAM,cAAc,OAAO,QAAQ,qBAAqB,KAAK;AAE7D,MAAI,aAAa;AACb,YAAQ,uBAAuB,IAAI,GAAG,UAAU,GAAG,WAAW;AAAA,EAClE;AAEA,QAAM,SAAS,WAAA;AACf,MAAI,QAAQ;AACR,YAAQ,WAAW,IAAI;AAAA,EAC3B;AAEA,SAAO;AACX;AAQA,MAAM,aAAa,MAA0B;AACzC,MAAI;AACA,UAAM,MAAM,aAAa,QAAQ,sBAAsB;AACvD,QAAI,CAAC,KAAK;AACN,aAAO;AAAA,IACX;AACA,WAAO,KAAK,MAAM,GAAG,GAAG,OAAO,MAAM;AAAA,EACzC,SAAS,OAAO;AACZ,YAAQ,MAAM,6CAA6C,KAAK;AAChE,WAAO;AAAA,EACX;AACJ;"}
|
|
@@ -1,31 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { TOKEN_NAME_IN_STORAGE, TOKEN_TYPE, REQUEST_HEADER_AUTH_KEY } from "../../constants/api.constant.js";
|
|
1
|
+
import { authHeaders } from "../aiAuthHeaders.js";
|
|
3
2
|
const AxiosRequestIntrceptorConfigCallback = (config) => {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
if (storage === "localStorage") {
|
|
8
|
-
accessToken = localStorage.getItem(TOKEN_NAME_IN_STORAGE) || "";
|
|
9
|
-
}
|
|
10
|
-
if (storage === "sessionStorage") {
|
|
11
|
-
accessToken = sessionStorage.getItem(TOKEN_NAME_IN_STORAGE) || "";
|
|
12
|
-
}
|
|
13
|
-
if (accessToken) {
|
|
14
|
-
config.headers[REQUEST_HEADER_AUTH_KEY] = `${TOKEN_TYPE}${accessToken}`;
|
|
15
|
-
}
|
|
16
|
-
try {
|
|
17
|
-
const sessionUserStore = localStorage.getItem("SessionUserPageStore");
|
|
18
|
-
if (sessionUserStore) {
|
|
19
|
-
const parsedStore = JSON.parse(sessionUserStore);
|
|
20
|
-
const userId = parsedStore?.state?.user?.userId;
|
|
21
|
-
if (userId) {
|
|
22
|
-
config.headers["X-User-Id"] = userId;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
} catch (error) {
|
|
26
|
-
console.debug("Could not read userId from session store:", error);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
3
|
+
Object.entries(authHeaders()).forEach(([chave, valor]) => {
|
|
4
|
+
config.headers[chave] = valor;
|
|
5
|
+
});
|
|
29
6
|
return config;
|
|
30
7
|
};
|
|
31
8
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AxiosRequestIntrceptorConfigCallback.js","sources":["../../../../lib/@ecme/services/axios/AxiosRequestIntrceptorConfigCallback.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"file":"AxiosRequestIntrceptorConfigCallback.js","sources":["../../../../lib/@ecme/services/axios/AxiosRequestIntrceptorConfigCallback.ts"],"sourcesContent":["import { authHeaders } from '../aiAuthHeaders'\nimport type { InternalAxiosRequestConfig } from 'axios'\n\n/**\n * Injeta Authorization e X-User-Id em toda requisicao do Axios.\n *\n * As regras de onde o token mora vivem em `authHeaders` — compartilhadas com o\n * chat de IA, que usa `fetch` e nao passa por aqui.\n */\nconst AxiosRequestIntrceptorConfigCallback = (\n config: InternalAxiosRequestConfig,\n) => {\n Object.entries(authHeaders()).forEach(([chave, valor]) => {\n config.headers[chave] = valor\n })\n\n return config\n}\n\nexport default AxiosRequestIntrceptorConfigCallback\n"],"names":[],"mappings":";AASA,MAAM,uCAAuC,CACzC,WACC;AACD,SAAO,QAAQ,aAAa,EAAE,QAAQ,CAAC,CAAC,OAAO,KAAK,MAAM;AACtD,WAAO,QAAQ,KAAK,IAAI;AAAA,EAC5B,CAAC;AAED,SAAO;AACX;"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { default as default2 } from "./ApiService.js";
|
|
2
2
|
import { apiGetPricingPlans, apiGetRolesPermissionsRoles, apiGetRolesPermissionsUsers, apiGetSettingsBilling, apiGetSettingsIntergration, apiGetSettingsNotification, apiGetSettingsProfile } from "./AccontsService.js";
|
|
3
|
-
import { AI_API_URL,
|
|
3
|
+
import { AI_API_URL, apiGetChatHistory, apiGetImages, apiPostImages, resumeChat, streamChat } from "./AiService.js";
|
|
4
4
|
import { apiForgotPassword, apiResetPassword, apiSignIn, apiSignOut, apiSignUp } from "./AuthService.js";
|
|
5
5
|
import { apiGetCalendar } from "./CalendarService.js";
|
|
6
6
|
import { apiGetChats, apiGetContactDetails, apiGetContacts, apiGetConversation } from "./ChatService.js";
|
|
@@ -17,10 +17,8 @@ import { apiGetProduct, apiGetProductList } from "./ProductService.js";
|
|
|
17
17
|
import { apiGetProject, apiGetProjectMembers, apiGetProjectTask, apiGetProjectTasks, apiGetProjects, apiGetScrumBoards, apiPostProject } from "./ProjectService.js";
|
|
18
18
|
export {
|
|
19
19
|
AI_API_URL,
|
|
20
|
-
AI_MODEL_HEADER,
|
|
21
20
|
default2 as ApiService,
|
|
22
21
|
apiForgotPassword,
|
|
23
|
-
apiGetAiModels,
|
|
24
22
|
apiGetAnalyticDashboard,
|
|
25
23
|
apiGetArticleList,
|
|
26
24
|
apiGetCalendar,
|
|
@@ -65,12 +63,13 @@ export {
|
|
|
65
63
|
apiGetSupportHubCategories,
|
|
66
64
|
apiGithubOauthSignIn,
|
|
67
65
|
apiGoogleOauthSignIn,
|
|
68
|
-
apiPostChat,
|
|
69
66
|
apiPostImages,
|
|
70
67
|
apiPostProject,
|
|
71
68
|
apiResetPassword,
|
|
72
69
|
apiSignIn,
|
|
73
70
|
apiSignOut,
|
|
74
|
-
apiSignUp
|
|
71
|
+
apiSignUp,
|
|
72
|
+
resumeChat,
|
|
73
|
+
streamChat
|
|
75
74
|
};
|
|
76
75
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const SEPARADOR = /\r?\n\r?\n/;
|
|
2
|
+
async function readSse(body, onEvent) {
|
|
3
|
+
const reader = body.getReader();
|
|
4
|
+
const decoder = new TextDecoder();
|
|
5
|
+
let buffer = "";
|
|
6
|
+
try {
|
|
7
|
+
for (; ; ) {
|
|
8
|
+
const { done, value } = await reader.read();
|
|
9
|
+
if (done) {
|
|
10
|
+
emitir(buffer, onEvent);
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
buffer += decoder.decode(value, { stream: true });
|
|
14
|
+
const blocos = buffer.split(SEPARADOR);
|
|
15
|
+
buffer = blocos.pop() ?? "";
|
|
16
|
+
blocos.forEach((bloco) => emitir(bloco, onEvent));
|
|
17
|
+
}
|
|
18
|
+
} finally {
|
|
19
|
+
reader.releaseLock();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function emitir(bloco, onEvent) {
|
|
23
|
+
if (!bloco.trim()) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
let event = "message";
|
|
27
|
+
const dados = [];
|
|
28
|
+
bloco.split(/\r?\n/).forEach((linha) => {
|
|
29
|
+
if (linha.startsWith("event:")) {
|
|
30
|
+
event = linha.slice(6).trim();
|
|
31
|
+
} else if (linha.startsWith("data:")) {
|
|
32
|
+
dados.push(linha.slice(5).replace(/^ /, ""));
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
if (dados.length) {
|
|
36
|
+
onEvent({ event, data: dados.join("\n") });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export {
|
|
40
|
+
readSse
|
|
41
|
+
};
|
|
42
|
+
//# sourceMappingURL=sseParser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sseParser.js","sources":["../../../lib/@ecme/services/sseParser.ts"],"sourcesContent":["/**\n * Parser de Server-Sent Events sobre um ReadableStream.\n *\n * O EventSource nativo do browser nao serve aqui: ele so faz GET e nao aceita\n * headers, e o chat e um POST autenticado. Entao lemos o corpo do `fetch` na\n * mao.\n *\n * Duas bordas do protocolo que uma implementacao ingenua erra:\n *\n * 1. um chunk da rede pode cortar um evento no meio — por isso o resto fica no\n * buffer ate chegar o proximo `\\n\\n`;\n * 2. um chunk pode trazer varios eventos de uma vez.\n */\n\nexport type SseEvent = {\n event: string\n data: string\n}\n\nconst SEPARADOR = /\\r?\\n\\r?\\n/\n\n/** Le o stream ate o fim, chamando `onEvent` a cada evento completo. */\nexport async function readSse(\n body: ReadableStream<Uint8Array>,\n onEvent: (evento: SseEvent) => void,\n): Promise<void> {\n const reader = body.getReader()\n const decoder = new TextDecoder()\n let buffer = ''\n\n try {\n for (;;) {\n const { done, value } = await reader.read()\n\n if (done) {\n // O ultimo evento pode nao vir seguido de linha em branco.\n emitir(buffer, onEvent)\n return\n }\n\n buffer += decoder.decode(value, { stream: true })\n\n const blocos = buffer.split(SEPARADOR)\n // O ultimo pedaco pode estar incompleto: volta para o buffer.\n buffer = blocos.pop() ?? ''\n blocos.forEach((bloco) => emitir(bloco, onEvent))\n }\n } finally {\n reader.releaseLock()\n }\n}\n\n/** Converte um bloco \"event: x\\ndata: y\" em SseEvent. */\nfunction emitir(bloco: string, onEvent: (evento: SseEvent) => void) {\n if (!bloco.trim()) {\n return\n }\n\n let event = 'message'\n const dados: string[] = []\n\n bloco.split(/\\r?\\n/).forEach((linha) => {\n if (linha.startsWith('event:')) {\n event = linha.slice(6).trim()\n } else if (linha.startsWith('data:')) {\n // O espaco depois de \"data:\" e opcional no protocolo.\n dados.push(linha.slice(5).replace(/^ /, ''))\n }\n // Linhas iniciadas por \":\" sao comentarios (keep-alive) e sao ignoradas.\n })\n\n if (dados.length) {\n onEvent({ event, data: dados.join('\\n') })\n }\n}\n"],"names":[],"mappings":"AAmBA,MAAM,YAAY;AAGlB,eAAsB,QAClB,MACA,SACa;AACb,QAAM,SAAS,KAAK,UAAA;AACpB,QAAM,UAAU,IAAI,YAAA;AACpB,MAAI,SAAS;AAEb,MAAI;AACA,eAAS;AACL,YAAM,EAAE,MAAM,MAAA,IAAU,MAAM,OAAO,KAAA;AAErC,UAAI,MAAM;AAEN,eAAO,QAAQ,OAAO;AACtB;AAAA,MACJ;AAEA,gBAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,MAAM;AAEhD,YAAM,SAAS,OAAO,MAAM,SAAS;AAErC,eAAS,OAAO,SAAS;AACzB,aAAO,QAAQ,CAAC,UAAU,OAAO,OAAO,OAAO,CAAC;AAAA,IACpD;AAAA,EACJ,UAAA;AACI,WAAO,YAAA;AAAA,EACX;AACJ;AAGA,SAAS,OAAO,OAAe,SAAqC;AAChE,MAAI,CAAC,MAAM,QAAQ;AACf;AAAA,EACJ;AAEA,MAAI,QAAQ;AACZ,QAAM,QAAkB,CAAA;AAExB,QAAM,MAAM,OAAO,EAAE,QAAQ,CAAC,UAAU;AACpC,QAAI,MAAM,WAAW,QAAQ,GAAG;AAC5B,cAAQ,MAAM,MAAM,CAAC,EAAE,KAAA;AAAA,IAC3B,WAAW,MAAM,WAAW,OAAO,GAAG;AAElC,YAAM,KAAK,MAAM,MAAM,CAAC,EAAE,QAAQ,MAAM,EAAE,CAAC;AAAA,IAC/C;AAAA,EAEJ,CAAC;AAED,MAAI,MAAM,QAAQ;AACd,YAAQ,EAAE,OAAO,MAAM,MAAM,KAAK,IAAI,GAAG;AAAA,EAC7C;AACJ;"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { TbPlugConnectedX } from "react-icons/tb";
|
|
3
|
+
const AiErrorMessage = () => {
|
|
4
|
+
return /* @__PURE__ */ jsxs("span", { className: "flex items-start gap-3", children: [
|
|
5
|
+
/* @__PURE__ */ jsx("span", { className: "mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-full bg-red-100 text-red-500 dark:bg-red-500/15 dark:text-red-400", children: /* @__PURE__ */ jsx(TbPlugConnectedX, { size: 18 }) }),
|
|
6
|
+
/* @__PURE__ */ jsxs("span", { className: "flex flex-col gap-0.5", children: [
|
|
7
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-red-600 dark:text-red-400", children: "Falha na comunicação" }),
|
|
8
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-red-500/90 dark:text-red-300/90", children: "Desculpe, estou com um pequeno problema de comunicação e não consigo te atender no momento. Tente novamente em instantes." })
|
|
9
|
+
] })
|
|
10
|
+
] });
|
|
11
|
+
};
|
|
12
|
+
export {
|
|
13
|
+
AiErrorMessage as default
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=AiErrorMessage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AiErrorMessage.js","sources":["../../../../../../../lib/@ecme/views/concepts/ai/Chat/components/AiErrorMessage.tsx"],"sourcesContent":["import { TbPlugConnectedX } from 'react-icons/tb'\n\n/**\n * Mensagem de erro do agente Orbe AI — exibida no lugar da resposta quando a\n * comunicação com o serviço de IA falha, com acento vermelho para sinalizar\n * o erro sem quebrar o tom visual do chat.\n */\nconst AiErrorMessage = () => {\n return (\n <span className=\"flex items-start gap-3\">\n <span className=\"mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-full bg-red-100 text-red-500 dark:bg-red-500/15 dark:text-red-400\">\n <TbPlugConnectedX size={18} />\n </span>\n <span className=\"flex flex-col gap-0.5\">\n <span className=\"text-sm font-semibold text-red-600 dark:text-red-400\">\n Falha na comunicação\n </span>\n <span className=\"text-sm text-red-500/90 dark:text-red-300/90\">\n Desculpe, estou com um pequeno problema de comunicação e\n não consigo te atender no momento. Tente novamente em\n instantes.\n </span>\n </span>\n </span>\n )\n}\n\nexport default AiErrorMessage\n"],"names":[],"mappings":";;AAOA,MAAM,iBAAiB,MAAM;AACzB,SACI,qBAAC,QAAA,EAAK,WAAU,0BACZ,UAAA;AAAA,IAAA,oBAAC,UAAK,WAAU,qIACZ,8BAAC,kBAAA,EAAiB,MAAM,IAAI,EAAA,CAChC;AAAA,IACA,qBAAC,QAAA,EAAK,WAAU,yBACZ,UAAA;AAAA,MAAA,oBAAC,QAAA,EAAK,WAAU,wDAAuD,UAAA,wBAEvE;AAAA,MACA,oBAAC,QAAA,EAAK,WAAU,gDAA+C,UAAA,4HAAA,CAI/D;AAAA,IAAA,EAAA,CACJ;AAAA,EAAA,GACJ;AAER;"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { TbLock } from "react-icons/tb";
|
|
4
|
+
import "../../../../../components/ui/Button/index.js";
|
|
5
|
+
import { iconeFerramenta, camposVisiveis, rotularFerramenta } from "./toolPresentation.js";
|
|
6
|
+
import Button from "../../../../../components/ui/Button/Button.js";
|
|
7
|
+
const ApprovalCard = ({ approval, onDecide }) => {
|
|
8
|
+
const [decisao, setDecisao] = useState(null);
|
|
9
|
+
const decidir = (aprovado) => {
|
|
10
|
+
setDecisao(aprovado ? "aprovar" : "negar");
|
|
11
|
+
onDecide(aprovado);
|
|
12
|
+
};
|
|
13
|
+
return /* @__PURE__ */ jsxs("div", { className: "not-prose mt-1 overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm dark:border-gray-700 dark:bg-gray-800", children: [
|
|
14
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-b border-gray-200 px-4 py-2.5 dark:border-gray-700", children: [
|
|
15
|
+
/* @__PURE__ */ jsx(TbLock, { size: 16, className: "text-gray-400 dark:text-gray-500" }),
|
|
16
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400", children: "Confirmação necessária" })
|
|
17
|
+
] }),
|
|
18
|
+
/* @__PURE__ */ jsxs("div", { className: "px-4 py-3.5", children: [
|
|
19
|
+
approval.calls.map((call) => {
|
|
20
|
+
const Icone = iconeFerramenta(call.name);
|
|
21
|
+
const campos = camposVisiveis(call.args);
|
|
22
|
+
return /* @__PURE__ */ jsxs("div", { className: "mb-4 last:mb-0", children: [
|
|
23
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-3 flex items-start gap-2.5", children: [
|
|
24
|
+
/* @__PURE__ */ jsx("span", { className: "mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-lg bg-primary-subtle text-primary", children: /* @__PURE__ */ jsx(Icone, { size: 17 }) }),
|
|
25
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
26
|
+
/* @__PURE__ */ jsx("div", { className: "font-semibold text-gray-900 dark:text-gray-100", children: rotularFerramenta(call.name) }),
|
|
27
|
+
/* @__PURE__ */ jsx("div", { className: "text-sm text-gray-500 dark:text-gray-400", children: "Revise os dados antes de confirmar." })
|
|
28
|
+
] })
|
|
29
|
+
] }),
|
|
30
|
+
/* @__PURE__ */ jsx("dl", { className: "divide-y divide-gray-100 rounded-lg border border-gray-100 dark:divide-gray-700 dark:border-gray-700", children: campos.map((campo) => /* @__PURE__ */ jsxs(
|
|
31
|
+
"div",
|
|
32
|
+
{
|
|
33
|
+
className: "flex items-baseline justify-between gap-4 px-3 py-2",
|
|
34
|
+
children: [
|
|
35
|
+
/* @__PURE__ */ jsx("dt", { className: "shrink-0 text-sm text-gray-500 dark:text-gray-400", children: campo.rotulo }),
|
|
36
|
+
/* @__PURE__ */ jsx("dd", { className: "truncate text-sm font-medium text-gray-900 dark:text-gray-100", children: campo.valor })
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
campo.chave
|
|
40
|
+
)) })
|
|
41
|
+
] }, call.id);
|
|
42
|
+
}),
|
|
43
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-4 flex items-center gap-2", children: [
|
|
44
|
+
/* @__PURE__ */ jsx(
|
|
45
|
+
Button,
|
|
46
|
+
{
|
|
47
|
+
variant: "solid",
|
|
48
|
+
size: "sm",
|
|
49
|
+
loading: decisao === "aprovar",
|
|
50
|
+
disabled: decisao !== null,
|
|
51
|
+
onClick: () => decidir(true),
|
|
52
|
+
children: "Confirmar"
|
|
53
|
+
}
|
|
54
|
+
),
|
|
55
|
+
/* @__PURE__ */ jsx(
|
|
56
|
+
Button,
|
|
57
|
+
{
|
|
58
|
+
size: "sm",
|
|
59
|
+
loading: decisao === "negar",
|
|
60
|
+
disabled: decisao !== null,
|
|
61
|
+
onClick: () => decidir(false),
|
|
62
|
+
children: "Cancelar"
|
|
63
|
+
}
|
|
64
|
+
),
|
|
65
|
+
/* @__PURE__ */ jsx("span", { className: "ml-auto text-xs text-gray-400 dark:text-gray-500", children: "Nada é gravado até você confirmar" })
|
|
66
|
+
] })
|
|
67
|
+
] })
|
|
68
|
+
] });
|
|
69
|
+
};
|
|
70
|
+
export {
|
|
71
|
+
ApprovalCard as default
|
|
72
|
+
};
|
|
73
|
+
//# sourceMappingURL=ApprovalCard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ApprovalCard.js","sources":["../../../../../../../lib/@ecme/views/concepts/ai/Chat/components/ApprovalCard.tsx"],"sourcesContent":["import { useState } from 'react'\nimport { TbLock } from 'react-icons/tb'\nimport Button from '@/components/ui/Button'\nimport { camposVisiveis, iconeFerramenta, rotularFerramenta } from './toolPresentation'\nimport type { PendingApproval } from '../types'\n\ntype ApprovalCardProps = {\n approval: PendingApproval\n onDecide: (approved: boolean) => void\n}\n\n/**\n * Confirmacao de uma operacao que grava no ERP.\n *\n * O agente fica PARADO enquanto este card estiver na tela — so volta a\n * responder depois do clique. Por isso ele nao usa a paleta de alerta: nao e um\n * aviso de erro, e uma decisao de negocio que o usuario precisa tomar.\n */\nconst ApprovalCard = ({ approval, onDecide }: ApprovalCardProps) => {\n const [decisao, setDecisao] = useState<'aprovar' | 'negar' | null>(null)\n\n const decidir = (aprovado: boolean) => {\n setDecisao(aprovado ? 'aprovar' : 'negar')\n onDecide(aprovado)\n }\n\n return (\n <div className=\"not-prose mt-1 overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm dark:border-gray-700 dark:bg-gray-800\">\n <div className=\"flex items-center gap-2 border-b border-gray-200 px-4 py-2.5 dark:border-gray-700\">\n <TbLock size={16} className=\"text-gray-400 dark:text-gray-500\" />\n <span className=\"text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400\">\n Confirmação necessária\n </span>\n </div>\n\n <div className=\"px-4 py-3.5\">\n {approval.calls.map((call) => {\n const Icone = iconeFerramenta(call.name)\n const campos = camposVisiveis(call.args)\n\n return (\n <div key={call.id} className=\"mb-4 last:mb-0\">\n <div className=\"mb-3 flex items-start gap-2.5\">\n <span className=\"mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-lg bg-primary-subtle text-primary\">\n <Icone size={17} />\n </span>\n <div className=\"min-w-0\">\n <div className=\"font-semibold text-gray-900 dark:text-gray-100\">\n {rotularFerramenta(call.name)}\n </div>\n <div className=\"text-sm text-gray-500 dark:text-gray-400\">\n Revise os dados antes de confirmar.\n </div>\n </div>\n </div>\n\n <dl className=\"divide-y divide-gray-100 rounded-lg border border-gray-100 dark:divide-gray-700 dark:border-gray-700\">\n {campos.map((campo) => (\n <div\n key={campo.chave}\n className=\"flex items-baseline justify-between gap-4 px-3 py-2\"\n >\n <dt className=\"shrink-0 text-sm text-gray-500 dark:text-gray-400\">\n {campo.rotulo}\n </dt>\n <dd className=\"truncate text-sm font-medium text-gray-900 dark:text-gray-100\">\n {campo.valor}\n </dd>\n </div>\n ))}\n </dl>\n </div>\n )\n })}\n\n <div className=\"mt-4 flex items-center gap-2\">\n <Button\n variant=\"solid\"\n size=\"sm\"\n loading={decisao === 'aprovar'}\n disabled={decisao !== null}\n onClick={() => decidir(true)}\n >\n Confirmar\n </Button>\n <Button\n size=\"sm\"\n loading={decisao === 'negar'}\n disabled={decisao !== null}\n onClick={() => decidir(false)}\n >\n Cancelar\n </Button>\n <span className=\"ml-auto text-xs text-gray-400 dark:text-gray-500\">\n Nada é gravado até você confirmar\n </span>\n </div>\n </div>\n </div>\n )\n}\n\nexport default ApprovalCard\n"],"names":[],"mappings":";;;;;;AAkBA,MAAM,eAAe,CAAC,EAAE,UAAU,eAAkC;AAChE,QAAM,CAAC,SAAS,UAAU,IAAI,SAAqC,IAAI;AAEvE,QAAM,UAAU,CAAC,aAAsB;AACnC,eAAW,WAAW,YAAY,OAAO;AACzC,aAAS,QAAQ;AAAA,EACrB;AAEA,SACI,qBAAC,OAAA,EAAI,WAAU,6HACX,UAAA;AAAA,IAAA,qBAAC,OAAA,EAAI,WAAU,qFACX,UAAA;AAAA,MAAA,oBAAC,QAAA,EAAO,MAAM,IAAI,WAAU,oCAAmC;AAAA,MAC/D,oBAAC,QAAA,EAAK,WAAU,kFAAiF,UAAA,yBAAA,CAEjG;AAAA,IAAA,GACJ;AAAA,IAEA,qBAAC,OAAA,EAAI,WAAU,eACV,UAAA;AAAA,MAAA,SAAS,MAAM,IAAI,CAAC,SAAS;AAC1B,cAAM,QAAQ,gBAAgB,KAAK,IAAI;AACvC,cAAM,SAAS,eAAe,KAAK,IAAI;AAEvC,eACI,qBAAC,OAAA,EAAkB,WAAU,kBACzB,UAAA;AAAA,UAAA,qBAAC,OAAA,EAAI,WAAU,iCACX,UAAA;AAAA,YAAA,oBAAC,UAAK,WAAU,qGACZ,8BAAC,OAAA,EAAM,MAAM,IAAI,EAAA,CACrB;AAAA,YACA,qBAAC,OAAA,EAAI,WAAU,WACX,UAAA;AAAA,cAAA,oBAAC,SAAI,WAAU,kDACV,UAAA,kBAAkB,KAAK,IAAI,GAChC;AAAA,cACA,oBAAC,OAAA,EAAI,WAAU,4CAA2C,UAAA,sCAAA,CAE1D;AAAA,YAAA,EAAA,CACJ;AAAA,UAAA,GACJ;AAAA,8BAEC,MAAA,EAAG,WAAU,wGACT,UAAA,OAAO,IAAI,CAAC,UACT;AAAA,YAAC;AAAA,YAAA;AAAA,cAEG,WAAU;AAAA,cAEV,UAAA;AAAA,gBAAA,oBAAC,MAAA,EAAG,WAAU,qDACT,UAAA,MAAM,QACX;AAAA,gBACA,oBAAC,MAAA,EAAG,WAAU,iEACT,gBAAM,MAAA,CACX;AAAA,cAAA;AAAA,YAAA;AAAA,YARK,MAAM;AAAA,UAAA,CAUlB,EAAA,CACL;AAAA,QAAA,EAAA,GA7BM,KAAK,EA8Bf;AAAA,MAER,CAAC;AAAA,MAED,qBAAC,OAAA,EAAI,WAAU,gCACX,UAAA;AAAA,QAAA;AAAA,UAAC;AAAA,UAAA;AAAA,YACG,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,SAAS,YAAY;AAAA,YACrB,UAAU,YAAY;AAAA,YACtB,SAAS,MAAM,QAAQ,IAAI;AAAA,YAC9B,UAAA;AAAA,UAAA;AAAA,QAAA;AAAA,QAGD;AAAA,UAAC;AAAA,UAAA;AAAA,YACG,MAAK;AAAA,YACL,SAAS,YAAY;AAAA,YACrB,UAAU,YAAY;AAAA,YACtB,SAAS,MAAM,QAAQ,KAAK;AAAA,YAC/B,UAAA;AAAA,UAAA;AAAA,QAAA;AAAA,QAGD,oBAAC,QAAA,EAAK,WAAU,oDAAmD,UAAA,oCAAA,CAEnE;AAAA,MAAA,EAAA,CACJ;AAAA,IAAA,EAAA,CACJ;AAAA,EAAA,GACJ;AAER;"}
|