From 1d6faa93eb4f14f261fa6222d29b57c2e65b0a31 Mon Sep 17 00:00:00 2001 From: n4ze3m Date: Sun, 14 Jul 2024 00:16:01 +0530 Subject: [PATCH] feat: support for procted bot (beta) --- app/ui/src/@types/bot.ts | 43 ++--- .../components/Bot/Settings/SettingPwdP.tsx | 110 ++++++++++++ .../components/Bot/Settings/SettingsBody.tsx | 9 +- app/ui/src/routes/bot/settings.tsx | 11 +- app/widget/package.json | 1 + app/widget/src/App.tsx | 70 +++++--- app/widget/src/components/BotForm.tsx | 10 +- app/widget/src/components/BotHeader.tsx | 74 +++++--- app/widget/src/components/BotLogin.tsx | 163 ++++++++++++++++++ app/widget/src/hooks/useAuth.tsx | 61 +++++++ .../src/hooks/useDynamicTextareaSize.tsx | 38 ++++ app/widget/src/hooks/useMessage.tsx | 21 ++- app/widget/src/main.tsx | 5 +- app/widget/src/utils/getUrl.ts | 7 + app/widget/src/utils/types.ts | 1 + pnpm-lock.yaml | 58 ++++++- server/package.json | 2 + server/prisma/migrations/q_28/migration.sql | 5 + server/prisma/schema.prisma | 5 +- server/src/handlers/api/v1/bot/bot/index.ts | 3 +- .../api/v1/bot/bot/settings.handler.ts | 51 ++++++ server/src/handlers/api/v1/bot/bot/types.ts | 21 ++- server/src/handlers/bot/bot-login.handler.ts | 54 ++++++ server/src/handlers/bot/get.handler.ts | 2 + server/src/handlers/bot/index.ts | 3 +- server/src/handlers/bot/post.handler.ts | 160 +++++++++++++++++ server/src/handlers/bot/types.ts | 13 ++ server/src/routes/api/v1/bot/root.ts | 15 +- server/src/routes/bot/root.ts | 10 ++ server/src/schema/api/v1/bot/bot/index.ts | 38 +++- server/src/schema/bot/index.ts | 26 +++ server/src/utils/jwt.ts | 22 +++ server/yarn.lock | 53 ++++++ 33 files changed, 1058 insertions(+), 107 deletions(-) create mode 100644 app/ui/src/components/Bot/Settings/SettingPwdP.tsx create mode 100644 app/widget/src/components/BotLogin.tsx create mode 100644 app/widget/src/hooks/useAuth.tsx create mode 100644 app/widget/src/hooks/useDynamicTextareaSize.tsx create mode 100644 server/prisma/migrations/q_28/migration.sql create mode 100644 server/src/handlers/api/v1/bot/bot/settings.handler.ts create mode 100644 server/src/handlers/bot/bot-login.handler.ts create mode 100644 server/src/utils/jwt.ts diff --git a/app/ui/src/@types/bot.ts b/app/ui/src/@types/bot.ts index ff342c41..62d86a37 100644 --- a/app/ui/src/@types/bot.ts +++ b/app/ui/src/@types/bot.ts @@ -1,39 +1,40 @@ export type BotSettings = { data: { id: string; - name: string; - model: string; - public_id: string; - temperature: number; - embedding: string; - noOfDocumentsToRetrieve: number; - qaPrompt: string; - questionGeneratorPrompt: string; - streaming: boolean; - showRef: boolean; - use_hybrid_search: boolean; - bot_protect: boolean; - use_rag: boolean; - bot_model_api_key: string; - noOfChatHistoryInContext: number; - semanticSearchSimilarityScore: string - }, + name: string; + model: string; + public_id: string; + temperature: number; + embedding: string; + noOfDocumentsToRetrieve: number; + qaPrompt: string; + questionGeneratorPrompt: string; + streaming: boolean; + showRef: boolean; + use_hybrid_search: boolean; + publicBotPwdProtected: boolean; + publicBotPwd: string; + bot_protect: boolean; + use_rag: boolean; + bot_model_api_key: string; + noOfChatHistoryInContext: number; + semanticSearchSimilarityScore: string; + }; chatModel: { label: string; value: string; stream: boolean; - }[], + }[]; embeddingModel: { label: string; value: string; - }[], + }[]; }; - export type BotIntegrationAPI = { is_api_enabled: boolean; data: { public_url: string | null; api_key: string | null; }; -} \ No newline at end of file +}; diff --git a/app/ui/src/components/Bot/Settings/SettingPwdP.tsx b/app/ui/src/components/Bot/Settings/SettingPwdP.tsx new file mode 100644 index 00000000..daa9610f --- /dev/null +++ b/app/ui/src/components/Bot/Settings/SettingPwdP.tsx @@ -0,0 +1,110 @@ +import { Form, Switch, Input, notification } from "antd"; +import { useParams } from "react-router-dom"; +import api from "../../../services/api"; +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import axios from "axios"; + +type Props = { + publicBotPwdProtected: boolean; + publicBotPwd: string; +}; + +export const SettingsPwdP: React.FC = ({ + publicBotPwd, + publicBotPwdProtected, +}) => { + const params = useParams<{ id: string }>(); + const [form] = Form.useForm(); + const isEnabled = Form.useWatch("publicBotPwdProtected", form); + const client = useQueryClient(); + const onFinish = async (values: any) => { + const response = await api.put(`/bot/${params.id}/password`, values); + return response.data; + }; + + const { mutate, isLoading } = useMutation(onFinish, { + onSuccess: () => { + client.invalidateQueries(["getBotSettings", params.id]); + + notification.success({ + message: "Bot settings updated successfully", + }); + }, + onError: (error: any) => { + if (axios.isAxiosError(error)) { + const message = error.response?.data?.message || "Something went wrong"; + notification.error({ + message, + }); + return; + } + notification.error({ + message: "Something went wrong", + }); + }, + }); + return ( +
+
+
+
+

+ Password Protection +

+

+ Proctect bot's public access with a password. +

+
+
+ + + + + + + + +
+ This feature is in preview and only works with web interface for + now +
+
+
+ +
+ +
+
+
+ ); +}; diff --git a/app/ui/src/components/Bot/Settings/SettingsBody.tsx b/app/ui/src/components/Bot/Settings/SettingsBody.tsx index 611bac73..756246bd 100644 --- a/app/ui/src/components/Bot/Settings/SettingsBody.tsx +++ b/app/ui/src/components/Bot/Settings/SettingsBody.tsx @@ -17,6 +17,7 @@ import { HELPFUL_ASSISTANT_WITHOUT_CONTEXT_PROMPT, } from "../../../utils/prompts"; import { BotSettings } from "../../../@types/bot"; +import { SettingsPwdP } from "./SettingPwdP"; export const SettingsBody: React.FC = ({ data, @@ -147,7 +148,6 @@ export const SettingsBody: React.FC = ({

- {/* centerize the div */}
= ({
+
+ +
+

diff --git a/app/ui/src/routes/bot/settings.tsx b/app/ui/src/routes/bot/settings.tsx index 9a1c902b..0196040c 100644 --- a/app/ui/src/routes/bot/settings.tsx +++ b/app/ui/src/routes/bot/settings.tsx @@ -14,8 +14,7 @@ export default function BotSettingsRoot() { ["getBotSettings", param.id], async () => { const response = await api.get(`/bot/${param.id}/settings`); - return response.data as BotSettings - + return response.data as BotSettings; }, { refetchInterval: 1000, @@ -28,9 +27,11 @@ export default function BotSettingsRoot() { } }, [status]); return ( -
- {status === "loading" && } - {status === "success" && } +
+
+ {status === "loading" && } + {status === "success" && } +
); } diff --git a/app/widget/package.json b/app/widget/package.json index 08bd8681..2ab36865 100644 --- a/app/widget/package.json +++ b/app/widget/package.json @@ -17,6 +17,7 @@ "antd": "^5.5.2", "axios": "^1.4.0", "react": "^18.2.0", + "react-cookie": "^7.1.4", "react-dom": "^18.2.0", "react-markdown": "^8.0.7", "react-syntax-highlighter": "^15.5.0", diff --git a/app/widget/src/App.tsx b/app/widget/src/App.tsx index 53281236..f91a44b9 100644 --- a/app/widget/src/App.tsx +++ b/app/widget/src/App.tsx @@ -12,10 +12,14 @@ import BotChatBubble from "./components/BotChatBubble"; import { BotStyle } from "./utils/types"; import { Modal } from "antd"; import { useStoreReference } from "./store"; +import { useAuth } from "./hooks/useAuth"; +import LoginPage from "./components/BotLogin"; function App() { const { openReferences, setOpenReferences, referenceData } = useStoreReference(); + const { isAuthenticated } = useAuth(); + const divRef = React.useRef(null); const { messages, setMessages, setStreaming, setHistory } = useMessage(); @@ -61,35 +65,49 @@ function App() { } }, [botStyle]); + if (status === "loading") { + return ; + } + + if (status === "error") { + return ( +
+ there was an error occured +
+ ); + } + + if (botStyle?.data?.is_protected && !isAuthenticated) { + return ( + + + + ); + } + return (
- {status === "loading" && } - - {status === "success" && ( - <> -
- -
-
-
- {messages.map((message, index) => { - return ( - - ); - })} -
-
-
-
- -
- - )} +
+ +
+
+
+ {messages.map((message, index) => { + return ( + + ); + })} +
+
+
+
+ +
(false); + const textAreaRef = useRef(null); + + useEffect(() => { + if (textAreaRef.current) { + textAreaRef.current.focus(); + } + }, []); const form = useForm({ initialValues: { @@ -36,6 +43,7 @@ export default function BotForm({}: { botStyle: BotStyle }) { >