mirror of
https://github.com/wassname/Open-Assistant.git
synced 2026-07-04 17:20:19 +08:00
Merge pull request #440 from jojopirker/messageNavigation
#309 - Message navigation
This commit is contained in:
@@ -3,7 +3,17 @@ import { boolean } from "boolean";
|
||||
import NextLink from "next/link";
|
||||
import { FlaggableElement } from "../FlaggableElement";
|
||||
|
||||
export function MessageTableEntry({ item, idx }) {
|
||||
interface Message {
|
||||
text: string;
|
||||
id: string;
|
||||
is_assistant: boolean;
|
||||
}
|
||||
interface MessageTableEntryProps {
|
||||
item: Message;
|
||||
idx: number;
|
||||
}
|
||||
export function MessageTableEntry(props: MessageTableEntryProps) {
|
||||
const { item, idx } = props;
|
||||
const bgColor = useColorModeValue(idx % 2 === 0 ? "bg-slate-800" : "bg-black", "bg-sky-900");
|
||||
|
||||
return (
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
import { Box, CircularProgress, Flex, HStack, StackDivider, Text, TextProps, StackProps } from "@chakra-ui/react";
|
||||
import { useState } from "react";
|
||||
import useSWR from "swr";
|
||||
|
||||
import fetcher from "src/lib/fetcher";
|
||||
import { MessageTableEntry } from "./MessageTableEntry";
|
||||
import { boolean } from "boolean";
|
||||
|
||||
const MessageHeaderProps: TextProps = {
|
||||
align: "center",
|
||||
fontSize: "xl",
|
||||
py: "2",
|
||||
};
|
||||
|
||||
const MessageStackProps: StackProps = {
|
||||
spacing: "2",
|
||||
alignItems: "start",
|
||||
justifyContent: "center",
|
||||
divider: <StackDivider />,
|
||||
};
|
||||
|
||||
interface MessageWithChildrenProps {
|
||||
id: string;
|
||||
depth?: number;
|
||||
maxDepth?: number;
|
||||
isOnlyChild?: boolean;
|
||||
}
|
||||
|
||||
export function MessageWithChildren(props: MessageWithChildrenProps) {
|
||||
const { id, depth, maxDepth, isOnlyChild = true } = props;
|
||||
|
||||
const [message, setMessage] = useState(null);
|
||||
const [children, setChildren] = useState(null);
|
||||
|
||||
const { isLoading } = useSWR(id ? `/api/messages/${id}` : null, fetcher, {
|
||||
onSuccess: (data) => {
|
||||
setMessage(data);
|
||||
},
|
||||
onError: (err, key, config) => {
|
||||
setMessage(null);
|
||||
},
|
||||
});
|
||||
const { isLoading: isLoadingChildren } = useSWR(id ? `/api/messages/${id}/children` : null, fetcher, {
|
||||
onSuccess: (data) => {
|
||||
setChildren(data);
|
||||
},
|
||||
onError: (err, key, config) => {
|
||||
setChildren(null);
|
||||
},
|
||||
});
|
||||
|
||||
const renderRecursive = maxDepth && ((depth && depth < maxDepth) || !depth);
|
||||
const isFirst = depth === 0 || !depth;
|
||||
const isFirstOrOnly = isFirst || boolean(isOnlyChild);
|
||||
|
||||
if (isLoading || isLoadingChildren) {
|
||||
return <CircularProgress isIndeterminate />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{message && (
|
||||
<>
|
||||
<Text {...MessageHeaderProps}>{isFirst ? "Message" : depth === 1 ? "Children" : "Ancestor"}</Text>
|
||||
<Flex justifyContent="center" pb="2">
|
||||
<Box maxWidth="container.sm" flex="1" px={isFirstOrOnly ? [4, 6, 8, 9] : "0"}>
|
||||
<Box px={isFirstOrOnly ? "2" : "0"}>
|
||||
<MessageTableEntry item={message} idx={1} />
|
||||
</Box>
|
||||
</Box>
|
||||
</Flex>
|
||||
</>
|
||||
)}
|
||||
{children && Array.isArray(children) && children.length > 0 ? (
|
||||
renderRecursive ? (
|
||||
<HStack {...MessageStackProps}>
|
||||
{children.map((item, idx) => (
|
||||
<Box flex="1" key={`recursiveMessageWChildren_${idx}`}>
|
||||
<MessageWithChildren
|
||||
id={item.id}
|
||||
depth={depth ? depth + 1 : 1}
|
||||
maxDepth={maxDepth}
|
||||
isOnlyChild={children.length === 1 && isOnlyChild}
|
||||
/>
|
||||
</Box>
|
||||
))}
|
||||
</HStack>
|
||||
) : (
|
||||
<>
|
||||
<Text {...MessageHeaderProps}>{isFirstOrOnly ? "Children" : "Ancestor"}</Text>
|
||||
<HStack {...MessageStackProps}>
|
||||
{children.map((item, idx) => (
|
||||
<Box maxWidth="container.sm" flex="1" key={`recursiveMessageWChildren_${idx}`}>
|
||||
<MessageTableEntry item={item} idx={idx * 2} />
|
||||
</Box>
|
||||
))}
|
||||
</HStack>
|
||||
</>
|
||||
)
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { getToken } from "next-auth/jwt";
|
||||
|
||||
const handler = async (req, res) => {
|
||||
const token = await getToken({ req });
|
||||
|
||||
// Return nothing if the user isn't registered.
|
||||
if (!token) {
|
||||
res.status(401).end();
|
||||
return;
|
||||
}
|
||||
|
||||
const { id } = req.query;
|
||||
|
||||
const messagesRes = await fetch(`${process.env.FASTAPI_URL}/api/v1/messages/${id}/children`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"X-API-Key": process.env.FASTAPI_KEY,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
const messages = await messagesRes.json();
|
||||
|
||||
// Send recieved messages to the client.
|
||||
res.status(200).json(messages);
|
||||
};
|
||||
|
||||
export default handler;
|
||||
@@ -0,0 +1,27 @@
|
||||
import { getToken } from "next-auth/jwt";
|
||||
|
||||
const handler = async (req, res) => {
|
||||
const token = await getToken({ req });
|
||||
|
||||
// Return nothing if the user isn't registered.
|
||||
if (!token) {
|
||||
res.status(401).end();
|
||||
return;
|
||||
}
|
||||
|
||||
const { id } = req.query;
|
||||
|
||||
const messagesRes = await fetch(`${process.env.FASTAPI_URL}/api/v1/messages/${id}/conversation`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"X-API-Key": process.env.FASTAPI_KEY,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
const messages = await messagesRes.json();
|
||||
|
||||
// Send recieved messages to the client.
|
||||
res.status(200).json(messages);
|
||||
};
|
||||
|
||||
export default handler;
|
||||
@@ -0,0 +1,27 @@
|
||||
import { getToken } from "next-auth/jwt";
|
||||
|
||||
const handler = async (req, res) => {
|
||||
const token = await getToken({ req });
|
||||
|
||||
// Return nothing if the user isn't registered.
|
||||
if (!token) {
|
||||
res.status(401).end();
|
||||
return;
|
||||
}
|
||||
|
||||
const { id } = req.query;
|
||||
|
||||
const messageRes = await fetch(`${process.env.FASTAPI_URL}/api/v1/messages/${id}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"X-API-Key": process.env.FASTAPI_KEY,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
const message = await messageRes.json();
|
||||
|
||||
// Send recieved messages to the client.
|
||||
res.status(200).json(message);
|
||||
};
|
||||
|
||||
export default handler;
|
||||
@@ -0,0 +1,48 @@
|
||||
import { getToken } from "next-auth/jwt";
|
||||
|
||||
const handler = async (req, res) => {
|
||||
const token = await getToken({ req });
|
||||
|
||||
// Return nothing if the user isn't registered.
|
||||
if (!token) {
|
||||
res.status(401).end();
|
||||
return;
|
||||
}
|
||||
|
||||
const { id } = req.query;
|
||||
|
||||
if (!id) {
|
||||
res.status(400).end();
|
||||
return;
|
||||
}
|
||||
|
||||
const messageRes = await fetch(`${process.env.FASTAPI_URL}/api/v1/messages/${id}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"X-API-Key": process.env.FASTAPI_KEY,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
const message = await messageRes.json();
|
||||
|
||||
if (!message.parent_id) {
|
||||
res.status(404).end();
|
||||
return;
|
||||
}
|
||||
|
||||
const parentRes = await fetch(`${process.env.FASTAPI_URL}/api/v1/messages/${message.parent_id}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"X-API-Key": process.env.FASTAPI_KEY,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
const parent = await parentRes.json();
|
||||
|
||||
// Send recieved messages to the client.
|
||||
res.status(200).json(parent);
|
||||
};
|
||||
|
||||
export default handler;
|
||||
@@ -0,0 +1,64 @@
|
||||
import { Box, Container, Text, useColorModeValue } from "@chakra-ui/react";
|
||||
import Head from "next/head";
|
||||
import { useRouter } from "next/router";
|
||||
import { useState } from "react";
|
||||
import useSWR from "swr";
|
||||
|
||||
import fetcher from "src/lib/fetcher";
|
||||
import { MessageTableEntry } from "src/components/Messages/MessageTableEntry";
|
||||
import { LoadingScreen } from "src/components/Loading/LoadingScreen";
|
||||
import { MessageWithChildren } from "src/components/Messages/MessageWithChildren";
|
||||
|
||||
const MessageDetail = ({ id }) => {
|
||||
const mainBg = useColorModeValue("bg-slate-300", "bg-slate-900");
|
||||
|
||||
const [parent, setParent] = useState(null);
|
||||
|
||||
const { isLoading: isLoadingParent } = useSWR(id ? `/api/messages/${id}/parent` : null, fetcher, {
|
||||
onSuccess: (data) => {
|
||||
setParent(data);
|
||||
},
|
||||
onError: (err, key, config) => {
|
||||
setParent(null);
|
||||
},
|
||||
});
|
||||
|
||||
if (isLoadingParent) {
|
||||
return <LoadingScreen text="Loading..." />;
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Open Assistant</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="Conversational AI for everyone. An open source project to create a chat enabled GPT LLM run by LAION and contributors around the world."
|
||||
/>
|
||||
</Head>
|
||||
<main className={`${mainBg}`}>
|
||||
<Container w="100%" pt={[2, 2, 4, 4]}>
|
||||
{parent && (
|
||||
<>
|
||||
<Text align="center" fontSize="xl">
|
||||
Parent
|
||||
</Text>
|
||||
<Box rounded="lg" p="2">
|
||||
<MessageTableEntry item={parent} idx={1} />
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
</Container>
|
||||
<Box pb="4" maxW="full" px="2">
|
||||
<MessageWithChildren id={id} maxDepth={2} />
|
||||
</Box>
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
MessageDetail.getInitialProps = async ({ query }) => {
|
||||
const { id } = query;
|
||||
return { id };
|
||||
};
|
||||
|
||||
export default MessageDetail;
|
||||
Reference in New Issue
Block a user