Merge branch 'main' into 766_admin_enhancement

This commit is contained in:
notmd
2023-01-20 23:12:43 +07:00
63 changed files with 874 additions and 225 deletions
@@ -1,19 +1,19 @@
import { Box, Flex, GridItem, Heading, SimpleGrid, Text, useColorModeValue } from "@chakra-ui/react";
import Link from "next/link";
import { TaskTypes } from "../Tasks/TaskTypes";
import { TaskCategory, TaskCategoryLabels, TaskTypes } from "../Tasks/TaskTypes";
export const TaskOption = ({ displayTaskCategories }) => {
export const TaskOption = ({ displayTaskCategories }: { displayTaskCategories: TaskCategory[] }) => {
const backgroundColor = useColorModeValue("white", "gray.700");
return (
<Box className="flex flex-col gap-14">
{displayTaskCategories.map((category, categoryIndex) => (
<div key={categoryIndex}>
<Text className="text-2xl font-bold pb-4">{category}</Text>
{displayTaskCategories.map((category) => (
<div key={category}>
<Text className="text-2xl font-bold pb-4">{TaskCategoryLabels[category]}</Text>
<SimpleGrid columns={[1, 1, 2, 2, 3, 4]} gap={4}>
{TaskTypes.filter((task) => task.category === category).map((item, itemIndex) => (
<Link key={itemIndex} href={item.pathname}>
{TaskTypes.filter((task) => task.category === category).map((item) => (
<Link key={category + item.label} href={item.pathname}>
<GridItem
bg={backgroundColor}
borderRadius="xl"
+3 -5
View File
@@ -25,8 +25,8 @@ import clsx from "clsx";
import { useEffect, useReducer } from "react";
import { FiAlertCircle } from "react-icons/fi";
import { get, post } from "src/lib/api";
import { Message } from "src/types/Conversation";
import { colors } from "src/styles/Theme/colors";
import { Message } from "src/types/Conversation";
import useSWR from "swr";
import useSWRMutation from "swr/mutation";
@@ -114,9 +114,7 @@ export const FlaggableElement = (props: FlaggableElementProps) => {
}, [data, isLoading]);
const { trigger } = useSWRMutation("/api/set_label", post, {
onSuccess: () => {
setIsEditing.off();
},
onSuccess: setIsEditing.off,
});
const submitResponse = () => {
@@ -149,7 +147,7 @@ export const FlaggableElement = (props: FlaggableElementProps) => {
isLazy
lazyBehavior="keepMounted"
>
<Box display="flex" alignItems="center" gap="2">
<Box display="flex" alignItems="center" flexDirection={["column", "row"]} gap="2">
<PopoverAnchor>{props.children}</PopoverAnchor>
<Tooltip label="Report" bg="red.500" aria-label="A tooltip">
+12 -10
View File
@@ -1,9 +1,11 @@
import { Box, Divider, Flex, Text, useColorMode } from "@chakra-ui/react";
import Image from "next/image";
import Link from "next/link";
import { useTranslation } from "next-i18next";
import { useMemo } from "react";
export function Footer() {
const { t } = useTranslation();
const { colorMode } = useColorMode();
const backgroundColor = colorMode === "light" ? "white" : "gray.800";
const textColor = colorMode === "light" ? "black" : "gray.300";
@@ -33,10 +35,10 @@ export function Footer() {
<Box>
<Text fontSize="md" fontWeight="bold">
Open Assistant
{t("title")}
</Text>
<Text fontSize="sm" color="gray.500">
Conversational AI for everyone.
{t("conversational")}
</Text>
</Box>
</Flex>
@@ -45,23 +47,23 @@ export function Footer() {
<Box display="flex" flexDirection={["column", "row"]} gap={["6", "14"]} fontSize="sm">
<Flex direction="column" alignItems={["center", "start"]}>
<Text fontWeight="bold" color={textColor}>
Legal
{t("legal")}
</Text>
<FooterLink href="/privacy-policy" label="Privacy Policy" />
<FooterLink href="/terms-of-service" label="Terms of Service" />
<FooterLink href="/privacy-policy" label={t("privacy_policy")} />
<FooterLink href="/terms-of-service" label={t("terms_of_service")} />
</Flex>
<Flex direction="column" alignItems={["center", "start"]}>
<Text fontWeight="bold" color={textColor}>
Connect
{t("connect")}
</Text>
<FooterLink href="https://github.com/LAION-AI/Open-Assistant" label="Github" />
<FooterLink href="https://ykilcher.com/open-assistant-discord" label="Discord" />
<FooterLink href="https://github.com/LAION-AI/Open-Assistant" label={t("github")} />
<FooterLink href="https://ykilcher.com/open-assistant-discord" label={t("discord")} />
</Flex>
<Flex direction="column" alignItems={["center", "start"]}>
<Text fontWeight="bold" color={textColor}>
About
{t("about")}
</Text>
<FooterLink href="https://projects.laion.ai/Open-Assistant" label="Docs" />
<FooterLink href="https://projects.laion.ai/Open-Assistant" label={t("docs")} />
</Flex>
</Box>
</nav>
+5 -3
View File
@@ -1,7 +1,8 @@
import { Box, Button, Text, Flex } from "@chakra-ui/react";
import { Box, Button, Flex, Text } from "@chakra-ui/react";
import Image from "next/image";
import Link from "next/link";
import { useSession } from "next-auth/react";
import { useTranslation } from "next-i18next";
import { Flags } from "react-feature-flags";
import { FaUser } from "react-icons/fa";
@@ -23,7 +24,8 @@ function AccountButton() {
);
}
export function Header(props) {
export function Header() {
const { t } = useTranslation();
const { data: session } = useSession();
const homeURL = session ? "/dashboard" : "/";
@@ -34,7 +36,7 @@ export function Header(props) {
<Flex alignItems="center">
<Image src="/images/logos/logo.svg" className="mx-auto object-fill" width="50" height="50" alt="logo" />
<Text fontFamily="inter" fontSize="2xl" fontWeight="bold" ml="3">
Open Assistant
{t("title")}
</Text>
</Flex>
</Link>
+11 -9
View File
@@ -13,6 +13,7 @@ import {
} from "@chakra-ui/react";
import NextLink from "next/link";
import { signOut, useSession } from "next-auth/react";
import { useTranslation } from "next-i18next";
import React, { ElementType, useCallback } from "react";
import { FiAlertTriangle, FiLayout, FiLogOut, FiSettings, FiShield } from "react-icons/fi";
@@ -25,6 +26,7 @@ interface MenuOption {
}
export function UserMenu() {
const { t } = useTranslation();
const borderColor = useColorModeValue("gray.300", "gray.600");
const handleSignOut = useCallback(() => {
signOut({ callbackUrl: "/" });
@@ -36,23 +38,23 @@ export function UserMenu() {
}
const options: MenuOption[] = [
{
name: "Dashboard",
name: t("dashboard"),
href: "/dashboard",
desc: "Dashboard",
desc: t("dashboard"),
icon: FiLayout,
isExternal: false,
},
{
name: "Account Settings",
name: t("account_settings"),
href: "/account",
desc: "Account Settings",
desc: t("account_settings"),
icon: FiSettings,
isExternal: false,
},
{
name: "Report a Bug",
name: t("report_a_bug"),
href: "https://github.com/LAION-AI/Open-Assistant/issues/new/choose",
desc: "Report a Bug",
desc: t("report_a_bug"),
icon: FiAlertTriangle,
isExternal: true,
},
@@ -60,9 +62,9 @@ export function UserMenu() {
if (session.user.role === "admin") {
options.unshift({
name: "Admin Dashboard",
name: t("admin_dashboard"),
href: "/admin",
desc: "Admin Dashboard",
desc: t("admin_dashboard"),
icon: FiShield,
isExternal: false,
});
@@ -105,7 +107,7 @@ export function UserMenu() {
<MenuDivider />
<MenuItem gap="3" borderRadius="md" p="4" onClick={handleSignOut}>
<FiLogOut className="text-blue-500" aria-hidden="true" />
<Text>Sign Out</Text>
<Text>{t("sign_out")}</Text>
</MenuItem>
</MenuList>
</Menu>
+1 -1
View File
@@ -2,8 +2,8 @@ import { Box, Text, useColorMode } from "@chakra-ui/react";
import Image from "next/image";
import { useTranslation } from "next-i18next";
import { Container } from "./Container";
import { AnimatedCircles } from "./AnimatedCircles";
import { Container } from "./Container";
export function Hero() {
const { t } = useTranslation("index");
+3 -3
View File
@@ -23,7 +23,7 @@ export const getDefaultLayout = (page: React.ReactElement) => (
export const getTransparentHeaderLayout = (page: React.ReactElement) => (
<div className="grid grid-rows-[min-content_1fr_min-content] h-full justify-items-stretch">
<Header transparent={true} />
<Header />
{page}
<Footer />
</div>
@@ -31,7 +31,7 @@ export const getTransparentHeaderLayout = (page: React.ReactElement) => (
export const getDashboardLayout = (page: React.ReactElement) => (
<Grid templateRows="min-content 1fr" h="full">
<Header transparent={true} />
<Header />
<SideMenuLayout
menuButtonOptions={[
{
@@ -66,7 +66,7 @@ export const getDashboardLayout = (page: React.ReactElement) => (
export const getAdminLayout = (page: React.ReactElement) => (
<div className="grid grid-rows-[min-content_1fr_min-content] h-full justify-items-stretch">
<Header transparent={true} />
<Header />
<SideMenuLayout
menuButtonOptions={[
{
@@ -9,7 +9,7 @@ interface MessageTableProps {
export function MessageTable({ messages, enableLink }: MessageTableProps) {
return (
<Stack spacing="3">
<Stack spacing="4">
{messages.map((item) => (
<MessageTableEntry enabled={enableLink} item={item} key={item.id + item.frontend_message_id} />
))}
@@ -1,6 +1,8 @@
import { Avatar, Box, HStack, LinkBox, useColorModeValue } from "@chakra-ui/react";
import { Avatar, Box, HStack, LinkBox, useBreakpoint, useBreakpointValue, useColorModeValue } from "@chakra-ui/react";
import { boolean } from "boolean";
import Link from "next/link";
import { useRouter } from "next/router";
import { useCallback, useMemo } from "react";
import { FlaggableElement } from "src/components/FlaggableElement";
import { Message } from "src/types/Conversation";
@@ -10,47 +12,48 @@ interface MessageTableEntryProps {
}
export function MessageTableEntry(props: MessageTableEntryProps) {
const router = useRouter();
const { item } = props;
const goToMessage = useCallback(() => router.push(`/messages/${item.id}`), [router, item.id]);
const backgroundColor = useColorModeValue("gray.100", "gray.700");
const backgroundColor2 = useColorModeValue("#DFE8F1", "#42536B");
const avatarColor = useColorModeValue("white", "black");
const borderColor = useColorModeValue("blackAlpha.200", "whiteAlpha.200");
const inlineAvatar = useBreakpointValue({ base: true, sm: false });
const avatar = useMemo(
() => (
<Avatar
borderColor={borderColor}
size={inlineAvatar ? "xs" : "sm"}
mr={inlineAvatar ? 2 : 0}
name={`${boolean(item.is_assistant) ? "Assistant" : "User"}`}
src={`${boolean(item.is_assistant) ? "/images/logos/logo.png" : "/images/temp-avatars/av1.jpg"}`}
/>
),
[borderColor, inlineAvatar, item.is_assistant]
);
return (
<FlaggableElement message={item}>
<HStack w={["full", "full", "full", "fit-content"]} gap={2}>
<Box borderRadius="full" border="solid" borderWidth="1px" borderColor={borderColor} bg={avatarColor}>
<Avatar
size="sm"
name={`${boolean(item.is_assistant) ? "Assistant" : "User"}`}
src={`${boolean(item.is_assistant) ? "/images/logos/logo.png" : "/images/temp-avatars/av1.jpg"}`}
/>
{!inlineAvatar && avatar}
<Box
width={["full", "full", "full", "fit-content"]}
maxWidth={["full", "full", "full", "2xl"]}
p="4"
borderRadius="md"
bg={item.is_assistant ? backgroundColor : backgroundColor2}
onClick={props.enabled && goToMessage}
_hover={props.enabled && { cursor: "pointer", opacity: 0.9 }}
>
{inlineAvatar && avatar}
{item.text}
</Box>
{props.enabled ? (
<Box width={["full", "full", "full", "fit-content"]} maxWidth={["full", "full", "full", "2xl"]}>
<Link href={`/messages/${item.id}`}>
<LinkBox
bg={item.is_assistant ? backgroundColor : backgroundColor2}
p="4"
borderRadius="md"
whiteSpace="pre-line"
>
{item.text}
</LinkBox>
</Link>
</Box>
) : (
<Box
width={["full", "full", "full", "fit-content"]}
maxWidth={["full", "full", "full", "2xl"]}
bg={item.is_assistant ? backgroundColor : backgroundColor2}
p="4"
borderRadius="md"
>
{item.text}
</Box>
)}
</HStack>
</FlaggableElement>
);
+5 -8
View File
@@ -1,22 +1,19 @@
import { Box, BoxProps, useColorModeValue } from "@chakra-ui/react";
import clsx from "clsx";
import { PropsWithChildren } from "react";
interface SurveyCardProps {
className?: string;
children: React.ReactNode;
}
export const SurveyCard = (props: SurveyCardProps) => {
export const SurveyCard = (props: PropsWithChildren<{ className?: string }>) => {
const backgroundColor = useColorModeValue("white", "gray.700");
const BoxClasses: BoxProps = {
gap: "2",
borderRadius: "xl",
shadow: "base",
className: "p-4 sm:p-6",
className: clsx("p-4 sm:p-6", props.className),
};
return (
<Box bg={backgroundColor} {...BoxClasses}>
<Box as="section" bg={backgroundColor} {...BoxClasses}>
{props.children}
</Box>
);
+10 -3
View File
@@ -1,5 +1,5 @@
export enum TaskCategory {
Tasks = "Tasks",
Random = "Random",
Create = "Create",
Evaluate = "Evaluate",
Label = "Label",
@@ -20,12 +20,19 @@ export interface TaskInfo {
unchanged_message?: string;
}
export const TaskCategoryLabels: { [key in TaskCategory]: string } = {
[TaskCategory.Random]: "I'm feeling lucky",
[TaskCategory.Create]: "Create",
[TaskCategory.Evaluate]: "Evaluate",
[TaskCategory.Label]: "Label",
};
export const TaskTypes: TaskInfo[] = [
// general/random
{
label: "Start a Task",
desc: "Help us improve Open Assistant by starting a random task.",
category: TaskCategory.Tasks,
category: TaskCategory.Random,
pathname: "/tasks/random",
help_link: "https://projects.laion.ai/Open-Assistant/docs/guides/prompting",
type: "random",
@@ -121,7 +128,7 @@ export const TaskTypes: TaskInfo[] = [
category: TaskCategory.Label,
pathname: "/label/label_prompter_reply",
help_link: "https://projects.laion.ai/Open-Assistant/docs/tasks/label_prompter_reply",
overview: "Given the following discussion, provide labels for the final prompt",
overview: "Given the following discussion, provide labels for the final prompt.",
type: "label_prompter_reply",
mode: "full",
update_type: "text_labels",
@@ -1,23 +1,22 @@
import { useState } from "react";
import { get, post } from "src/lib/api";
import { BaseTask, TaskResponse } from "src/types/Task";
import { BaseTask, TaskResponse, TaskType as TaskTypeEnum } from "src/types/Task";
import useSWRImmutable from "swr/immutable";
import useSWRMutation from "swr/mutation";
export const useGenericTaskAPI = <TaskType extends BaseTask>(taskApiEndpoint: string) => {
export const useGenericTaskAPI = <TaskType extends BaseTask>(taskType: TaskTypeEnum) => {
type ConcreteTaskResponse = TaskResponse<TaskType>;
const [tasks, setTasks] = useState<ConcreteTaskResponse[]>([]);
const { isLoading, mutate, error } = useSWRImmutable<ConcreteTaskResponse>("/api/new_task/" + taskApiEndpoint, get, {
const { isLoading, mutate, error } = useSWRImmutable<ConcreteTaskResponse>("/api/new_task/" + taskType, get, {
onSuccess: (data) => setTasks([data]),
revalidateOnMount: true,
dedupingInterval: 500,
});
const { trigger } = useSWRMutation("/api/update_task", post, {
onSuccess: async (response) => {
const newTask: ConcreteTaskResponse = response;
onSuccess: async (newTask: ConcreteTaskResponse) => {
setTasks((oldTasks) => [...oldTasks, newTask]);
mutate();
},
+7
View File
@@ -0,0 +1,7 @@
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
export const getDefaultStaticProps = async ({ locale }) => ({
props: {
...(await serverSideTranslations(locale)),
},
});
+13 -14
View File
@@ -1,7 +1,7 @@
import { JWT } from "next-auth/jwt";
import type { Message } from "src/types/Conversation";
import { LeaderboardReply, LeaderboardTimeFrame } from "src/types/Leaderboard";
import type { BackendUser } from "src/types/Users";
import type { AvailableTasks } from "src/types/Task";
import type { BackendUser, BackendUserCore } from "src/types/Users";
export class OasstError {
message: string;
@@ -108,14 +108,10 @@ export class OasstApiClient {
// TODO return a strongly typed Task?
// This method is used to store a task in RegisteredTask.task.
// This is a raw Json type, so we can't use it to strongly type the task.
async fetchTask(taskType: string, userToken: JWT): Promise<any> {
async fetchTask(taskType: string, user: BackendUserCore): Promise<any> {
return this.post("/api/v1/tasks/", {
type: taskType,
user: {
id: userToken.sub,
display_name: userToken.name,
auth_method: "local",
},
user,
});
}
@@ -140,15 +136,11 @@ export class OasstApiClient {
messageId: string,
userMessageId: string,
content: object,
userToken: JWT
user: BackendUserCore
): Promise<any> {
return this.post("/api/v1/tasks/interaction", {
type: updateType,
user: {
id: userToken.sub,
display_name: userToken.name,
auth_method: "local",
},
user,
task_id: taskId,
message_id: messageId,
user_message_id: userMessageId,
@@ -224,6 +216,13 @@ export class OasstApiClient {
async fetch_leaderboard(time_frame: LeaderboardTimeFrame): Promise<LeaderboardReply> {
return this.get(`/api/v1/leaderboards/${time_frame}`);
}
/**
* Returns the counts of all tasks (some might be zero)
*/
async fetch_available_tasks(user: BackendUserCore): Promise<AvailableTasks> {
return this.post(`/api/v1/tasks/availability`, user);
}
}
const oasstApiClient = new OasstApiClient(process.env.FASTAPI_URL, process.env.FASTAPI_KEY);
+38
View File
@@ -0,0 +1,38 @@
import prisma from "src/lib/prismadb";
import type { BackendUserCore } from "src/types/Users";
/**
* Returns a `BackendUserCore` that can be used for interacting with the Backend service.
*
* @param {string} id The user's web auth id.
*
* @return {BackendUserCore} The most specific auth type and id for the user.
*/
const getBackendUserCore = async (id: string) => {
const user = await prisma.user.findUnique({
where: { id },
select: {
id: true,
name: true,
accounts: true,
},
});
// If there are no linked accounts, just use what we have locally.
if (user.accounts.length === 0) {
return {
id: user.id,
display_name: user.name,
auth_method: "local",
} as BackendUserCore;
}
// Otherwise, use the first linked account that the user created.
return {
id: user.accounts[0].providerAccountId,
display_name: user.name,
auth_method: user.accounts[0].provider,
} as BackendUserCore;
};
export { getBackendUserCore };
+1
View File
@@ -3,6 +3,7 @@ import Head from "next/head";
import { FiAlertTriangle } from "react-icons/fi";
import { EmptyState } from "src/components/EmptyState";
import { getTransparentHeaderLayout } from "src/components/Layout";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
function Error() {
return (
+1
View File
@@ -3,6 +3,7 @@ import Head from "next/head";
import { FiAlertTriangle } from "react-icons/fi";
import { EmptyState } from "src/components/EmptyState";
import { getTransparentHeaderLayout } from "src/components/Layout";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
function ServerError() {
return (
+1
View File
@@ -4,6 +4,7 @@ import { Container } from "src/components/Container";
import Roadmap from "src/components/Roadmap";
import Services from "src/components/Services";
import Vision from "src/components/Vision";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
const AboutPage = () => {
return (
+1
View File
@@ -4,6 +4,7 @@ import Router from "next/router";
import { useSession } from "next-auth/react";
import React from "react";
import { Control, useForm, useWatch } from "react-hook-form";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
export default function Account() {
const { data: session } = useSession();
+26 -10
View File
@@ -1,8 +1,11 @@
import { Button } from "@chakra-ui/react";
import { Button, Divider, Flex, Grid, Icon, Text } from "@chakra-ui/react";
import Head from "next/head";
import Link from "next/link";
import { useSession } from "next-auth/react";
import React from "react";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
import { MdOutlineEdit } from "react-icons/md";
import { SurveyCard } from "src/components/Survey/SurveyCard";
export default function Account() {
const { data: session } = useSession();
@@ -19,15 +22,28 @@ export default function Account() {
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>
<div className="oa-basic-theme">
<main className="h-3/4 z-0 flex flex-col items-center justify-center">
<p>{session.user.name || "No username"}</p>
<Button>
<Link href="/account/edit">Edit Username</Link>
</Button>
<p>{session.user.email}</p>
</main>
</div>
<main className="oa-basic-theme p-6">
<Flex m="auto" className="max-w-7xl" alignContent="center">
<SurveyCard className="w-full">
<Text as="b" display="block" fontSize="2xl" py={2}>
Your Account
</Text>
<Divider />
<Grid gridTemplateColumns="repeat(2, max-content)" alignItems="center" gap={6} py={4}>
<Text as="b">Username</Text>
<Flex gap={2}>
{session.user.name ?? "(No username)"}
<Link href="/account/edit">
<Icon boxSize={5} as={MdOutlineEdit} />
</Link>
</Flex>
<Text as="b">Email</Text>
<Text>{session.user.email ?? "(No Email)"}</Text>
</Grid>
<p></p>
</SurveyCard>
</Flex>
</main>
</>
);
}
+1
View File
@@ -4,6 +4,7 @@ import { useSession } from "next-auth/react";
import { useEffect } from "react";
import { getAdminLayout } from "src/components/Layout";
import { UserTable } from "src/components/UserTable";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
/**
* Provides the admin index page that will display a list of users and give
+3 -1
View File
@@ -3,6 +3,7 @@ import { InferGetServerSidePropsType } from "next";
import Head from "next/head";
import { useRouter } from "next/router";
import { useSession } from "next-auth/react";
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
import { useEffect } from "react";
import { useForm } from "react-hook-form";
import { getAdminLayout } from "src/components/Layout";
@@ -111,7 +112,7 @@ const ManageUser = ({ user }: InferGetServerSidePropsType<typeof getServerSidePr
/**
* Fetch the user's data on the server side when rendering.
*/
export async function getServerSideProps({ query }) {
export async function getServerSideProps({ query, locale }) {
const backend_user = await oasstApiClient.fetch_user(query.id);
const local_user = await prisma.user.findUnique({
where: { id: backend_user.id },
@@ -126,6 +127,7 @@ export async function getServerSideProps({ query }) {
return {
props: {
user,
...(await serverSideTranslations(locale, ["common"])),
},
};
}
+11
View File
@@ -0,0 +1,11 @@
import { withoutRole } from "src/lib/auth";
import { oasstApiClient } from "src/lib/oasst_api_client";
import { getBackendUserCore } from "src/lib/users";
const handler = withoutRole("banned", async (req, res, token) => {
const user = await getBackendUserCore(token.sub);
const availableTasks = await oasstApiClient.fetch_available_tasks(user);
res.status(200).json(availableTasks);
});
export default handler;
@@ -1,6 +1,7 @@
import { withoutRole } from "src/lib/auth";
import { oasstApiClient } from "src/lib/oasst_api_client";
import prisma from "src/lib/prismadb";
import { getBackendUserCore } from "src/lib/users";
/**
* Returns a new task created from the Task Backend. We do a few things here:
@@ -14,9 +15,10 @@ const handler = withoutRole("banned", async (req, res, token) => {
// Fetch the new task.
const { task_type } = req.query;
const user = await getBackendUserCore(token.sub);
let task;
try {
task = await oasstApiClient.fetchTask(task_type as string, token);
task = await oasstApiClient.fetchTask(task_type as string, user);
} catch (err) {
console.error(err);
res.status(500).json(err);
+3 -1
View File
@@ -2,6 +2,7 @@ import { Prisma } from "@prisma/client";
import { withoutRole } from "src/lib/auth";
import { oasstApiClient } from "src/lib/oasst_api_client";
import prisma from "src/lib/prismadb";
import { getBackendUserCore } from "src/lib/users";
/**
* Stores the task interaction with the Task Backend and then returns the next task generated.
@@ -39,9 +40,10 @@ const handler = withoutRole("banned", async (req, res, token) => {
},
});
const user = await getBackendUserCore(token.sub);
let newTask;
try {
newTask = await oasstApiClient.interactTask(update_type, taskId, frontendId, interaction.id, content, token);
newTask = await oasstApiClient.interactTask(update_type, taskId, frontendId, interaction.id, content, user);
} catch (err) {
console.error(JSON.stringify(err));
return res.status(500).json(err);
+4 -3
View File
@@ -5,6 +5,7 @@ import Head from "next/head";
import Link from "next/link";
import { useRouter } from "next/router";
import { ClientSafeProvider, getProviders, signIn } from "next-auth/react";
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
import React, { useEffect, useRef, useState } from "react";
import { useForm } from "react-hook-form";
import { FaBug, FaDiscord, FaEnvelope, FaGithub } from "react-icons/fa";
@@ -47,7 +48,6 @@ interface SigninProps {
function Signin({ providers }: SigninProps) {
const router = useRouter();
const { discord, email, github, credentials } = providers;
const emailEl = useRef(null);
const [error, setError] = useState("");
useEffect(() => {
@@ -151,7 +151,7 @@ function Signin({ providers }: SigninProps) {
Signin.getLayout = (page) => (
<div className="grid grid-rows-[min-content_1fr_min-content] h-full justify-items-stretch">
<Header transparent={true} />
<Header />
{page}
<Footer />
</div>
@@ -209,11 +209,12 @@ const DebugSigninForm = ({ credentials, bgColorClass }: { credentials: ClientSaf
);
};
export const getServerSideProps: GetServerSideProps<SigninProps> = async () => {
export const getServerSideProps: GetServerSideProps<SigninProps> = async ({ locale }) => {
const providers = await getProviders();
return {
props: {
providers,
...(await serverSideTranslations(locale, ["common"])),
},
};
};
@@ -4,6 +4,7 @@ import { getDashboardLayout } from "src/components/Layout";
import { LoadingScreen } from "src/components/Loading/LoadingScreen";
import { Task } from "src/components/Tasks/Task";
import { useCreateAssistantReply } from "src/hooks/tasks/useCreateReply";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
const AssistantReply = () => {
const { tasks, isLoading, reset, trigger } = useCreateAssistantReply();
@@ -4,6 +4,7 @@ import { getDashboardLayout } from "src/components/Layout";
import { LoadingScreen } from "src/components/Loading/LoadingScreen";
import { Task } from "src/components/Tasks/Task";
import { useCreateInitialPrompt } from "src/hooks/tasks/useCreateReply";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
const InitialPrompt = () => {
const { tasks, isLoading, reset, trigger } = useCreateInitialPrompt();
+1
View File
@@ -4,6 +4,7 @@ import { getDashboardLayout } from "src/components/Layout";
import { LoadingScreen } from "src/components/Loading/LoadingScreen";
import { Task } from "src/components/Tasks/Task";
import { useCreatePrompterReply } from "src/hooks/tasks/useCreateReply";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
const UserReply = () => {
const { tasks, isLoading, reset, trigger } = useCreatePrompterReply();
+18 -2
View File
@@ -1,10 +1,20 @@
import { Flex } from "@chakra-ui/react";
import Head from "next/head";
import { useMemo } from "react";
import { LeaderboardTable, TaskOption, WelcomeCard } from "src/components/Dashboard";
import { getDashboardLayout } from "src/components/Layout";
import { TaskCategory } from "src/components/Tasks/TaskTypes";
import { get } from "src/lib/api";
import type { AvailableTasks, TaskType } from "src/types/Task";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
import useSWRImmutable from "swr/immutable";
const Dashboard = () => {
const { data } = useSWRImmutable<AvailableTasks>("/api/available_tasks", get);
// TODO: show only these tasks:
const availableTasks = useMemo(() => filterAvailableTasks(data ?? {}), [data]);
return (
<>
<Head>
@@ -13,13 +23,19 @@ const Dashboard = () => {
</Head>
<Flex direction="column" gap="10">
<WelcomeCard />
<TaskOption displayTaskCategories={[TaskCategory.Tasks]} />
<TaskOption displayTaskCategories={[TaskCategory.Random]} />
<LeaderboardTable />
</Flex>
</>
);
};
Dashboard.getLayout = (page) => getDashboardLayout(page);
Dashboard.getLayout = getDashboardLayout;
export default Dashboard;
const filterAvailableTasks = (availableTasks: Partial<AvailableTasks>) =>
Object.entries(availableTasks)
.filter(([_, count]) => count > 0)
.sort((a, b) => b[1] - a[1])
.map(([taskType]) => taskType) as TaskType[];
@@ -4,6 +4,7 @@ import { getDashboardLayout } from "src/components/Layout";
import { LoadingScreen } from "src/components/Loading/LoadingScreen";
import { Task } from "src/components/Tasks/Task";
import { useRankAssistantRepliesTask } from "src/hooks/tasks/useRankReplies";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
const RankAssistantReplies = () => {
const { tasks, isLoading, reset, trigger } = useRankAssistantRepliesTask();
@@ -4,6 +4,7 @@ import { getDashboardLayout } from "src/components/Layout";
import { LoadingScreen } from "src/components/Loading/LoadingScreen";
import { Task } from "src/components/Tasks/Task";
import { useRankInitialPromptsTask } from "src/hooks/tasks/useRankReplies";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
const RankInitialPrompts = () => {
const { tasks, isLoading, reset, trigger } = useRankInitialPromptsTask();
@@ -4,6 +4,7 @@ import { getDashboardLayout } from "src/components/Layout";
import { LoadingScreen } from "src/components/Loading/LoadingScreen";
import { Task } from "src/components/Tasks/Task";
import { useRankPrompterRepliesTask } from "src/hooks/tasks/useRankReplies";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
const RankUserReplies = () => {
const { tasks, isLoading, reset, trigger } = useRankPrompterRepliesTask();
@@ -4,6 +4,7 @@ import { getDashboardLayout } from "src/components/Layout";
import { LoadingScreen } from "src/components/Loading/LoadingScreen";
import { Task } from "src/components/Tasks/Task";
import { useLabelAssistantReplyTask } from "src/hooks/tasks/useLabelingTask";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
const LabelAssistantReply = () => {
const { tasks, isLoading, trigger, reset } = useLabelAssistantReplyTask();
@@ -4,6 +4,7 @@ import { getDashboardLayout } from "src/components/Layout";
import { LoadingScreen } from "src/components/Loading/LoadingScreen";
import { Task } from "src/components/Tasks/Task";
import { useLabelInitialPromptTask } from "src/hooks/tasks/useLabelingTask";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
const LabelInitialPrompt = () => {
const { tasks, isLoading, trigger, reset } = useLabelInitialPromptTask();
@@ -4,6 +4,7 @@ import { getDashboardLayout } from "src/components/Layout";
import { LoadingScreen } from "src/components/Loading/LoadingScreen";
import { Task } from "src/components/Tasks/Task";
import { useLabelPrompterReplyTask } from "src/hooks/tasks/useLabelingTask";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
const LabelPrompterReply = () => {
const { tasks, isLoading, trigger, reset } = useLabelPrompterReplyTask();
+1
View File
@@ -2,6 +2,7 @@ import { Box, Heading, Tab, TabList, TabPanel, TabPanels, Tabs } from "@chakra-u
import Head from "next/head";
import { getDashboardLayout } from "src/components/Layout";
import { LeaderboardGridCell } from "src/components/LeaderboardGridCell";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
import { LeaderboardTimeFrame } from "src/types/Leaderboard";
const Leaderboard = () => {
+9 -5
View File
@@ -1,5 +1,6 @@
import { Box, Text, useColorModeValue } from "@chakra-ui/react";
import Head from "next/head";
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
import { getDashboardLayout } from "src/components/Layout";
import { MessageLoading } from "src/components/Loading/MessageLoading";
import { MessageTableEntry } from "src/components/Messages/MessageTableEntry";
@@ -48,10 +49,13 @@ const MessageDetail = ({ id }: { id: string }) => {
);
};
MessageDetail.getInitialProps = async ({ query }) => {
const { id } = query;
return { id };
};
MessageDetail.getLayout = (page) => getDashboardLayout(page);
export const getServerSideProps = async ({ locale, query }) => ({
props: {
id: query.id,
...(await serverSideTranslations(locale, ["common"])),
},
});
export default MessageDetail;
+1
View File
@@ -4,6 +4,7 @@ import { getDashboardLayout } from "src/components/Layout";
import { MessageTable } from "src/components/Messages/MessageTable";
import { get } from "src/lib/api";
import useSWRImmutable from "swr/immutable";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
const MessagesDashboard = () => {
const boxBgColor = useColorModeValue("white", "gray.800");
+1
View File
@@ -3,6 +3,7 @@ import Head from "next/head";
import { getTransparentHeaderLayout } from "src/components/Layout";
import { PolicyChapterCard } from "src/components/PolicyCards/PolicyChapterCard";
import { PolicySectionCard } from "src/components/PolicyCards/PolicySectionCard";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
const PrivacyPolicy = () => {
const backgroundColor = useColorModeValue("gray.100", "gray.800");
+2 -1
View File
@@ -4,9 +4,10 @@ import { getDashboardLayout } from "src/components/Layout";
import { LoadingScreen } from "src/components/Loading/LoadingScreen";
import { Task } from "src/components/Tasks/Task";
import { useGenericTaskAPI } from "src/hooks/tasks/useGenericTaskAPI";
import { TaskType } from "src/types/Task";
const RandomTask = () => {
const { tasks, isLoading, trigger, reset } = useGenericTaskAPI("random");
const { tasks, isLoading, trigger, reset } = useGenericTaskAPI(TaskType.random);
if (isLoading) {
return <LoadingScreen text="Loading..." />;
+1
View File
@@ -3,6 +3,7 @@ import Head from "next/head";
import { getTransparentHeaderLayout } from "src/components/Layout";
import { PolicyChapterCard } from "src/components/PolicyCards/PolicyChapterCard";
import { PolicySectionCard } from "src/components/PolicyCards/PolicySectionCard";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
const TermsOfService = () => {
const TermsData = [
+4
View File
@@ -10,6 +10,8 @@ export const enum TaskType {
label_initial_prompt = "label_initial_prompt",
label_prompter_reply = "label_prompter_reply",
label_assistant_reply = "label_assistant_reply",
random = "random",
}
// we need to reconsider how to handle task content types
@@ -32,3 +34,5 @@ export interface TaskResponse<Task extends BaseTask> {
userId: string;
task: Task;
}
export type AvailableTasks = { [taskType in TaskType]: number };
+6 -4
View File
@@ -1,7 +1,4 @@
/**
* Reports the Backend's knowledge of a user.
*/
export interface BackendUser {
export interface BackendUserCore {
/**
* The user's unique ID according to the `auth_method`.
*/
@@ -18,7 +15,12 @@ export interface BackendUser {
* - local
*/
auth_method: string;
}
/**
* Reports the Backend's knowledge of a user.
*/
export interface BackendUser extends BackendUserCore {
/**
* The backend's UUID for this user.
*/