From 9e2fb95aeef9be528b48d7870bb2faab411b574a Mon Sep 17 00:00:00 2001 From: Ilia Date: Thu, 3 Oct 2024 13:26:18 +0200 Subject: [PATCH] feat: init AI chat widget (#36610) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Fixes #36541 > [!WARNING] > _If no issue exists, please create an issue first, and check with the maintainers if the issue is valid._ ## Automation /ok-to-test tags="" ### :mag: Cypress test results > [!WARNING] > Tests have not run on the HEAD c4a6e25abc716cc6a54e612a3800ca95079ba8a0 yet >
Thu, 03 Oct 2024 11:06:19 UTC ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No ## Summary by CodeRabbit - **New Features** - Introduced the WDS AI Chat Widget for interactive chat experiences using OpenAI. - Added the AIChat component for enhanced chat functionality. - Expanded the collection of available widgets with the new WDS AI Chat Widget. - Introduced the ThreadMessage component for structured message rendering in the chat interface. - Added UserAvatar and ChatTitle components for improved user interaction and display. - Introduced new icons and thumbnails for AI Chat and Date Picker to enhance visual representation. - **Bug Fixes** - Resolved issues related to widget integration within the existing framework. - **Documentation** - Updated configuration files to enhance modularity and organization. - Expanded documentation to include new icons and thumbnails. - **Chores** - Added the OpenAI, React Markdown, and React Syntax Highlighter dependencies for improved functionality. - Introduced a new type declaration dependency for better type support. --------- Co-authored-by: Valera Melnikov Co-authored-by: saiprabhu-dandanayak Co-authored-by: Rudraprasad Das Co-authored-by: Abhishek Pandey <66054987+a6hishekpandey@users.noreply.github.com> Co-authored-by: NandanAnantharamu <67676905+NandanAnantharamu@users.noreply.github.com> Co-authored-by: “NandanAnantharamu” <“nandan@thinkify.io”> Co-authored-by: Anagh Hegde Co-authored-by: Abhijeet Co-authored-by: Abhijeet <41686026+abhvsn@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: albinAppsmith <87797149+albinAppsmith@users.noreply.github.com> Co-authored-by: sneha122 Co-authored-by: “sneha122” <“sneha@appsmith.com”> Co-authored-by: Arpit Mohan Co-authored-by: Nidhi Nair Co-authored-by: Nilansh Bansal Co-authored-by: Rishabh Rathod Co-authored-by: vadim --- app/client/jest.config.js | 2 +- app/client/package.json | 1 + .../design-system/widgets/jest.config.js | 1 + .../design-system/widgets/package.json | 5 +- .../widgets/src/components/AIChat/index.ts | 1 + .../src/components/AIChat/src/AIChat.tsx | 85 ++ .../AIChat/src/ChatTitle/ChatTitle.tsx | 13 + .../components/AIChat/src/ChatTitle/index.ts | 2 + .../AIChat/src/ChatTitle/styles.module.css | 22 + .../components/AIChat/src/ChatTitle/types.ts | 5 + .../src/ThreadMessage/ThreadMessage.tsx | 64 + .../AIChat/src/ThreadMessage/index.ts | 2 + .../src/ThreadMessage/styles.module.css | 27 + .../AIChat/src/ThreadMessage/types.ts | 7 + .../AIChat/src/UserAvatar/UserAvatar.tsx | 27 + .../components/AIChat/src/UserAvatar/index.ts | 2 + .../AIChat/src/UserAvatar/styles.module.css | 13 + .../components/AIChat/src/UserAvatar/types.ts | 5 + .../src/components/AIChat/src/index.ts | 2 + .../components/AIChat/src/styles.module.css | 48 + .../src/components/AIChat/src/types.ts | 18 + .../design-system/widgets/src/index.ts | 1 + .../icons/src/components/Icons/AIChatIcon.tsx | 2 + .../components/Icons/ComboboxSelectIcon.tsx | 2 +- .../src/components/Icons/DatePickerIcon.tsx | 2 + .../icons/src/components/Icons/InputIcon.tsx | 2 +- .../components/Thumbnails/AIChatThumbnail.tsx | 2 + .../Thumbnails/DatePickerThumbnail.tsx | 2 + .../packages/icons/src/icons/Icons/AIChat.svg | 1 + .../icons/src/icons/Icons/ComboboxSelect.svg | 2 +- .../icons/src/icons/Icons/DatePicker.svg | 1 + .../packages/icons/src/icons/Icons/Input.svg | 2 +- .../icons/src/icons/Thumbnails/AIChat.svg | 1 + .../icons/src/icons/Thumbnails/DatePicker.svg | 1 + app/client/packages/icons/src/index.ts | 4 + .../packages/icons/src/stories/Icons.mdx | 4 + .../packages/icons/src/stories/Thumbnails.mdx | 4 + .../ui/wds/WDSAIChatWidget/index.tsx | 3 + .../widget/config/anvilConfig.ts | 11 + .../widget/config/autocompleteConfig.ts | 5 + .../widget/config/defaultConfig.ts | 10 + .../WDSAIChatWidget/widget/config/index.ts | 17 + .../widget/config/metaConfig.ts | 9 + .../widget/config/methodsConfig.ts | 6 + .../widget/config/propertyPaneContent.ts | 140 +++ .../widget/config/propertyPaneStyle.ts | 1 + .../ui/wds/WDSAIChatWidget/widget/index.tsx | 214 ++++ .../modules/ui-builder/ui/wds/constants.ts | 1 + app/client/src/widgets/index.ts | 2 + app/client/test/__mocks__/reactMarkdown.tsx | 3 + app/client/yarn.lock | 1031 ++++++++++++++++- 51 files changed, 1814 insertions(+), 24 deletions(-) create mode 100644 app/client/packages/design-system/widgets/src/components/AIChat/index.ts create mode 100644 app/client/packages/design-system/widgets/src/components/AIChat/src/AIChat.tsx create mode 100644 app/client/packages/design-system/widgets/src/components/AIChat/src/ChatTitle/ChatTitle.tsx create mode 100644 app/client/packages/design-system/widgets/src/components/AIChat/src/ChatTitle/index.ts create mode 100644 app/client/packages/design-system/widgets/src/components/AIChat/src/ChatTitle/styles.module.css create mode 100644 app/client/packages/design-system/widgets/src/components/AIChat/src/ChatTitle/types.ts create mode 100644 app/client/packages/design-system/widgets/src/components/AIChat/src/ThreadMessage/ThreadMessage.tsx create mode 100644 app/client/packages/design-system/widgets/src/components/AIChat/src/ThreadMessage/index.ts create mode 100644 app/client/packages/design-system/widgets/src/components/AIChat/src/ThreadMessage/styles.module.css create mode 100644 app/client/packages/design-system/widgets/src/components/AIChat/src/ThreadMessage/types.ts create mode 100644 app/client/packages/design-system/widgets/src/components/AIChat/src/UserAvatar/UserAvatar.tsx create mode 100644 app/client/packages/design-system/widgets/src/components/AIChat/src/UserAvatar/index.ts create mode 100644 app/client/packages/design-system/widgets/src/components/AIChat/src/UserAvatar/styles.module.css create mode 100644 app/client/packages/design-system/widgets/src/components/AIChat/src/UserAvatar/types.ts create mode 100644 app/client/packages/design-system/widgets/src/components/AIChat/src/index.ts create mode 100644 app/client/packages/design-system/widgets/src/components/AIChat/src/styles.module.css create mode 100644 app/client/packages/design-system/widgets/src/components/AIChat/src/types.ts create mode 100644 app/client/packages/icons/src/components/Icons/AIChatIcon.tsx create mode 100644 app/client/packages/icons/src/components/Icons/DatePickerIcon.tsx create mode 100644 app/client/packages/icons/src/components/Thumbnails/AIChatThumbnail.tsx create mode 100644 app/client/packages/icons/src/components/Thumbnails/DatePickerThumbnail.tsx create mode 100644 app/client/packages/icons/src/icons/Icons/AIChat.svg create mode 100644 app/client/packages/icons/src/icons/Icons/DatePicker.svg create mode 100644 app/client/packages/icons/src/icons/Thumbnails/AIChat.svg create mode 100644 app/client/packages/icons/src/icons/Thumbnails/DatePicker.svg create mode 100644 app/client/src/modules/ui-builder/ui/wds/WDSAIChatWidget/index.tsx create mode 100644 app/client/src/modules/ui-builder/ui/wds/WDSAIChatWidget/widget/config/anvilConfig.ts create mode 100644 app/client/src/modules/ui-builder/ui/wds/WDSAIChatWidget/widget/config/autocompleteConfig.ts create mode 100644 app/client/src/modules/ui-builder/ui/wds/WDSAIChatWidget/widget/config/defaultConfig.ts create mode 100644 app/client/src/modules/ui-builder/ui/wds/WDSAIChatWidget/widget/config/index.ts create mode 100644 app/client/src/modules/ui-builder/ui/wds/WDSAIChatWidget/widget/config/metaConfig.ts create mode 100644 app/client/src/modules/ui-builder/ui/wds/WDSAIChatWidget/widget/config/methodsConfig.ts create mode 100644 app/client/src/modules/ui-builder/ui/wds/WDSAIChatWidget/widget/config/propertyPaneContent.ts create mode 100644 app/client/src/modules/ui-builder/ui/wds/WDSAIChatWidget/widget/config/propertyPaneStyle.ts create mode 100644 app/client/src/modules/ui-builder/ui/wds/WDSAIChatWidget/widget/index.tsx create mode 100644 app/client/test/__mocks__/reactMarkdown.tsx diff --git a/app/client/jest.config.js b/app/client/jest.config.js index abe29d26d8..bc9bc713c1 100644 --- a/app/client/jest.config.js +++ b/app/client/jest.config.js @@ -5,7 +5,7 @@ const LOG_LEVELS = ["debug", "error"]; const CONFIG_LOG_LEVEL_INDEX = 1; module.exports = { - setupFiles: ["jest-canvas-mock"], + setupFiles: ["jest-canvas-mock", "/test/__mocks__/reactMarkdown.tsx"], roots: ["/src"], transform: { "^.+\\.(png|js|ts|tsx)$": "ts-jest", diff --git a/app/client/package.json b/app/client/package.json index 9ce6628afc..a8dbd76851 100644 --- a/app/client/package.json +++ b/app/client/package.json @@ -161,6 +161,7 @@ "nanoid": "^2.0.4", "node-forge": "^1.3.0", "object-hash": "^3.0.0", + "openai": "^4.64.0", "path-to-regexp": "^6.3.0", "popper.js": "^1.15.0", "prismjs": "^1.27.0", diff --git a/app/client/packages/design-system/widgets/jest.config.js b/app/client/packages/design-system/widgets/jest.config.js index 59574a2a95..08272cd0c5 100644 --- a/app/client/packages/design-system/widgets/jest.config.js +++ b/app/client/packages/design-system/widgets/jest.config.js @@ -1,6 +1,7 @@ module.exports = { preset: "ts-jest", roots: ["/src"], + setupFiles: ["../../../test/__mocks__/reactMarkdown.tsx"], testEnvironment: "jsdom", moduleNameMapper: { "\\.(css)$": "../../../test/__mocks__/styleMock.js", diff --git a/app/client/packages/design-system/widgets/package.json b/app/client/packages/design-system/widgets/package.json index d1069bce6c..12607a4be3 100644 --- a/app/client/packages/design-system/widgets/package.json +++ b/app/client/packages/design-system/widgets/package.json @@ -26,10 +26,13 @@ "@tabler/icons-react": "^3.10.0", "clsx": "^2.0.0", "lodash": "*", - "react-aria-components": "^1.2.1" + "react-aria-components": "^1.2.1", + "react-markdown": "^9.0.1", + "react-syntax-highlighter": "^15.5.0" }, "devDependencies": { "@types/fs-extra": "^11.0.4", + "@types/react-syntax-highlighter": "^15.5.13", "eslint-plugin-storybook": "^0.6.10" }, "peerDependencies": { diff --git a/app/client/packages/design-system/widgets/src/components/AIChat/index.ts b/app/client/packages/design-system/widgets/src/components/AIChat/index.ts new file mode 100644 index 0000000000..3bd16e178a --- /dev/null +++ b/app/client/packages/design-system/widgets/src/components/AIChat/index.ts @@ -0,0 +1 @@ +export * from "./src"; diff --git a/app/client/packages/design-system/widgets/src/components/AIChat/src/AIChat.tsx b/app/client/packages/design-system/widgets/src/components/AIChat/src/AIChat.tsx new file mode 100644 index 0000000000..3a7c0f7559 --- /dev/null +++ b/app/client/packages/design-system/widgets/src/components/AIChat/src/AIChat.tsx @@ -0,0 +1,85 @@ +import { Button, Spinner, Text, TextArea } from "@appsmith/wds"; +import type { FormEvent, ForwardedRef, KeyboardEvent } from "react"; +import React, { forwardRef, useCallback } from "react"; +import { ChatTitle } from "./ChatTitle"; +import styles from "./styles.module.css"; +import { ThreadMessage } from "./ThreadMessage"; +import type { AIChatProps, ChatMessage } from "./types"; +import { UserAvatar } from "./UserAvatar"; + +const MIN_PROMPT_LENGTH = 3; + +const _AIChat = (props: AIChatProps, ref: ForwardedRef) => { + const { + // assistantName, + chatTitle, + description, + isWaitingForResponse = false, + onPromptChange, + onSubmit, + prompt, + promptInputPlaceholder, + thread, + username, + ...rest + } = props; + + const handleFormSubmit = useCallback( + (event: FormEvent) => { + event.preventDefault(); + onSubmit?.(); + }, + [onSubmit], + ); + + const handlePromptInputKeyDown = useCallback( + (event: KeyboardEvent) => { + if (event.key === "Enter" && event.shiftKey) { + event.preventDefault(); + onSubmit?.(); + } + }, + [onSubmit], + ); + + return ( +
+
+ {chatTitle != null && } + + {description ?? {description}} +
+ + {username} +
+
+ +
    + {thread.map((message: ChatMessage) => ( + + ))} + + {isWaitingForResponse && ( +
  • + +
  • + )} +
+ +
+