rm ai chat

main
alex 2024-12-29 13:34:56 +01:00
parent 73d5804f8c
commit 9daa737a24
15 changed files with 211 additions and 102 deletions

32
deploy-production.sh Executable file
View File

@ -0,0 +1,32 @@
npm run build
# create zip file of build folder
zip -r build.zip build
# connect to server to clear folder
ssh root@93.177.67.38 << EOF
cd /var/www/html/navilearn-dashboard-web/
rm -rf *
exit
EOF
# copy zip file to server
scp build.zip root@93.177.67.38:/var/www/html/navilearn-dashboard-web/
# connect to server
ssh root@93.177.67.38 << EOF
cd /var/www/html/navilearn-dashboard-web/
unzip build.zip
mv /var/www/html/navilearn-dashboard-web/build/* /var/www/html/navilearn-dashboard-web/
rm -rf /var/www/html/navilearn-dashboard-web/build
rm build.zip
exit
EOF
# remove zip file from local machine
rm build.zip

BIN
public/apple-touch-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
public/favicon-16x16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
public/favicon-32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -5,39 +5,43 @@
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#000000" />
<meta <meta name="description" content="Dashboard for NaviLearn" />
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!-- <link
manifest.json provides metadata used when your web app is installed on a rel="apple-touch-icon"
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ sizes="180x180"
--> href="%PUBLIC_URL%/apple-touch-icon.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="%PUBLIC_URL%/favicon-32x32.png"
/>
<link rel="icon" type="image/png" sizes="16x16"
href=%PUBLIC_URL%"/favicon-16x16.png">
<meta name="msapplication-TileColor" content="#da532c" />
<meta name="theme-color" content="#ffffff" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!-- <title>NaviLearn</title>
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will <script type="text/javascript">
work correctly both with client-side routing and a non-root public URL. (function (c, l, a, r, i, t, y) {
Learn how to configure a non-root public URL by running `npm run build`. c[a] =
--> c[a] ||
<title>App</title> function () {
(c[a].q = c[a].q || []).push(arguments);
};
t = l.createElement(r);
t.async = 1;
t.src = "https://www.clarity.ms/tag/" + i;
y = l.getElementsByTagName(r)[0];
y.parentNode.insertBefore(t, y);
})(window, document, "clarity", "script", "o4tg2haxvt");
</script>
</head> </head>
<body> <body>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div> <div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body> </body>
</html> </html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 103 KiB

View File

@ -1,6 +1,6 @@
{ {
"short_name": "React App", "short_name": "NaviLearn",
"name": "Create React App Sample", "name": "NaviLearn",
"icons": [ "icons": [
{ {
"src": "favicon.ico", "src": "favicon.ico",

BIN
public/mstile-150x150.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -1,78 +1,124 @@
import { ConfigProvider, Layout, theme } from 'antd'; import { ConfigProvider, Layout, theme } from "antd";
import DashboardLayout from './core/components/DashboardLayout'; import DashboardLayout from "./core/components/DashboardLayout";
import { darkMode, primaryColor, setBannerUrl, setLogoUrl, setPrimaryColor, setUserAuthenticated, userAuthenticated, setUserProfilePictureUrl } from './core/reducers/appSlice'; import {
import { useDispatch, useSelector } from 'react-redux'; darkMode,
import SignIn from './features/Auth/SignIn'; primaryColor,
import { useEffect } from 'react'; setBannerUrl,
import { myFetch } from './core/utils/utils'; setLogoUrl,
import MyCenteredSpin from './shared/components/MyCenteredSpin'; setPrimaryColor,
import webSocketService, { WebSocketMessageHandler } from 'core/services/websocketService'; setUserAuthenticated,
import { MessageProvider } from 'core/context/MessageContext'; userAuthenticated,
setUserProfilePictureUrl,
} from "./core/reducers/appSlice";
import { useDispatch, useSelector } from "react-redux";
import SignIn from "./features/Auth/SignIn";
import { useEffect } from "react";
import { myFetch } from "./core/utils/utils";
import MyCenteredSpin from "./shared/components/MyCenteredSpin";
import webSocketService, {
WebSocketMessageHandler,
} from "core/services/websocketService";
import { MessageProvider } from "core/context/MessageContext";
const { defaultAlgorithm, darkAlgorithm } = theme; const { defaultAlgorithm, darkAlgorithm } = theme;
export default function App() { export default function App() {
const dispatch = useDispatch(); const dispatch = useDispatch();
const isDarkMode = useSelector(darkMode); const isDarkMode = useSelector(darkMode);
const uAuthenticated = useSelector(userAuthenticated); const uAuthenticated = useSelector(userAuthenticated);
const primColor = useSelector(primaryColor); const primColor = useSelector(primaryColor);
console.info( console.info(
'\n %c LMS %c v1.0.0 %c \n', "\n %c LMS %c v1.0.0 %c \n",
'background-color: #555;color: #fff;padding: 3px 2px 3px 3px;border-radius: 3px 0 0 3px;font-family: DejaVu Sans,Verdana,Geneva,sans-serif;text-shadow: 0 1px 0 rgba(1, 1, 1, 0.3)', "background-color: #555;color: #fff;padding: 3px 2px 3px 3px;border-radius: 3px 0 0 3px;font-family: DejaVu Sans,Verdana,Geneva,sans-serif;text-shadow: 0 1px 0 rgba(1, 1, 1, 0.3)",
'background-color: #bc81e0;background-image: linear-gradient(90deg, #e67e22, #9b59b6);color: #fff;padding: 3px 3px 3px 2px;border-radius: 0 3px 3px 0;font-family: DejaVu Sans,Verdana,Geneva,sans-serif;text-shadow: 0 1px 0 rgba(1, 1, 1, 0.3)', "background-color: #bc81e0;background-image: linear-gradient(90deg, #e67e22, #9b59b6);color: #fff;padding: 3px 3px 3px 2px;border-radius: 0 3px 3px 0;font-family: DejaVu Sans,Verdana,Geneva,sans-serif;text-shadow: 0 1px 0 rgba(1, 1, 1, 0.3)",
'background-color: transparent' "background-color: transparent"
); );
useEffect(() => { useEffect(() => {
if (uAuthenticated) { if (uAuthenticated) {
(async () => { (async () => {
try { try {
const response = await myFetch({ const response = await myFetch({
url: '/app', url: "/app",
method: 'GET', method: "GET",
}); });
if (response) { if (response) {
dispatch(setPrimaryColor(`#${response.Organization.PrimaryColor}`)); dispatch(setPrimaryColor(`#${response.Organization.PrimaryColor}`));
dispatch(setLogoUrl(response.Organization.LogoUrl)); dispatch(setLogoUrl(response.Organization.LogoUrl));
dispatch(setBannerUrl(response.Organization.BannerUrl)); dispatch(setBannerUrl(response.Organization.BannerUrl));
dispatch(setUserProfilePictureUrl(response.User.ProfilePictureUrl)); dispatch(setUserProfilePictureUrl(response.User.ProfilePictureUrl));
dispatch(setUserAuthenticated(true));
webSocketService.connect();
webSocketService.setHandler(WebSocketMessageHandler, dispatch);
}
} catch (error) {}
})();
return () => {
webSocketService.disconnect();
};
}
}, [uAuthenticated]);
useEffect(() => {
if (!localStorage.getItem('session')) {
dispatch(setUserAuthenticated(false));
} else {
dispatch(setUserAuthenticated(true)); dispatch(setUserAuthenticated(true));
}
}, [dispatch]);
return ( webSocketService.connect();
<Layout style={{ minHeight: '100vh' }}> webSocketService.setHandler(WebSocketMessageHandler, dispatch);
<ConfigProvider }
theme={{ } catch (error) {}
algorithm: isDarkMode ? darkAlgorithm : defaultAlgorithm, })();
token: {
colorPrimary: primColor, return () => {
}, webSocketService.disconnect();
}} };
> }
<MessageProvider>{uAuthenticated == null ? <MyCenteredSpin /> : uAuthenticated ? <DashboardLayout /> : <SignIn />}</MessageProvider> }, [uAuthenticated]);
</ConfigProvider>
</Layout> useEffect(() => {
); const query = new URLSearchParams(window.location.search);
if (!localStorage.getItem("session") && !query.has("s")) {
dispatch(setUserAuthenticated(false));
} else if (query.has("s")) {
const searchParam = query.get("s");
if (searchParam) {
localStorage.setItem("session", searchParam);
window.history.replaceState(
{},
document.title,
window.location.pathname
);
dispatch(setUserAuthenticated(true));
} else {
dispatch(setUserAuthenticated(false));
}
} else {
dispatch(setUserAuthenticated(true));
}
}, [dispatch]);
useEffect(() => {
const plScript = document.createElement("script");
plScript.src = "https://anal.jannex.de/js/script.js";
plScript.async = true;
plScript.defer = true;
plScript.setAttribute("data-domain", "dashboard.navilearn.io");
document.head.appendChild(plScript);
}, []);
return (
<Layout style={{ minHeight: "100vh" }}>
<ConfigProvider
theme={{
algorithm: isDarkMode ? darkAlgorithm : defaultAlgorithm,
token: {
colorPrimary: primColor,
},
}}
>
<MessageProvider>
{uAuthenticated == null ? (
<MyCenteredSpin />
) : uAuthenticated ? (
<DashboardLayout />
) : (
<SignIn />
)}
</MessageProvider>
</ConfigProvider>
</Layout>
);
} }

View File

@ -51,7 +51,7 @@ export default function DashboardLayout() {
<PageContent /> <PageContent />
<AiChat /> {/* <AiChat /> */}
</Layout> </Layout>
</Layout> </Layout>
</MyDndContext> </MyDndContext>

