diff --git a/ProductivitySuite/README.md b/ProductivitySuite/README.md new file mode 100644 index 000000000..036b2711e --- /dev/null +++ b/ProductivitySuite/README.md @@ -0,0 +1,23 @@ +# OPEA Productivity Suite Application + +OPEA Productivity Suite, is a powerful tool designed to streamline your workflow and boost productivity. This application leverages the cutting-edge OPEA microservices to provide a comprehensive suite of features that cater to the diverse needs of modern enterprises. + +### Key Features + +- Chat with Documents: Engage in intelligent conversations with your documents using our advanced RAG Capabilities. Our Retrieval-Augmented Generation (RAG) model allows you to ask questions, receive relevant information, and gain insights from your documents in real-time. + +- Content Summarization: Save time and effort by automatically summarizing lengthy documents or articles, enabling you to quickly grasp the key takeaways. + +- FAQ Generation: Effortlessly create comprehensive FAQs based on your documents, ensuring that your users have access to the information they need. + +- Code Generation: Boost your coding productivity with our code generation feature. Simply provide a description of the functionality you require, and the application will generate the corresponding code snippets, saving you valuable time and effort. + +- User Context Management: Maintain a seamless workflow by managing your user's context within the application. Our context management system keeps track of your documents and chat history, allowing for personalized experiences. + +- Identity and access management: uses OpenSource platform (Keycloak) for single sign-on identity and access management. + +Refer to the [Keycloak Configuration Guide](./docker/xeon/keycloak_setup_guide.md) for more instruction on setup Keycloak. + +Refer to the [Xeon Guide](./docker/xeon/README.md) for more instructions on building docker images from source and running the application via docker compose. + +Refer to the [Xeon Kubernetes Guide](./kubernetes/manifests/README.md) for more instruction on deploying the application via kubernetes. diff --git a/ProductivitySuite/assets/img/Login_page.png b/ProductivitySuite/assets/img/Login_page.png new file mode 100644 index 000000000..0c325e5f2 Binary files /dev/null and b/ProductivitySuite/assets/img/Login_page.png differ diff --git a/ProductivitySuite/assets/img/chat_qna_init.png b/ProductivitySuite/assets/img/chat_qna_init.png new file mode 100644 index 000000000..c13630594 Binary files /dev/null and b/ProductivitySuite/assets/img/chat_qna_init.png differ diff --git a/ProductivitySuite/assets/img/chatqna_with_conversation.png b/ProductivitySuite/assets/img/chatqna_with_conversation.png new file mode 100644 index 000000000..1dad3a099 Binary files /dev/null and b/ProductivitySuite/assets/img/chatqna_with_conversation.png differ diff --git a/ProductivitySuite/assets/img/codegen.png b/ProductivitySuite/assets/img/codegen.png new file mode 100644 index 000000000..a4d38f6f4 Binary files /dev/null and b/ProductivitySuite/assets/img/codegen.png differ diff --git a/ProductivitySuite/assets/img/create_client.png b/ProductivitySuite/assets/img/create_client.png new file mode 100644 index 000000000..ab7d22808 Binary files /dev/null and b/ProductivitySuite/assets/img/create_client.png differ diff --git a/ProductivitySuite/assets/img/create_productivitysuite_realm.png b/ProductivitySuite/assets/img/create_productivitysuite_realm.png new file mode 100644 index 000000000..47b364991 Binary files /dev/null and b/ProductivitySuite/assets/img/create_productivitysuite_realm.png differ diff --git a/ProductivitySuite/assets/img/create_realm.png b/ProductivitySuite/assets/img/create_realm.png new file mode 100644 index 000000000..d05e5ec26 Binary files /dev/null and b/ProductivitySuite/assets/img/create_realm.png differ diff --git a/ProductivitySuite/assets/img/create_roles.png b/ProductivitySuite/assets/img/create_roles.png new file mode 100644 index 000000000..75417ebd6 Binary files /dev/null and b/ProductivitySuite/assets/img/create_roles.png differ diff --git a/ProductivitySuite/assets/img/create_users.png b/ProductivitySuite/assets/img/create_users.png new file mode 100644 index 000000000..5e3205e3a Binary files /dev/null and b/ProductivitySuite/assets/img/create_users.png differ diff --git a/ProductivitySuite/assets/img/data_source.png b/ProductivitySuite/assets/img/data_source.png new file mode 100644 index 000000000..ae45e1223 Binary files /dev/null and b/ProductivitySuite/assets/img/data_source.png differ diff --git a/ProductivitySuite/assets/img/doc_summary_file.png b/ProductivitySuite/assets/img/doc_summary_file.png new file mode 100644 index 000000000..d4c18ebd4 Binary files /dev/null and b/ProductivitySuite/assets/img/doc_summary_file.png differ diff --git a/ProductivitySuite/assets/img/doc_summary_paste.png b/ProductivitySuite/assets/img/doc_summary_paste.png new file mode 100644 index 000000000..ddaa2f3b3 Binary files /dev/null and b/ProductivitySuite/assets/img/doc_summary_paste.png differ diff --git a/ProductivitySuite/assets/img/faq_generator.png b/ProductivitySuite/assets/img/faq_generator.png new file mode 100644 index 000000000..7c25eea1a Binary files /dev/null and b/ProductivitySuite/assets/img/faq_generator.png differ diff --git a/ProductivitySuite/assets/img/keycloak_login.png b/ProductivitySuite/assets/img/keycloak_login.png new file mode 100644 index 000000000..abbdbebee Binary files /dev/null and b/ProductivitySuite/assets/img/keycloak_login.png differ diff --git a/ProductivitySuite/assets/img/productivitysuite_client_settings.png b/ProductivitySuite/assets/img/productivitysuite_client_settings.png new file mode 100644 index 000000000..8c64451c2 Binary files /dev/null and b/ProductivitySuite/assets/img/productivitysuite_client_settings.png differ diff --git a/ProductivitySuite/assets/img/set_user_password.png b/ProductivitySuite/assets/img/set_user_password.png new file mode 100644 index 000000000..24af0caf3 Binary files /dev/null and b/ProductivitySuite/assets/img/set_user_password.png differ diff --git a/ProductivitySuite/assets/img/user_role_mapping.png b/ProductivitySuite/assets/img/user_role_mapping.png new file mode 100644 index 000000000..2dc0feab2 Binary files /dev/null and b/ProductivitySuite/assets/img/user_role_mapping.png differ diff --git a/ProductivitySuite/docker/docker_build_compose.yaml b/ProductivitySuite/docker/docker_build_compose.yaml new file mode 100644 index 000000000..4b205a361 --- /dev/null +++ b/ProductivitySuite/docker/docker_build_compose.yaml @@ -0,0 +1,100 @@ +# Copyright (C) 2024 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +services: + chatqna: + build: + args: + http_proxy: ${http_proxy} + https_proxy: ${https_proxy} + no_proxy: ${no_proxy} + context: ../../ChatQnA/docker/ + dockerfile: ./Dockerfile + image: ${REGISTRY:-opea}/chatqna:${TAG:-latest} + embedding-tei: + build: + context: GenAIComps + dockerfile: comps/embeddings/langchain/docker/Dockerfile + extends: chatqna + image: ${REGISTRY:-opea}/embedding-tei:${TAG:-latest} + retriever-redis: + build: + context: GenAIComps + dockerfile: comps/retrievers/langchain/redis/docker/Dockerfile + extends: chatqna + image: ${REGISTRY:-opea}/retriever-redis:${TAG:-latest} + reranking-tei: + build: + context: GenAIComps + dockerfile: comps/reranks/tei/docker/Dockerfile + extends: chatqna + image: ${REGISTRY:-opea}/reranking-tei:${TAG:-latest} + llm-tgi: + build: + context: GenAIComps + dockerfile: comps/llms/text-generation/tgi/Dockerfile + extends: chatqna + image: ${REGISTRY:-opea}/llm-tgi:${TAG:-latest} + dataprep-redis: + build: + context: GenAIComps + dockerfile: comps/dataprep/redis/langchain/docker/Dockerfile + extends: chatqna + image: ${REGISTRY:-opea}/dataprep-redis:${TAG:-latest} + promptregistry-mongo: + build: + context: GenAIComps + dockerfile: comps/prompt_registry/mongo/docker/Dockerfile + extends: chatqna + image: ${REGISTRY:-opea}/promptregistry-mongo-server:${TAG:-latest} + chathistory-mongo: + build: + context: GenAIComps + dockerfile: comps/chathistory/mongo/docker/Dockerfile + extends: chatqna + image: ${REGISTRY:-opea}/chathistory-mongo-server:${TAG:-latest} + productivity-suite-react-ui: + build: + context: ui + dockerfile: ./docker/Dockerfile.react + extends: chatqna + image: ${REGISTRY:-opea}/productivity-suite-react-ui-server:${TAG:-latest} + codegen: + build: + args: + http_proxy: ${http_proxy} + https_proxy: ${https_proxy} + no_proxy: ${no_proxy} + context: ../../CodeGen/docker/ + dockerfile: ./Dockerfile + image: ${REGISTRY:-opea}/codegen:${TAG:-latest} + docsum: + build: + args: + http_proxy: ${http_proxy} + https_proxy: ${https_proxy} + no_proxy: ${no_proxy} + context: ../../DocSum/docker/ + dockerfile: ./Dockerfile + image: ${REGISTRY:-opea}/docsum:${TAG:-latest} + faqgen: + build: + args: + http_proxy: ${http_proxy} + https_proxy: ${https_proxy} + no_proxy: ${no_proxy} + context: ../../FaqGen/docker/ + dockerfile: ./Dockerfile + image: ${REGISTRY:-opea}/faqgen:${TAG:-latest} + llm_faqgen: + build: + context: GenAIComps + dockerfile: comps/llms/faq-generation/tgi/Dockerfile + extends: faqgen + image: ${REGISTRY:-opea}/llm-faqgen-tgi:${TAG:-latest} + llm_docsum_server: + build: + context: GenAIComps + dockerfile: comps/llms/summarization/tgi/Dockerfile + extends: docsum + image: ${REGISTRY:-opea}/llm-docsum-tgi:${TAG:-latest} diff --git a/ProductivitySuite/docker/ui/docker/Dockerfile.react b/ProductivitySuite/docker/ui/docker/Dockerfile.react new file mode 100644 index 000000000..f023b7afb --- /dev/null +++ b/ProductivitySuite/docker/ui/docker/Dockerfile.react @@ -0,0 +1,21 @@ +# Copyright (C) 2024 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +# Use node 20.11.1 as the base image +FROM node:20.11.1 as vite-app + +COPY ./react /usr/app/react +WORKDIR /usr/app/react + + +RUN ["npm", "install"] +RUN ["npm", "run", "build"] + + +FROM nginx:alpine + +COPY --from=vite-app /usr/app/react/dist /usr/share/nginx/html +COPY ./react/env.sh /docker-entrypoint.d/env.sh + +COPY ./react/nginx.conf /etc/nginx/conf.d/default.conf +RUN chmod +x /docker-entrypoint.d/env.sh \ No newline at end of file diff --git a/ProductivitySuite/docker/ui/react/.env.production b/ProductivitySuite/docker/ui/react/.env.production new file mode 100644 index 000000000..a7b38a272 --- /dev/null +++ b/ProductivitySuite/docker/ui/react/.env.production @@ -0,0 +1,16 @@ +VITE_BACKEND_SERVICE_ENDPOINT_CHATQNA=APP_BACKEND_SERVICE_ENDPOINT_CHATQNA +VITE_BACKEND_SERVICE_ENDPOINT_CODEGEN=APP_BACKEND_SERVICE_ENDPOINT_CODEGEN +VITE_BACKEND_SERVICE_ENDPOINT_DOCSUM=APP_BACKEND_SERVICE_ENDPOINT_DOCSUM +VITE_BACKEND_SERVICE_ENDPOINT_FAQGEN=APP_BACKEND_SERVICE_ENDPOINT_FAQGEN +VITE_KEYCLOAK_SERVICE_ENDPOINT=APP_KEYCLOAK_SERVICE_ENDPOINT + + +VITE_DATAPREP_SERVICE_ENDPOINT=APP_DATAPREP_SERVICE_ENDPOINT +VITE_DATAPREP_GET_FILE_ENDPOINT=APP_DATAPREP_GET_FILE_ENDPOINT +VITE_DATAPREP_DELETE_FILE_ENDPOINT=APP_DATAPREP_DELETE_FILE_ENDPOINT + +VITE_CHAT_HISTORY_CREATE_ENDPOINT=APP_CHAT_HISTORY_CREATE_ENDPOINT +VITE_CHAT_HISTORY_GET_ENDPOINT=APP_CHAT_HISTORY_GET_ENDPOINT +VITE_CHAT_HISTORY_DELETE_ENDPOINT=APP_CHAT_HISTORY_DELETE_ENDPOINT +VITE_PROMPT_SERVICE_GET_ENDPOINT=APP_PROMPT_SERVICE_GET_ENDPOINT +VITE_PROMPT_SERVICE_CREATE_ENDPOINT=APP_PROMPT_SERVICE_CREATE_ENDPOINT \ No newline at end of file diff --git a/ProductivitySuite/docker/ui/react/.eslintrc.cjs b/ProductivitySuite/docker/ui/react/.eslintrc.cjs new file mode 100644 index 000000000..78174f683 --- /dev/null +++ b/ProductivitySuite/docker/ui/react/.eslintrc.cjs @@ -0,0 +1,11 @@ +module.exports = { + root: true, + env: { browser: true, es2020: true }, + extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended", "plugin:react-hooks/recommended"], + ignorePatterns: ["dist", ".eslintrc.cjs"], + parser: "@typescript-eslint/parser", + plugins: ["react-refresh"], + rules: { + "react-refresh/only-export-components": ["warn", { allowConstantExport: true }], + }, +}; diff --git a/ProductivitySuite/docker/ui/react/.gitignore b/ProductivitySuite/docker/ui/react/.gitignore new file mode 100644 index 000000000..a547bf36d --- /dev/null +++ b/ProductivitySuite/docker/ui/react/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/ProductivitySuite/docker/ui/react/README.md b/ProductivitySuite/docker/ui/react/README.md new file mode 100644 index 000000000..72703ef3b --- /dev/null +++ b/ProductivitySuite/docker/ui/react/README.md @@ -0,0 +1,82 @@ +

