bibot 1.0.5 → 1.0.7
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/.babelrc +7 -0
- package/.vscode/settings.json +5 -0
- package/dist/bibot.js +175 -0
- package/dist/bibot.js.map +1 -0
- package/dist/component/bibot.d.ts +5 -0
- package/dist/component/bibot.js +170 -0
- package/dist/component/bibot.js.map +1 -0
- package/dist/config/appStateEnums.js +10 -5
- package/dist/config/endpointEnums.js +27 -22
- package/dist/config/index.js +38 -5
- package/dist/config/statusCode.js +49 -44
- package/dist/context/AppContext.js +73 -56
- package/dist/context/index.js +16 -3
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.js +38 -4
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/mobileView.js +33 -18
- package/dist/hooks/useBiBotChatBot.d.ts +29 -0
- package/dist/hooks/useBiBotChatBot.js +206 -0
- package/dist/hooks/useBiBotChatBot.js.map +1 -0
- package/dist/hooks/usePluginFactory.js +60 -77
- package/dist/index.css +36 -0
- package/dist/index.d.ts +1 -2
- package/dist/index.js +9 -6
- package/dist/index.js.map +1 -1
- package/dist/reducers/appReducer.js +24 -22
- package/dist/reducers/index.js +16 -3
- package/dist/services/index.js +16 -3
- package/dist/services/plugin-api.js +179 -182
- package/dist/styles/RegisterPageStyle.css +63 -0
- package/dist/styles/adminPortal.css +26 -0
- package/dist/styles/appConfig.css +90 -0
- package/dist/styles/buttonStyle.css +27 -0
- package/dist/styles/chatStyle.css +140 -0
- package/dist/styles/index.css +82 -0
- package/dist/styles/predefinedStyle.css +35 -0
- package/dist/styles/themeStyle.css +42 -0
- package/dist/styles/training.css +86 -0
- package/dist/types/coreInterfaces.d.ts +1 -10
- package/dist/types/coreInterfaces.js +5 -2
- package/dist/types/index.js +16 -3
- package/dist/utils/index.js +27 -3
- package/dist/utils/sessionManager.js +16 -12
- package/dist/utils/trimWhitespace.js +15 -11
- package/package.json +51 -54
- package/src/component/bibot.tsx +103 -0
- package/src/config/appStateEnums.ts +3 -0
- package/src/config/endpointEnums.ts +28 -0
- package/src/config/index.ts +5 -0
- package/src/config/statusCode.ts +49 -0
- package/src/context/AppContext.tsx +66 -0
- package/src/context/index.ts +3 -0
- package/src/hooks/index.ts +5 -0
- package/src/hooks/mobileView.tsx +17 -0
- package/src/hooks/useBiBotChatBot.tsx +107 -0
- package/src/hooks/usePluginFactory.tsx +38 -0
- package/src/index.css +36 -0
- package/src/index.tsx +3 -0
- package/src/reducers/appReducer.ts +16 -0
- package/src/reducers/index.ts +4 -0
- package/src/services/index.ts +2 -0
- package/src/services/plugin-api.tsx +120 -0
- package/src/styles/RegisterPageStyle.css +63 -0
- package/src/styles/adminPortal.css +26 -0
- package/src/styles/appConfig.css +90 -0
- package/src/styles/buttonStyle.css +27 -0
- package/src/styles/chatStyle.css +140 -0
- package/src/styles/index.css +82 -0
- package/src/styles/predefinedStyle.css +35 -0
- package/src/styles/themeStyle.css +42 -0
- package/src/styles/training.css +86 -0
- package/src/types/coreInterfaces.ts +69 -0
- package/src/types/index.ts +4 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/sessionManager.tsx +15 -0
- package/src/utils/trimWhitespace.ts +11 -0
- package/tsconfig.json +25 -0
- package/webpack.config.js +19 -0
- package/dist/components/bibot.js +0 -171
- package/dist/components/bibot.js.map +0 -1
- /package/dist/{components/bibot.d.ts → bibot.d.ts} +0 -0
| @@ -0,0 +1,103 @@ | |
| 1 | 
            +
            import { Avatar, Indicator } from '@mantine/core'
         | 
| 2 | 
            +
            import { Close, SendRounded } from '@mui/icons-material'
         | 
| 3 | 
            +
            import ChatIcon from '@mui/icons-material/Chat'
         | 
| 4 | 
            +
            import { Button } from 'antd'
         | 
| 5 | 
            +
            import { useBiBotChatBot } from '../hooks'
         | 
| 6 | 
            +
            import { AppProvider } from '../context/AppContext'
         | 
