diff --git a/frontends/main/Dockerfile.web b/frontends/main/Dockerfile.web index 1d495f0535..8577a892f7 100644 --- a/frontends/main/Dockerfile.web +++ b/frontends/main/Dockerfile.web @@ -57,6 +57,7 @@ FROM node:22-alpine RUN apk update RUN apk add --no-cache libc6-compat +RUN apk add --no-cache git WORKDIR /app diff --git a/frontends/main/package.json b/frontends/main/package.json index 2b3985f5ce..b55cdfcdb6 100644 --- a/frontends/main/package.json +++ b/frontends/main/package.json @@ -14,10 +14,8 @@ "@emotion/cache": "^11.13.1", "@emotion/styled": "^11.11.0", "@mitodl/course-search-utils": "3.3.2", - "@mitodl/smoot-design": "^3.0.1", + "@mitodl/smoot-design": "^3.2.0", "@next/bundle-analyzer": "^14.2.15", - "@nlux/react": "^2.17.1", - "@nlux/themes": "^2.17.1", "@remixicon/react": "^4.2.0", "@sentry/nextjs": "^8.36.0", "@tanstack/react-query": "^4.36.1", diff --git a/frontends/main/public/images/icons/tim.svg b/frontends/main/public/images/icons/tim.svg new file mode 100644 index 0000000000..53690473f8 --- /dev/null +++ b/frontends/main/public/images/icons/tim.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/frontends/main/src/app-pages/ChatPage/ChatPage.tsx b/frontends/main/src/app-pages/ChatPage/ChatPage.tsx index 056719b8ab..fe8d84a9cd 100644 --- a/frontends/main/src/app-pages/ChatPage/ChatPage.tsx +++ b/frontends/main/src/app-pages/ChatPage/ChatPage.tsx @@ -1,61 +1,61 @@ "use client" -import React, { useMemo } from "react" -import { makeSend } from "./send" -import { FeatureFlags } from "@/common/feature_flags" -import { useFeatureFlagEnabled } from "posthog-js/react" -import StyledContainer from "@/page-components/StyledContainer/StyledContainer" +import React from "react" import { styled } from "ol-components" -import { NluxAiChat } from "@/page-components/Nlux-AiChat/AiChat" +import { getCsrfToken } from "@/common/utils" +import { AiChat, AiChatProps } from "@mitodl/smoot-design/ai" -const StyledChat = styled(NluxAiChat)({ - maxHeight: "60vh", - flex: 1, +const Container = styled.div({ + margin: "40px auto", + width: "60%", }) -const CONVERSATION_OPTIONS = { - conversationStarters: [ - { - prompt: - "I'm interested in courses on quantum computing that offer certificates.", - }, - { - prompt: - "I want to learn about global warming, can you recommend any videos?", - }, - { - prompt: - "I am curious about AI applications for business. Do you have any free courses about that?", - }, - { - prompt: - "I would like to learn about linear regression, preferably at no cost.", - }, - ], -} +const INITIAL_MESSAGES: AiChatProps["initialMessages"] = [ + { + content: "What do you want to learn about today?", + role: "assistant", + }, +] + +export const STARTERS = [ + { + content: + "I'm interested in courses on quantum computing that offer certificates.", + }, + { + content: + "I want to learn about global warming, can you recommend any videos?", + }, + { + content: + "I am curious about AI applications for business. Do you have any free courses about that?", + }, + { + content: + "I would like to learn about linear regression, preferably at no cost.", + }, +] const ChatPage = () => { - const recommendationBotEnabled = useFeatureFlagEnabled( - FeatureFlags.RecommendationBot, - ) - const send = useMemo(() => { - return makeSend({ url: "/api/v0/chat_agent/" }) - }, []) return ( - - { - // eslint-disable-next-line no-constant-condition - recommendationBotEnabled ? ( - - ) : ( - <> - ) - } - + + ({ + message: messages[messages.length - 1].content, + }), + }} + /> + ) } diff --git a/frontends/main/src/app-pages/ChatPage/send.ts b/frontends/main/src/app-pages/ChatPage/send.ts deleted file mode 100644 index edcc672760..0000000000 --- a/frontends/main/src/app-pages/ChatPage/send.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { NluxAiChatProps } from "@/page-components/Nlux-AiChat/AiChat" - -function getCookie(name: string) { - const value = `; ${document.cookie}` - const parts = value.split(`; ${name}=`) - if (parts.length === 2) { - return parts.pop()?.split(";").shift() - } -} - -type EndpointOpts = { - url: "/api/v0/chat_agent/" - extraBody?: Record -} - -const makeRequest = async (opts: EndpointOpts, message: string) => - fetch(`${process.env.NEXT_PUBLIC_MITOL_API_BASE_URL}${opts.url}`, { - method: "POST", - headers: { - "Content-Type": "application/json", - "X-CSRFToken": - getCookie(process.env.NEXT_PUBLIC_CSRF_COOKIE_NAME || "csrftoken") ?? - "", - }, - credentials: "include", // TODO Remove this, should be handled by same-origin - body: JSON.stringify({ message, ...opts.extraBody }), - }) - -const RESPONSE_DELAY = 500 - -// Function to send query to the server and receive a stream of chunks as response -const makeSend = - ( - opts: EndpointOpts, - processContent: (content: string) => string = (content) => content, - ): NluxAiChatProps["send"] => - async (message, observer) => { - const response = await makeRequest(opts, message) - - if (response.status !== 200) { - observer.error(new Error("Failed to connect to the server")) - return - } - - if (!response.body) { - return - } - - // Read a stream of server-sent events - // and feed them to the observer as they are being generated - const reader = response.body.getReader() - const textDecoder = new TextDecoder() - - // eslint-disable-next-line no-constant-condition - while (true) { - const { value, done } = await reader.read() - if (done) { - /** - * Without the pause here, some messages were getting displayed completely - * empty. Unsure why. - * - * Maybe related to stream having only a single chunk? - */ - await new Promise((res) => setTimeout(res, RESPONSE_DELAY)) - break - } - - const content = textDecoder.decode(value) - if (content) { - observer.next(processContent(content)) - } - } - - observer.complete() - } - -export { makeSend } -export type { EndpointOpts } diff --git a/frontends/main/src/app-pages/ChatSyllabusPage/ChatSyllabusPage.tsx b/frontends/main/src/app-pages/ChatSyllabusPage/ChatSyllabusPage.tsx index 6a65999fea..b1bf5de211 100644 --- a/frontends/main/src/app-pages/ChatSyllabusPage/ChatSyllabusPage.tsx +++ b/frontends/main/src/app-pages/ChatSyllabusPage/ChatSyllabusPage.tsx @@ -1,7 +1,6 @@ "use client" import React, { useState } from "react" import { styled, MenuItem, Alert } from "ol-components" - import { FeatureFlags } from "@/common/feature_flags" import { useFeatureFlagEnabled } from "posthog-js/react" import StyledContainer from "@/page-components/StyledContainer/StyledContainer" @@ -40,9 +39,6 @@ const StyledDebugPre = styled.pre({ width: "80%", whiteSpace: "pre-wrap", }) -const AiChatStyled = styled(AiChat)({ - height: "60vh", -}) const ChatSyllabusPage = () => { const botEnabled = useFeatureFlagEnabled(FeatureFlags.RecommendationBot) @@ -52,111 +48,108 @@ const ChatSyllabusPage = () => { return ( - { - // eslint-disable-next-line no-constant-condition - botEnabled ? ( - <> -
- -
- Course - - Contentfile Chunk Size - -
-
-
- { - return { - message: messages[messages.length - 1].content, - readable_id: readableId, - collection_name: collectionName, - } - }, - onFinish: (message) => { - const contentParts = message.content.split("