Merging from main

This commit is contained in:
Keith Stevens
2023-01-28 18:05:56 +09:00
188 changed files with 5516 additions and 2442 deletions
+3 -3
View File
@@ -1,6 +1,6 @@
import { Box, Button, Center, Link, Text } from "@chakra-ui/react";
import { AlertTriangle } from "lucide-react";
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";
@@ -13,12 +13,12 @@ function Error() {
<meta name="404" content="Sorry, this page doesn't exist." />
</Head>
<Center flexDirection="column" gap="4" fontSize="lg" className="subpixel-antialiased">
<EmptyState text="Sorry, the page you are looking for does not exist." icon={FiAlertTriangle} />
<EmptyState text="Sorry, the page you are looking for does not exist." icon={AlertTriangle} />
<Box display="flex" flexDirection="column" alignItems="center" gap="2" mt="6">
<Text fontSize="sm">If you were trying to contribute data but ended up here, please file a bug.</Text>
<Button
width="fit-content"
leftIcon={<FiAlertTriangle className="text-blue-500" aria-hidden="true" />}
leftIcon={<AlertTriangle size={"1em"} className="text-blue-500" aria-hidden="true" />}
variant="solid"
size="xs"
>
+3 -6
View File
@@ -1,6 +1,6 @@
import { Box, Button, Center, Link, Text } from "@chakra-ui/react";
import { AlertTriangle } from "lucide-react";
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";
@@ -13,15 +13,12 @@ function ServerError() {
<meta name="404" content="Sorry, this page doesn't exist." />
</Head>
<Center flexDirection="column" gap="4" fontSize="lg" className="subpixel-antialiased">
<EmptyState
text="Sorry, we encountered a server error. We're not sure what went wrong."
icon={FiAlertTriangle}
/>
<EmptyState text="Sorry, we encountered a server error. We're not sure what went wrong." icon={AlertTriangle} />
<Box display="flex" flexDirection="column" alignItems="center" gap="2" mt="6">
<Text fontSize="sm">If you were trying to contribute data but ended up here, please file a bug.</Text>
<Button
width="fit-content"
leftIcon={<FiAlertTriangle className="text-blue-500" aria-hidden="true" />}
leftIcon={<AlertTriangle size="1em" className="text-blue-500" aria-hidden="true" />}
variant="solid"
size="xs"
>
+3 -3
View File
@@ -1,10 +1,10 @@
import { Button, Divider, Flex, Grid, Icon, Text } from "@chakra-ui/react";
import { 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 { Pencil } from "lucide-react";
import { SurveyCard } from "src/components/Survey/SurveyCard";
export default function Account() {
@@ -34,7 +34,7 @@ export default function Account() {
<Flex gap={2}>
{session.user.name ?? "(No username)"}
<Link href="/account/edit">
<Icon boxSize={5} as={MdOutlineEdit} />
<Icon boxSize={5} as={Pencil} size="1em" />
</Link>
</Flex>
<Text as="b">Email</Text>
+2 -3
View File
@@ -3,7 +3,7 @@ import { useRouter } from "next/router";
import { useSession } from "next-auth/react";
import { useEffect } from "react";
import { getAdminLayout } from "src/components/Layout";
import UsersCell from "src/components/UsersCell";
import { UserTable } from "src/components/UserTable";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
/**
@@ -28,7 +28,6 @@ const AdminIndex = () => {
}
router.push("/");
}, [router, session, status]);
return (
<>
<Head>
@@ -38,7 +37,7 @@ const AdminIndex = () => {
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="oa-basic-theme">{status === "loading" ? "loading..." : <UsersCell />}</main>
<main>{status === "loading" ? "loading..." : <UserTable />}</main>
</>
);
};
+2 -2
View File
@@ -10,7 +10,7 @@ import { getAdminLayout } from "src/components/Layout";
import { Role, RoleSelect } from "src/components/RoleSelect";
import { UserMessagesCell } from "src/components/UserMessagesCell";
import { post } from "src/lib/api";
import { oasstApiClient } from "src/lib/oasst_api_client";
import { userlessApiClient } from "src/lib/oasst_client_factory";
import prisma from "src/lib/prismadb";
import useSWRMutation from "swr/mutation";
@@ -113,7 +113,7 @@ const ManageUser = ({ user }: InferGetServerSidePropsType<typeof getServerSidePr
* Fetch the user's data on the server side when rendering.
*/
export async function getServerSideProps({ query, locale }) {
const backend_user = await oasstApiClient.fetch_user(query.id);
const backend_user = await userlessApiClient.fetch_user(query.id);
const local_user = await prisma.user.findUnique({
where: { id: backend_user.id },
select: {
+3 -2
View File
@@ -4,12 +4,12 @@ import {
CardBody,
CircularProgress,
SimpleGrid,
Text,
Table,
TableCaption,
TableContainer,
Tbody,
Td,
Text,
Th,
Thead,
Tr,
@@ -19,9 +19,10 @@ import Head from "next/head";
import { useRouter } from "next/router";
import { useSession } from "next-auth/react";
import { useEffect } from "react";
import useSWRImmutable from "swr/immutable";
import { getAdminLayout } from "src/components/Layout";
import { get } from "src/lib/api";
import useSWRImmutable from "swr/immutable";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
/**
* Provides the admin status page that shows result of calls to several backend API endpoints,
+3 -3
View File
@@ -1,17 +1,17 @@
import { getToken } from "next-auth/jwt";
import { withRole } from "src/lib/auth";
import { oasstApiClient } from "src/lib/oasst_api_client";
import { getBackendUserCore } from "src/lib/users";
import { createApiClientFromUser } from "src/lib/oasst_client_factory";
/**
* Returns tasks availability, stats, and tree manager stats.
*/
const handler = withRole("admin", async (req, res) => {
// NOTE: why are we using a dummy user here?
const dummyUser = {
id: "__dummy_user__",
display_name: "Dummy User",
auth_method: "local",
};
const oasstApiClient = createApiClientFromUser(dummyUser);
const [tasksAvailabilityOutcome, statsOutcome, treeManagerOutcome] = await Promise.allSettled([
oasstApiClient.fetch_tasks_availability(dummyUser),
oasstApiClient.fetch_stats(),
+5 -8
View File
@@ -1,22 +1,19 @@
import { withRole } from "src/lib/auth";
import { oasstApiClient } from "src/lib/oasst_api_client";
import { createApiClient } from "src/lib/oasst_client_factory";
import prisma from "src/lib/prismadb";
/**
* Update's the user's data in the database. Accessible only to admins.
*/
const handler = withRole("admin", async (req, res) => {
const handler = withRole("admin", async (req, res, token) => {
const { id, auth_method, user_id, notes, role } = req.body;
const oasstApiClient = await createApiClient(token);
// If the user is authorized by the web, update their role.
if (auth_method === "local") {
await prisma.user.update({
where: {
id,
},
data: {
role,
},
where: { id },
data: { role },
});
}
// Tell the backend the user's enabled or not enabled status.
+3 -2
View File
@@ -1,12 +1,13 @@
import { withRole } from "src/lib/auth";
import { oasstApiClient } from "src/lib/oasst_api_client";
import { createApiClient } from "src/lib/oasst_client_factory";
import type { Message } from "src/types/Conversation";
/**
* Returns the messages recorded by the backend for a user.
*/
const handler = withRole("admin", async (req, res) => {
const handler = withRole("admin", async (req, res, token) => {
const { user } = req.query;
const oasstApiClient = await createApiClient(token);
const messages: Message[] = await oasstApiClient.fetch_user_messages(user as string);
res.status(200).json(messages);
});
+16 -5
View File
@@ -1,6 +1,7 @@
import { withRole } from "src/lib/auth";
import { oasstApiClient } from "src/lib/oasst_api_client";
import { createApiClient } from "src/lib/oasst_client_factory";
import prisma from "src/lib/prismadb";
import { FetchUsersParams } from "src/types/Users";
/**
* The number of users to fetch in a single request. Could later be a query parameter.
@@ -16,11 +17,18 @@ const PAGE_SIZE = 20;
* - `direction`: Either "forward" or "backward" representing the pagination
* direction.
*/
const handler = withRole("admin", async (req, res) => {
const { cursor, direction } = req.query;
const handler = withRole("admin", async (req, res, token) => {
const { cursor, direction, searchDisplayName = "", sortKey = "username" } = req.query;
const oasstApiClient = await createApiClient(token);
// First, get all the users according to the backend.
const all_users = await oasstApiClient.fetch_users(PAGE_SIZE, cursor as string, direction === "forward");
const { items: all_users, ...rest } = await oasstApiClient.fetch_users({
searchDisplayName: searchDisplayName as FetchUsersParams["searchDisplayName"],
direction: direction as FetchUsersParams["direction"],
limit: PAGE_SIZE,
cursor: cursor as FetchUsersParams["cursor"],
sortKey: sortKey === "username" || sortKey === "display_name" ? sortKey : undefined,
});
// Next, get all the users stored in the web's auth database to fetch their role.
const local_user_ids = all_users.map(({ id }) => id);
@@ -51,7 +59,10 @@ const handler = withRole("admin", async (req, res) => {
};
});
res.status(200).json(users);
res.status(200).json({
items: users,
...rest,
});
});
export default handler;
+5 -3
View File
@@ -1,10 +1,12 @@
import { withoutRole } from "src/lib/auth";
import { oasstApiClient } from "src/lib/oasst_api_client";
import { getBackendUserCore } from "src/lib/users";
import { createApiClientFromUser } from "src/lib/oasst_client_factory";
import { getBackendUserCore, getUserLanguage } 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);
const oasstApiClient = createApiClientFromUser(user);
const userLanguage = getUserLanguage(req);
const availableTasks = await oasstApiClient.fetch_available_tasks(user, userLanguage);
res.status(200).json(availableTasks);
});
+4 -3
View File
@@ -1,13 +1,14 @@
import { withoutRole } from "src/lib/auth";
import { oasstApiClient } from "src/lib/oasst_api_client";
import { createApiClient } from "src/lib/oasst_client_factory";
import { LeaderboardTimeFrame } from "src/types/Leaderboard";
/**
* Returns the set of valid labels that can be applied to messages.
*/
const handler = withoutRole("banned", async (req, res) => {
const handler = withoutRole("banned", async (req, res, token) => {
const oasstApiClient = await createApiClient(token);
const time_frame = (req.query.time_frame as LeaderboardTimeFrame) ?? LeaderboardTimeFrame.day;
const info = await oasstApiClient.fetch_leaderboard(time_frame);
const info = await oasstApiClient.fetch_leaderboard(time_frame, { limit: req.query.limit as unknown as number });
res.status(200).json(info);
});
@@ -1,18 +1,10 @@
import { withoutRole } from "src/lib/auth";
import { createApiClient } from "src/lib/oasst_client_factory";
const handler = withoutRole("banned", async (req, res) => {
const handler = withoutRole("banned", async (req, res, token) => {
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.
const client = await createApiClient(token);
const messages = await client.fetch_message_children(id as string);
res.status(200).json(messages);
});
@@ -1,18 +1,10 @@
import { withoutRole } from "src/lib/auth";
import { createApiClient } from "src/lib/oasst_client_factory";
const handler = withoutRole("banned", async (req, res) => {
const handler = withoutRole("banned", async (req, res, token) => {
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.
const client = await createApiClient(token);
const messages = await client.fetch_conversation(id as string);
res.status(200).json(messages);
});
@@ -0,0 +1,31 @@
import { withoutRole } from "src/lib/auth";
import { createApiClientFromUser } from "src/lib/oasst_client_factory";
import { getBackendUserCore } from "src/lib/users";
const handler = withoutRole("banned", async (req, res, token) => {
const { id } = req.query;
if (!id) {
res.status(400).end();
return;
}
const messageId = id as string;
const { emoji, op } = req.body;
const user = await getBackendUserCore(token.sub);
const oasstApiClient = createApiClientFromUser(user);
try {
await oasstApiClient.set_user_message_emoji(messageId, user, emoji, op);
} catch (err) {
console.error(JSON.stringify(err));
return res.status(500).json(err);
}
// Get updated emoji
const message = await oasstApiClient.fetch_message(messageId, user);
res.status(200).json({ emojis: message.emojis, user_emojis: message.user_emojis });
});
export default handler;
+6 -12
View File
@@ -1,18 +1,12 @@
import { withoutRole } from "src/lib/auth";
import { createApiClientFromUser } from "src/lib/oasst_client_factory";
import { getBackendUserCore } from "src/lib/users";
const handler = withoutRole("banned", async (req, res) => {
const handler = withoutRole("banned", async (req, res, token) => {
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.
const user = await getBackendUserCore(token.sub);
const client = createApiClientFromUser(user);
const message = await client.fetch_message(id as string, user);
res.status(200).json(message);
});
+7 -21
View File
@@ -1,6 +1,8 @@
import { withoutRole } from "src/lib/auth";
import { createApiClient, createApiClientFromUser } from "src/lib/oasst_client_factory";
import { getBackendUserCore } from "src/lib/users";
const handler = withoutRole("banned", async (req, res) => {
const handler = withoutRole("banned", async (req, res, token) => {
const { id } = req.query;
if (!id) {
@@ -8,32 +10,16 @@ const handler = withoutRole("banned", async (req, res) => {
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();
const user = await getBackendUserCore(token.sub);
const client = createApiClientFromUser(user);
const message = await client.fetch_message(id as string, user);
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.
const parent = await client.fetch_message(message.parent_id, user);
res.status(200).json(parent);
});
+4 -10
View File
@@ -1,15 +1,9 @@
import { withoutRole } from "src/lib/auth";
import { createApiClient } from "src/lib/oasst_client_factory";
const handler = withoutRole("banned", async (req, res) => {
const messagesRes = await fetch(`${process.env.FASTAPI_URL}/api/v1/messages`, {
method: "GET",
headers: {
"X-API-Key": process.env.FASTAPI_KEY,
},
});
const messages = await messagesRes.json();
// Send recieved messages to the client.
const handler = withoutRole("banned", async (req, res, token) => {
const client = await createApiClient(token);
const messages = await client.fetch_recent_messages();
res.status(200).json(messages);
});
+5 -14
View File
@@ -1,20 +1,11 @@
import { withoutRole } from "src/lib/auth";
import { createApiClientFromUser } from "src/lib/oasst_client_factory";
import { getBackendUserCore } from "src/lib/users";
const handler = withoutRole("banned", async (req, res, token) => {
//TODO: add params if needed
const params = new URLSearchParams({
username: token.sub,
});
const messagesRes = await fetch(`${process.env.FASTAPI_URL}/api/v1/messages?${params}`, {
method: "GET",
headers: {
"X-API-Key": process.env.FASTAPI_KEY,
},
});
const messages = await messagesRes.json();
// Send recieved messages to the client.
const user = await getBackendUserCore(token.sub);
const client = createApiClientFromUser(user);
const messages = await client.fetch_my_messages(user);
res.status(200).json(messages);
});
@@ -1,7 +1,7 @@
import { withoutRole } from "src/lib/auth";
import { oasstApiClient } from "src/lib/oasst_api_client";
import { createApiClientFromUser } from "src/lib/oasst_client_factory";
import prisma from "src/lib/prismadb";
import { getBackendUserCore } from "src/lib/users";
import { getBackendUserCore, getUserLanguage } from "src/lib/users";
/**
* Returns a new task created from the Task Backend. We do a few things here:
@@ -14,11 +14,13 @@ import { getBackendUserCore } from "src/lib/users";
const handler = withoutRole("banned", async (req, res, token) => {
// Fetch the new task.
const { task_type } = req.query;
const userLanguage = getUserLanguage(req);
const user = await getBackendUserCore(token.sub);
const oasstApiClient = createApiClientFromUser(user);
let task;
try {
task = await oasstApiClient.fetchTask(task_type as string, user);
task = await oasstApiClient.fetchTask(task_type as string, user, userLanguage);
} catch (err) {
console.error(err);
res.status(500).json(err);
+8 -6
View File
@@ -1,19 +1,21 @@
import { Prisma } from "@prisma/client";
import { withoutRole } from "src/lib/auth";
import { oasstApiClient } from "src/lib/oasst_api_client";
import { createApiClient } from "src/lib/oasst_client_factory";
import prisma from "src/lib/prismadb";
const handler = withoutRole("banned", async (req, res) => {
const handler = withoutRole("banned", async (req, res, token) => {
// Parse out the local task ID and the interaction contents.
const { id: frontendId, reason } = req.body;
const registeredTask = await prisma.registeredTask.findUniqueOrThrow({ where: { id: frontendId } });
const [oasstApiClient, registeredTask] = await Promise.all([
createApiClient(token),
prisma.registeredTask.findUniqueOrThrow({ where: { id: frontendId } }),
]);
const task = registeredTask.task as Prisma.JsonObject;
const id = task.id as string;
const taskId = (registeredTask.task as Prisma.JsonObject).id as string;
// Update the backend with the rejection
await oasstApiClient.nackTask(id, reason);
await oasstApiClient.nackTask(taskId, reason);
// Send the results to the client.
res.status(200).json({});
+25
View File
@@ -0,0 +1,25 @@
import { withoutRole } from "src/lib/auth";
import { createApiClientFromUser } from "src/lib/oasst_client_factory";
import { getBackendUserCore } from "src/lib/users";
/**
* Adds a report for a message
*
*/
const handler = withoutRole("banned", async (req, res, token) => {
// Parse out the local message_id, and the interaction contents.
const { message_id, text } = req.body;
const user = await getBackendUserCore(token.sub);
const oasstApiClient = createApiClientFromUser(user);
try {
await oasstApiClient.send_report(message_id, user, text);
} catch (err) {
console.error(JSON.stringify(err));
return res.status(500).json(err);
}
res.status(200).end();
});
export default handler;
+5 -2
View File
@@ -5,8 +5,10 @@ import { withoutRole } from "src/lib/auth";
*
*/
const handler = withoutRole("banned", async (req, res, token) => {
// TODO: move to oasst_api_client
// Parse out the local message_id, and the interaction contents.
const { message_id, label_map, text } = req.body;
const { message_id, label_map } = req.body;
const interactionRes = await fetch(`${process.env.FASTAPI_URL}/api/v1/text_labels`, {
method: "POST",
headers: {
@@ -17,7 +19,8 @@ const handler = withoutRole("banned", async (req, res, token) => {
type: "text_labels",
message_id: message_id,
labels: label_map,
text: text,
text: "", // used only in reporting
is_report: false,
user: {
id: token.sub,
display_name: token.name || token.email,
+23 -9
View File
@@ -1,8 +1,8 @@
import { Prisma } from "@prisma/client";
import { withoutRole } from "src/lib/auth";
import { oasstApiClient } from "src/lib/oasst_api_client";
import { createApiClient } from "src/lib/oasst_client_factory";
import prisma from "src/lib/prismadb";
import { getBackendUserCore } from "src/lib/users";
import { getBackendUserCore, getUserLanguage } from "src/lib/users";
/**
* Stores the task interaction with the Task Backend and then returns the next task generated.
@@ -18,13 +18,18 @@ const handler = withoutRole("banned", async (req, res, token) => {
// Parse out the local task ID and the interaction contents.
const { id: frontendId, content, update_type } = req.body;
// Record that the user has done meaningful work and is no longer new.
await prisma.user.update({ where: { id: token.sub }, data: { isNew: false } });
// do in parallel since they are independent
const [_, registeredTask, oasstApiClient] = await Promise.all([
// Record that the user has done meaningful work and is no longer new.
prisma.user.update({ where: { id: token.sub }, data: { isNew: false } }),
// Accept the task so that we can complete it, this will probably go away soon.
prisma.registeredTask.findUniqueOrThrow({ where: { id: frontendId } }),
// Create client for upcoming requests
createApiClient(token),
]);
const taskId = (registeredTask.task as Prisma.JsonObject).id as string;
// Accept the task so that we can complete it, this will probably go away soon.
const registeredTask = await prisma.registeredTask.findUniqueOrThrow({ where: { id: frontendId } });
const task = registeredTask.task as Prisma.JsonObject;
const taskId = task.id as string;
await oasstApiClient.ackTask(taskId, registeredTask.id);
// Log the interaction locally to create our user_post_id needed by the Task
@@ -41,9 +46,18 @@ const handler = withoutRole("banned", async (req, res, token) => {
});
const user = await getBackendUserCore(token.sub);
const userLanguage = getUserLanguage(req);
let newTask;
try {
newTask = await oasstApiClient.interactTask(update_type, taskId, frontendId, interaction.id, content, user);
newTask = await oasstApiClient.interactTask(
update_type,
taskId,
frontendId,
interaction.id,
content,
user,
userLanguage
);
} catch (err) {
console.error(JSON.stringify(err));
return res.status(500).json(err);
+4 -3
View File
@@ -1,11 +1,12 @@
import { withoutRole } from "src/lib/auth";
import { oasstApiClient } from "src/lib/oasst_api_client";
import { createApiClient } from "src/lib/oasst_client_factory";
/**
* Returns the set of valid labels that can be applied to messages.
*/
const handler = withoutRole("banned", async (req, res) => {
const valid_labels = await oasstApiClient.fetch_valid_text();
const handler = withoutRole("banned", async (req, res, token) => {
const client = await createApiClient(token);
const valid_labels = await client.fetch_valid_text();
res.status(200).json(valid_labels);
});
+8 -7
View File
@@ -1,17 +1,18 @@
import { Button, ButtonProps, Input, Stack, useColorModeValue } from "@chakra-ui/react";
import { useColorMode } from "@chakra-ui/react";
import { Bug, Github, Mail } from "lucide-react";
import { GetServerSideProps } from "next";
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 React, { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { FaBug, FaDiscord, FaEnvelope, FaGithub } from "react-icons/fa";
import { AuthLayout } from "src/components/AuthLayout";
import { Footer } from "src/components/Footer";
import { Header } from "src/components/Header";
import { Discord } from "src/components/Icons/Discord";
import { Role, RoleSelect } from "src/components/RoleSelect";
export type SignInErrorTypes =
@@ -89,7 +90,7 @@ function Signin({ providers }: SigninProps) {
placeholder="Email Address"
{...register("email")}
/>
<SigninButton data-cy="signin-email-button" leftIcon={<FaEnvelope />}>
<SigninButton data-cy="signin-email-button" leftIcon={<Mail />}>
Continue with Email
</SigninButton>
</Stack>
@@ -103,7 +104,7 @@ function Signin({ providers }: SigninProps) {
bg: "#454FBF",
}}
size="lg"
leftIcon={<FaDiscord />}
leftIcon={<Discord />}
color="white"
onClick={() => signIn(discord.id, { callbackUrl: "/" })}
// isDisabled="false"
@@ -119,7 +120,7 @@ function Signin({ providers }: SigninProps) {
bg: "#101010",
}}
size={"lg"}
leftIcon={<FaGithub />}
leftIcon={<Github />}
colorScheme="blue"
// isDisabled="false"
>
@@ -165,7 +166,7 @@ const SigninButton = (props: ButtonProps) => {
return (
<Button
size={"lg"}
leftIcon={<FaEnvelope />}
leftIcon={<Mail />}
type="submit"
colorScheme={buttonColorScheme}
color="white"
@@ -203,7 +204,7 @@ const DebugSigninForm = ({ credentials, bgColorClass }: { credentials: ClientSaf
<Stack>
<Input variant="outline" size="lg" placeholder="Username" {...register("username")} />
<RoleSelect {...register("role")}></RoleSelect>
<SigninButton leftIcon={<FaBug />}>Continue with Debug User</SigninButton>
<SigninButton leftIcon={<Bug />}>Continue with Debug User</SigninButton>
</Stack>
</form>
);
+3 -26
View File
@@ -1,32 +1,9 @@
import Head from "next/head";
import { TaskEmptyState } from "src/components/EmptyState";
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";
import { TaskPage } from "src/components/TaskPage/TaskPage";
import { TaskType } from "src/types/Task";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
const AssistantReply = () => {
const { tasks, isLoading, reset, trigger } = useCreateAssistantReply();
if (isLoading) {
return <LoadingScreen text="Loading..." />;
}
if (tasks.length === 0) {
return <TaskEmptyState />;
}
return (
<>
<Head>
<title>Reply as Assistant</title>
<meta name="description" content="Reply as Assistant." />
</Head>
<Task key={tasks[0].task.id} frontendId={tasks[0].id} task={tasks[0].task} trigger={trigger} mutate={reset} />
</>
);
};
const AssistantReply = () => <TaskPage type={TaskType.assistant_reply} />;
AssistantReply.getLayout = getDashboardLayout;
+3 -26
View File
@@ -1,32 +1,9 @@
import Head from "next/head";
import { TaskEmptyState } from "src/components/EmptyState";
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";
import { TaskPage } from "src/components/TaskPage/TaskPage";
import { TaskType } from "src/types/Task";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
const InitialPrompt = () => {
const { tasks, isLoading, reset, trigger } = useCreateInitialPrompt();
if (isLoading) {
return <LoadingScreen text="Loading..." />;
}
if (tasks.length === 0) {
return <TaskEmptyState />;
}
return (
<>
<Head>
<title>Initial Prompt</title>
<meta name="description" content="Add an initial Prompt." />
</Head>
<Task key={tasks[0].task.id} frontendId={tasks[0].id} task={tasks[0].task} trigger={trigger} mutate={reset} />
</>
);
};
const InitialPrompt = () => <TaskPage type={TaskType.initial_prompt} />;
InitialPrompt.getLayout = getDashboardLayout;
+5 -28
View File
@@ -1,33 +1,10 @@
import Head from "next/head";
import { TaskEmptyState } from "src/components/EmptyState";
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";
import { TaskPage } from "src/components/TaskPage/TaskPage";
import { TaskType } from "src/types/Task";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
const UserReply = () => {
const { tasks, isLoading, reset, trigger } = useCreatePrompterReply();
const PrompterReply = () => <TaskPage type={TaskType.prompter_reply} />;
if (isLoading) {
return <LoadingScreen text="Loading..." />;
}
PrompterReply.getLayout = getDashboardLayout;
if (tasks.length === 0) {
return <TaskEmptyState />;
}
return (
<>
<Head>
<title>Reply as User</title>
<meta name="description" content="Reply as User." />
</Head>
<Task key={tasks[0].task.id} frontendId={tasks[0].id} task={tasks[0].task} trigger={trigger} mutate={reset} />
</>
);
};
UserReply.getLayout = getDashboardLayout;
export default UserReply;
export default PrompterReply;
+30 -11
View File
@@ -1,33 +1,52 @@
import { Flex } from "@chakra-ui/react";
import Head from "next/head";
import { useMemo } from "react";
import { LeaderboardTable, TaskOption, WelcomeCard } from "src/components/Dashboard";
import { useTranslation } from "next-i18next";
import { useEffect, useMemo, useState } from "react";
import { LeaderboardWidget, 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";
import { AvailableTasks, TaskType } from "src/types/Task";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
import useSWRImmutable from "swr/immutable";
import useSWR from "swr";
const Dashboard = () => {
// Adding a demonstrative call to the backend that includes the web's JWT.
useSWRImmutable(`${process.env.FASTAPI_URL}/api/v1/auth/check`, get);
const { data } = useSWRImmutable<AvailableTasks>("/api/available_tasks", get);
const {
t,
i18n: { language },
} = useTranslation(["dashboard", "common", "tasks"]);
const [activeLang, setLang] = useState<string>(null);
const { data, mutate: fetchTasks } = useSWR<AvailableTasks>("/api/available_tasks", get, {
refreshInterval: 2 * 60 * 1000, //2 minutes
revalidateOnMount: false, // triggered in the hook below
});
// TODO: show only these tasks:
const availableTasks = useMemo(() => filterAvailableTasks(data ?? {}), [data]);
useEffect(() => {
// re-fetch tasks if the language has changed
if (activeLang !== language) {
setLang(language);
fetchTasks();
}
}, [activeLang, setLang, language, fetchTasks]);
const availableTaskTypes = useMemo(() => {
const taskTypes = filterAvailableTasks(data ?? {});
return { [TaskCategory.Random]: taskTypes };
}, [data]);
return (
<>
<Head>
<title>Dashboard - Open Assistant</title>
<title>{`${t("dashboard")} - ${t("common:title")}`}</title>
<meta name="description" content="Chat with Open Assistant and provide feedback." />
</Head>
<Flex direction="column" gap="10">
<WelcomeCard />
<TaskOption displayTaskCategories={[TaskCategory.Random]} />
<LeaderboardTable />
<TaskOption content={availableTaskTypes} />
<LeaderboardWidget />
</Flex>
</>
);
@@ -39,6 +58,6 @@ export default Dashboard;
const filterAvailableTasks = (availableTasks: Partial<AvailableTasks>) =>
Object.entries(availableTasks)
.filter(([_, count]) => count > 0)
.filter(([, count]) => count > 0)
.sort((a, b) => b[1] - a[1])
.map(([taskType]) => taskType) as TaskType[];
@@ -1,32 +1,9 @@
import Head from "next/head";
import { TaskEmptyState } from "src/components/EmptyState";
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";
import { TaskPage } from "src/components/TaskPage/TaskPage";
import { TaskType } from "src/types/Task";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
const RankAssistantReplies = () => {
const { tasks, isLoading, reset, trigger } = useRankAssistantRepliesTask();
if (isLoading) {
return <LoadingScreen text="Loading..." />;
}
if (tasks.length === 0) {
return <TaskEmptyState />;
}
return (
<>
<Head>
<title>Rank Assistant Replies</title>
<meta name="description" content="Rank Assistant Replies." />
</Head>
<Task key={tasks[0].task.id} frontendId={tasks[0].id} task={tasks[0].task} trigger={trigger} mutate={reset} />
</>
);
};
const RankAssistantReplies = () => <TaskPage type={TaskType.rank_assistant_replies} />;
RankAssistantReplies.getLayout = getDashboardLayout;
@@ -1,32 +1,9 @@
import Head from "next/head";
import { TaskEmptyState } from "src/components/EmptyState";
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";
import { TaskPage } from "src/components/TaskPage/TaskPage";
import { TaskType } from "src/types/Task";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
const RankInitialPrompts = () => {
const { tasks, isLoading, reset, trigger } = useRankInitialPromptsTask();
if (isLoading) {
return <LoadingScreen text="Loading..." />;
}
if (tasks.length === 0) {
return <TaskEmptyState />;
}
return (
<>
<Head>
<title>Rank Initial Prompts</title>
<meta name="description" content="Rank initial prompts." />
</Head>
<Task key={tasks[0].task.id} frontendId={tasks[0].id} task={tasks[0].task} trigger={trigger} mutate={reset} />
</>
);
};
const RankInitialPrompts = () => <TaskPage type={TaskType.rank_initial_prompts} />;
RankInitialPrompts.getLayout = getDashboardLayout;
@@ -1,33 +1,10 @@
import Head from "next/head";
import { TaskEmptyState } from "src/components/EmptyState";
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";
import { TaskPage } from "src/components/TaskPage/TaskPage";
import { TaskType } from "src/types/Task";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
const RankUserReplies = () => {
const { tasks, isLoading, reset, trigger } = useRankPrompterRepliesTask();
const RankPrompterReplies = () => <TaskPage type={TaskType.rank_prompter_replies} />;
if (isLoading) {
return <LoadingScreen text="Loading..." />;
}
RankPrompterReplies.getLayout = getDashboardLayout;
if (tasks.length === 0) {
return <TaskEmptyState />;
}
return (
<>
<Head>
<title>Rank User Replies</title>
<meta name="description" content="Rank User Replies." />
</Head>
<Task key={tasks[0].task.id} frontendId={tasks[0].id} task={tasks[0].task} trigger={trigger} mutate={reset} />
</>
);
};
RankUserReplies.getLayout = getDashboardLayout;
export default RankUserReplies;
export default RankPrompterReplies;
+1 -1
View File
@@ -24,7 +24,7 @@ const Home = () => {
<>
<Head>
<title>{t("title")}</title>
<meta name="description" content={t("description")} />
<meta name="description" content={t("index:description")} />
</Head>
<Box as="main" className="oa-basic-theme">
<Hero />
@@ -1,32 +1,9 @@
import Head from "next/head";
import { TaskEmptyState } from "src/components/EmptyState";
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";
import { TaskPage } from "src/components/TaskPage/TaskPage";
import { TaskType } from "src/types/Task";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
const LabelAssistantReply = () => {
const { tasks, isLoading, trigger, reset } = useLabelAssistantReplyTask();
if (isLoading) {
return <LoadingScreen />;
}
if (tasks.length === 0) {
return <TaskEmptyState />;
}
return (
<>
<Head>
<title>Label Assistant Reply</title>
<meta name="description" content="Label Assistant Reply" />
</Head>
<Task key={tasks[0].task.id} frontendId={tasks[0].id} task={tasks[0].task} trigger={trigger} mutate={reset} />
</>
);
};
const LabelAssistantReply = () => <TaskPage type={TaskType.label_assistant_reply} />;
LabelAssistantReply.getLayout = getDashboardLayout;
@@ -1,32 +1,9 @@
import Head from "next/head";
import { TaskEmptyState } from "src/components/EmptyState";
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";
import { TaskPage } from "src/components/TaskPage/TaskPage";
import { TaskType } from "src/types/Task";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
const LabelInitialPrompt = () => {
const { tasks, isLoading, trigger, reset } = useLabelInitialPromptTask();
if (isLoading) {
return <LoadingScreen />;
}
if (tasks.length === 0) {
return <TaskEmptyState />;
}
return (
<>
<Head>
<title>Label Initial Prompt</title>
<meta name="description" content="Label Initial Prompt" />
</Head>
<Task key={tasks[0].task.id} frontendId={tasks[0].id} task={tasks[0].task} trigger={trigger} mutate={reset} />
</>
);
};
const LabelInitialPrompt = () => <TaskPage type={TaskType.label_initial_prompt} />;
LabelInitialPrompt.getLayout = getDashboardLayout;
@@ -1,32 +1,9 @@
import Head from "next/head";
import { TaskEmptyState } from "src/components/EmptyState";
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";
import { TaskPage } from "src/components/TaskPage/TaskPage";
import { TaskType } from "src/types/Task";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
const LabelPrompterReply = () => {
const { tasks, isLoading, trigger, reset } = useLabelPrompterReplyTask();
if (isLoading) {
return <LoadingScreen />;
}
if (tasks.length === 0) {
return <TaskEmptyState />;
}
return (
<>
<Head>
<title>Label Prompter Reply</title>
<meta name="description" content="Label Prompter Reply" />
</Head>
<Task key={tasks[0].task.id} frontendId={tasks[0].id} task={tasks[0].task} trigger={trigger} mutate={reset} />
</>
);
};
const LabelPrompterReply = () => <TaskPage type={TaskType.label_prompter_reply} />;
LabelPrompterReply.getLayout = getDashboardLayout;
+28 -25
View File
@@ -1,9 +1,9 @@
import { Box, Heading, Tab, TabList, TabPanel, TabPanels, Tabs } from "@chakra-ui/react";
import { Box, Card, CardBody, Heading, Tab, TabList, TabPanel, TabPanels, Tabs } from "@chakra-ui/react";
import Head from "next/head";
import { useTranslation } from "next-i18next";
import { getDashboardLayout } from "src/components/Layout";
import { LeaderboardGridCell } from "src/components/LeaderboardGridCell";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
import { LeaderboardTable } from "src/components/LeaderboardTable";
import { LeaderboardTimeFrame } from "src/types/Leaderboard";
const Leaderboard = () => {
@@ -18,29 +18,32 @@ const Leaderboard = () => {
<Heading fontSize="2xl" fontWeight="bold" pb="4">
{t("leaderboard")}
</Heading>
<Tabs isFitted isLazy>
<TabList>
<Tab>{t("daily")}</Tab>
<Tab>{t("weekly")}</Tab>
<Tab>{t("monthly")}</Tab>
<Tab>{t("overall")}</Tab>
</TabList>
<TabPanels>
<TabPanel p="0">
<LeaderboardGridCell timeFrame={LeaderboardTimeFrame.day} />
</TabPanel>
<TabPanel p="0">
<LeaderboardGridCell timeFrame={LeaderboardTimeFrame.week} />
</TabPanel>
<TabPanel p="0">
<LeaderboardGridCell timeFrame={LeaderboardTimeFrame.month} />
</TabPanel>
<TabPanel p="0">
<LeaderboardGridCell timeFrame={LeaderboardTimeFrame.total} />
</TabPanel>
</TabPanels>
</Tabs>
<Card>
<CardBody>
<Tabs isFitted isLazy>
<TabList>
<Tab>{t("daily")}</Tab>
<Tab>{t("weekly")}</Tab>
<Tab>{t("monthly")}</Tab>
<Tab>{t("overall")}</Tab>
</TabList>
<TabPanels>
<TabPanel p="0">
<LeaderboardTable timeFrame={LeaderboardTimeFrame.day} limit={20} />
</TabPanel>
<TabPanel p="0">
<LeaderboardTable timeFrame={LeaderboardTimeFrame.week} limit={20} />
</TabPanel>
<TabPanel p="0">
<LeaderboardTable timeFrame={LeaderboardTimeFrame.month} limit={20} />
</TabPanel>
<TabPanel p="0">
<LeaderboardTable timeFrame={LeaderboardTimeFrame.total} limit={20} />
</TabPanel>
</TabPanels>
</Tabs>
</CardBody>
</Card>
</Box>
</>
);
+1 -1
View File
@@ -35,7 +35,7 @@ const MessageDetail = ({ id }: { id: string }) => {
Parent
</Text>
<Box bg={backgroundColor} padding="4" borderRadius="xl" boxShadow="base" width="fit-content">
<MessageTableEntry enabled item={parent} />
<MessageTableEntry enabled message={parent} />
</Box>
</Box>
</>
+2 -2
View File
@@ -1,7 +1,7 @@
import Head from "next/head";
import { TaskOption } from "src/components/Dashboard";
import { allTaskOptions } from "src/components/Dashboard/TaskOption";
import { getDashboardLayout } from "src/components/Layout";
import { TaskCategory } from "src/components/Tasks/TaskTypes";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
const AllTasks = () => {
@@ -11,7 +11,7 @@ const AllTasks = () => {
<title>All Tasks - Open Assistant</title>
<meta name="description" content="All tasks for Open Assistant." />
</Head>
<TaskOption displayTaskCategories={[TaskCategory.Create, TaskCategory.Evaluate, TaskCategory.Label]} />
<TaskOption content={allTaskOptions} />
</>
);
};
+4 -28
View File
@@ -1,34 +1,10 @@
import Head from "next/head";
import { TaskEmptyState } from "src/components/EmptyState";
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 { TaskPage } from "src/components/TaskPage/TaskPage";
export { getDefaultStaticProps as getStaticProps } from "src/lib/default_static_props";
import { TaskType } from "src/types/Task";
const RandomTask = () => {
const { tasks, isLoading, trigger, reset } = useGenericTaskAPI(TaskType.random);
const Random = () => <TaskPage type={TaskType.random} />;
if (isLoading) {
return <LoadingScreen text="Loading..." />;
}
Random.getLayout = getDashboardLayout;
if (tasks.length === 0) {
return <TaskEmptyState />;
}
return (
<>
<Head>
<title>Random Task</title>
<meta name="description" content="Random Task." />
</Head>
<Task key={tasks[0].task.id} frontendId={tasks[0].id} task={tasks[0].task} trigger={trigger} mutate={reset} />
</>
);
};
RandomTask.getLayout = (page) => getDashboardLayout(page);
export default RandomTask;
export default Random;