| 7 | 
            +
            interface bubbleProps {
         | 
| 8 | 
            +
              clientId: string
         | 
| 9 | 
            +
            }
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            interface PredefinedQuestionsProps {
         | 
| 12 | 
            +
              onSelect: (question: string) => void
         | 
| 13 | 
            +
              questions: string[]
         | 
| 14 | 
            +
            }
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            const PredefinedQuestions = ({ questions, onSelect }: PredefinedQuestionsProps) => {
         | 
| 17 | 
            +
              return (
         | 
| 18 | 
            +
                <div className="predefined-questions">
         | 
| 19 | 
            +
                  {questions.map((question, index) => (
         | 
| 20 | 
            +
                    <div key={index} className="predefined-question" onClick={() => onSelect(question)}>
         | 
| 21 | 
            +
                      {question}
         | 
| 22 | 
            +
                    </div>
         | 
| 23 | 
            +
                  ))}
         | 
| 24 | 
            +
                </div>
         | 
| 25 | 
            +
              );
         | 
| 26 | 
            +
            };
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            const BiBot = ({ clientId }: bubbleProps) => {
         | 
| 29 | 
            +
              const {
         | 
| 30 | 
            +
                chatIsOpen,
         | 
| 31 | 
            +
                messages,
         | 
| 32 | 
            +
                isLoading,
         | 
| 33 | 
            +
                messageEndRef,
         | 
| 34 | 
            +
                userInput,
         | 
| 35 | 
            +
                handleUserInput,
         | 
| 36 | 
            +
                handleKeyPress,
         | 
| 37 | 
            +
                sendInputInquiry,
         | 
| 38 | 
            +
                toggleChat,
         | 
| 39 | 
            +
                chatBubbleConfig,
         | 
| 40 | 
            +
                showPredefinedQuestions,
         | 
| 41 | 
            +
                predefinedQuestions,
         | 
| 42 | 
            +
                handlePredefinedQuestionSelect,
         | 
| 43 | 
            +
              } = useBiBotChatBot({clientId})
         | 
| 44 | 
            +
             | 
| 45 | 
            +
              return (
         | 
| 46 | 
            +
                <AppProvider>
         | 
| 47 | 
            +
                <div className={`chat-bubble ${chatIsOpen ? 'open' : ''}`}>
         | 
| 48 | 
            +
                  {chatIsOpen && (
         | 
| 49 | 
            +
                    <div className="chat-window" style={{ backgroundColor: chatBubbleConfig?.bgColor }}>
         | 
| 50 | 
            +
                      <div className="chat-header" style={{ backgroundColor: chatBubbleConfig?.color ?? '#dedede' }}>
         | 
| 51 | 
            +
                        <div style={{ alignItems: 'center', display: 'flex', color: '#fff', fontWeight: 'bold' }}>
         | 
| 52 | 
            +
                        <Indicator inline size={12} offset={7} position="bottom-end" color={ 'green' }>
         | 
| 53 | 
            +
                        <Avatar color="white" src={chatBubbleConfig?.logo_url} alt="profile" />
         | 
| 54 | 
            +
                          </Indicator>
         | 
| 55 | 
            +
                           </div>
         | 
| 56 | 
            +
                           <div style={{ display: 'flex', flexDirection: 'column', textAlign: 'left', paddingLeft: '10px', justifyContent: 'flex-start', color: '#fff' }}>
         | 
| 57 | 
            +
                              <span style={{ fontWeight: 'bold' }}>{chatBubbleConfig?.title}</span>
         | 
| 58 | 
            +
                            {}
         | 
| 59 | 
            +
                          {isLoading ? <span style={{ fontSize: '12px', lineHeight: '0.5' }}>Typing...</span> : <span style={{ fontSize: '12px', lineHeight: '0.5' }}>{'Online'}</span>}
         | 
| 60 | 
            +
                            </div>
         | 
| 61 | 
            +
                        </div>
         | 
| 62 | 
            +
                      <div className="message-list">
         | 
| 63 | 
            +
                        {messages.map((message: { sender: 'user' | 'bot', text: string }, index: number) => (
         | 
| 64 | 
            +
                          message.sender === 'user'
         | 
| 65 | 
            +
                            ? <div key={index} className={`message ${message.sender}`}>
         | 
| 66 | 
            +
                            {message.text}
         | 
| 67 | 
            +
                          </div>
         | 
| 68 | 
            +
                            : <div key={index} style={{ display: 'flex' }}>
         | 
| 69 | 
            +
                          <Avatar color="white" src={chatBubbleConfig?.logo_url} size={25} alt="profile" />
         | 
| 70 | 
            +
                          <div className={`message ${message.sender}`}>
         | 
| 71 | 
            +
                          {message.text}
         | 
| 72 | 
            +
                          </div>
         | 
| 73 | 
            +
                          </div>
         | 
| 74 | 
            +
                        ))}
         | 
| 75 | 
            +
                                   {showPredefinedQuestions && predefinedQuestions && predefinedQuestions.length > 0 && (
         | 
| 76 | 
            +
                          <PredefinedQuestions questions={predefinedQuestions} onSelect={handlePredefinedQuestionSelect} />
         | 
| 77 | 
            +
                        )}
         | 
| 78 | 
            +
                        {isLoading &&  <div style={{marginLeft: '20px'}} className='message'> <div className="loader"></div>  </div> }
         | 
| 79 | 
            +
                        <div ref={messageEndRef} />
         | 
| 80 | 
            +
                      </div>
         | 
| 81 | 
            +
                      <div className="input-area">
         | 
| 82 | 
            +
                        <input
         | 
| 83 | 
            +
                          autoFocus={true}
         | 
| 84 | 
            +
                          type="text"
         | 
| 85 | 
            +
                          value={userInput}
         | 
| 86 | 
            +
                          onChange={handleUserInput}
         | 
| 87 | 
            +
                          onKeyPress={handleKeyPress}
         | 
| 88 | 
            +
                          placeholder="Ask a question"
         | 
| 89 | 
            +
                        />
         | 
| 90 | 
            +
                        <Button disabled={isLoading ?? true} style={{ backgroundColor: 'transparent', color: isLoading ? '#dedede' : chatBubbleConfig?.color }} size='middle' icon={<SendRounded />} onClick={sendInputInquiry}/>
         | 
| 91 | 
            +
                      </div>
         | 
| 92 | 
            +
                    </div>
         | 
| 93 | 
            +
                  )}
         | 
| 94 | 
            +
                  <Button type='link' onClick={toggleChat} className="chat-toggle" style={{ backgroundColor: chatBubbleConfig?.color ?? '#dedede' }}>
         | 
| 95 | 
            +
                    {chatIsOpen ? <Close style={{ width: 30, height: 30, color: '#fff' }} /> : <ChatIcon style={{ width: 30, height: 30, color: '#fff' }}/>}
         | 
| 96 | 
            +
                  </Button>
         | 
| 97 | 
            +
                </div>
         | 
| 98 | 
            +
                </AppProvider>
         | 
| 99 | 
            +
             | 
| 100 | 
            +
              )
         | 
| 101 | 
            +
            }
         | 