Productivity Suite React UI

+ +### 📸 Project Screenshots + +![project-screenshot](../../../assets/img/chat_qna_init.png) +![project-screenshot](../../../assets/img/Login_page.png) + +

🧐 Features

+ +Here're some of the project's features: + +#### CHAT QNA + +- Start a Text Chat:Initiate a text chat with the ability to input written conversations, where the dialogue content can also be customized based on uploaded files. +- Context Awareness: The AI assistant maintains the context of the conversation, understanding references to previous statements or questions. This allows for more natural and coherent exchanges. + + ##### DATA SOURCE + + - The choice between uploading locally or copying a remote link. Chat according to uploaded knowledge base. + - Uploaded File would get listed and user would be able add or remove file/links + + ###### Screen Shot + + ![project-screenshot](../../../assets/img/data_source.png) + +- Clear: Clear the record of the current dialog box without retaining the contents of the dialog box. +- Chat history: Historical chat records can still be retained after refreshing, making it easier for users to view the context. +- Conversational Chat : The application maintains a history of the conversation, allowing users to review previous messages and the AI to refer back to earlier points in the dialogue when necessary. + ###### Screen Shots + ![project-screenshot](../../../assets/img/chat_qna_init.png) + ![project-screenshot](../../../assets/img/chatqna_with_conversation.png) + +#### CODEGEN + +- Generate code: generate the corresponding code based on the current user's input. + ###### Screen Shot + ![project-screenshot](../../../assets/img/codegen.png) + +#### DOC SUMMARY + +- Summarizing Uploaded Files: Upload files from their local device, then click 'Generate Summary' to summarize the content of the uploaded file. The summary will be displayed on the 'Summary' box. +- Summarizing Text via Pasting: Paste the text to be summarized into the text box, then click 'Generate Summary' to produce a condensed summary of the content, which will be displayed in the 'Summary' box on the right. +- Scroll to Bottom: The summarized content will automatically scroll to the bottom. + ###### Screen Shot + ![project-screenshot](../../../assets/img/doc_summary_paste.png) + ![project-screenshot](../../../assets/img/doc_summary_file.png) + +#### FAQ Generator + +- Generate FAQs from Text via Pasting: Paste the text to into the text box, then click 'Generate FAQ' to produce a condensed FAQ of the content, which will be displayed in the 'FAQ' box below. + +- Generate FAQs from Text via txt file Upload: Upload the file in the Upload bar, then click 'Generate FAQ' to produce a condensed FAQ of the content, which will be displayed in the 'FAQ' box below. + ###### Screen Shot + ![project-screenshot](../../../assets/img/faq_generator.png) + +

