Skip to content

Commit

Permalink
View chat list (#1915)
Browse files Browse the repository at this point in the history
Close #1881

Barebones chat list UI.

The chats we have only contain the ID, we need to expand them to show
more stuff so that the users can recongnise which chat it is. Maybe
showing the last message and the date of the message would be helpful.

I tried as much as possible to avoid potential conflicts with #1913. 


Known issues: Currently we don't fetch all messages for a given chat ID
& therefore we cannot continue a previous chat (because we need the id
of the last message), this could be fixed easily by adding a fetch call
to `ChatConversion` or whichever equivalent component.



![image](https://user-images.githubusercontent.com/24505302/221964414-42a904bd-7ae7-4448-99e3-61e2892063d0.png)


![image](https://user-images.githubusercontent.com/24505302/221965689-3a38d7a6-6a33-4353-8a07-91e9f5ce73c4.png)
  • Loading branch information
AbdBarho committed Mar 1, 2023
1 parent 54711ce commit 123fc98
Show file tree
Hide file tree
Showing 8 changed files with 148 additions and 50 deletions.
4 changes: 4 additions & 0 deletions website/public/locales/en/chat.json
@@ -0,0 +1,4 @@
{
"back_to_chat_list": "Back to chat list",
"your_chats": "Your chats"
}
9 changes: 7 additions & 2 deletions website/src/lib/oasst_inference_client.ts
Expand Up @@ -35,15 +35,16 @@ export class OasstInferenceClient {
if (this.inferenceToken) {
return this.inferenceToken;
}
console.log("fetching new token");
// we might want to include the inference token in our JWT, but this won't be trivial.
// or we might have to force log-in the user every time a new JWT is created

// TODO: we have not decided on a format for the user yet, this is here for debug only
const res = await fetch(process.env.INFERENCE_SERVER_HOST + `/auth/login/debug?username=${this.userTokenSub}`);
const inferenceResponse: InferenceDebugTokenResponse = await res.json();
this.inferenceToken = inferenceResponse.access_token;
this.cookies.set("inference_token", this.inferenceToken);
this.cookies.set("inference_token", this.inferenceToken, {
maxAge: 1000 * 60 * 5, // 5 minutes
});
// console.dir(this.inferenceToken);
return this.inferenceToken;
}
Expand All @@ -58,4 +59,8 @@ export class OasstInferenceClient {
responseType: "stream",
});
}

get_my_chats() {
return this.request("GET", "/chat");
}
}
13 changes: 11 additions & 2 deletions website/src/pages/api/chat/index.ts
Expand Up @@ -3,8 +3,17 @@ import { OasstInferenceClient } from "src/lib/oasst_inference_client";

const handler = withoutRole("banned", async (req, res, token) => {
const client = new OasstInferenceClient(req, res, token);
const data = await client.create_chat();
return res.status(200).json(data);
let data;
if (req.method === "GET") {
data = await client.get_my_chats();
} else if (req.method === "POST") {
data = await client.create_chat();
}

if (data) {
return res.status(200).json(data);
}
res.status(400).end();
});

export default handler;
46 changes: 0 additions & 46 deletions website/src/pages/chat.tsx

This file was deleted.

48 changes: 48 additions & 0 deletions website/src/pages/chat/[id].tsx
@@ -0,0 +1,48 @@
import { Button, Flex } from "@chakra-ui/react";
import { List } from "lucide-react";
import { GetServerSideProps } from "next";
import Head from "next/head";
import Link from "next/link";
import { useTranslation } from "next-i18next";
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
import { Flags } from "react-feature-flags";
import { ChatConversation } from "src/components/Chat/ChatConversation";
import { getDashboardLayout } from "src/components/Layout";