| 102 | 
            +
             | 
| 103 | 
            +
            export default BiBot
         | 
| @@ -0,0 +1,28 @@ | |
| 1 | 
            +
             | 
| 2 | 
            +
            export const APP_DATA = {
         | 
| 3 | 
            +
              APP_NAME: 'Bibot'
         | 
| 4 | 
            +
            }
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            const baseUrls = {
         | 
| 7 | 
            +
              inference: 'https://inference.dev.bibot.thespuka.com/v0',
         | 
| 8 | 
            +
            }
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            export const endpoints = {
         | 
| 11 | 
            +
              get inference () {
         | 
| 12 | 
            +
                return baseUrls.inference
         | 
| 13 | 
            +
              },
         | 
| 14 | 
            +
            } as const
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            export enum domain {
         | 
| 17 | 
            +
              app = '/app',
         | 
| 18 | 
            +
              bibot = '/bibot',
         | 
| 19 | 
            +
              inference = '/inference',
         | 
| 20 | 
            +
            }
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            export enum resources {
         | 
| 23 | 
            +
              chatBubble = '/chat-bubble-config',
         | 
| 24 | 
            +
              predefinedQ = '/predefined-q',
         | 
| 25 | 
            +
              localQ = '/local-q',
         | 
| 26 | 
            +
              timedOutLocalQ = '/t-local-q',
         | 
| 27 | 
            +
              q = '/q'
         | 
| 28 | 
            +
            }
         | 
| @@ -0,0 +1,49 @@ | |
| 1 | 
            +
            export enum statusCode {
         | 
| 2 | 
            +
              ok = 200
         | 
| 3 | 
            +
              , created = 201
         | 
| 4 | 
            +
              , accepted = 202
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              // 3xx codes
         | 
| 7 | 
            +
              , unmodified = 304
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              // 4xx Client Error
         | 
| 10 | 
            +
              , sucMsg = 'success'
         | 
| 11 | 
            +
              , badReq = 400
         | 
| 12 | 
            +
              , unauthorized = 401
         | 
| 13 | 
            +
              , paymentReq = 402
         | 
| 14 | 
            +
              , forbidden = 403
         | 
| 15 | 
            +
              , notFound = 404
         | 
| 16 | 
            +
              , methodNotAllowed = 405
         | 
| 17 | 
            +
              , notAcceptable = 406
         | 
| 18 | 
            +
              , pxyAuthReq = 407
         | 
| 19 | 
            +
              , reqTimeOut = 408
         | 
| 20 | 
            +
              , conflict = 409
         | 
| 21 | 
            +
              , gone = 410
         | 
| 22 | 
            +
              , lengthReq = 411
         | 
| 23 | 
            +
              , preConFailed = 412
         | 
| 24 | 
            +
              , payloadTooLarge = 413
         | 
| 25 | 
            +
              , urlTooLong = 414
         | 
| 26 | 
            +
              , unsupportedMediaType = 415
         | 
| 27 | 
            +
              , rangeNotSatisfiable = 416
         | 
| 28 | 
            +
              , expectationFailed = 417
         | 
| 29 | 
            +
             | 
| 30 | 
            +
              , misdirectedReq = 421
         | 
| 31 | 
            +
              , unprocessableEntity = 422
         | 
| 32 | 
            +
              , locked = 423
         | 
| 33 | 
            +
              , failedDependency = 424
         | 
| 34 | 
            +
              , tooLarge = 425
         | 
| 35 | 
            +
              , upgradeRequired = 426
         | 
| 36 | 
            +
              , preconReq = 428
         | 
| 37 | 
            +
              , tooManyReq = 429
         | 
| 38 | 
            +
              , reqHeaderTooLarge = 431
         | 
| 39 | 
            +
              , unavailableForLegalReasons = 451
         | 
| 40 | 
            +
             | 
| 41 | 
            +
              // 5xx Server Error
         | 
| 42 | 
            +
              , internalServerError = 500
         | 
| 43 | 
            +
              , notImplemented = 501
         | 
| 44 | 
            +
              , badGateway = 502
         | 
| 45 | 
            +
              , svcUnavalable = 503
         | 
| 46 | 
            +
              , gtwayTimeout = 504
         | 
| 47 | 
            +
              , httpVNotSupported = 505
         | 
| 48 | 
            +
              , networkAuthReq = 511
         | 
| 49 | 
            +
            }
         | 
| @@ -0,0 +1,66 @@ | |
| 1 | 
            +
            import { appStateEnums } from '../config/appStateEnums'
         | 
| 2 | 
            +
            import React, { type ReactNode, createContext, useReducer, useEffect } from 'react'
         | 
| 3 | 
            +
            import { appReducer } from '../reducers/appReducer'
         | 
| 4 | 
            +
            import type { AppContextProps, AppStates } from '../types/coreInterfaces'
         | 