🛠️ Get it Running:

+ +1. Clone the repo. + +2. cd command to the current folder. + +3. create a .env file and add the following variables and values. + ```env + VITE_BACKEND_SERVICE_ENDPOINT_CHATQNA='' + VITE_BACKEND_SERVICE_ENDPOINT_CODEGEN='' + VITE_BACKEND_SERVICE_ENDPOINT_DOCSUM='' + VITE_BACKEND_SERVICE_ENDPOINT_FAQGEN='' + VITE_KEYCLOAK_SERVICE_ENDPOINT='' + VITE_DATAPREP_SERVICE_ENDPOINT='' + VITE_DATAPREP_GET_FILE_ENDPOINT='' + VITE_DATAPREP_DELETE_FILE_ENDPOINT='' + VITE_CHAT_HISTORY_CREATE_ENDPOINT='' + VITE_CHAT_HISTORY_GET_ENDPOINT='' + VITE_CHAT_HISTORY_DELETE_ENDPOINT='' + VITE_PROMPT_SERVICE_GET_ENDPOINT='' + VITE_PROMPT_SERVICE_CREATE_ENDPOINT='' + ``` +4. Execute `npm install` to install the corresponding dependencies. + +5. Execute `npm run dev` + +6. open http://localhost:5174 in browser to the see the UI diff --git a/ProductivitySuite/docker/ui/react/env.sh b/ProductivitySuite/docker/ui/react/env.sh new file mode 100644 index 000000000..ce1372ea6 --- /dev/null +++ b/ProductivitySuite/docker/ui/react/env.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# Copyright (C) 2024 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +for i in $(env | grep APP_) #// Make sure to use the prefix MY_APP_ if you have any other prefix in env.production file variable name replace it with MY_APP_ +do + key=$(echo $i | cut -d '=' -f 1) + value=$(echo $i | cut -d '=' -f 2-) + echo $key=$value + # sed All files + # find /usr/share/nginx/html -type f -exec sed -i "s|${key}|${value}|g" '{}' + + + # sed JS and CSS only + find /usr/share/nginx/html -type f \( -name '*.js' -o -name '*.css' \) -exec sed -i "s|${key}|${value}|g" '{}' + +done diff --git a/ProductivitySuite/docker/ui/react/index.html b/ProductivitySuite/docker/ui/react/index.html new file mode 100644 index 000000000..fbe87e0fd --- /dev/null +++ b/ProductivitySuite/docker/ui/react/index.html @@ -0,0 +1,18 @@ + + + + + + + + + Conversations UI + + +
+ + + diff --git a/ProductivitySuite/docker/ui/react/nginx.conf b/ProductivitySuite/docker/ui/react/nginx.conf new file mode 100644 index 000000000..00433fcda --- /dev/null +++ b/ProductivitySuite/docker/ui/react/nginx.conf @@ -0,0 +1,20 @@ +server { + listen 80; + + gzip on; + gzip_proxied any; + gzip_comp_level 6; + gzip_buffers 16 8k; + gzip_http_version 1.1; + gzip_types font/woff2 text/css application/javascript application/json application/font-woff application/font-tff image/gif image/png image/svg+xml application/octet-stream; + + location / { + root /usr/share/nginx/html; + index index.html index.htm; + try_files $uri $uri/ /index.html =404; + + location ~* \.(gif|jpe?g|png|webp|ico|svg|css|js|mp4|woff2)$ { + expires 1d; + } + } +} \ No newline at end of file diff --git a/ProductivitySuite/docker/ui/react/package.json b/ProductivitySuite/docker/ui/react/package.json new file mode 100644 index 000000000..322808acc --- /dev/null +++ b/ProductivitySuite/docker/ui/react/package.json @@ -0,0 +1,56 @@ +{ + "name": "ui", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", + "preview": "vite preview", + "test": "vitest run" + }, + "dependencies": { + "@mantine/core": "^7.11.1", + "@mantine/dropzone": "^7.11.1", + "@mantine/hooks": "^7.11.1", + "@mantine/notifications": "^7.10.2", + "@microsoft/fetch-event-source": "^2.0.1", + "@react-keycloak/web": "^3.4.0", + "@reduxjs/toolkit": "^2.2.5", + "@tabler/icons-react": "^3.5.0", + "axios": "^1.7.2", + "keycloak-js": "^25.0.2", + "luxon": "^3.4.4", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-markdown": "^9.0.1", + "react-redux": "^9.1.2", + "react-router-dom": "^6.25.1", + "react-syntax-highlighter": "^15.5.0", + "remark-frontmatter": "^5.0.0", + "remark-gfm": "^4.0.0" + }, + "devDependencies": { + "@testing-library/react": "^16.0.0", + "@types/luxon": "^3.4.2", + "@types/node": "^20.12.12", + "@types/react": "^18.2.66", + "@types/react-dom": "^18.2.22", + "@types/react-syntax-highlighter": "^15.5.13", + "@typescript-eslint/eslint-plugin": "^7.2.0", + "@typescript-eslint/parser": "^7.2.0", + "@vitejs/plugin-react": "^4.2.1", + "eslint": "^8.57.0", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.6", + "jsdom": "^24.1.0", + "postcss": "^8.4.38", + "postcss-preset-mantine": "^1.15.0", + "postcss-simple-vars": "^7.0.1", + "sass": "1.64.2", + "typescript": "^5.2.2", + "vite": "^5.2.13", + "vitest": "^1.6.0" + } +} diff --git a/ProductivitySuite/docker/ui/react/postcss.config.cjs b/ProductivitySuite/docker/ui/react/postcss.config.cjs new file mode 100644 index 000000000..e817f567b --- /dev/null +++ b/ProductivitySuite/docker/ui/react/postcss.config.cjs @@ -0,0 +1,14 @@ +module.exports = { + plugins: { + "postcss-preset-mantine": {}, + "postcss-simple-vars": { + variables: { + "mantine-breakpoint-xs": "36em", + "mantine-breakpoint-sm": "48em", + "mantine-breakpoint-md": "62em", + "mantine-breakpoint-lg": "75em", + "mantine-breakpoint-xl": "88em", + }, + }, + }, +}; diff --git a/ProductivitySuite/docker/ui/react/src/App.scss b/ProductivitySuite/docker/ui/react/src/App.scss new file mode 100644 index 000000000..187764a17 --- /dev/null +++ b/ProductivitySuite/docker/ui/react/src/App.scss @@ -0,0 +1,42 @@ +// Copyright (C) 2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +@import "./styles/styles"; + +.root { + @include flex(row, nowrap, flex-start, flex-start); +} + +.layout-wrapper { + @include absolutes; + + display: grid; + + width: 100%; + height: 100%; + + grid-template-columns: 80px auto; + grid-template-rows: 1fr; +} + +/* ===== Scrollbar CSS ===== */ +/* Firefox */ +* { + scrollbar-width: thin; + scrollbar-color: #d6d6d6 #ffffff; +} + +/* Chrome, Edge, and Safari */ +*::-webkit-scrollbar { + width: 8px; +} + +*::-webkit-scrollbar-track { + background: #ffffff; +} + +*::-webkit-scrollbar-thumb { + background-color: #d6d6d6; + border-radius: 16px; + border: 4px double #dedede; +} diff --git a/ProductivitySuite/docker/ui/react/src/App.tsx b/ProductivitySuite/docker/ui/react/src/App.tsx new file mode 100644 index 000000000..c12ee1d8f --- /dev/null +++ b/ProductivitySuite/docker/ui/react/src/App.tsx @@ -0,0 +1,68 @@ +// Copyright (C) 2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +import "./App.scss" +import {MantineProvider } from "@mantine/core" +import '@mantine/notifications/styles.css'; +import { SideNavbar, SidebarNavList } from "./components/sidebar/sidebar" +import { IconMessages, IconFileTextAi, IconCode, IconFileInfo, IconDatabaseCog } from "@tabler/icons-react" +import Conversation from "./components/Conversation/Conversation" +import { Notifications } from '@mantine/notifications'; +import { BrowserRouter, Route, Routes } from "react-router-dom"; +import CodeGen from "./components/CodeGen/CodeGen"; +import DocSum from "./components/DocSum/DocSum"; +import FaqGen from "./components/FaqGen/FaqGen"; +import { useKeycloak } from "@react-keycloak/web"; +import DataSource from "./components/Conversation/DataSource"; +import { useAppDispatch } from "./redux/store"; +import { setUser } from "./redux/User/userSlice"; +import { useEffect } from "react"; + +const title = "Chat QnA" +const navList: SidebarNavList = [ + { icon: IconMessages, label: "Chat Qna", path: "/", children: }, + { icon: IconCode, label: "CodeGen", path: "/codegen", children: }, + { icon: IconFileTextAi, label: "DocSum", path: "/docsum", children: }, + { icon: IconFileInfo, label: "FaqGen", path: "/faqgen", children: }, + { icon: IconDatabaseCog, label: "Data Management", path: "/data-management", children: } +] + +function App() { + const { keycloak } = useKeycloak(); + const dispatch = useAppDispatch() + useEffect(()=>{ + dispatch(setUser(keycloak?.idTokenParsed?.preferred_username)) + },[keycloak.idTokenParsed]) + + return ( + <> + + {!keycloak.authenticated ? ( + "redirecting to sso ..." + ) : ( + + + +
+ +
+ + {navList.map(tab => { + return () + })} + + + + +
+
+
+ )} +
+ + + ) + +} + +export default App diff --git a/ProductivitySuite/docker/ui/react/src/__tests__/util.test.ts b/ProductivitySuite/docker/ui/react/src/__tests__/util.test.ts new file mode 100644 index 000000000..e67ba2c86 --- /dev/null +++ b/ProductivitySuite/docker/ui/react/src/__tests__/util.test.ts @@ -0,0 +1,14 @@ +// Copyright (C) 2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +import { describe, expect, test } from "vitest"; +import { getCurrentTimeStamp, uuidv4 } from "../common/util"; + +describe("unit tests", () => { + test("check UUID is of length 36", () => { + expect(uuidv4()).toHaveLength(36); + }); + test("check TimeStamp generated is of unix", () => { + expect(getCurrentTimeStamp()).toBe(Math.floor(Date.now() / 1000)); + }); +}); diff --git a/ProductivitySuite/docker/ui/react/src/assets/opea-icon-black.svg b/ProductivitySuite/docker/ui/react/src/assets/opea-icon-black.svg new file mode 100644 index 000000000..5c96dc762 --- /dev/null +++ b/ProductivitySuite/docker/ui/react/src/assets/opea-icon-black.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ProductivitySuite/docker/ui/react/src/assets/opea-icon-color.svg b/ProductivitySuite/docker/ui/react/src/assets/opea-icon-color.svg new file mode 100644 index 000000000..790151171 --- /dev/null +++ b/ProductivitySuite/docker/ui/react/src/assets/opea-icon-color.svg @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ProductivitySuite/docker/ui/react/src/assets/react.svg b/ProductivitySuite/docker/ui/react/src/assets/react.svg new file mode 100644 index 000000000..6c87de9bb --- /dev/null +++ b/ProductivitySuite/docker/ui/react/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ProductivitySuite/docker/ui/react/src/common/client.ts b/ProductivitySuite/docker/ui/react/src/common/client.ts new file mode 100644 index 000000000..7512f73e3 --- /dev/null +++ b/ProductivitySuite/docker/ui/react/src/common/client.ts @@ -0,0 +1,8 @@ +// Copyright (C) 2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +import axios from "axios"; + +//add iterceptors to add any request headers + +export default axios; diff --git a/ProductivitySuite/docker/ui/react/src/common/util.ts b/ProductivitySuite/docker/ui/react/src/common/util.ts new file mode 100644 index 000000000..df65b2d8e --- /dev/null +++ b/ProductivitySuite/docker/ui/react/src/common/util.ts @@ -0,0 +1,12 @@ +// Copyright (C) 2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +export const getCurrentTimeStamp = () => { + return Math.floor(Date.now() / 1000); +}; + +export const uuidv4 = () => { + return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, (c) => + (+c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (+c / 4)))).toString(16), + ); +}; diff --git a/ProductivitySuite/docker/ui/react/src/components/CodeGen/CodeGen.tsx b/ProductivitySuite/docker/ui/react/src/components/CodeGen/CodeGen.tsx new file mode 100644 index 000000000..29c96f61c --- /dev/null +++ b/ProductivitySuite/docker/ui/react/src/components/CodeGen/CodeGen.tsx @@ -0,0 +1,140 @@ +// Copyright (C) 2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +import { KeyboardEventHandler, SyntheticEvent, useEffect, useRef, useState } from 'react' +import styleClasses from "./codeGen.module.scss" +import { ActionIcon, Textarea, Title, rem } from '@mantine/core' +import { IconArrowRight } from '@tabler/icons-react' +import { ConversationMessage } from '../Message/conversationMessage' +import { fetchEventSource } from '@microsoft/fetch-event-source' +import { CODE_GEN_URL } from '../../config' + + + +const CodeGen = () => { + const [prompt, setPrompt] = useState("") + const [submittedPrompt, setSubmittedPrompt] = useState("") + const [response,setResponse] = useState(""); + const promptInputRef = useRef(null) + const scrollViewport = useRef(null) + + const toSend = "Enter" + + const handleSubmit = async () => { + setResponse("") + setSubmittedPrompt(prompt) + const body = { + messages:prompt + } + fetchEventSource(CODE_GEN_URL, { + method: "POST", + headers: { + "Content-Type": "application/json", + "Accept":"*/*" + }, + body: JSON.stringify(body), + openWhenHidden: true, + async onopen(response) { + if (response.ok) { + return; + } else if (response.status >= 400 && response.status < 500 && response.status !== 429) { + const e = await response.json(); + console.log(e); + throw Error(e.error.message); + } else { + console.log("error", response); + } + }, + onmessage(msg) { + if (msg?.data != "[DONE]") { + try { + const match = msg.data.match(/b'([^']*)'/); + if (match && match[1] != "") { + const extractedText = match[1].replace(/\\n/g, "\n"); + setResponse(prev=>prev+extractedText); + } + } catch (e) { + console.log("something wrong in msg", e); + throw e; + } + } + }, + onerror(err) { + console.log("error", err); + setResponse("") + throw err; + }, + onclose() { + setPrompt("") + }, + }); + + } + + const scrollToBottom = () => { + scrollViewport.current!.scrollTo({ top: scrollViewport.current!.scrollHeight }) + } + + useEffect(() => { + scrollToBottom() + }, [response]) + + const handleKeyDown: KeyboardEventHandler = (event) => { + if (!event.shiftKey && event.key === toSend) { + handleSubmit() + setTimeout(() => { + setPrompt("") + }, 1) + } + } + + const handleChange = (event: SyntheticEvent) => { + event.preventDefault() + setPrompt((event.target as HTMLTextAreaElement).value) + } + return ( +
+
+
+
+ CodeGen +
+ +
+ {!submittedPrompt && !response && + (<> +
Start by asking a question
+ ) + } + {submittedPrompt && ( + + )} + {response && ( + + )} +
+ +
+