const Chat = ({ id }: { id: string }) => {
const { t } = useTranslation(["common", "chat"]);

return (
<>
<Head>
<title>{t("chat")}</title>
</Head>

<Flags authorizedFlags={["chat"]}>
<Flex direction="column" gap="2">
<Link href="/chat">
<Button leftIcon={<List />} size="lg">
{t("chat:back_to_chat_list")}
</Button>
</Link>

<ChatConversation chatId={id} />
</Flex>
</Flags>
</>
);
};

Chat.getLayout = getDashboardLayout;

export const getServerSideProps: GetServerSideProps<{ id: string }, { id: string }> = async ({
locale = "en",
params,
}) => ({
props: {
id: params.id,
...(await serverSideTranslations(locale)),
},
});

export default Chat;
71 changes: 71 additions & 0 deletions website/src/pages/chat/index.tsx
@@ -0,0 +1,71 @@
import { Button, Divider, Flex, Progress, Text } from "@chakra-ui/react";
import Head from "next/head";
import { useTranslation } from "next-i18next";
import { useCallback, useMemo } from "react";
import { getDashboardLayout } from "src/components/Layout";
import { get, post } from "src/lib/api";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
import Link from "next/link";
import { useRouter } from "next/router";
import { Flags } from "react-feature-flags";
import { SurveyCard } from "src/components/Survey/SurveyCard";
import { GetChatsResponse } from "src/types/Chat";
import useSWRImmutable from "swr/immutable";
import useSWRMutation from "swr/mutation";

const Chat = () => {
const { t } = useTranslation(["common", "chat"]);
const router = useRouter();

const { data } = useSWRImmutable<GetChatsResponse>("/api/chat", get);

const { trigger: newChatTrigger } = useSWRMutation<{ id: string }>("/api/chat", post);

const createChat = useCallback(async () => {
const { id } = await newChatTrigger();
router.push(`/chat/${id}`);
}, [newChatTrigger, router]);

const content = useMemo(() => {
if (!data) {
return <Progress size="sm" isIndeterminate />;
}
return (
<SurveyCard>
<Flex direction="column" gap="4">
<Text fontSize="xl" fontWeight="bold">
{t("chat:your_chats")}
</Text>
<Divider />
{data.chats.map(({ id }) => (
<Link key={id} href={`/chat/${id}`}>
{/* TODO: we really only the have the id for each case our users will probably have no idea which is which
maybe we could show the last message & its date, this is not provided by the API right now */}
<Text as={Button} py={2} display="block" bg="inherit" w="full" textAlign="start" borderRadius="sm">
{id}
</Text>
</Link>
))}
<Divider />
<Button maxW="2xs" onClick={createChat}>
{t("create_chat")}
</Button>
</Flex>
</SurveyCard>
);
}, [data, createChat, t]);

return (
<>
<Head>
<title>{t("chat")}</title>
</Head>

<Flags authorizedFlags={["chat"]}>{content}</Flags>
</>
);
};

Chat.getLayout = getDashboardLayout;

export default Chat;
4 changes: 4 additions & 0 deletions website/src/types/Chat.ts
Expand Up @@ -18,3 +18,7 @@ export interface InferenceMessage {
state: "manual" | "pending";
role: "assistant" | "prompter";
}

export interface GetChatsResponse {
chats: InferenceCreateChatResponse[];
}
3 changes: 3 additions & 0 deletions website/types/i18next.d.ts
@@ -1,3 +1,4 @@
import type chat from "public/locales/en/chat.json";
import type common from "public/locales/en/common.json";
import type dashboard from "public/locales/en/dashboard.json";
import type error from "public/locales/en/error.json";
Expand All @@ -8,9 +9,11 @@ import type message from "public/locales/en/message.json";
import type stats from "public/locales/en/stats.json";
import type tasks from "public/locales/en/tasks.json";
import type tos from "public/locales/en/tos.json";

declare module "i18next" {
interface CustomTypeOptions {
resources: {
chat: typeof chat;
common: typeof common;
dashboard: typeof dashboard;
error: typeof error;
Expand Down

0 comments on commit 123fc98

Please sign in to comment.