| 5 | 
            +
            import { getSessionId } from '../utils/sessionManager'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            interface AppProps {
         | 
| 8 | 
            +
              children: ReactNode
         | 
| 9 | 
            +
            }
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            const dummyDispatch = () => {} // A no-op function.
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            const defaultContextValue: AppContextProps = {
         | 
| 14 | 
            +
              state: {
         | 
| 15 | 
            +
                chatIsOpen: false,
         | 
| 16 | 
            +
                sessionId: getSessionId()
         | 
| 17 | 
            +
              },
         | 
| 18 | 
            +
              dispatch: dummyDispatch
         | 
| 19 | 
            +
            }
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            const AppContext = createContext<AppContextProps>(defaultContextValue)
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            const AppProvider: React.FC<AppProps> = ({ children }) => {
         | 
| 24 | 
            +
              const APP_STATE_KEY = 'app_states'
         | 
| 25 | 
            +
              const initialState: AppStates = {
         | 
| 26 | 
            +
                chatIsOpen: false,
         | 
| 27 | 
            +
                sessionId: getSessionId()
         | 
| 28 | 
            +
              }
         | 
| 29 | 
            +
             | 
| 30 | 
            +
              const [state, dispatch] = useReducer(appReducer, initialState)
         | 
| 31 | 
            +
             | 
| 32 | 
            +
              useEffect(() => {
         | 
| 33 | 
            +
                // Pool the initial states from local storage
         | 
| 34 | 
            +
                const storedStates = localStorage.getItem(APP_STATE_KEY)
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                if (storedStates) {
         | 
| 37 | 
            +
                  try {
         | 
| 38 | 
            +
                    const parsedStates = JSON.parse(storedStates)
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                    // Merge stored states with initial states
         | 
| 41 | 
            +
                    const updatedStates = {
         | 
| 42 | 
            +
                      ...initialState,
         | 
| 43 | 
            +
                      ...parsedStates
         | 
| 44 | 
            +
                    }
         | 
| 45 | 
            +
                    console.log(initialState, parsedStates, updatedStates)
         | 
| 46 | 
            +
                    // Dispatch action to update the states
         | 
| 47 | 
            +
                    dispatch({ type: appStateEnums.BIBOT, ...updatedStates })
         | 
| 48 | 
            +
                  } catch (error) {
         | 
| 49 | 
            +
                    console.error('Failed to parse app states from local storage:', error)
         | 
| 50 | 
            +
                  }
         | 
| 51 | 
            +
                }
         | 
| 52 | 
            +
              }, [])
         | 
| 53 | 
            +
             | 
| 54 | 
            +
              useEffect(() => {
         | 
| 55 | 
            +
                console.log('Changes in state: ', state)
         | 
| 56 | 
            +
                localStorage.setItem(APP_STATE_KEY, JSON.stringify(state))
         | 
| 57 | 
            +
              }, [state])
         | 
| 58 | 
            +
             | 
| 59 | 
            +
              return (
         | 
| 60 | 
            +
                <AppContext.Provider value={{ state, dispatch }}>
         | 
| 61 | 
            +
                  {children}
         | 
| 62 | 
            +
                </AppContext.Provider>
         | 
| 63 | 
            +
              )
         | 
| 64 | 
            +
            }
         | 
| 65 | 
            +
             | 
| 66 | 
            +
            export { AppContext, AppProvider }
         | 
| @@ -0,0 +1,17 @@ | |
| 1 | 
            +
            import React, { useState, useEffect } from 'react'
         | 
| 2 | 
            +
            export default function MobileView () {
         | 
| 3 | 
            +
              const [isMobile, setIsMobile] = useState<boolean>(false)
         | 
| 4 | 
            +
              useEffect(() => {
         | 
| 5 | 
            +
                const isMobileDevice = () => {
         | 
| 6 | 
            +
                  const screenWidth = window.innerWidth
         | 
| 7 | 
            +
                  const mobileThreshold = 768
         | 
| 8 | 
            +
                  setIsMobile(screenWidth < mobileThreshold)
         | 
| 9 | 
            +
                }
         | 
| 10 | 
            +
                isMobileDevice()
         | 
| 11 | 
            +
                window.addEventListener('resize', isMobileDevice)
         | 
| 12 | 
            +
                return () => { // clean up event listner on when component unmount
         | 
| 13 | 
            +
                  window.removeEventListener('resize', isMobileDevice)
         | 
| 14 | 
            +
                }
         | 
| 15 | 
            +
              }, [])
         | 
| 16 | 
            +
              return isMobile
         | 
| 17 | 
            +
            }
         | 
| @@ -0,0 +1,107 @@ | |
| 1 | 
            +
            import { message } from 'antd'
         | 
| 2 | 
            +
            import { appStateEnums } from '../config/appStateEnums'
         | 
| 3 | 
            +
            import React, { useEffect, useRef, useState, useContext, useCallback } from 'react'
         | 
| 4 | 
            +
            import { AppContext } from '../context/AppContext'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            import { v4 as uuidv4 } from 'uuid'
         | 
| 7 | 
            +
            import { askBiBot, getRemoteClientChatBubbleConfig, getRemoteClientChatPredefinedQuestions } from '../services/plugin-api'
         | 
| 8 | 
            +
            interface UseBiBotChatBotProps {
         | 
| 9 | 
            +
                clientId: string
         | 
| 10 | 
            +
              }
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            interface ChatBubbleConfigProps {
         | 
| 13 | 
            +
                bgColor?: string,
         | 
| 14 | 
            +
                color?: string,
         | 
| 15 | 
            +
                title?: string,
         | 
| 16 | 
            +
                logo_url?: string
         | 
| 17 | 
            +
            }
         | 