View File

@ -7,9 +7,25 @@ import { getUserSessionFromLocalStorage } from 'core/utils/utils';
import { Marked, marked } from 'marked'; import { Marked, marked } from 'marked';
import { createDirectives, presetDirectiveConfigs } from 'marked-directive'; import { createDirectives, presetDirectiveConfigs } from 'marked-directive';
interface MessageContent {
role?: string;
text?: string;
files?: any[];
html?: string;
}
let chatHistory: MessageContent[] = [
{
text: 'Hallo! Ich bin ein Chatbot. Stell mir Fragen :)',
role: 'ai',
},
];
function AiChat() { function AiChat() {
const [visible, setVisible] = React.useState(false); const [visible, setVisible] = React.useState(false);
//const [chatHistory, setChatHistory] = React.useState<MessageContent[]>([{ text: 'Stell mir Fragen :)', role: 'ai' }]);
return ( return (
<> <>
{visible ? ( {visible ? (
@ -35,7 +51,13 @@ function AiChat() {
position: 'absolute', position: 'absolute',
}} }}
avatars={true} avatars={true}
history={[{ text: 'Stell mir Fragen :)', role: 'ai' }]} history={chatHistory}
onMessage={(message) => {
if (message.isHistory) return;
//setChatHistory([...chatHistory, message.message]);
chatHistory.push(message.message);
}}
connect={{ connect={{
url: '/api/chat/v1/prompt/', url: '/api/chat/v1/prompt/',
method: 'POST', method: 'POST',
@ -63,6 +85,11 @@ function AiChat() {
}, },
}, },
}} }}
requestInterceptor={async (requestDetails) => {
console.log(requestDetails); // printed above
requestDetails.body.isFirstMessage = chatHistory.length <= 1;
return requestDetails;
}}
responseInterceptor={async (response: any) => { responseInterceptor={async (response: any) => {
let _response = { ...response }; let _response = { ...response };

View File

@ -6,13 +6,13 @@
background-position: center; background-position: center;
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: cover; background-size: cover;
height: 100%; height: 100vh;
width: 100%; width: 100%;
} }
.darkenBackground { .darkenBackground {
position: absolute; position: absolute;
background-color: rgba(0, 0, 0, 0.5); background-color: rgba(0, 0, 0, 0.5);
height: 100%; height: 100vh;
width: 100%; width: 100%;
} }

View File

@ -412,7 +412,7 @@ function SubdomainCard({
message: t( message: t(
"organizationSettings.subdomainCard.rules.minLength", "organizationSettings.subdomainCard.rules.minLength",
{ {
min: Constants.GLOBALS.MIN_SUBDOMAIN_LENGTH, minLength: Constants.GLOBALS.MIN_SUBDOMAIN_LENGTH,
} }
), ),
}, },
@ -421,7 +421,7 @@ function SubdomainCard({
message: t( message: t(
"organizationSettings.subdomainCard.rules.maxLength", "organizationSettings.subdomainCard.rules.maxLength",
{ {
max: Constants.GLOBALS.MAX_SUBDOMAIN_LENGTH, maxLength: Constants.GLOBALS.MAX_SUBDOMAIN_LENGTH,
} }
), ),
}, },