@red-hat-developer-hub/backstage-plugin-lightspeed 0.6.0 → 1.0.0

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.
Files changed (48) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +40 -58
  3. package/app-config.yaml +4 -0
  4. package/config.d.ts +1 -24
  5. package/dist/alpha.d.ts +111 -0
  6. package/dist/alpha.esm.js +3 -0
  7. package/dist/alpha.esm.js.map +1 -0
  8. package/dist/api/LightspeedApiClient.esm.js +26 -11
  9. package/dist/api/LightspeedApiClient.esm.js.map +1 -1
  10. package/dist/api/api.esm.js.map +1 -1
  11. package/dist/components/LightSpeedChat.esm.js +17 -1
  12. package/dist/components/LightSpeedChat.esm.js.map +1 -1
  13. package/dist/components/LightspeedChatBox.esm.js +3 -5
  14. package/dist/components/LightspeedChatBox.esm.js.map +1 -1
  15. package/dist/components/LightspeedChatBoxHeader.esm.js +14 -3
  16. package/dist/components/LightspeedChatBoxHeader.esm.js.map +1 -1
  17. package/dist/components/LightspeedPage.esm.js +17 -2
  18. package/dist/components/LightspeedPage.esm.js.map +1 -1
  19. package/dist/const.esm.js +4 -1
  20. package/dist/const.esm.js.map +1 -1
  21. package/dist/hooks/useConversationMessages.esm.js +23 -21
  22. package/dist/hooks/useConversationMessages.esm.js.map +1 -1
  23. package/dist/hooks/useCreateCoversationMessage.esm.js +2 -0
  24. package/dist/hooks/useCreateCoversationMessage.esm.js.map +1 -1
  25. package/dist/hooks/useQuestionValidation.esm.js +16 -0
  26. package/dist/hooks/useQuestionValidation.esm.js.map +1 -0
  27. package/dist/hooks/useTranslation.esm.js +1 -1
  28. package/dist/hooks/useTranslation.esm.js.map +1 -1
  29. package/dist/hooks/useWelcomePrompts.esm.js +3 -2
  30. package/dist/hooks/useWelcomePrompts.esm.js.map +1 -1
  31. package/dist/index.d.ts +1 -8
  32. package/dist/index.esm.js +0 -1
  33. package/dist/index.esm.js.map +1 -1
  34. package/dist/translations/de.esm.js +1 -1
  35. package/dist/translations/de.esm.js.map +1 -1
  36. package/dist/translations/es.esm.js +1 -1
  37. package/dist/translations/es.esm.js.map +1 -1
  38. package/dist/translations/fr.esm.js +1 -1
  39. package/dist/translations/fr.esm.js.map +1 -1
  40. package/dist/translations/index.esm.js +3 -3
  41. package/dist/translations/index.esm.js.map +1 -1
  42. package/dist/translations/{translationRef.esm.js → ref.esm.js} +1 -1
  43. package/dist/translations/ref.esm.js.map +1 -0
  44. package/dist/types.esm.js.map +1 -1
  45. package/dist/utils/lightspeed-chatbox-utils.esm.js +18 -8
  46. package/dist/utils/lightspeed-chatbox-utils.esm.js.map +1 -1
  47. package/package.json +32 -16
  48. package/dist/translations/translationRef.esm.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"LightSpeedChat.esm.js","sources":["../../src/components/LightSpeedChat.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { MouseEvent, useCallback, useEffect, useState } from 'react';\nimport { FileRejection } from 'react-dropzone/.';\n\nimport { ErrorPanel } from '@backstage/core-components';\n\nimport { Box, makeStyles } from '@material-ui/core';\nimport {\n Chatbot,\n ChatbotAlert,\n ChatbotContent,\n ChatbotDisplayMode,\n ChatbotFooter,\n ChatbotFootnote,\n ChatbotHeader,\n ChatbotHeaderMain,\n ChatbotHeaderMenu,\n ChatbotHeaderTitle,\n FileDropZone,\n MessageBar,\n MessageProps,\n} from '@patternfly/chatbot';\nimport ChatbotConversationHistoryNav from '@patternfly/chatbot/dist/dynamic/ChatbotConversationHistoryNav';\nimport { DropdownItem, DropEvent, Title } from '@patternfly/react-core';\nimport { useQueryClient } from '@tanstack/react-query';\n\nimport { supportedFileTypes, TEMP_CONVERSATION_ID } from '../const';\nimport {\n useBackstageUserIdentity,\n useConversationMessages,\n useConversations,\n useDeleteConversation,\n useIsMobile,\n useLastOpenedConversation,\n useLightspeedDeletePermission,\n} from '../hooks';\nimport { useTranslation } from '../hooks/useTranslation';\nimport { useWelcomePrompts } from '../hooks/useWelcomePrompts';\nimport { ConversationSummary } from '../types';\nimport { getAttachments } from '../utils/attachment-utils';\nimport {\n getCategorizeMessages,\n getFootnoteProps,\n} from '../utils/lightspeed-chatbox-utils';\nimport Attachment from './Attachment';\nimport { useFileAttachmentContext } from './AttachmentContext';\nimport { DeleteModal } from './DeleteModal';\nimport FilePreview from './FilePreview';\nimport { LightspeedChatBox } from './LightspeedChatBox';\nimport { LightspeedChatBoxHeader } from './LightspeedChatBoxHeader';\n\nconst useStyles = makeStyles(theme => ({\n body: {\n // remove default margin and padding from common elements\n '& h1, & h2, & h3, & h4, & h5, & h6, & p, & ul, & ol, & li': {\n margin: 0,\n padding: 0,\n },\n },\n header: {\n padding: `${theme.spacing(3)}px !important`,\n },\n errorContainer: {\n padding: theme.spacing(3),\n },\n headerMenu: {\n // align hamburger icon with title\n '& .pf-v6-c-button': {\n display: 'flex',\n alignItems: 'center',\n },\n },\n headerTitle: {\n justifyContent: 'left !important',\n },\n footer: {\n '&>.pf-chatbot__footer-container': {\n width: '95% !important',\n maxWidth: 'unset !important',\n },\n },\n footerPopover: {\n '& img': {\n maxWidth: '100%',\n },\n },\n}));\n\ntype LightspeedChatProps = {\n selectedModel: string;\n userName?: string;\n avatar?: string;\n profileLoading: boolean;\n handleSelectedModel: (item: string) => void;\n models: { label: string; value: string }[];\n};\n\nexport const LightspeedChat = ({\n selectedModel,\n userName,\n avatar,\n profileLoading,\n handleSelectedModel,\n models,\n}: LightspeedChatProps) => {\n const isMobile = useIsMobile();\n const classes = useStyles();\n const { t } = useTranslation();\n const user = useBackstageUserIdentity();\n const [filterValue, setFilterValue] = useState<string>('');\n const [announcement, setAnnouncement] = useState<string>('');\n const [conversationId, setConversationId] = useState<string>('');\n const [isDrawerOpen, setIsDrawerOpen] = useState<boolean>(!isMobile);\n const [newChatCreated, setNewChatCreated] = useState<boolean>(false);\n const [isSendButtonDisabled, setIsSendButtonDisabled] =\n useState<boolean>(false);\n const [error, setError] = useState<Error | null>(null);\n const [targetConversationId, setTargetConversationId] = useState<string>('');\n const [isDeleteModalOpen, setIsDeleteModalOpen] = useState<boolean>(false);\n const { isReady, lastOpenedId, setLastOpenedId, clearLastOpenedId } =\n useLastOpenedConversation(user);\n\n const {\n uploadError,\n showAlert,\n fileContents,\n setShowAlert,\n setFileContents,\n handleFileUpload,\n setUploadError,\n } = useFileAttachmentContext();\n\n // Sync conversationId with lastOpenedId whenever lastOpenedId changes\n useEffect(() => {\n if (isReady && lastOpenedId !== null) {\n setConversationId(lastOpenedId);\n }\n }, [lastOpenedId, isReady]);\n\n const queryClient = useQueryClient();\n\n const {\n data: conversations = [],\n isLoading,\n isRefetching,\n } = useConversations();\n const { mutateAsync: deleteConversation } = useDeleteConversation();\n const { allowed: hasDeleteAccess } = useLightspeedDeletePermission();\n const samplePrompts = useWelcomePrompts();\n useEffect(() => {\n if (user && lastOpenedId === null && isReady) {\n setConversationId(TEMP_CONVERSATION_ID);\n setNewChatCreated(true);\n }\n }, [user, isReady, lastOpenedId, setConversationId]);\n\n useEffect(() => {\n // Clear last opened conversationId when there are no conversations.\n if (\n !isLoading &&\n !isRefetching &&\n conversations.length === 0 &&\n lastOpenedId\n ) {\n clearLastOpenedId();\n }\n }, [isLoading, isRefetching, conversations, lastOpenedId, clearLastOpenedId]);\n\n useEffect(() => {\n // Update last opened conversation whenever `conversationId` changes\n if (conversationId) {\n setLastOpenedId(conversationId);\n }\n }, [conversationId, setLastOpenedId]);\n\n const onStart = (conv_id: string) => {\n setConversationId(conv_id);\n };\n\n const onComplete = (message: string) => {\n setIsSendButtonDisabled(false);\n setAnnouncement(`Message from Bot: ${message}`);\n queryClient.invalidateQueries({\n queryKey: ['conversations'],\n });\n queryClient.invalidateQueries({\n queryKey: ['conversationMessages', conversationId],\n });\n setNewChatCreated(false);\n };\n\n const { conversationMessages, handleInputPrompt, scrollToBottomRef } =\n useConversationMessages(\n conversationId,\n userName,\n selectedModel,\n avatar,\n onComplete,\n onStart,\n );\n\n const [messages, setMessages] =\n useState<MessageProps[]>(conversationMessages);\n\n const sendMessage = (message: string | number) => {\n if (conversationId !== TEMP_CONVERSATION_ID) {\n setNewChatCreated(false);\n }\n setAnnouncement(\n t('conversation.announcement.userMessage' as any, {\n prompt: message.toString(),\n }),\n );\n handleInputPrompt(message.toString(), getAttachments(fileContents));\n setIsSendButtonDisabled(true);\n setFileContents([]);\n };\n\n const onNewChat = useCallback(() => {\n (async () => {\n if (conversationId !== TEMP_CONVERSATION_ID) {\n setMessages([]);\n setFileContents([]);\n setUploadError({ message: null });\n setConversationId(TEMP_CONVERSATION_ID);\n setNewChatCreated(true);\n }\n })();\n }, [\n conversationId,\n setConversationId,\n setMessages,\n setUploadError,\n setFileContents,\n ]);\n\n const openDeleteModal = (conversation_id: string) => {\n setTargetConversationId(conversation_id);\n setIsDeleteModalOpen(true);\n };\n\n const handleDeleteConversation = useCallback(() => {\n (async () => {\n try {\n await deleteConversation({\n conversation_id: targetConversationId,\n invalidateCache: false,\n });\n if (targetConversationId === lastOpenedId) {\n onNewChat();\n clearLastOpenedId();\n }\n setIsDeleteModalOpen(false);\n } catch (e) {\n // eslint-disable-next-line no-console\n console.warn(e);\n setError(e);\n }\n })();\n }, [\n deleteConversation,\n clearLastOpenedId,\n lastOpenedId,\n onNewChat,\n targetConversationId,\n ]);\n\n const additionalMessageProps = useCallback(\n (conversationSummary: ConversationSummary) => ({\n menuItems: (\n <DropdownItem\n isDisabled={!hasDeleteAccess}\n onClick={() => openDeleteModal(conversationSummary.conversation_id)}\n >\n {t('conversation.delete')}\n </DropdownItem>\n ),\n }),\n [hasDeleteAccess, t],\n );\n const categorizedMessages = getCategorizeMessages(\n conversations,\n additionalMessageProps,\n t,\n );\n\n const filterConversations = useCallback(\n (targetValue: string) => {\n const filteredConversations = Object.entries(categorizedMessages).reduce(\n (acc, [key, items]) => {\n const filteredItems = items.filter(item =>\n item.text\n .toLocaleLowerCase('en-US')\n .includes(targetValue.toLocaleLowerCase('en-US')),\n );\n if (filteredItems.length > 0) {\n acc[key] = filteredItems;\n }\n return acc;\n },\n {} as any,\n );\n return filteredConversations;\n },\n [categorizedMessages],\n );\n\n useEffect(() => {\n setMessages(conversationMessages);\n }, [conversationMessages]);\n\n const onSelectActiveItem = useCallback(\n (_: MouseEvent | undefined, selectedItem: string | number | undefined) => {\n setNewChatCreated(false);\n setConversationId((c_id: string) => {\n if (c_id !== selectedItem) {\n return String(selectedItem);\n }\n return c_id;\n });\n setFileContents([]);\n setUploadError({ message: null });\n scrollToBottomRef.current?.scrollToBottom();\n },\n [setConversationId, setUploadError, setFileContents, scrollToBottomRef],\n );\n\n const conversationFound = !!conversations.find(\n (c: ConversationSummary) => c.conversation_id === conversationId,\n );\n\n const welcomePrompts =\n (newChatCreated && conversationMessages.length === 0) ||\n (!conversationFound && conversationMessages.length === 0)\n ? samplePrompts?.map(prompt => {\n const p = prompt as { title: string; message: string };\n return {\n title: p.title,\n message: p.message,\n onClick: () => {\n sendMessage(p.message);\n },\n };\n })\n : [];\n\n const handleFilter = useCallback((value: string) => {\n setFilterValue(value);\n }, []);\n\n const onDrawerToggle = useCallback(() => {\n setIsDrawerOpen(isOpen => !isOpen);\n }, []);\n\n const handleAttach = (data: File[], event: DropEvent) => {\n event.preventDefault();\n handleFileUpload(data);\n };\n\n const onAttachRejected = (data: FileRejection[]) => {\n data.forEach(attachment => {\n if (!!attachment.errors.find(e => e.code === 'file-invalid-type')) {\n setShowAlert(true);\n setUploadError({\n message: t('file.upload.error.unsupportedType'),\n });\n }\n });\n };\n\n if (error) {\n return (\n <Box padding={1}>\n <ErrorPanel error={error} />\n </Box>\n );\n }\n\n return (\n <>\n {isDeleteModalOpen && (\n <DeleteModal\n isOpen={isDeleteModalOpen}\n onClose={() => setIsDeleteModalOpen(false)}\n onConfirm={handleDeleteConversation}\n />\n )}\n <Chatbot\n displayMode={ChatbotDisplayMode.embedded}\n className={classes.body}\n >\n <ChatbotHeader className={classes.header}>\n <ChatbotHeaderMain>\n <ChatbotHeaderMenu\n aria-expanded={isDrawerOpen}\n onMenuToggle={() => setIsDrawerOpen(!isDrawerOpen)}\n className={classes.headerMenu}\n />\n <ChatbotHeaderTitle className={classes.headerTitle}>\n <Title headingLevel=\"h1\" size=\"3xl\">\n {t('chatbox.header.title')}\n </Title>\n </ChatbotHeaderTitle>\n </ChatbotHeaderMain>\n\n <LightspeedChatBoxHeader\n selectedModel={selectedModel}\n handleSelectedModel={item => handleSelectedModel(item)}\n models={models}\n />\n </ChatbotHeader>\n <ChatbotConversationHistoryNav\n drawerPanelContentProps={{ isResizable: true, minSize: '200px' }}\n reverseButtonOrder\n displayMode={ChatbotDisplayMode.embedded}\n onDrawerToggle={onDrawerToggle}\n isDrawerOpen={isDrawerOpen}\n setIsDrawerOpen={setIsDrawerOpen}\n activeItemId={conversationId}\n onSelectActiveItem={onSelectActiveItem}\n conversations={filterConversations(filterValue)}\n onNewChat={newChatCreated ? undefined : onNewChat}\n newChatButtonText={t('button.newChat')}\n handleTextInputChange={handleFilter}\n searchInputPlaceholder={t('chatbox.search.placeholder')}\n drawerContent={\n <FileDropZone\n onFileDrop={(e, data) => handleAttach(data, e)}\n displayMode={ChatbotDisplayMode.embedded}\n infoText={t('chatbox.fileUpload.infoText')}\n allowedFileTypes={supportedFileTypes}\n onAttachRejected={onAttachRejected}\n >\n {showAlert && uploadError.message && (\n <div className={classes.errorContainer}>\n <ChatbotAlert\n component=\"h4\"\n title={t('chatbox.fileUpload.failed')}\n variant={uploadError.type ?? 'danger'}\n isInline\n onClose={() => setUploadError({ message: null })}\n >\n {uploadError.message}\n </ChatbotAlert>\n </div>\n )}\n\n <ChatbotContent>\n <LightspeedChatBox\n userName={userName}\n messages={messages}\n profileLoading={profileLoading}\n announcement={announcement}\n ref={scrollToBottomRef}\n welcomePrompts={welcomePrompts}\n conversationId={conversationId}\n isStreaming={isSendButtonDisabled}\n />\n </ChatbotContent>\n <ChatbotFooter className={classes.footer}>\n <FilePreview />\n <MessageBar\n onSendMessage={sendMessage}\n isSendButtonDisabled={isSendButtonDisabled}\n hasAttachButton\n handleAttach={handleAttach}\n hasMicrophoneButton\n buttonProps={{\n attach: {\n inputTestId: 'attachment-input',\n tooltipContent: t('tooltip.attach'),\n },\n microphone: {\n tooltipContent: {\n active: t('tooltip.microphone.active'),\n inactive: t('tooltip.microphone.inactive'),\n },\n },\n send: {\n tooltipContent: t('tooltip.send'),\n },\n }}\n allowedFileTypes={supportedFileTypes}\n onAttachRejected={onAttachRejected}\n placeholder={t('chatbox.message.placeholder')}\n />\n <ChatbotFootnote\n {...getFootnoteProps(classes.footerPopover, t)}\n />\n </ChatbotFooter>\n </FileDropZone>\n }\n />\n </Chatbot>\n <Attachment />\n </>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkEA,MAAM,SAAA,GAAY,WAAW,CAAU,KAAA,MAAA;AAAA,EACrC,IAAM,EAAA;AAAA;AAAA,IAEJ,2DAA6D,EAAA;AAAA,MAC3D,MAAQ,EAAA,CAAA;AAAA,MACR,OAAS,EAAA;AAAA;AACX,GACF;AAAA,EACA,MAAQ,EAAA;AAAA,IACN,OAAS,EAAA,CAAA,EAAG,KAAM,CAAA,OAAA,CAAQ,CAAC,CAAC,CAAA,aAAA;AAAA,GAC9B;AAAA,EACA,cAAgB,EAAA;AAAA,IACd,OAAA,EAAS,KAAM,CAAA,OAAA,CAAQ,CAAC;AAAA,GAC1B;AAAA,EACA,UAAY,EAAA;AAAA;AAAA,IAEV,mBAAqB,EAAA;AAAA,MACnB,OAAS,EAAA,MAAA;AAAA,MACT,UAAY,EAAA;AAAA;AACd,GACF;AAAA,EACA,WAAa,EAAA;AAAA,IACX,cAAgB,EAAA;AAAA,GAClB;AAAA,EACA,MAAQ,EAAA;AAAA,IACN,iCAAmC,EAAA;AAAA,MACjC,KAAO,EAAA,gBAAA;AAAA,MACP,QAAU,EAAA;AAAA;AACZ,GACF;AAAA,EACA,aAAe,EAAA;AAAA,IACb,OAAS,EAAA;AAAA,MACP,QAAU,EAAA;AAAA;AACZ;AAEJ,CAAE,CAAA,CAAA;AAWK,MAAM,iBAAiB,CAAC;AAAA,EAC7B,aAAA;AAAA,EACA,QAAA;AAAA,EACA,MAAA;AAAA,EACA,cAAA;AAAA,EACA,mBAAA;AAAA,EACA;AACF,CAA2B,KAAA;AACzB,EAAA,MAAM,WAAW,WAAY,EAAA;AAC7B,EAAA,MAAM,UAAU,SAAU,EAAA;AAC1B,EAAM,MAAA,EAAE,CAAE,EAAA,GAAI,cAAe,EAAA;AAC7B,EAAA,MAAM,OAAO,wBAAyB,EAAA;AACtC,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAI,SAAiB,EAAE,CAAA;AACzD,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAI,SAAiB,EAAE,CAAA;AAC3D,EAAA,MAAM,CAAC,cAAA,EAAgB,iBAAiB,CAAA,GAAI,SAAiB,EAAE,CAAA;AAC/D,EAAA,MAAM,CAAC,YAAc,EAAA,eAAe,CAAI,GAAA,QAAA,CAAkB,CAAC,QAAQ,CAAA;AACnE,EAAA,MAAM,CAAC,cAAA,EAAgB,iBAAiB,CAAA,GAAI,SAAkB,KAAK,CAAA;AACnE,EAAA,MAAM,CAAC,oBAAA,EAAsB,uBAAuB,CAAA,GAClD,SAAkB,KAAK,CAAA;AACzB,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAAuB,IAAI,CAAA;AACrD,EAAA,MAAM,CAAC,oBAAA,EAAsB,uBAAuB,CAAA,GAAI,SAAiB,EAAE,CAAA;AAC3E,EAAA,MAAM,CAAC,iBAAA,EAAmB,oBAAoB,CAAA,GAAI,SAAkB,KAAK,CAAA;AACzE,EAAA,MAAM,EAAE,OAAS,EAAA,YAAA,EAAc,iBAAiB,iBAAkB,EAAA,GAChE,0BAA0B,IAAI,CAAA;AAEhC,EAAM,MAAA;AAAA,IACJ,WAAA;AAAA,IACA,SAAA;AAAA,IACA,YAAA;AAAA,IACA,YAAA;AAAA,IACA,eAAA;AAAA,IACA,gBAAA;AAAA,IACA;AAAA,MACE,wBAAyB,EAAA;AAG7B,EAAA,SAAA,CAAU,MAAM;AACd,IAAI,IAAA,OAAA,IAAW,iBAAiB,IAAM,EAAA;AACpC,MAAA,iBAAA,CAAkB,YAAY,CAAA;AAAA;AAChC,GACC,EAAA,CAAC,YAAc,EAAA,OAAO,CAAC,CAAA;AAE1B,EAAA,MAAM,cAAc,cAAe,EAAA;AAEnC,EAAM,MAAA;AAAA,IACJ,IAAA,EAAM,gBAAgB,EAAC;AAAA,IACvB,SAAA;AAAA,IACA;AAAA,MACE,gBAAiB,EAAA;AACrB,EAAA,MAAM,EAAE,WAAA,EAAa,kBAAmB,EAAA,GAAI,qBAAsB,EAAA;AAClE,EAAA,MAAM,EAAE,OAAA,EAAS,eAAgB,EAAA,GAAI,6BAA8B,EAAA;AACnE,EAAA,MAAM,gBAAgB,iBAAkB,EAAA;AACxC,EAAA,SAAA,CAAU,MAAM;AACd,IAAI,IAAA,IAAA,IAAQ,YAAiB,KAAA,IAAA,IAAQ,OAAS,EAAA;AAC5C,MAAA,iBAAA,CAAkB,oBAAoB,CAAA;AACtC,MAAA,iBAAA,CAAkB,IAAI,CAAA;AAAA;AACxB,KACC,CAAC,IAAA,EAAM,OAAS,EAAA,YAAA,EAAc,iBAAiB,CAAC,CAAA;AAEnD,EAAA,SAAA,CAAU,MAAM;AAEd,IAAA,IACE,CAAC,SACD,IAAA,CAAC,gBACD,aAAc,CAAA,MAAA,KAAW,KACzB,YACA,EAAA;AACA,MAAkB,iBAAA,EAAA;AAAA;AACpB,KACC,CAAC,SAAA,EAAW,cAAc,aAAe,EAAA,YAAA,EAAc,iBAAiB,CAAC,CAAA;AAE5E,EAAA,SAAA,CAAU,MAAM;AAEd,IAAA,IAAI,cAAgB,EAAA;AAClB,MAAA,eAAA,CAAgB,cAAc,CAAA;AAAA;AAChC,GACC,EAAA,CAAC,cAAgB,EAAA,eAAe,CAAC,CAAA;AAEpC,EAAM,MAAA,OAAA,GAAU,CAAC,OAAoB,KAAA;AACnC,IAAA,iBAAA,CAAkB,OAAO,CAAA;AAAA,GAC3B;AAEA,EAAM,MAAA,UAAA,GAAa,CAAC,OAAoB,KAAA;AACtC,IAAA,uBAAA,CAAwB,KAAK,CAAA;AAC7B,IAAgB,eAAA,CAAA,CAAA,kBAAA,EAAqB,OAAO,CAAE,CAAA,CAAA;AAC9C,IAAA,WAAA,CAAY,iBAAkB,CAAA;AAAA,MAC5B,QAAA,EAAU,CAAC,eAAe;AAAA,KAC3B,CAAA;AACD,IAAA,WAAA,CAAY,iBAAkB,CAAA;AAAA,MAC5B,QAAA,EAAU,CAAC,sBAAA,EAAwB,cAAc;AAAA,KAClD,CAAA;AACD,IAAA,iBAAA,CAAkB,KAAK,CAAA;AAAA,GACzB;AAEA,EAAA,MAAM,EAAE,oBAAA,EAAsB,iBAAmB,EAAA,iBAAA,EAC/C,GAAA,uBAAA;AAAA,IACE,cAAA;AAAA,IACA,QAAA;AAAA,IACA,aAAA;AAAA,IACA,MAAA;AAAA,IACA,UAAA;AAAA,IACA;AAAA,GACF;AAEF,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAC1B,SAAyB,oBAAoB,CAAA;AAE/C,EAAM,MAAA,WAAA,GAAc,CAAC,OAA6B,KAAA;AAChD,IAAA,IAAI,mBAAmB,oBAAsB,EAAA;AAC3C,MAAA,iBAAA,CAAkB,KAAK,CAAA;AAAA;AAEzB,IAAA,eAAA;AAAA,MACE,EAAE,uCAAgD,EAAA;AAAA,QAChD,MAAA,EAAQ,QAAQ,QAAS;AAAA,OAC1B;AAAA,KACH;AACA,IAAA,iBAAA,CAAkB,OAAQ,CAAA,QAAA,EAAY,EAAA,cAAA,CAAe,YAAY,CAAC,CAAA;AAClE,IAAA,uBAAA,CAAwB,IAAI,CAAA;AAC5B,IAAA,eAAA,CAAgB,EAAE,CAAA;AAAA,GACpB;AAEA,EAAM,MAAA,SAAA,GAAY,YAAY,MAAM;AAClC,IAAA,CAAC,YAAY;AACX,MAAA,IAAI,mBAAmB,oBAAsB,EAAA;AAC3C,QAAA,WAAA,CAAY,EAAE,CAAA;AACd,QAAA,eAAA,CAAgB,EAAE,CAAA;AAClB,QAAe,cAAA,CAAA,EAAE,OAAS,EAAA,IAAA,EAAM,CAAA;AAChC,QAAA,iBAAA,CAAkB,oBAAoB,CAAA;AACtC,QAAA,iBAAA,CAAkB,IAAI,CAAA;AAAA;AACxB,KACC,GAAA;AAAA,GACF,EAAA;AAAA,IACD,cAAA;AAAA,IACA,iBAAA;AAAA,IACA,WAAA;AAAA,IACA,cAAA;AAAA,IACA;AAAA,GACD,CAAA;AAED,EAAM,MAAA,eAAA,GAAkB,CAAC,eAA4B,KAAA;AACnD,IAAA,uBAAA,CAAwB,eAAe,CAAA;AACvC,IAAA,oBAAA,CAAqB,IAAI,CAAA;AAAA,GAC3B;AAEA,EAAM,MAAA,wBAAA,GAA2B,YAAY,MAAM;AACjD,IAAA,CAAC,YAAY;AACX,MAAI,IAAA;AACF,QAAA,MAAM,kBAAmB,CAAA;AAAA,UACvB,eAAiB,EAAA,oBAAA;AAAA,UACjB,eAAiB,EAAA;AAAA,SAClB,CAAA;AACD,QAAA,IAAI,yBAAyB,YAAc,EAAA;AACzC,UAAU,SAAA,EAAA;AACV,UAAkB,iBAAA,EAAA;AAAA;AAEpB,QAAA,oBAAA,CAAqB,KAAK,CAAA;AAAA,eACnB,CAAG,EAAA;AAEV,QAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AACd,QAAA,QAAA,CAAS,CAAC,CAAA;AAAA;AACZ,KACC,GAAA;AAAA,GACF,EAAA;AAAA,IACD,kBAAA;AAAA,IACA,iBAAA;AAAA,IACA,YAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,GACD,CAAA;AAED,EAAA,MAAM,sBAAyB,GAAA,WAAA;AAAA,IAC7B,CAAC,mBAA8C,MAAA;AAAA,MAC7C,SACE,kBAAA,GAAA;AAAA,QAAC,YAAA;AAAA,QAAA;AAAA,UACC,YAAY,CAAC,eAAA;AAAA,UACb,OAAS,EAAA,MAAM,eAAgB,CAAA,mBAAA,CAAoB,eAAe,CAAA;AAAA,UAEjE,YAAE,qBAAqB;AAAA;AAAA;AAC1B,KAEJ,CAAA;AAAA,IACA,CAAC,iBAAiB,CAAC;AAAA,GACrB;AACA,EAAA,MAAM,mBAAsB,GAAA,qBAAA;AAAA,IAC1B,aAAA;AAAA,IACA,sBAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,MAAM,mBAAsB,GAAA,WAAA;AAAA,IAC1B,CAAC,WAAwB,KAAA;AACvB,MAAA,MAAM,qBAAwB,GAAA,MAAA,CAAO,OAAQ,CAAA,mBAAmB,CAAE,CAAA,MAAA;AAAA,QAChE,CAAC,GAAA,EAAK,CAAC,GAAA,EAAK,KAAK,CAAM,KAAA;AACrB,UAAA,MAAM,gBAAgB,KAAM,CAAA,MAAA;AAAA,YAAO,CAAA,IAAA,KACjC,IAAK,CAAA,IAAA,CACF,iBAAkB,CAAA,OAAO,EACzB,QAAS,CAAA,WAAA,CAAY,iBAAkB,CAAA,OAAO,CAAC;AAAA,WACpD;AACA,UAAI,IAAA,aAAA,CAAc,SAAS,CAAG,EAAA;AAC5B,YAAA,GAAA,CAAI,GAAG,CAAI,GAAA,aAAA;AAAA;AAEb,UAAO,OAAA,GAAA;AAAA,SACT;AAAA,QACA;AAAC,OACH;AACA,MAAO,OAAA,qBAAA;AAAA,KACT;AAAA,IACA,CAAC,mBAAmB;AAAA,GACtB;AAEA,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,WAAA,CAAY,oBAAoB,CAAA;AAAA,GAClC,EAAG,CAAC,oBAAoB,CAAC,CAAA;AAEzB,EAAA,MAAM,kBAAqB,GAAA,WAAA;AAAA,IACzB,CAAC,GAA2B,YAA8C,KAAA;AACxE,MAAA,iBAAA,CAAkB,KAAK,CAAA;AACvB,MAAA,iBAAA,CAAkB,CAAC,IAAiB,KAAA;AAClC,QAAA,IAAI,SAAS,YAAc,EAAA;AACzB,UAAA,OAAO,OAAO,YAAY,CAAA;AAAA;AAE5B,QAAO,OAAA,IAAA;AAAA,OACR,CAAA;AACD,MAAA,eAAA,CAAgB,EAAE,CAAA;AAClB,MAAe,cAAA,CAAA,EAAE,OAAS,EAAA,IAAA,EAAM,CAAA;AAChC,MAAA,iBAAA,CAAkB,SAAS,cAAe,EAAA;AAAA,KAC5C;AAAA,IACA,CAAC,iBAAA,EAAmB,cAAgB,EAAA,eAAA,EAAiB,iBAAiB;AAAA,GACxE;AAEA,EAAM,MAAA,iBAAA,GAAoB,CAAC,CAAC,aAAc,CAAA,IAAA;AAAA,IACxC,CAAC,CAA2B,KAAA,CAAA,CAAE,eAAoB,KAAA;AAAA,GACpD;AAEA,EAAA,MAAM,cACH,GAAA,cAAA,IAAkB,oBAAqB,CAAA,MAAA,KAAW,CAClD,IAAA,CAAC,iBAAqB,IAAA,oBAAA,CAAqB,MAAW,KAAA,CAAA,GACnD,aAAe,EAAA,GAAA,CAAI,CAAU,MAAA,KAAA;AAC3B,IAAA,MAAM,CAAI,GAAA,MAAA;AACV,IAAO,OAAA;AAAA,MACL,OAAO,CAAE,CAAA,KAAA;AAAA,MACT,SAAS,CAAE,CAAA,OAAA;AAAA,MACX,SAAS,MAAM;AACb,QAAA,WAAA,CAAY,EAAE,OAAO,CAAA;AAAA;AACvB,KACF;AAAA,GACD,IACD,EAAC;AAEP,EAAM,MAAA,YAAA,GAAe,WAAY,CAAA,CAAC,KAAkB,KAAA;AAClD,IAAA,cAAA,CAAe,KAAK,CAAA;AAAA,GACtB,EAAG,EAAE,CAAA;AAEL,EAAM,MAAA,cAAA,GAAiB,YAAY,MAAM;AACvC,IAAgB,eAAA,CAAA,CAAA,MAAA,KAAU,CAAC,MAAM,CAAA;AAAA,GACnC,EAAG,EAAE,CAAA;AAEL,EAAM,MAAA,YAAA,GAAe,CAAC,IAAA,EAAc,KAAqB,KAAA;AACvD,IAAA,KAAA,CAAM,cAAe,EAAA;AACrB,IAAA,gBAAA,CAAiB,IAAI,CAAA;AAAA,GACvB;AAEA,EAAM,MAAA,gBAAA,GAAmB,CAAC,IAA0B,KAAA;AAClD,IAAA,IAAA,CAAK,QAAQ,CAAc,UAAA,KAAA;AACzB,MAAI,IAAA,CAAC,CAAC,UAAW,CAAA,MAAA,CAAO,KAAK,CAAK,CAAA,KAAA,CAAA,CAAE,IAAS,KAAA,mBAAmB,CAAG,EAAA;AACjE,QAAA,YAAA,CAAa,IAAI,CAAA;AACjB,QAAe,cAAA,CAAA;AAAA,UACb,OAAA,EAAS,EAAE,mCAAmC;AAAA,SAC/C,CAAA;AAAA;AACH,KACD,CAAA;AAAA,GACH;AAEA,EAAA,IAAI,KAAO,EAAA;AACT,IAAA,2BACG,GAAI,EAAA,EAAA,OAAA,EAAS,GACZ,QAAC,kBAAA,GAAA,CAAA,UAAA,EAAA,EAAW,OAAc,CAC5B,EAAA,CAAA;AAAA;AAIJ,EAAA,uBAEK,IAAA,CAAA,QAAA,EAAA,EAAA,QAAA,EAAA;AAAA,IACC,iBAAA,oBAAA,GAAA;AAAA,MAAC,WAAA;AAAA,MAAA;AAAA,QACC,MAAQ,EAAA,iBAAA;AAAA,QACR,OAAA,EAAS,MAAM,oBAAA,CAAqB,KAAK,CAAA;AAAA,QACzC,SAAW,EAAA;AAAA;AAAA,KACb;AAAA,oBAEF,IAAA;AAAA,MAAC,OAAA;AAAA,MAAA;AAAA,QACC,aAAa,kBAAmB,CAAA,QAAA;AAAA,QAChC,WAAW,OAAQ,CAAA,IAAA;AAAA,QAEnB,QAAA,EAAA;AAAA,0BAAC,IAAA,CAAA,aAAA,EAAA,EAAc,SAAW,EAAA,OAAA,CAAQ,MAChC,EAAA,QAAA,EAAA;AAAA,4BAAA,IAAA,CAAC,iBACC,EAAA,EAAA,QAAA,EAAA;AAAA,8BAAA,GAAA;AAAA,gBAAC,iBAAA;AAAA,gBAAA;AAAA,kBACC,eAAe,EAAA,YAAA;AAAA,kBACf,YAAc,EAAA,MAAM,eAAgB,CAAA,CAAC,YAAY,CAAA;AAAA,kBACjD,WAAW,OAAQ,CAAA;AAAA;AAAA,eACrB;AAAA,8BACC,GAAA,CAAA,kBAAA,EAAA,EAAmB,SAAW,EAAA,OAAA,CAAQ,aACrC,QAAC,kBAAA,GAAA,CAAA,KAAA,EAAA,EAAM,YAAa,EAAA,IAAA,EAAK,IAAK,EAAA,KAAA,EAC3B,QAAE,EAAA,CAAA,CAAA,sBAAsB,GAC3B,CACF,EAAA;AAAA,aACF,EAAA,CAAA;AAAA,4BAEA,GAAA;AAAA,cAAC,uBAAA;AAAA,cAAA;AAAA,gBACC,aAAA;AAAA,gBACA,mBAAA,EAAqB,CAAQ,IAAA,KAAA,mBAAA,CAAoB,IAAI,CAAA;AAAA,gBACrD;AAAA;AAAA;AACF,WACF,EAAA,CAAA;AAAA,0BACA,GAAA;AAAA,YAAC,6BAAA;AAAA,YAAA;AAAA,cACC,uBAAyB,EAAA,EAAE,WAAa,EAAA,IAAA,EAAM,SAAS,OAAQ,EAAA;AAAA,cAC/D,kBAAkB,EAAA,IAAA;AAAA,cAClB,aAAa,kBAAmB,CAAA,QAAA;AAAA,cAChC,cAAA;AAAA,cACA,YAAA;AAAA,cACA,eAAA;AAAA,cACA,YAAc,EAAA,cAAA;AAAA,cACd,kBAAA;AAAA,cACA,aAAA,EAAe,oBAAoB,WAAW,CAAA;AAAA,cAC9C,SAAA,EAAW,iBAAiB,SAAY,GAAA,SAAA;AAAA,cACxC,iBAAA,EAAmB,EAAE,gBAAgB,CAAA;AAAA,cACrC,qBAAuB,EAAA,YAAA;AAAA,cACvB,sBAAA,EAAwB,EAAE,4BAA4B,CAAA;AAAA,cACtD,aACE,kBAAA,IAAA;AAAA,gBAAC,YAAA;AAAA,gBAAA;AAAA,kBACC,YAAY,CAAC,CAAA,EAAG,IAAS,KAAA,YAAA,CAAa,MAAM,CAAC,CAAA;AAAA,kBAC7C,aAAa,kBAAmB,CAAA,QAAA;AAAA,kBAChC,QAAA,EAAU,EAAE,6BAA6B,CAAA;AAAA,kBACzC,gBAAkB,EAAA,kBAAA;AAAA,kBAClB,gBAAA;AAAA,kBAEC,QAAA,EAAA;AAAA,oBAAA,SAAA,IAAa,YAAY,OACxB,oBAAA,GAAA,CAAC,KAAI,EAAA,EAAA,SAAA,EAAW,QAAQ,cACtB,EAAA,QAAA,kBAAA,GAAA;AAAA,sBAAC,YAAA;AAAA,sBAAA;AAAA,wBACC,SAAU,EAAA,IAAA;AAAA,wBACV,KAAA,EAAO,EAAE,2BAA2B,CAAA;AAAA,wBACpC,OAAA,EAAS,YAAY,IAAQ,IAAA,QAAA;AAAA,wBAC7B,QAAQ,EAAA,IAAA;AAAA,wBACR,SAAS,MAAM,cAAA,CAAe,EAAE,OAAA,EAAS,MAAM,CAAA;AAAA,wBAE9C,QAAY,EAAA,WAAA,CAAA;AAAA;AAAA,qBAEjB,EAAA,CAAA;AAAA,wCAGD,cACC,EAAA,EAAA,QAAA,kBAAA,GAAA;AAAA,sBAAC,iBAAA;AAAA,sBAAA;AAAA,wBACC,QAAA;AAAA,wBACA,QAAA;AAAA,wBACA,cAAA;AAAA,wBACA,YAAA;AAAA,wBACA,GAAK,EAAA,iBAAA;AAAA,wBACL,cAAA;AAAA,wBACA,cAAA;AAAA,wBACA,WAAa,EAAA;AAAA;AAAA,qBAEjB,EAAA,CAAA;AAAA,oCACC,IAAA,CAAA,aAAA,EAAA,EAAc,SAAW,EAAA,OAAA,CAAQ,MAChC,EAAA,QAAA,EAAA;AAAA,sCAAA,GAAA,CAAC,WAAY,EAAA,EAAA,CAAA;AAAA,sCACb,GAAA;AAAA,wBAAC,UAAA;AAAA,wBAAA;AAAA,0BACC,aAAe,EAAA,WAAA;AAAA,0BACf,oBAAA;AAAA,0BACA,eAAe,EAAA,IAAA;AAAA,0BACf,YAAA;AAAA,0BACA,mBAAmB,EAAA,IAAA;AAAA,0BACnB,WAAa,EAAA;AAAA,4BACX,MAAQ,EAAA;AAAA,8BACN,WAAa,EAAA,kBAAA;AAAA,8BACb,cAAA,EAAgB,EAAE,gBAAgB;AAAA,6BACpC;AAAA,4BACA,UAAY,EAAA;AAAA,8BACV,cAAgB,EAAA;AAAA,gCACd,MAAA,EAAQ,EAAE,2BAA2B,CAAA;AAAA,gCACrC,QAAA,EAAU,EAAE,6BAA6B;AAAA;AAC3C,6BACF;AAAA,4BACA,IAAM,EAAA;AAAA,8BACJ,cAAA,EAAgB,EAAE,cAAc;AAAA;AAClC,2BACF;AAAA,0BACA,gBAAkB,EAAA,kBAAA;AAAA,0BAClB,gBAAA;AAAA,0BACA,WAAA,EAAa,EAAE,6BAA6B;AAAA;AAAA,uBAC9C;AAAA,sCACA,GAAA;AAAA,wBAAC,eAAA;AAAA,wBAAA;AAAA,0BACE,GAAG,gBAAA,CAAiB,OAAQ,CAAA,aAAA,EAAe,CAAC;AAAA;AAAA;AAC/C,qBACF,EAAA;AAAA;AAAA;AAAA;AACF;AAAA;AAEJ;AAAA;AAAA,KACF;AAAA,wBACC,UAAW,EAAA,EAAA;AAAA,GACd,EAAA,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"LightSpeedChat.esm.js","sources":["../../src/components/LightSpeedChat.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { MouseEvent, useCallback, useEffect, useState } from 'react';\nimport { FileRejection } from 'react-dropzone/.';\n\nimport { ErrorPanel } from '@backstage/core-components';\n\nimport { Box, makeStyles } from '@material-ui/core';\nimport {\n Chatbot,\n ChatbotAlert,\n ChatbotContent,\n ChatbotDisplayMode,\n ChatbotFooter,\n ChatbotFootnote,\n ChatbotHeader,\n ChatbotHeaderMain,\n ChatbotHeaderMenu,\n ChatbotHeaderTitle,\n FileDropZone,\n MessageBar,\n MessageProps,\n} from '@patternfly/chatbot';\nimport ChatbotConversationHistoryNav from '@patternfly/chatbot/dist/dynamic/ChatbotConversationHistoryNav';\nimport { DropdownItem, DropEvent, Title } from '@patternfly/react-core';\nimport { SearchIcon } from '@patternfly/react-icons';\nimport { useQueryClient } from '@tanstack/react-query';\n\nimport { supportedFileTypes, TEMP_CONVERSATION_ID } from '../const';\nimport {\n useBackstageUserIdentity,\n useConversationMessages,\n useConversations,\n useDeleteConversation,\n useIsMobile,\n useLastOpenedConversation,\n useLightspeedDeletePermission,\n} from '../hooks';\nimport { useTranslation } from '../hooks/useTranslation';\nimport { useWelcomePrompts } from '../hooks/useWelcomePrompts';\nimport { ConversationSummary } from '../types';\nimport { getAttachments } from '../utils/attachment-utils';\nimport {\n getCategorizeMessages,\n getFootnoteProps,\n} from '../utils/lightspeed-chatbox-utils';\nimport Attachment from './Attachment';\nimport { useFileAttachmentContext } from './AttachmentContext';\nimport { DeleteModal } from './DeleteModal';\nimport FilePreview from './FilePreview';\nimport { LightspeedChatBox } from './LightspeedChatBox';\nimport { LightspeedChatBoxHeader } from './LightspeedChatBoxHeader';\n\nconst useStyles = makeStyles(theme => ({\n body: {\n // remove default margin and padding from common elements\n '& h1, & h2, & h3, & h4, & h5, & h6, & p, & ul, & ol, & li': {\n margin: 0,\n padding: 0,\n },\n },\n header: {\n padding: `${theme.spacing(3)}px !important`,\n },\n errorContainer: {\n padding: theme.spacing(3),\n },\n headerMenu: {\n // align hamburger icon with title\n '& .pf-v6-c-button': {\n display: 'flex',\n alignItems: 'center',\n },\n },\n headerTitle: {\n justifyContent: 'left !important',\n },\n footer: {\n '&>.pf-chatbot__footer-container': {\n width: '95% !important',\n maxWidth: 'unset !important',\n },\n },\n footerPopover: {\n '& img': {\n maxWidth: '100%',\n },\n },\n}));\n\ntype LightspeedChatProps = {\n selectedModel: string;\n topicRestrictionEnabled: boolean;\n selectedProvider: string;\n userName?: string;\n avatar?: string;\n profileLoading: boolean;\n handleSelectedModel: (item: string) => void;\n models: { label: string; value: string; provider: string }[];\n};\n\nexport const LightspeedChat = ({\n selectedModel,\n topicRestrictionEnabled,\n selectedProvider,\n userName,\n avatar,\n profileLoading,\n handleSelectedModel,\n models,\n}: LightspeedChatProps) => {\n const isMobile = useIsMobile();\n const classes = useStyles();\n const { t } = useTranslation();\n const user = useBackstageUserIdentity();\n const [filterValue, setFilterValue] = useState<string>('');\n const [announcement, setAnnouncement] = useState<string>('');\n const [conversationId, setConversationId] = useState<string>('');\n const [isDrawerOpen, setIsDrawerOpen] = useState<boolean>(!isMobile);\n const [newChatCreated, setNewChatCreated] = useState<boolean>(false);\n const [isSendButtonDisabled, setIsSendButtonDisabled] =\n useState<boolean>(false);\n const [error, setError] = useState<Error | null>(null);\n const [targetConversationId, setTargetConversationId] = useState<string>('');\n const [isDeleteModalOpen, setIsDeleteModalOpen] = useState<boolean>(false);\n const { isReady, lastOpenedId, setLastOpenedId, clearLastOpenedId } =\n useLastOpenedConversation(user);\n\n const {\n uploadError,\n showAlert,\n fileContents,\n setShowAlert,\n setFileContents,\n handleFileUpload,\n setUploadError,\n } = useFileAttachmentContext();\n\n // Sync conversationId with lastOpenedId whenever lastOpenedId changes\n useEffect(() => {\n if (isReady && lastOpenedId !== null) {\n setConversationId(lastOpenedId);\n }\n }, [lastOpenedId, isReady]);\n\n const queryClient = useQueryClient();\n\n const {\n data: conversations = [],\n isLoading,\n isRefetching,\n } = useConversations();\n const { mutateAsync: deleteConversation } = useDeleteConversation();\n const { allowed: hasDeleteAccess } = useLightspeedDeletePermission();\n const samplePrompts = useWelcomePrompts();\n useEffect(() => {\n if (user && lastOpenedId === null && isReady) {\n setConversationId(TEMP_CONVERSATION_ID);\n setNewChatCreated(true);\n }\n }, [user, isReady, lastOpenedId, setConversationId]);\n\n useEffect(() => {\n // Clear last opened conversationId when there are no conversations.\n if (\n !isLoading &&\n !isRefetching &&\n conversations.length === 0 &&\n lastOpenedId\n ) {\n clearLastOpenedId();\n }\n }, [isLoading, isRefetching, conversations, lastOpenedId, clearLastOpenedId]);\n\n useEffect(() => {\n // Update last opened conversation whenever `conversationId` changes\n if (conversationId) {\n setLastOpenedId(conversationId);\n }\n }, [conversationId, setLastOpenedId]);\n\n const onStart = (conv_id: string) => {\n setConversationId(conv_id);\n };\n\n const onComplete = (message: string) => {\n setIsSendButtonDisabled(false);\n setAnnouncement(`Message from Bot: ${message}`);\n queryClient.invalidateQueries({\n queryKey: ['conversations'],\n });\n queryClient.invalidateQueries({\n queryKey: ['conversationMessages', conversationId],\n });\n setNewChatCreated(false);\n };\n\n const { conversationMessages, handleInputPrompt, scrollToBottomRef } =\n useConversationMessages(\n conversationId,\n userName,\n selectedModel,\n selectedProvider,\n avatar,\n onComplete,\n onStart,\n );\n\n const [messages, setMessages] =\n useState<MessageProps[]>(conversationMessages);\n\n const sendMessage = (message: string | number) => {\n if (conversationId !== TEMP_CONVERSATION_ID) {\n setNewChatCreated(false);\n }\n setAnnouncement(\n t('conversation.announcement.userMessage' as any, {\n prompt: message.toString(),\n }),\n );\n handleInputPrompt(message.toString(), getAttachments(fileContents));\n setIsSendButtonDisabled(true);\n setFileContents([]);\n };\n\n const onNewChat = useCallback(() => {\n (async () => {\n if (conversationId !== TEMP_CONVERSATION_ID) {\n setMessages([]);\n setFileContents([]);\n setUploadError({ message: null });\n setConversationId(TEMP_CONVERSATION_ID);\n setNewChatCreated(true);\n }\n })();\n }, [\n conversationId,\n setConversationId,\n setMessages,\n setUploadError,\n setFileContents,\n ]);\n\n const openDeleteModal = (conversation_id: string) => {\n setTargetConversationId(conversation_id);\n setIsDeleteModalOpen(true);\n };\n\n const handleDeleteConversation = useCallback(() => {\n (async () => {\n try {\n await deleteConversation({\n conversation_id: targetConversationId,\n invalidateCache: false,\n });\n if (targetConversationId === lastOpenedId) {\n onNewChat();\n clearLastOpenedId();\n }\n setIsDeleteModalOpen(false);\n } catch (e) {\n // eslint-disable-next-line no-console\n console.warn(e);\n setError(e);\n }\n })();\n }, [\n deleteConversation,\n clearLastOpenedId,\n lastOpenedId,\n onNewChat,\n targetConversationId,\n ]);\n\n const additionalMessageProps = useCallback(\n (conversationSummary: ConversationSummary) => ({\n menuItems: (\n <DropdownItem\n isDisabled={!hasDeleteAccess}\n onClick={() => openDeleteModal(conversationSummary.conversation_id)}\n >\n {t('conversation.delete')}\n </DropdownItem>\n ),\n }),\n [hasDeleteAccess, t],\n );\n const categorizedMessages = getCategorizeMessages(\n conversations,\n additionalMessageProps,\n t,\n );\n\n const filterConversations = useCallback(\n (targetValue: string) => {\n const filteredConversations = Object.entries(categorizedMessages).reduce(\n (acc, [key, items]) => {\n const filteredItems = items.filter(item =>\n item.text\n .toLocaleLowerCase('en-US')\n .includes(targetValue.toLocaleLowerCase('en-US')),\n );\n if (filteredItems.length > 0) {\n acc[key] = filteredItems;\n }\n return acc;\n },\n {} as any,\n );\n return filteredConversations;\n },\n [categorizedMessages],\n );\n\n useEffect(() => {\n setMessages(conversationMessages);\n }, [conversationMessages]);\n\n const onSelectActiveItem = useCallback(\n (_: MouseEvent | undefined, selectedItem: string | number | undefined) => {\n setNewChatCreated(false);\n setConversationId((c_id: string) => {\n if (c_id !== selectedItem) {\n return String(selectedItem);\n }\n return c_id;\n });\n setFileContents([]);\n setUploadError({ message: null });\n scrollToBottomRef.current?.scrollToBottom();\n },\n [setConversationId, setUploadError, setFileContents, scrollToBottomRef],\n );\n\n const conversationFound = !!conversations.find(\n (c: ConversationSummary) => c.conversation_id === conversationId,\n );\n\n const welcomePrompts =\n (newChatCreated && conversationMessages.length === 0) ||\n (!conversationFound && conversationMessages.length === 0)\n ? samplePrompts?.map(prompt => {\n const p = prompt as { title: string; message: string };\n return {\n title: p.title,\n message: p.message,\n onClick: () => {\n sendMessage(p.message);\n },\n };\n })\n : [];\n\n const handleFilter = useCallback((value: string) => {\n setFilterValue(value);\n }, []);\n\n const onDrawerToggle = useCallback(() => {\n setIsDrawerOpen(isOpen => !isOpen);\n }, []);\n\n const handleAttach = (data: File[], event: DropEvent) => {\n event.preventDefault();\n handleFileUpload(data);\n };\n\n const onAttachRejected = (data: FileRejection[]) => {\n data.forEach(attachment => {\n if (!!attachment.errors.find(e => e.code === 'file-invalid-type')) {\n setShowAlert(true);\n setUploadError({\n message: t('file.upload.error.unsupportedType'),\n });\n }\n });\n };\n\n if (error) {\n return (\n <Box padding={1}>\n <ErrorPanel error={error} />\n </Box>\n );\n }\n\n return (\n <>\n {isDeleteModalOpen && (\n <DeleteModal\n isOpen={isDeleteModalOpen}\n onClose={() => setIsDeleteModalOpen(false)}\n onConfirm={handleDeleteConversation}\n />\n )}\n <Chatbot\n displayMode={ChatbotDisplayMode.embedded}\n className={classes.body}\n >\n <ChatbotHeader className={classes.header}>\n <ChatbotHeaderMain>\n <ChatbotHeaderMenu\n aria-expanded={isDrawerOpen}\n onMenuToggle={() => setIsDrawerOpen(!isDrawerOpen)}\n className={classes.headerMenu}\n />\n <ChatbotHeaderTitle className={classes.headerTitle}>\n <Title headingLevel=\"h1\" size=\"3xl\">\n {t('chatbox.header.title')}\n </Title>\n </ChatbotHeaderTitle>\n </ChatbotHeaderMain>\n\n <LightspeedChatBoxHeader\n selectedModel={selectedModel}\n handleSelectedModel={item => handleSelectedModel(item)}\n models={models}\n />\n </ChatbotHeader>\n <ChatbotConversationHistoryNav\n drawerPanelContentProps={{ isResizable: true, minSize: '200px' }}\n reverseButtonOrder\n displayMode={ChatbotDisplayMode.embedded}\n onDrawerToggle={onDrawerToggle}\n isDrawerOpen={isDrawerOpen}\n setIsDrawerOpen={setIsDrawerOpen}\n activeItemId={conversationId}\n onSelectActiveItem={onSelectActiveItem}\n conversations={filterConversations(filterValue)}\n onNewChat={newChatCreated ? undefined : onNewChat}\n newChatButtonText={t('button.newChat')}\n handleTextInputChange={handleFilter}\n searchInputPlaceholder={t('chatbox.search.placeholder')}\n searchInputProps={{\n value: filterValue,\n onClear: () => {\n setFilterValue('');\n },\n }}\n noResultsState={\n filterValue &&\n Object.keys(filterConversations(filterValue)).length === 0\n ? {\n bodyText:\n 'Adjust your search query and try again. Check your spelling or try a more general term.',\n titleText: 'No results found',\n icon: SearchIcon,\n }\n : undefined\n }\n drawerContent={\n <FileDropZone\n onFileDrop={(e, data) => handleAttach(data, e)}\n displayMode={ChatbotDisplayMode.embedded}\n infoText={t('chatbox.fileUpload.infoText')}\n allowedFileTypes={supportedFileTypes}\n onAttachRejected={onAttachRejected}\n >\n {showAlert && uploadError.message && (\n <div className={classes.errorContainer}>\n <ChatbotAlert\n component=\"h4\"\n title={t('chatbox.fileUpload.failed')}\n variant={uploadError.type ?? 'danger'}\n isInline\n onClose={() => setUploadError({ message: null })}\n >\n {uploadError.message}\n </ChatbotAlert>\n </div>\n )}\n\n <ChatbotContent>\n <LightspeedChatBox\n userName={userName}\n messages={messages}\n profileLoading={profileLoading}\n announcement={announcement}\n ref={scrollToBottomRef}\n welcomePrompts={welcomePrompts}\n conversationId={conversationId}\n isStreaming={isSendButtonDisabled}\n topicRestrictionEnabled={topicRestrictionEnabled}\n />\n </ChatbotContent>\n <ChatbotFooter className={classes.footer}>\n <FilePreview />\n <MessageBar\n onSendMessage={sendMessage}\n isSendButtonDisabled={isSendButtonDisabled}\n hasAttachButton\n handleAttach={handleAttach}\n hasMicrophoneButton\n buttonProps={{\n attach: {\n inputTestId: 'attachment-input',\n tooltipContent: t('tooltip.attach'),\n },\n microphone: {\n tooltipContent: {\n active: t('tooltip.microphone.active'),\n inactive: t('tooltip.microphone.inactive'),\n },\n },\n send: {\n tooltipContent: t('tooltip.send'),\n },\n }}\n allowedFileTypes={supportedFileTypes}\n onAttachRejected={onAttachRejected}\n placeholder={t('chatbox.message.placeholder')}\n />\n <ChatbotFootnote\n {...getFootnoteProps(classes.footerPopover, t)}\n />\n </ChatbotFooter>\n </FileDropZone>\n }\n />\n </Chatbot>\n <Attachment />\n </>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -1,6 +1,5 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import { forwardRef, useRef, useImperativeHandle, useEffect, Fragment } from 'react';
3
- import { useApi, configApiRef } from '@backstage/core-plugin-api';
4
3
  import { makeStyles } from '@material-ui/core';
5
4
  import { MessageBox, ChatbotWelcomePrompt, Message } from '@patternfly/chatbot';
6
5
  import { Alert } from '@patternfly/react-core';
@@ -37,14 +36,13 @@ const LightspeedChatBox = forwardRef(
37
36
  conversationId,
38
37
  profileLoading,
39
38
  welcomePrompts,
40
- isStreaming
39
+ isStreaming,
40
+ topicRestrictionEnabled
41
41
  }, ref) => {
42
42
  const classes = useStyles();
43
43
  const scrollQueued = useRef(false);
44
44
  const containerRef = useRef(null);
45
45
  const { t } = useTranslation();
46
- const configApi = useApi(configApiRef);
47
- const questionValidationEnabled = configApi.getOptionalBoolean("lightspeed.questionValidation") ?? true;
48
46
  const cmessages = useBufferedMessages(messages, 30);
49
47
  const { autoScroll, scrollToBottom, scrollToTop } = useAutoScroll(containerRef);
50
48
  const conversationMessages = useFeedbackActions(
@@ -99,7 +97,7 @@ const LightspeedChatBox = forwardRef(
99
97
  variant: "info",
100
98
  isInline: true,
101
99
  className: classes.alert,
102
- children: questionValidationEnabled ? t("disclaimer.withValidation") : t("disclaimer.withoutValidation")
100
+ children: topicRestrictionEnabled ? t("disclaimer.withValidation") : t("disclaimer.withoutValidation")
103
101
  }
104
102
  ),
105
103
  /* @__PURE__ */ jsx("br", {})
@@ -1 +1 @@
1
- {"version":3,"file":"LightspeedChatBox.esm.js","sources":["../../src/components/LightspeedChatBox.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ForwardedRef,\n forwardRef,\n Fragment,\n useEffect,\n useImperativeHandle,\n useRef,\n} from 'react';\n\nimport { configApiRef, useApi } from '@backstage/core-plugin-api';\n\nimport { makeStyles } from '@material-ui/core';\nimport {\n ChatbotWelcomePrompt,\n Message,\n MessageBox,\n MessageBoxHandle,\n MessageProps,\n WelcomePrompt,\n} from '@patternfly/chatbot';\nimport { Alert } from '@patternfly/react-core';\n\nimport { useAutoScroll } from '../hooks/useAutoScroll';\nimport { useBufferedMessages } from '../hooks/useBufferedMessages';\nimport { useFeedbackActions } from '../hooks/useFeedbackActions';\nimport { useTranslation } from '../hooks/useTranslation';\n\nconst useStyles = makeStyles(theme => ({\n prompt: {\n 'justify-content': 'flex-end',\n },\n container: {\n maxWidth: 'unset !important',\n },\n alert: {\n background: 'unset !important',\n },\n userMessageText: {\n '& div.pf-chatbot__message--user': {\n '& div.pf-chatbot__message-text': {\n '& p': {\n color: theme.palette.common.white,\n },\n },\n },\n },\n}));\n\ntype LightspeedChatBoxProps = {\n userName?: string;\n messages: MessageProps[];\n profileLoading: boolean;\n announcement: string | undefined;\n welcomePrompts: WelcomePrompt[];\n conversationId: string;\n isStreaming: boolean;\n};\n\nexport interface ScrollContainerHandle {\n scrollToBottom: () => void;\n}\n\nexport const LightspeedChatBox = forwardRef(\n (\n {\n userName,\n messages,\n announcement,\n conversationId,\n profileLoading,\n welcomePrompts,\n isStreaming,\n }: LightspeedChatBoxProps,\n ref: ForwardedRef<ScrollContainerHandle>,\n ) => {\n const classes = useStyles();\n const scrollQueued = useRef(false);\n const containerRef = useRef<MessageBoxHandle>(null);\n const { t } = useTranslation();\n\n const configApi = useApi(configApiRef);\n const questionValidationEnabled =\n configApi.getOptionalBoolean('lightspeed.questionValidation') ?? true;\n const cmessages = useBufferedMessages(messages, 30);\n const { autoScroll, scrollToBottom, scrollToTop } =\n useAutoScroll(containerRef);\n const conversationMessages = useFeedbackActions(\n cmessages,\n conversationId,\n isStreaming,\n );\n\n useImperativeHandle(ref, () => ({\n scrollToBottom: () => {\n if (scrollQueued.current) return;\n scrollQueued.current = true;\n\n requestAnimationFrame(() => {\n scrollToBottom();\n scrollQueued.current = false;\n });\n },\n }));\n\n // Auto-scrolls to the latest message\n useEffect(() => {\n if (!autoScroll || scrollQueued.current) return undefined;\n\n scrollQueued.current = true;\n\n const rafId = requestAnimationFrame(() => {\n const container = containerRef.current;\n if (!container) return;\n\n setTimeout(() => {\n container.scrollTo({\n top: container.scrollHeight,\n behavior: 'auto',\n });\n }, 0);\n\n scrollQueued.current = false;\n });\n\n return () => {\n cancelAnimationFrame(rafId);\n scrollQueued.current = false;\n };\n\n // eslint-disable-next-line\n }, [autoScroll, cmessages, containerRef]);\n\n const messageBoxClasses = `${classes.container} ${classes.userMessageText}`;\n return (\n <MessageBox\n className={\n welcomePrompts.length\n ? `${messageBoxClasses} ${classes.prompt}`\n : messageBoxClasses\n }\n announcement={announcement}\n ref={containerRef}\n onScrollToTopClick={scrollToTop}\n onScrollToBottomClick={scrollToBottom}\n >\n <div>\n <Alert\n title={t('aria.important')}\n variant=\"info\"\n isInline\n className={classes.alert}\n >\n {questionValidationEnabled\n ? t('disclaimer.withValidation')\n : t('disclaimer.withoutValidation')}\n </Alert>\n <br />\n </div>\n {welcomePrompts.length ? (\n <ChatbotWelcomePrompt\n title={t('chatbox.welcome.greeting' as any, {\n userName: profileLoading\n ? t('user.loading')\n : (userName ?? t('user.guest')),\n })}\n description={t('chatbox.welcome.description')}\n prompts={welcomePrompts}\n />\n ) : (\n <br />\n )}\n {conversationMessages.map((message, index) => {\n if (index === cmessages.length - 1) {\n return (\n <Fragment key={`${message.role}-${index}`}>\n <Message key={`${message.role}-${index}`} {...message} />\n </Fragment>\n );\n }\n return <Message key={`${message.role}-${index}`} {...message} />;\n })}\n </MessageBox>\n );\n },\n);\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"LightspeedChatBox.esm.js","sources":["../../src/components/LightspeedChatBox.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ForwardedRef,\n forwardRef,\n Fragment,\n useEffect,\n useImperativeHandle,\n useRef,\n} from 'react';\n\nimport { makeStyles } from '@material-ui/core';\nimport {\n ChatbotWelcomePrompt,\n Message,\n MessageBox,\n MessageBoxHandle,\n MessageProps,\n WelcomePrompt,\n} from '@patternfly/chatbot';\nimport { Alert } from '@patternfly/react-core';\n\nimport { useAutoScroll } from '../hooks/useAutoScroll';\nimport { useBufferedMessages } from '../hooks/useBufferedMessages';\nimport { useFeedbackActions } from '../hooks/useFeedbackActions';\nimport { useTranslation } from '../hooks/useTranslation';\n\nconst useStyles = makeStyles(theme => ({\n prompt: {\n 'justify-content': 'flex-end',\n },\n container: {\n maxWidth: 'unset !important',\n },\n alert: {\n background: 'unset !important',\n },\n userMessageText: {\n '& div.pf-chatbot__message--user': {\n '& div.pf-chatbot__message-text': {\n '& p': {\n color: theme.palette.common.white,\n },\n },\n },\n },\n}));\n\ntype LightspeedChatBoxProps = {\n userName?: string;\n messages: MessageProps[];\n profileLoading: boolean;\n announcement: string | undefined;\n topicRestrictionEnabled: boolean;\n welcomePrompts: WelcomePrompt[];\n conversationId: string;\n isStreaming: boolean;\n};\n\nexport interface ScrollContainerHandle {\n scrollToBottom: () => void;\n}\n\nexport const LightspeedChatBox = forwardRef(\n (\n {\n userName,\n messages,\n announcement,\n conversationId,\n profileLoading,\n welcomePrompts,\n isStreaming,\n topicRestrictionEnabled,\n }: LightspeedChatBoxProps,\n ref: ForwardedRef<ScrollContainerHandle>,\n ) => {\n const classes = useStyles();\n const scrollQueued = useRef(false);\n const containerRef = useRef<MessageBoxHandle>(null);\n const { t } = useTranslation();\n\n const cmessages = useBufferedMessages(messages, 30);\n const { autoScroll, scrollToBottom, scrollToTop } =\n useAutoScroll(containerRef);\n const conversationMessages = useFeedbackActions(\n cmessages,\n conversationId,\n isStreaming,\n );\n\n useImperativeHandle(ref, () => ({\n scrollToBottom: () => {\n if (scrollQueued.current) return;\n scrollQueued.current = true;\n\n requestAnimationFrame(() => {\n scrollToBottom();\n scrollQueued.current = false;\n });\n },\n }));\n\n // Auto-scrolls to the latest message\n useEffect(() => {\n if (!autoScroll || scrollQueued.current) return undefined;\n\n scrollQueued.current = true;\n\n const rafId = requestAnimationFrame(() => {\n const container = containerRef.current;\n if (!container) return;\n\n setTimeout(() => {\n container.scrollTo({\n top: container.scrollHeight,\n behavior: 'auto',\n });\n }, 0);\n\n scrollQueued.current = false;\n });\n\n return () => {\n cancelAnimationFrame(rafId);\n scrollQueued.current = false;\n };\n\n // eslint-disable-next-line\n }, [autoScroll, cmessages, containerRef]);\n\n const messageBoxClasses = `${classes.container} ${classes.userMessageText}`;\n return (\n <MessageBox\n className={\n welcomePrompts.length\n ? `${messageBoxClasses} ${classes.prompt}`\n : messageBoxClasses\n }\n announcement={announcement}\n ref={containerRef}\n onScrollToTopClick={scrollToTop}\n onScrollToBottomClick={scrollToBottom}\n >\n <div>\n <Alert\n title={t('aria.important')}\n variant=\"info\"\n isInline\n className={classes.alert}\n >\n {topicRestrictionEnabled\n ? t('disclaimer.withValidation')\n : t('disclaimer.withoutValidation')}\n </Alert>\n <br />\n </div>\n {welcomePrompts.length ? (\n <ChatbotWelcomePrompt\n title={t('chatbox.welcome.greeting' as any, {\n userName: profileLoading\n ? t('user.loading')\n : (userName ?? t('user.guest')),\n })}\n description={t('chatbox.welcome.description')}\n prompts={welcomePrompts}\n />\n ) : (\n <br />\n )}\n {conversationMessages.map((message, index) => {\n if (index === cmessages.length - 1) {\n return (\n <Fragment key={`${message.role}-${index}`}>\n <Message key={`${message.role}-${index}`} {...message} />\n </Fragment>\n );\n }\n return <Message key={`${message.role}-${index}`} {...message} />;\n })}\n </MessageBox>\n );\n },\n);\n"],"names":[],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
- import { useState } from 'react';
2
+ import { useState, useMemo } from 'react';
3
3
  import { makeStyles, createStyles } from '@material-ui/core';
4
4
  import { ChatbotHeaderActions } from '@patternfly/chatbot';
5
- import { Dropdown, DropdownList, DropdownItem, MenuToggle } from '@patternfly/react-core';
5
+ import { Dropdown, DropdownList, DropdownGroup, DropdownItem, MenuToggle } from '@patternfly/react-core';
6
6
  import { useTranslation } from '../hooks/useTranslation.esm.js';
7
7
 
8
8
  const useStyles = makeStyles(
@@ -23,6 +23,17 @@ const LightspeedChatBoxHeader = ({
23
23
  const [isOptionsMenuOpen, setIsOptionsMenuOpen] = useState(false);
24
24
  const { t } = useTranslation();
25
25
  const styles = useStyles();
26
+ const groupedModels = useMemo(() => {
27
+ const groups = {};
28
+ models.forEach((model) => {
29
+ const provider = model.provider || "Other";
30
+ if (!groups[provider]) {
31
+ groups[provider] = [];
32
+ }
33
+ groups[provider].push(model);
34
+ });
35
+ return groups;
36
+ }, [models]);
26
37
  const toggle = (toggleRef) => /* @__PURE__ */ jsx(
27
38
  MenuToggle,
28
39
  {
@@ -48,7 +59,7 @@ const LightspeedChatBoxHeader = ({
48
59
  shouldFocusToggleOnSelect: true,
49
60
  shouldFocusFirstItemOnOpen: false,
50
61
  toggle,
51
- children: /* @__PURE__ */ jsx(DropdownList, { children: models.map((m) => /* @__PURE__ */ jsx(DropdownItem, { value: m.value, children: m.label }, m.value)) })
62
+ children: /* @__PURE__ */ jsx(DropdownList, { children: Object.entries(groupedModels).map(([provider, providerModels]) => /* @__PURE__ */ jsx(DropdownGroup, { label: provider, children: providerModels.map((model) => /* @__PURE__ */ jsx(DropdownItem, { value: model.value, children: model.label }, model.value)) }, provider)) })
52
63
  }
53
64
  ) });
54
65
  };
@@ -1 +1 @@
1
- {"version":3,"file":"LightspeedChatBoxHeader.esm.js","sources":["../../src/components/LightspeedChatBoxHeader.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Ref, useState } from 'react';\n\nimport { createStyles, makeStyles } from '@material-ui/core';\nimport { ChatbotHeaderActions } from '@patternfly/chatbot';\nimport {\n Dropdown,\n DropdownItem,\n DropdownList,\n MenuToggle,\n MenuToggleElement,\n} from '@patternfly/react-core';\n\nimport { useTranslation } from '../hooks/useTranslation';\n\ntype LightspeedChatBoxHeaderProps = {\n selectedModel: string;\n handleSelectedModel: (item: string) => void;\n models: { label: string; value: string }[];\n};\n\nconst useStyles = makeStyles(() =>\n createStyles({\n dropdown: {\n '& ul, & li': {\n padding: 0,\n margin: 0,\n },\n },\n }),\n);\n\nexport const LightspeedChatBoxHeader = ({\n selectedModel,\n handleSelectedModel,\n models,\n}: LightspeedChatBoxHeaderProps) => {\n const [isOptionsMenuOpen, setIsOptionsMenuOpen] = useState(false);\n const { t } = useTranslation();\n\n const styles = useStyles();\n\n const toggle = (toggleRef: Ref<MenuToggleElement>) => (\n <MenuToggle\n variant=\"secondary\"\n aria-label={t('aria.chatbotSelector')}\n ref={toggleRef}\n isExpanded={isOptionsMenuOpen}\n onClick={() => setIsOptionsMenuOpen(!isOptionsMenuOpen)}\n >\n {selectedModel}\n </MenuToggle>\n );\n\n return (\n <ChatbotHeaderActions>\n <Dropdown\n className={styles.dropdown}\n isOpen={isOptionsMenuOpen}\n onSelect={(_e, value) => {\n handleSelectedModel(value as string);\n setIsOptionsMenuOpen(false);\n }}\n onOpenChange={isOpen => setIsOptionsMenuOpen(isOpen)}\n popperProps={{ position: 'right' }}\n shouldFocusToggleOnSelect\n shouldFocusFirstItemOnOpen={false}\n toggle={toggle}\n >\n <DropdownList>\n {models.map(m => (\n <DropdownItem value={m.value} key={m.value}>\n {m.label}\n </DropdownItem>\n ))}\n </DropdownList>\n </Dropdown>\n </ChatbotHeaderActions>\n );\n};\n"],"names":[],"mappings":";;;;;;;AAoCA,MAAM,SAAY,GAAA,UAAA;AAAA,EAAW,MAC3B,YAAa,CAAA;AAAA,IACX,QAAU,EAAA;AAAA,MACR,YAAc,EAAA;AAAA,QACZ,OAAS,EAAA,CAAA;AAAA,QACT,MAAQ,EAAA;AAAA;AACV;AACF,GACD;AACH,CAAA;AAEO,MAAM,0BAA0B,CAAC;AAAA,EACtC,aAAA;AAAA,EACA,mBAAA;AAAA,EACA;AACF,CAAoC,KAAA;AAClC,EAAA,MAAM,CAAC,iBAAA,EAAmB,oBAAoB,CAAA,GAAI,SAAS,KAAK,CAAA;AAChE,EAAM,MAAA,EAAE,CAAE,EAAA,GAAI,cAAe,EAAA;AAE7B,EAAA,MAAM,SAAS,SAAU,EAAA;AAEzB,EAAM,MAAA,MAAA,GAAS,CAAC,SACd,qBAAA,GAAA;AAAA,IAAC,UAAA;AAAA,IAAA;AAAA,MACC,OAAQ,EAAA,WAAA;AAAA,MACR,YAAA,EAAY,EAAE,sBAAsB,CAAA;AAAA,MACpC,GAAK,EAAA,SAAA;AAAA,MACL,UAAY,EAAA,iBAAA;AAAA,MACZ,OAAS,EAAA,MAAM,oBAAqB,CAAA,CAAC,iBAAiB,CAAA;AAAA,MAErD,QAAA,EAAA;AAAA;AAAA,GACH;AAGF,EAAA,2BACG,oBACC,EAAA,EAAA,QAAA,kBAAA,GAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,WAAW,MAAO,CAAA,QAAA;AAAA,MAClB,MAAQ,EAAA,iBAAA;AAAA,MACR,QAAA,EAAU,CAAC,EAAA,EAAI,KAAU,KAAA;AACvB,QAAA,mBAAA,CAAoB,KAAe,CAAA;AACnC,QAAA,oBAAA,CAAqB,KAAK,CAAA;AAAA,OAC5B;AAAA,MACA,YAAA,EAAc,CAAU,MAAA,KAAA,oBAAA,CAAqB,MAAM,CAAA;AAAA,MACnD,WAAA,EAAa,EAAE,QAAA,EAAU,OAAQ,EAAA;AAAA,MACjC,yBAAyB,EAAA,IAAA;AAAA,MACzB,0BAA4B,EAAA,KAAA;AAAA,MAC5B,MAAA;AAAA,MAEA,QAAC,kBAAA,GAAA,CAAA,YAAA,EAAA,EACE,QAAO,EAAA,MAAA,CAAA,GAAA,CAAI,uBACT,GAAA,CAAA,YAAA,EAAA,EAAa,KAAO,EAAA,CAAA,CAAE,OACpB,QAAE,EAAA,CAAA,CAAA,KAAA,EAAA,EAD8B,CAAE,CAAA,KAErC,CACD,CACH,EAAA;AAAA;AAAA,GAEJ,EAAA,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"LightspeedChatBoxHeader.esm.js","sources":["../../src/components/LightspeedChatBoxHeader.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Ref, useMemo, useState } from 'react';\n\nimport { createStyles, makeStyles } from '@material-ui/core';\nimport { ChatbotHeaderActions } from '@patternfly/chatbot';\nimport {\n Dropdown,\n DropdownGroup,\n DropdownItem,\n DropdownList,\n MenuToggle,\n MenuToggleElement,\n} from '@patternfly/react-core';\n\nimport { useTranslation } from '../hooks/useTranslation';\n\ntype LightspeedChatBoxHeaderProps = {\n selectedModel: string;\n handleSelectedModel: (item: string) => void;\n models: { label: string; value: string; provider: string }[];\n};\n\nconst useStyles = makeStyles(() =>\n createStyles({\n dropdown: {\n '& ul, & li': {\n padding: 0,\n margin: 0,\n },\n },\n }),\n);\n\nexport const LightspeedChatBoxHeader = ({\n selectedModel,\n handleSelectedModel,\n models,\n}: LightspeedChatBoxHeaderProps) => {\n const [isOptionsMenuOpen, setIsOptionsMenuOpen] = useState(false);\n const { t } = useTranslation();\n\n const styles = useStyles();\n\n // Group models by provider\n const groupedModels = useMemo(() => {\n const groups: {\n [key: string]: { label: string; value: string; provider: string }[];\n } = {};\n\n models.forEach(model => {\n const provider = model.provider || 'Other';\n if (!groups[provider]) {\n groups[provider] = [];\n }\n groups[provider].push(model);\n });\n\n return groups;\n }, [models]);\n\n const toggle = (toggleRef: Ref<MenuToggleElement>) => (\n <MenuToggle\n variant=\"secondary\"\n aria-label={t('aria.chatbotSelector')}\n ref={toggleRef}\n isExpanded={isOptionsMenuOpen}\n onClick={() => setIsOptionsMenuOpen(!isOptionsMenuOpen)}\n >\n {selectedModel}\n </MenuToggle>\n );\n\n return (\n <ChatbotHeaderActions>\n <Dropdown\n className={styles.dropdown}\n isOpen={isOptionsMenuOpen}\n onSelect={(_e, value) => {\n handleSelectedModel(value as string);\n setIsOptionsMenuOpen(false);\n }}\n onOpenChange={isOpen => setIsOptionsMenuOpen(isOpen)}\n popperProps={{ position: 'right' }}\n shouldFocusToggleOnSelect\n shouldFocusFirstItemOnOpen={false}\n toggle={toggle}\n >\n <DropdownList>\n {Object.entries(groupedModels).map(([provider, providerModels]) => (\n <DropdownGroup key={provider} label={provider}>\n {providerModels.map(model => (\n <DropdownItem value={model.value} key={model.value}>\n {model.label}\n </DropdownItem>\n ))}\n </DropdownGroup>\n ))}\n </DropdownList>\n </Dropdown>\n </ChatbotHeaderActions>\n );\n};\n"],"names":[],"mappings":";;;;;;;AAqCA,MAAM,SAAY,GAAA,UAAA;AAAA,EAAW,MAC3B,YAAa,CAAA;AAAA,IACX,QAAU,EAAA;AAAA,MACR,YAAc,EAAA;AAAA,QACZ,OAAS,EAAA,CAAA;AAAA,QACT,MAAQ,EAAA;AAAA;AACV;AACF,GACD;AACH,CAAA;AAEO,MAAM,0BAA0B,CAAC;AAAA,EACtC,aAAA;AAAA,EACA,mBAAA;AAAA,EACA;AACF,CAAoC,KAAA;AAClC,EAAA,MAAM,CAAC,iBAAA,EAAmB,oBAAoB,CAAA,GAAI,SAAS,KAAK,CAAA;AAChE,EAAM,MAAA,EAAE,CAAE,EAAA,GAAI,cAAe,EAAA;AAE7B,EAAA,MAAM,SAAS,SAAU,EAAA;AAGzB,EAAM,MAAA,aAAA,GAAgB,QAAQ,MAAM;AAClC,IAAA,MAAM,SAEF,EAAC;AAEL,IAAA,MAAA,CAAO,QAAQ,CAAS,KAAA,KAAA;AACtB,MAAM,MAAA,QAAA,GAAW,MAAM,QAAY,IAAA,OAAA;AACnC,MAAI,IAAA,CAAC,MAAO,CAAA,QAAQ,CAAG,EAAA;AACrB,QAAO,MAAA,CAAA,QAAQ,IAAI,EAAC;AAAA;AAEtB,MAAO,MAAA,CAAA,QAAQ,CAAE,CAAA,IAAA,CAAK,KAAK,CAAA;AAAA,KAC5B,CAAA;AAED,IAAO,OAAA,MAAA;AAAA,GACT,EAAG,CAAC,MAAM,CAAC,CAAA;AAEX,EAAM,MAAA,MAAA,GAAS,CAAC,SACd,qBAAA,GAAA;AAAA,IAAC,UAAA;AAAA,IAAA;AAAA,MACC,OAAQ,EAAA,WAAA;AAAA,MACR,YAAA,EAAY,EAAE,sBAAsB,CAAA;AAAA,MACpC,GAAK,EAAA,SAAA;AAAA,MACL,UAAY,EAAA,iBAAA;AAAA,MACZ,OAAS,EAAA,MAAM,oBAAqB,CAAA,CAAC,iBAAiB,CAAA;AAAA,MAErD,QAAA,EAAA;AAAA;AAAA,GACH;AAGF,EAAA,2BACG,oBACC,EAAA,EAAA,QAAA,kBAAA,GAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,WAAW,MAAO,CAAA,QAAA;AAAA,MAClB,MAAQ,EAAA,iBAAA;AAAA,MACR,QAAA,EAAU,CAAC,EAAA,EAAI,KAAU,KAAA;AACvB,QAAA,mBAAA,CAAoB,KAAe,CAAA;AACnC,QAAA,oBAAA,CAAqB,KAAK,CAAA;AAAA,OAC5B;AAAA,MACA,YAAA,EAAc,CAAU,MAAA,KAAA,oBAAA,CAAqB,MAAM,CAAA;AAAA,MACnD,WAAA,EAAa,EAAE,QAAA,EAAU,OAAQ,EAAA;AAAA,MACjC,yBAAyB,EAAA,IAAA;AAAA,MACzB,0BAA4B,EAAA,KAAA;AAAA,MAC5B,MAAA;AAAA,MAEA,QAAC,kBAAA,GAAA,CAAA,YAAA,EAAA,EACE,QAAO,EAAA,MAAA,CAAA,OAAA,CAAQ,aAAa,CAAE,CAAA,GAAA,CAAI,CAAC,CAAC,QAAU,EAAA,cAAc,CAC3D,qBAAA,GAAA,CAAC,iBAA6B,KAAO,EAAA,QAAA,EAClC,QAAe,EAAA,cAAA,CAAA,GAAA,CAAI,CAClB,KAAA,qBAAA,GAAA,CAAC,YAAa,EAAA,EAAA,KAAA,EAAO,MAAM,KACxB,EAAA,QAAA,EAAA,KAAA,CAAM,KAD8B,EAAA,EAAA,KAAA,CAAM,KAE7C,CACD,CALiB,EAAA,EAAA,QAMpB,CACD,CACH,EAAA;AAAA;AAAA,GAEJ,EAAA,CAAA;AAEJ;;;;"}
@@ -7,6 +7,7 @@ import { makeStyles, createStyles, useTheme } from '@material-ui/core/styles';
7
7
  import { QueryClientProvider } from '@tanstack/react-query';
8
8
  import { useAllModels } from '../hooks/useAllModels.esm.js';
9
9
  import { useLightspeedViewPermission } from '../hooks/useLightspeedViewPermission.esm.js';
10
+ import { useTopicRestrictionStatus } from '../hooks/useQuestionValidation.esm.js';
10
11
  import { useTranslation } from '../hooks/useTranslation.esm.js';
11
12
  import queryClient from '../utils/queryClient.esm.js';
12
13
  import FileAttachmentContextProvider from './AttachmentContext.esm.js';
@@ -35,8 +36,14 @@ const LightspeedPageInner = () => {
35
36
  async () => await identityApi.getProfileInfo()
36
37
  );
37
38
  const [selectedModel, setSelectedModel] = useState("");
39
+ const [selectedProvider, setSelectedProvider] = useState("");
40
+ const { data: topicRestrictionEnabled } = useTopicRestrictionStatus();
38
41
  const modelsItems = useMemo(
39
- () => models ? models.map((m) => ({ label: m.id, value: m.id })) : [],
42
+ () => models ? models.map((m) => ({
43
+ label: m.provider_resource_id,
44
+ value: m.provider_resource_id,
45
+ provider: m.provider_id
46
+ })) : [],
40
47
  [models]
41
48
  );
42
49
  useEffect(() => {
@@ -48,7 +55,10 @@ const LightspeedPageInner = () => {
48
55
  }
49
56
  }, [type]);
50
57
  useEffect(() => {
51
- if (modelsItems.length > 0) setSelectedModel(modelsItems[0].value);
58
+ if (modelsItems.length > 0) {
59
+ setSelectedModel(modelsItems[0].value);
60
+ setSelectedProvider(modelsItems[0].provider);
61
+ }
52
62
  }, [modelsItems]);
53
63
  if (loading) {
54
64
  return null;
@@ -66,8 +76,13 @@ const LightspeedPageInner = () => {
66
76
  LightspeedChat,
67
77
  {
68
78
  selectedModel,
79
+ selectedProvider,
80
+ topicRestrictionEnabled: topicRestrictionEnabled ?? false,
69
81
  handleSelectedModel: (item) => {
70
82
  setSelectedModel(item);
83
+ setSelectedProvider(
84
+ modelsItems.find((m) => m.value === item)?.provider || ""
85
+ );
71
86
  },
72
87
  models: modelsItems,
73
88
  userName: profile?.displayName,
@@ -1 +1 @@
1
- {"version":3,"file":"LightspeedPage.esm.js","sources":["../../src/components/LightspeedPage.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useEffect, useMemo, useState } from 'react';\nimport { useAsync } from 'react-use';\n\nimport { Content, Header, Page } from '@backstage/core-components';\nimport { identityApiRef, useApi } from '@backstage/core-plugin-api';\n\nimport { createStyles, makeStyles, useTheme } from '@material-ui/core/styles';\nimport { QueryClientProvider } from '@tanstack/react-query';\n\nimport { useAllModels } from '../hooks/useAllModels';\nimport { useLightspeedViewPermission } from '../hooks/useLightspeedViewPermission';\nimport { useTranslation } from '../hooks/useTranslation';\nimport queryClient from '../utils/queryClient';\nimport FileAttachmentContextProvider from './AttachmentContext';\nimport { LightspeedChat } from './LightSpeedChat';\nimport PermissionRequiredState from './PermissionRequiredState';\n\nconst useStyles = makeStyles(() =>\n createStyles({\n container: {\n padding: '0px',\n },\n }),\n);\n\nconst THEME_DARK = 'dark';\nconst THEME_DARK_CLASS = 'pf-v6-theme-dark';\n\nconst LightspeedPageInner = () => {\n const classes = useStyles();\n const { t } = useTranslation();\n const {\n palette: { type },\n } = useTheme();\n\n const identityApi = useApi(identityApiRef);\n\n const { data: models } = useAllModels();\n const { allowed: hasViewAccess, loading } = useLightspeedViewPermission();\n\n const { value: profile, loading: profileLoading } = useAsync(\n async () => await identityApi.getProfileInfo(),\n );\n\n const [selectedModel, setSelectedModel] = useState('');\n\n const modelsItems = useMemo(\n () => (models ? models.map(m => ({ label: m.id, value: m.id })) : []),\n [models],\n );\n\n useEffect(() => {\n const htmlTagElement = document.documentElement;\n if (type === THEME_DARK) {\n htmlTagElement.classList.add(THEME_DARK_CLASS);\n } else {\n htmlTagElement.classList.remove(THEME_DARK_CLASS);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [type]);\n\n useEffect(() => {\n if (modelsItems.length > 0) setSelectedModel(modelsItems[0].value);\n }, [modelsItems]);\n\n if (loading) {\n return null;\n }\n\n return (\n <Page themeId=\"tool\">\n <Header\n title={t('page.title')}\n style={{ display: 'none' }}\n pageTitleOverride={t('page.title')}\n />\n <Content className={classes.container}>\n {!hasViewAccess ? (\n <PermissionRequiredState />\n ) : (\n <FileAttachmentContextProvider>\n <LightspeedChat\n selectedModel={selectedModel}\n handleSelectedModel={item => {\n setSelectedModel(item);\n }}\n models={modelsItems}\n userName={profile?.displayName}\n avatar={profile?.picture}\n profileLoading={profileLoading}\n />\n </FileAttachmentContextProvider>\n )}\n </Content>\n </Page>\n );\n};\n\nexport const LightspeedPage = () => {\n return (\n <QueryClientProvider client={queryClient}>\n <LightspeedPageInner />\n </QueryClientProvider>\n );\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"LightspeedPage.esm.js","sources":["../../src/components/LightspeedPage.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useEffect, useMemo, useState } from 'react';\nimport { useAsync } from 'react-use';\n\nimport { Content, Header, Page } from '@backstage/core-components';\nimport { identityApiRef, useApi } from '@backstage/core-plugin-api';\n\nimport { createStyles, makeStyles, useTheme } from '@material-ui/core/styles';\nimport { QueryClientProvider } from '@tanstack/react-query';\n\nimport { useAllModels } from '../hooks/useAllModels';\nimport { useLightspeedViewPermission } from '../hooks/useLightspeedViewPermission';\nimport { useTopicRestrictionStatus } from '../hooks/useQuestionValidation';\nimport { useTranslation } from '../hooks/useTranslation';\nimport queryClient from '../utils/queryClient';\nimport FileAttachmentContextProvider from './AttachmentContext';\nimport { LightspeedChat } from './LightSpeedChat';\nimport PermissionRequiredState from './PermissionRequiredState';\n\nconst useStyles = makeStyles(() =>\n createStyles({\n container: {\n padding: '0px',\n },\n }),\n);\n\nconst THEME_DARK = 'dark';\nconst THEME_DARK_CLASS = 'pf-v6-theme-dark';\n\nconst LightspeedPageInner = () => {\n const classes = useStyles();\n const { t } = useTranslation();\n const {\n palette: { type },\n } = useTheme();\n\n const identityApi = useApi(identityApiRef);\n\n const { data: models } = useAllModels();\n const { allowed: hasViewAccess, loading } = useLightspeedViewPermission();\n\n const { value: profile, loading: profileLoading } = useAsync(\n async () => await identityApi.getProfileInfo(),\n );\n\n const [selectedModel, setSelectedModel] = useState('');\n const [selectedProvider, setSelectedProvider] = useState('');\n\n const { data: topicRestrictionEnabled } = useTopicRestrictionStatus();\n\n const modelsItems = useMemo(\n () =>\n models\n ? models.map(m => ({\n label: m.provider_resource_id,\n value: m.provider_resource_id,\n provider: m.provider_id,\n }))\n : [],\n [models],\n );\n\n useEffect(() => {\n const htmlTagElement = document.documentElement;\n if (type === THEME_DARK) {\n htmlTagElement.classList.add(THEME_DARK_CLASS);\n } else {\n htmlTagElement.classList.remove(THEME_DARK_CLASS);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [type]);\n\n useEffect(() => {\n if (modelsItems.length > 0) {\n setSelectedModel(modelsItems[0].value);\n setSelectedProvider(modelsItems[0].provider);\n }\n }, [modelsItems]);\n\n if (loading) {\n return null;\n }\n\n return (\n <Page themeId=\"tool\">\n <Header\n title={t('page.title')}\n style={{ display: 'none' }}\n pageTitleOverride={t('page.title')}\n />\n <Content className={classes.container}>\n {!hasViewAccess ? (\n <PermissionRequiredState />\n ) : (\n <FileAttachmentContextProvider>\n <LightspeedChat\n selectedModel={selectedModel}\n selectedProvider={selectedProvider}\n topicRestrictionEnabled={topicRestrictionEnabled ?? false}\n handleSelectedModel={item => {\n setSelectedModel(item);\n setSelectedProvider(\n modelsItems.find((m: any) => m.value === item)?.provider ||\n '',\n );\n }}\n models={modelsItems}\n userName={profile?.displayName}\n avatar={profile?.picture}\n profileLoading={profileLoading}\n />\n </FileAttachmentContextProvider>\n )}\n </Content>\n </Page>\n );\n};\n\nexport const LightspeedPage = () => {\n return (\n <QueryClientProvider client={queryClient}>\n <LightspeedPageInner />\n </QueryClientProvider>\n );\n};\n"],"names":[],"mappings":"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"}
package/dist/const.esm.js CHANGED
@@ -39,6 +39,9 @@ const RHDH_SAMPLE_PROMPTS = [
39
39
  createPrompt("prompts.openshift.title", "prompts.openshift.message"),
40
40
  createPrompt("prompts.rhdh.title", "prompts.rhdh.message")
41
41
  ];
42
+ const VALID_TOPIC_RESTRICTION_PROVIDER_IDS = [
43
+ "lightspeed_question_validity-shield"
44
+ ];
42
45
 
43
- export { DEFAULT_SAMPLE_PROMPTS, RHDH_SAMPLE_PROMPTS, TEMP_CONVERSATION_ID, supportedFileTypes };
46
+ export { DEFAULT_SAMPLE_PROMPTS, RHDH_SAMPLE_PROMPTS, TEMP_CONVERSATION_ID, VALID_TOPIC_RESTRICTION_PROVIDER_IDS, supportedFileTypes };
44
47
  //# sourceMappingURL=const.esm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"const.esm.js","sources":["../src/const.ts"],"sourcesContent":["import { SamplePrompts } from './types';\n\n/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nexport const TEMP_CONVERSATION_ID = 'temp-conversation-id';\n\n// Translation keys for disclaimers\nexport const FUNCTION_DISCLAIMER_WITHOUT_QUESTION_VALIDATION_KEY =\n 'disclaimer.withoutValidation';\nexport const FUNCTION_DISCLAIMER_KEY = 'disclaimer.withValidation';\n\nconst createPrompt = (titleKey: string, messageKey: string) => {\n return { titleKey, messageKey };\n};\n\nexport const supportedFileTypes = {\n 'text/plain': ['.txt'],\n 'application/json': ['.json'],\n 'application/yaml': ['.yaml', '.yml'],\n 'application/xml': ['.xml'],\n};\n\nexport const DEFAULT_SAMPLE_PROMPTS: SamplePrompts = [\n createPrompt(\n 'prompts.codeReadability.title',\n 'prompts.codeReadability.message',\n ),\n createPrompt('prompts.debugging.title', 'prompts.debugging.message'),\n createPrompt(\n 'prompts.developmentConcept.title',\n 'prompts.developmentConcept.message',\n ),\n createPrompt(\n 'prompts.codeOptimization.title',\n 'prompts.codeOptimization.message',\n ),\n createPrompt('prompts.documentation.title', 'prompts.documentation.message'),\n createPrompt('prompts.gitWorkflows.title', 'prompts.gitWorkflows.message'),\n createPrompt(\n 'prompts.testingStrategies.title',\n 'prompts.testingStrategies.message',\n ),\n createPrompt(\n 'prompts.sortingAlgorithms.title',\n 'prompts.sortingAlgorithms.message',\n ),\n createPrompt('prompts.eventDriven.title', 'prompts.eventDriven.message'),\n];\n\nexport const RHDH_SAMPLE_PROMPTS: SamplePrompts = [\n createPrompt('prompts.tekton.title', 'prompts.tekton.message'),\n createPrompt('prompts.openshift.title', 'prompts.openshift.message'),\n createPrompt('prompts.rhdh.title', 'prompts.rhdh.message'),\n];\n"],"names":[],"mappings":"AAiBO,MAAM,oBAAuB,GAAA;AAOpC,MAAM,YAAA,GAAe,CAAC,QAAA,EAAkB,UAAuB,KAAA;AAC7D,EAAO,OAAA,EAAE,UAAU,UAAW,EAAA;AAChC,CAAA;AAEO,MAAM,kBAAqB,GAAA;AAAA,EAChC,YAAA,EAAc,CAAC,MAAM,CAAA;AAAA,EACrB,kBAAA,EAAoB,CAAC,OAAO,CAAA;AAAA,EAC5B,kBAAA,EAAoB,CAAC,OAAA,EAAS,MAAM,CAAA;AAAA,EACpC,iBAAA,EAAmB,CAAC,MAAM;AAC5B;AAEO,MAAM,sBAAwC,GAAA;AAAA,EACnD,YAAA;AAAA,IACE,+BAAA;AAAA,IACA;AAAA,GACF;AAAA,EACA,YAAA,CAAa,2BAA2B,2BAA2B,CAAA;AAAA,EACnE,YAAA;AAAA,IACE,kCAAA;AAAA,IACA;AAAA,GACF;AAAA,EACA,YAAA;AAAA,IACE,gCAAA;AAAA,IACA;AAAA,GACF;AAAA,EACA,YAAA,CAAa,+BAA+B,+BAA+B,CAAA;AAAA,EAC3E,YAAA,CAAa,8BAA8B,8BAA8B,CAAA;AAAA,EACzE,YAAA;AAAA,IACE,iCAAA;AAAA,IACA;AAAA,GACF;AAAA,EACA,YAAA;AAAA,IACE,iCAAA;AAAA,IACA;AAAA,GACF;AAAA,EACA,YAAA,CAAa,6BAA6B,6BAA6B;AACzE;AAEO,MAAM,mBAAqC,GAAA;AAAA,EAChD,YAAA,CAAa,wBAAwB,wBAAwB,CAAA;AAAA,EAC7D,YAAA,CAAa,2BAA2B,2BAA2B,CAAA;AAAA,EACnE,YAAA,CAAa,sBAAsB,sBAAsB;AAC3D;;;;"}
1
+ {"version":3,"file":"const.esm.js","sources":["../src/const.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { SamplePrompts } from './types';\n\nexport const TEMP_CONVERSATION_ID = 'temp-conversation-id';\n\n// Translation keys for disclaimers\nexport const FUNCTION_DISCLAIMER_WITHOUT_QUESTION_VALIDATION_KEY =\n 'disclaimer.withoutValidation';\nexport const FUNCTION_DISCLAIMER_KEY = 'disclaimer.withValidation';\n\nconst createPrompt = (titleKey: string, messageKey: string) => {\n return { titleKey, messageKey };\n};\n\nexport const supportedFileTypes = {\n 'text/plain': ['.txt'],\n 'application/json': ['.json'],\n 'application/yaml': ['.yaml', '.yml'],\n 'application/xml': ['.xml'],\n};\n\nexport const DEFAULT_SAMPLE_PROMPTS: SamplePrompts = [\n createPrompt(\n 'prompts.codeReadability.title',\n 'prompts.codeReadability.message',\n ),\n createPrompt('prompts.debugging.title', 'prompts.debugging.message'),\n createPrompt(\n 'prompts.developmentConcept.title',\n 'prompts.developmentConcept.message',\n ),\n createPrompt(\n 'prompts.codeOptimization.title',\n 'prompts.codeOptimization.message',\n ),\n createPrompt('prompts.documentation.title', 'prompts.documentation.message'),\n createPrompt('prompts.gitWorkflows.title', 'prompts.gitWorkflows.message'),\n createPrompt(\n 'prompts.testingStrategies.title',\n 'prompts.testingStrategies.message',\n ),\n createPrompt(\n 'prompts.sortingAlgorithms.title',\n 'prompts.sortingAlgorithms.message',\n ),\n createPrompt('prompts.eventDriven.title', 'prompts.eventDriven.message'),\n];\n\nexport const RHDH_SAMPLE_PROMPTS: SamplePrompts = [\n createPrompt('prompts.tekton.title', 'prompts.tekton.message'),\n createPrompt('prompts.openshift.title', 'prompts.openshift.message'),\n createPrompt('prompts.rhdh.title', 'prompts.rhdh.message'),\n];\n\n// Topic restriction valid provider IDs\nexport const VALID_TOPIC_RESTRICTION_PROVIDER_IDS = [\n 'lightspeed_question_validity-shield',\n];\n"],"names":[],"mappings":"AAkBO,MAAM,oBAAuB,GAAA;AAOpC,MAAM,YAAA,GAAe,CAAC,QAAA,EAAkB,UAAuB,KAAA;AAC7D,EAAO,OAAA,EAAE,UAAU,UAAW,EAAA;AAChC,CAAA;AAEO,MAAM,kBAAqB,GAAA;AAAA,EAChC,YAAA,EAAc,CAAC,MAAM,CAAA;AAAA,EACrB,kBAAA,EAAoB,CAAC,OAAO,CAAA;AAAA,EAC5B,kBAAA,EAAoB,CAAC,OAAA,EAAS,MAAM,CAAA;AAAA,EACpC,iBAAA,EAAmB,CAAC,MAAM;AAC5B;AAEO,MAAM,sBAAwC,GAAA;AAAA,EACnD,YAAA;AAAA,IACE,+BAAA;AAAA,IACA;AAAA,GACF;AAAA,EACA,YAAA,CAAa,2BAA2B,2BAA2B,CAAA;AAAA,EACnE,YAAA;AAAA,IACE,kCAAA;AAAA,IACA;AAAA,GACF;AAAA,EACA,YAAA;AAAA,IACE,gCAAA;AAAA,IACA;AAAA,GACF;AAAA,EACA,YAAA,CAAa,+BAA+B,+BAA+B,CAAA;AAAA,EAC3E,YAAA,CAAa,8BAA8B,8BAA8B,CAAA;AAAA,EACzE,YAAA;AAAA,IACE,iCAAA;AAAA,IACA;AAAA,GACF;AAAA,EACA,YAAA;AAAA,IACE,iCAAA;AAAA,IACA;AAAA,GACF;AAAA,EACA,YAAA,CAAa,6BAA6B,6BAA6B;AACzE;AAEO,MAAM,mBAAqC,GAAA;AAAA,EAChD,YAAA,CAAa,wBAAwB,wBAAwB,CAAA;AAAA,EAC7D,YAAA,CAAa,2BAA2B,2BAA2B,CAAA;AAAA,EACnE,YAAA,CAAa,sBAAsB,sBAAsB;AAC3D;AAGO,MAAM,oCAAuC,GAAA;AAAA,EAClD;AACF;;;;"}
@@ -5,7 +5,7 @@ import { lightspeedApiRef } from '../api/api.esm.js';
5
5
  import { TEMP_CONVERSATION_ID } from '../const.esm.js';
6
6
  import botAvatar from '../images/bot-avatar.svg';
7
7
  import userAvatar from '../images/user-avatar.svg';
8
- import { getMessageData, createUserMessage, createBotMessage, transformDocumentsToSources, getTimestamp } from '../utils/lightspeed-chatbox-utils.esm.js';
8
+ import { getConversationsData, createUserMessage, createBotMessage, transformDocumentsToSources, getTimestamp } from '../utils/lightspeed-chatbox-utils.esm.js';
9
9
  import { useCreateConversationMessage } from './useCreateCoversationMessage.esm.js';
10
10
 
11
11
  const useFetchConversationMessages = (currentConversation) => {
@@ -19,7 +19,7 @@ const useFetchConversationMessages = (currentConversation) => {
19
19
  retry: false
20
20
  });
21
21
  };
22
- const useConversationMessages = (conversationId, userName, selectedModel, avatar = userAvatar, onComplete, onStart) => {
22
+ const useConversationMessages = (conversationId, userName, selectedModel, selectedProvider, avatar = userAvatar, onComplete, onStart) => {
23
23
  const { mutateAsync: createMessage } = useCreateConversationMessage();
24
24
  const scrollToBottomRef = React.useRef(null);
25
25
  const [currentConversation, setCurrentConversation] = React.useState(conversationId);
@@ -49,31 +49,27 @@ const useConversationMessages = (conversationId, userName, selectedModel, avatar
49
49
  const _conversations = {
50
50
  [currentConversation]: []
51
51
  };
52
- for (let i = 0; i < conversationsData.length; i += 2) {
53
- const userMessage = conversationsData[i];
54
- const aiMessage = conversationsData[i + 1];
55
- const { content: humanMessage, timestamp: userTimestamp } = getMessageData(userMessage);
56
- const {
57
- model,
58
- content: botMessage,
59
- timestamp: botTimestamp,
60
- referencedDocuments
61
- } = getMessageData(aiMessage);
52
+ for (let i = 0; i < conversationsData.length; i++) {
53
+ const [userMessage, aiMessage] = getConversationsData(
54
+ conversationsData[i]
55
+ );
62
56
  _conversations[currentConversation].push(
63
57
  ...[
64
58
  createUserMessage({
65
59
  avatar,
66
60
  name: userName,
67
- content: humanMessage,
68
- timestamp: userTimestamp
61
+ content: userMessage.content,
62
+ timestamp: userMessage.timestamp
69
63
  }),
70
64
  createBotMessage({
71
65
  avatar: botAvatar,
72
66
  isLoading: false,
73
- name: model ?? selectedModel,
74
- content: botMessage,
75
- timestamp: botTimestamp,
76
- sources: transformDocumentsToSources(referencedDocuments)
67
+ name: conversationsData[i].model ?? selectedModel,
68
+ content: aiMessage.content,
69
+ timestamp: aiMessage.timestamp,
70
+ sources: transformDocumentsToSources(
71
+ aiMessage?.referencedDocuments ?? []
72
+ )
77
73
  })
78
74
  ]
79
75
  );
@@ -133,6 +129,7 @@ const useConversationMessages = (conversationId, userName, selectedModel, avatar
133
129
  const reader = await createMessage({
134
130
  prompt,
135
131
  selectedModel,
132
+ selectedProvider,
136
133
  currentConversation,
137
134
  attachments
138
135
  });
@@ -154,7 +151,7 @@ const useConversationMessages = (conversationId, userName, selectedModel, avatar
154
151
  newConversationId = data?.conversation_id;
155
152
  }
156
153
  }
157
- if (event === "token") {
154
+ if (event === "token" && data?.role === "inference") {
158
155
  const content = data?.token || "";
159
156
  finalMessages.push(content);
160
157
  const [humanMessage, aiMessage] = streamingConversations.current[currentConversation];
@@ -169,10 +166,13 @@ const useConversationMessages = (conversationId, userName, selectedModel, avatar
169
166
  content: "",
170
167
  timestamp: getTimestamp(Date.now())
171
168
  }) : { ...conversation[lastMessageIndex] };
172
- lastMessage.isLoading = false;
169
+ if ((lastMessage?.content ?? "").trim().length > 0) {
170
+ lastMessage.isLoading = false;
171
+ }
173
172
  lastMessage.content += content;
174
173
  lastMessage.name = data?.response_metadata?.model || selectedModel;
175
174
  lastMessage.timestamp = getTimestamp(
175
+ // TODO: To be fixed in the query response
176
176
  data?.response_metadata?.created_at || Date.now()
177
177
  );
178
178
  const updatedConversation = [
@@ -192,8 +192,9 @@ const useConversationMessages = (conversationId, userName, selectedModel, avatar
192
192
  const lastMessageIndex = conversation.length - 1;
193
193
  const lastMessage = conversation.length === 0 ? createBotMessage({
194
194
  content: "",
195
+ isLoading: false,
195
196
  timestamp: getTimestamp(Date.now())
196
- }) : { ...conversation[lastMessageIndex] };
197
+ }) : { ...conversation[lastMessageIndex], isLoading: false };
197
198
  if (documents.length) {
198
199
  lastMessage.sources = {
199
200
  sources: documents.map((doc) => ({
@@ -270,6 +271,7 @@ const useConversationMessages = (conversationId, userName, selectedModel, avatar
270
271
  onComplete,
271
272
  onStart,
272
273
  selectedModel,
274
+ selectedProvider,
273
275
  createMessage,
274
276
  currentConversation
275
277
  ]