| 18 | 
            +
            const useBiBotChatBot = ({ clientId }: UseBiBotChatBotProps) => {
         | 
| 19 | 
            +
              const [predefinedQuestions, setPredefinedQuestions] = useState<string[]>([]) // State to store predefined questions
         | 
| 20 | 
            +
              const [showPredefinedQuestions, setShowPredefinedQuestions] = useState(true); // State to toggle predefined questions
         | 
| 21 | 
            +
              const { state, dispatch } = useContext(AppContext)
         | 
| 22 | 
            +
              const { chatIsOpen } = state
         | 
| 23 | 
            +
              const [messages, setMessages] = useState<Array<{ sender: 'user' | 'bot', text: string }>>([])
         | 
| 24 | 
            +
              const [userInput, setUserInput] = useState('')
         | 
| 25 | 
            +
              const [isLoading, setIsLoading] = useState(false)
         | 
| 26 | 
            +
              const messageEndRef = useRef<HTMLDivElement>(null)
         | 
| 27 | 
            +
              const [chatBubbleConfig, setChatBubbleConfig] = useState<ChatBubbleConfigProps>()
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  // Function to handle selecting a predefined question
         | 
| 30 | 
            +
                  const handlePredefinedQuestionSelect = (question: any) => {
         | 
| 31 | 
            +
                    setUserInput(question);
         | 
| 32 | 
            +
                    sendInputInquiry();
         | 
| 33 | 
            +
                    setShowPredefinedQuestions(false); // Hide predefined questions after selection
         | 
| 34 | 
            +
                  }
         | 
| 35 | 
            +
                  
         | 
| 36 | 
            +
              const getChatBubbleConfig = useCallback(async()=>{
         | 
| 37 | 
            +
                const remotePredefinedQuestions = await getRemoteClientChatPredefinedQuestions({client_id: clientId})
         | 
| 38 | 
            +
                if (remotePredefinedQuestions){
         | 
| 39 | 
            +
                    setPredefinedQuestions(remotePredefinedQuestions)
         | 
| 40 | 
            +
                }
         | 
| 41 | 
            +
                const remoteChatBubbleConfig = await getRemoteClientChatBubbleConfig({client_id: clientId})
         | 
| 42 | 
            +
                if (remoteChatBubbleConfig){
         | 
| 43 | 
            +
                    setChatBubbleConfig(remoteChatBubbleConfig)
         | 
| 44 | 
            +
                }
         | 
| 45 | 
            +
              },[clientId])
         | 
| 46 | 
            +
             | 
| 47 | 
            +
              useEffect(()=>{
         | 
| 48 | 
            +
                void getChatBubbleConfig()
         | 
| 49 | 
            +
              }, [getChatBubbleConfig])
         | 
| 50 | 
            +
              
         | 
| 51 | 
            +
              useEffect(() => {
         | 
| 52 | 
            +
                if (messageEndRef?.current) { messageEndRef.current.scrollIntoView({ behavior: 'smooth' }) }
         | 
| 53 | 
            +
              }, [messages])
         | 
| 54 | 
            +
             | 
| 55 | 
            +
              const toggleChat = () => {
         | 
| 56 | 
            +
                dispatch({ type: appStateEnums.BIBOT, chatIsOpen: !chatIsOpen })
         | 
| 57 | 
            +
              }
         | 
| 58 | 
            +
             | 
| 59 | 
            +
              const handleUserInput = (e: React.ChangeEvent<HTMLInputElement>) => {
         | 
| 60 | 
            +
                setUserInput(e.target.value)
         | 
| 61 | 
            +
              }
         | 
| 62 | 
            +
             | 
| 63 | 
            +
              async function sendInputInquiry () {
         | 
| 64 | 
            +
                setIsLoading(true)
         | 
| 65 | 
            +
                setUserInput('')
         | 
| 66 | 
            +
                try {
         | 
| 67 | 
            +
                  if (userInput.trim()) {
         | 
| 68 | 
            +
                    // dispatch({ type: appStateEnums.BIBOT, chatIsOpen: true })
         | 
| 69 | 
            +
                    setMessages(messages => [...messages, { sender: 'user', text: userInput }])
         | 
| 70 | 
            +
                    const response = await askBiBot({
         | 
| 71 | 
            +
                      client_id: clientId,
         | 
| 72 | 
            +
                      q: userInput.trim(),
         | 
| 73 | 
            +
                      session_id: state.sessionId,
         | 
| 74 | 
            +
                      chat_id: uuidv4()
         | 
| 75 | 
            +
                    })
         | 
| 76 | 
            +
                    setMessages(messages => [...messages, { sender: 'bot', text: response }])
         | 
| 77 | 
            +
                  }
         | 
| 78 | 
            +
                } catch (error: any) {
         | 
| 79 | 
            +
                  void message.error(error?.message ?? 'Failed to get response from server')
         | 
| 80 | 
            +
                } finally {
         | 
| 81 | 
            +
                  setIsLoading(false)
         | 
| 82 | 
            +
                }
         | 
| 83 | 
            +
              }
         | 
| 84 | 
            +
             | 
| 85 | 
            +
              const handleKeyPress = async (e: React.KeyboardEvent<HTMLInputElement>) => {
         | 
| 86 | 
            +
                if (e.key === 'Enter' && !isLoading) {
         | 
| 87 | 
            +
                  await sendInputInquiry()
         | 
| 88 | 
            +
                }
         | 
| 89 | 
            +
              }
         | 
| 90 | 
            +
              return {
         | 
| 91 | 
            +
                chatIsOpen,
         | 
| 92 | 
            +
                messages,
         | 
| 93 | 
            +
                isLoading,
         | 
| 94 | 
            +
                messageEndRef,
         | 
| 95 | 
            +
                userInput,
         | 
| 96 | 
            +
                handleUserInput,
         | 
| 97 | 
            +
                handleKeyPress,
         | 
| 98 | 
            +
                toggleChat,
         | 
| 99 | 
            +
                sendInputInquiry,
         | 
| 100 | 
            +
                chatBubbleConfig,
         | 
| 101 | 
            +
                showPredefinedQuestions,
         | 
| 102 | 
            +
                predefinedQuestions,
         | 
| 103 | 
            +
                handlePredefinedQuestionSelect,
         | 
| 104 | 
            +
              }
         | 
| 105 | 
            +
            }
         | 
| 106 | 
            +
             | 
| 107 | 
            +
            export { useBiBotChatBot }
         | 
| @@ -0,0 +1,38 @@ | |
| 1 | 
            +
            import axios from 'axios';
         | 
| 2 | 
            +
            import { endpoints } from '../config/endpointEnums';
         | 
| 3 | 
            +
            import React from 'react';
         | 
| 4 | 
            +
            const inferenceBaseURL = endpoints.inference;
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            export const createPluginAxiosInstance = (params = {}, headers = {}) => {
         | 
| 7 | 
            +
              const instance = axios.create({
         | 
| 8 | 
            +
                baseURL: inferenceBaseURL,
         | 
| 9 | 
            +
                timeout: 60000, // 1 minute
         | 
| 10 | 
            +
                headers: {
         | 
| 11 | 
            +
                  'Content-Type': 'application/json',
         | 
| 12 | 
            +
                  ...headers
         | 
| 13 | 
            +
                },
         | 
| 14 | 
            +
                ...params
         | 
| 15 | 
            +
              });
         | 
| 16 | 
            +
             | 
| 17 | 
            +
             | 
| 18 | 
            +
              instance.interceptors.response.use(
         | 
| 19 | 
            +
                (response) => {
         | 
| 20 | 
            +
                  return response
         | 
| 21 | 
            +
                },
         | 
| 22 | 
            +
                async (error) => {
         | 
| 23 | 
            +
                  let errMsg = 'An unknown error occurred'
         | 
| 24 | 
            +
                  if (error.response) {
         | 
| 25 | 
            +
                    errMsg = error.response.data.message
         | 
| 26 | 
            +
                  } else if (error.request) {
         | 
| 27 | 
            +
                    errMsg = 'No response received from the server.'
         | 
| 28 | 
            +
                  } else {
         | 
| 29 | 
            +
                    errMsg = `Error setting up the request: ${error.message}`
         | 
| 30 | 
            +
                  }
         | 
| 31 | 
            +
                  return await Promise.reject(new Error(errMsg))
         | 
| 32 | 
            +
                }
         | 
| 33 | 
            +
              )
         | 
| 34 | 
            +
             | 
| 35 | 
            +
              return instance
         | 
| 36 | 
            +
            }
         | 
| 37 | 
            +
             | 
| 38 | 
            +
              
         | 
    
        package/src/index.css
    ADDED
    
    | @@ -0,0 +1,36 @@ | |
| 1 | 
            +
            body {
         | 
| 2 | 
            +
              margin: 0;
         | 
| 3 | 
            +
              font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
         | 
| 4 | 
            +
                'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
         | 
| 5 | 
            +
                sans-serif;
         | 
| 6 | 
            +
              -webkit-font-smoothing: antialiased;
         | 
| 7 | 
            +
              -moz-osx-font-smoothing: grayscale;
         | 
| 8 | 
            +
            }
         | 
| 9 | 
            +
             | 
| 10 | 
            +
             | 
| 11 | 
            +
            *{
         | 
| 12 | 
            +
              margin: 0;
         | 
| 13 | 
            +
              padding: 0;
         | 
| 14 | 
            +
              box-sizing: border-box;
         | 
| 15 | 
            +
            }
         | 
| 16 | 
            +
            code {
         | 
| 17 | 
            +
              font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
         | 
| 18 | 
            +
                monospace;
         | 
| 19 | 
            +
            }
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            .upload-component {
         | 
| 22 | 
            +
              .drop-area {
         | 
| 23 | 
            +
                border: 2px dashed #ccc;
         | 
| 24 | 
            +
                border-radius: 5px;
         | 
| 25 | 
            +
                padding: 20px;
         | 
| 26 | 
            +
                text-align: center;
         | 
| 27 | 
            +
                cursor: pointer;
         | 
| 28 | 
            +
                &:hover, &:focus {
         | 
| 29 | 
            +
                  border-color: #007bff;
         | 
| 30 | 
            +
                }
         | 
| 31 | 
            +
              }
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              .uploading { background-color: #fff3cd; }
         | 
| 34 | 
            +
              .completed { background-color: #d4edda; }
         | 
| 35 | 
            +
              .error { background-color: #f8d7da; }
         | 
| 36 | 
            +
            }
         | 
    
        package/src/index.tsx
    ADDED
    
    
| @@ -0,0 +1,16 @@ | |
| 1 | 
            +
            import { appStateEnums } from '../config/appStateEnums'
         | 
| 2 | 
            +
            import type { AppStates, AppAction } from 'types'
         | 
| 3 | 
            +
            import React from 'react';
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            export const appReducer = (state: AppStates, action: AppAction): AppStates => {
         | 
| 6 | 
            +
              console.log('This is the appReducer state', state, action)
         | 
| 7 | 
            +
              switch (action.type) {
         | 
| 8 | 
            +
                case appStateEnums.BIBOT:
         | 
| 9 | 
            +
                  return {
         | 
| 10 | 
            +
                    ...state,
         | 
| 11 | 
            +
                    chatIsOpen: action.chatIsOpen
         | 
| 12 | 
            +
                  }
         | 
| 13 | 
            +
                default:
         | 
| 14 | 
            +
                  return state
         | 
| 15 | 
            +
              }
         | 
| 16 | 
            +
            }
         | 
| @@ -0,0 +1,120 @@ | |
| 1 | 
            +
            import { domain, resources } from '../config/endpointEnums'
         | 
| 2 | 
            +
            import React from 'react';
         | 
| 3 | 
            +
            // import { createPluginAxiosInstance } from '../hooks/usePluginFactory'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            // const pluginAxiosInstance=createPluginAxiosInstance()
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            interface Q_DATA_TYPE {
         | 
| 8 | 
            +
              client_id: string
         | 
| 9 | 
            +
                q: string
         | 
| 10 | 
            +
                endSession?: boolean
         | 
| 11 | 
            +
                session_id: string
         | 
| 12 | 
            +
                chat_id: string
         | 
| 13 | 
            +
                tries?: number
         | 
| 14 | 
            +
            }
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            interface RemoteChatBubbleConfigProps {
         | 
| 17 | 
            +
                bgColor: string,
         | 
| 18 | 
            +
                chatColor: string,
         | 
| 19 | 
            +
                title: string,
         | 
| 20 | 
            +
                userImage: string
         | 
| 21 | 
            +
            }
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            async function askTimedOutBiBot(data: Q_DATA_TYPE): Promise<string> {
         | 
| 24 | 
            +
                try {
         | 
| 25 | 
            +
                    return 'Hello'
         | 
| 26 | 
            +
                    // const path=`${domain.bibot}${resources.timedOutLocalQ}`
         | 
| 27 | 
            +
                    // const response=await pluginAxiosInstance.post<any>(path, data)
         | 
| 28 | 
            +
                    // console.log(response)
         | 
| 29 | 
            +
                    // return response.data.message
         | 
| 30 | 
            +
                } catch (error: any) {
         | 
| 31 | 
            +
                    console.log(error.message)
         | 
| 32 | 
            +
                    return error.message
         | 
| 33 | 
            +
                }
         | 
| 34 | 
            +
            }
         | 
| 35 | 
            +
             | 
| 36 | 
            +
            async function askBiBot(data: Q_DATA_TYPE): Promise<string> {
         | 
| 37 | 
            +
                try {
         | 
| 38 | 
            +
                    // const path=`${domain.inference}${resources.q}`
         | 
| 39 | 
            +
                    // const response=await pluginAxiosInstance.post<any>(path, data)
         | 
| 40 | 
            +
                    // console.log(response)
         | 
| 41 | 
            +
                    // return response.data.message
         | 
| 42 | 
            +
                    return 'Hello'
         | 
| 43 | 
            +
                } catch (error1: any) {
         | 
| 44 | 
            +
                    console.log(error1.message)
         | 
| 45 | 
            +
                    if (error1.code==='ECONNABORTED'||error1.message.includes('Endpoint request timed out')) {
         | 
| 46 | 
            +
                        try {
         | 
| 47 | 
            +
                            return await askTimedOutBiBot({
         | 
| 48 | 
            +
                                ...data,
         | 
| 49 | 
            +
                                tries: 2
         | 
| 50 | 
            +
                            })
         | 
| 51 | 
            +
                        } catch (error2: any) {
         | 
| 52 | 
            +
                            if (error2.code==='ECONNABORTED'||error2.message.includes('Endpoint request timed out')) {
         | 
| 53 | 
            +
                                try {
         | 
| 54 | 
            +
                                    return await askTimedOutBiBot({
         | 
| 55 | 
            +
                                        ...data,
         | 
| 56 | 
            +
                                        tries: 3
         | 
| 57 | 
            +
                                    })
         | 
| 58 | 
            +
                                } catch (error3: any) {
         | 
| 59 | 
            +
                                    return error3.message
         | 
| 60 | 
            +
                                }
         | 
| 61 | 
            +
                            } else {
         | 
| 62 | 
            +
                                return error2.message
         | 
| 63 | 
            +
                            }
         | 
| 64 | 
            +
                        }
         | 
| 65 | 
            +
                    } else {
         | 
| 66 | 
            +
                        return error1.message
         | 
| 67 | 
            +
                    }
         | 
| 68 | 
            +
                }
         | 
| 69 | 
            +
            }
         | 
| 70 | 
            +
            // TODO: Emmanuel fix the default returned values, especially the userImage to a default robot image
         | 
| 71 | 
            +
            async function getRemoteClientChatBubbleConfig(params: { client_id: string }): Promise<RemoteChatBubbleConfigProps> {
         | 
| 72 | 
            +
                try {
         | 
| 73 | 
            +
                    return {
         | 
| 74 | 
            +
                        bgColor: 'white',
         | 
| 75 | 
            +
                        chatColor: 'blue',
         | 
| 76 | 
            +
                        title: 'ChatBot',
         | 
| 77 | 
            +
                        userImage: 'string'
         | 
| 78 | 
            +
                    }
         | 
| 79 | 
            +
                    // const path=`${domain.inference}${resources.chatBubble}`
         | 
| 80 | 
            +
                    // const response=await pluginAxiosInstance.get<any>(path, { params })
         | 
| 81 | 
            +
                    // return response.data
         | 
| 82 | 
            +
                } catch (error: any) {
         | 
| 83 | 
            +
                    return {
         | 
| 84 | 
            +
                        bgColor: 'white',
         | 
| 85 | 
            +
                        chatColor: 'blue',
         | 
| 86 | 
            +
                        title: 'ChatBot',
         | 
| 87 | 
            +
                        userImage: 'string'
         | 
| 88 | 
            +
                    }
         | 
| 89 | 
            +
                }
         | 
| 90 | 
            +
            }
         | 
| 91 | 
            +
             | 
| 92 | 
            +
            async function getRemoteClientChatPredefinedQuestions(params: { client_id: string }): Promise<string[]> {
         | 
| 93 | 
            +
                try {
         | 
| 94 | 
            +
                    return ['Hello']
         | 
| 95 | 
            +
                    // const path=`${domain.inference}${resources.predefinedQ}`
         | 
| 96 | 
            +
                    // const response=await pluginAxiosInstance.get<any>(path, { params })
         | 
| 97 | 
            +
                    // return response.data.predefined_messages
         | 
| 98 | 
            +
                } catch (error: any) {
         | 
| 99 | 
            +
                    return ['These are placeholders', 'They will be removed in production', 'This will be empty if there are no predefined questions', 'So hide if there are no predefined questions']
         | 
| 100 | 
            +
                }
         | 
| 101 | 
            +
            }
         | 
| 102 | 
            +
             | 
| 103 | 
            +
            async function GetPredefinedQuestion (){
         | 
| 104 | 
            +
                const clientId = '6c74b4bb-0395-4751-a55f-7d065d67c56b'
         | 
| 105 | 
            +
                try {
         | 
| 106 | 
            +
                    return [{question: "q", answer: "a"}]
         | 
| 107 | 
            +
                //   const path = `${domain.inference}${resources.predefinedQ}?client_id=${clientId}`
         | 
| 108 | 
            +
                //   const response = await pluginAxiosInstance.get(path)
         | 
| 109 | 
            +
                //   return response.data
         | 
| 110 | 
            +
                } catch (error) {
         | 
| 111 | 
            +
                  console.error('Error fetching subscription:', error)
         | 
| 112 | 
            +
                }
         | 
| 113 | 
            +
              }
         | 
| 114 | 
            +
             | 
| 115 | 
            +
            export {
         | 
| 116 | 
            +
                askBiBot,
         | 
| 117 | 
            +
                getRemoteClientChatBubbleConfig,
         | 
| 118 | 
            +
                getRemoteClientChatPredefinedQuestions,
         | 
| 119 | 
            +
                GetPredefinedQuestion
         | 
| 120 | 
            +
            }
         | 
| @@ -0,0 +1,63 @@ | |
| 1 | 
            +
             | 
| 2 | 
            +
            .amplify-button--primary {
         | 
| 3 | 
            +
                background-color: #0fa781;
         | 
| 4 | 
            +
            }
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            .preAuditLogo-on-registerPage{
         | 
| 7 | 
            +
                max-height: 50px;
         | 
| 8 | 
            +
                margin-bottom: 20px;
         | 
| 9 | 
            +
               }
         | 
| 10 | 
            +
            .amplify-tabs-item[data-state=active] {
         | 
| 11 | 
            +
             color: #fff;
         | 
| 12 | 
            +
             border-color: #0fa781;
         | 
| 13 | 
            +
            }
         | 
| 14 | 
            +
            .amplify-tabs-item[data-state=active]:hover {
         | 
| 15 | 
            +
                color: #fff;
         | 
| 16 | 
            +
               }
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            .amplify-tabs-item:hover {
         | 
| 19 | 
            +
                color: #00152a;
         | 
| 20 | 
            +
               }
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            [data-amplify-authenticator] [data-amplify-router] {
         | 
| 23 | 
            +
             background-color: #ffffff;
         | 
| 24 | 
            +
             border-color: #b9eee1;
         | 
| 25 | 
            +
            }
         | 
| 26 | 
            +
            .amplify-tabs-item[data-spacing=equal]{
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            }
         | 
| 29 | 
            +
            .amplify-button--link {
         | 
| 30 | 
            +
                color: #00152a;
         | 
| 31 | 
            +
            }
         | 
| 32 | 
            +
            .amplify-button--link:hover {
         | 
| 33 | 
            +
                color: #00152a;
         | 
| 34 | 
            +
                background-color: #fff;
         | 
| 35 | 
            +
            }
         | 
| 36 | 
            +
             | 
| 37 | 
            +
            .amplify-input, .amplify-input:focus {
         | 
| 38 | 
            +
            border-color: #bed7f0;
         | 
| 39 | 
            +
            border: 1px solid;
         | 
| 40 | 
            +
            }
         | 
| 41 | 
            +
            .fieldContainer{
         | 
| 42 | 
            +
                display: flex;
         | 
| 43 | 
            +
                justify-content: space-between;
         | 
| 44 | 
            +
                flex-direction: row;
         | 
| 45 | 
            +
            }
         | 
| 46 | 
            +
            select, .amplify-field-group__outer-end .amplify-field-group__control, .amplify-field-group__outer-start .amplify-select__wrapper:not(:first-child) .amplify-select:not(:first-child), .amplify-field-group__outer-start--quiet .amplify-field-group__control, .amplify-field-group__outer-start .amplify-field-group__control:not(:first-child), .amplify-field-group :not(:first-child) .amplify-input {
         | 
| 47 | 
            +
            border-color: #c9ebe2;
         | 
| 48 | 
            +
            }
         | 
| 49 | 
            +
            .amplify-input{
         | 
| 50 | 
            +
                border-color: #c9ebe2;
         | 
| 51 | 
            +
            }
         | 
| 52 | 
            +
             | 
| 53 | 
            +
            .amplify-checkbox__icon {
         | 
| 54 | 
            +
              background-color: #c9ebe2;
         | 
| 55 | 
            +
              border-color: #c9ebe2;
         | 
| 56 | 
            +
            }
         | 
| 57 | 
            +
            .input-select-field{
         | 
| 58 | 
            +
                border-color: #0fa781;
         | 
| 59 | 
            +
            }
         | 
| 60 | 
            +
            .amplify-select{
         | 
| 61 | 
            +
                border-color: #c9ebe2 !important;
         | 
| 62 | 
            +
             | 
| 63 | 
            +
            }
         |