Merge pull request #905 from rjmacarthy/chore/localisation-tasks

website: Add localisation to dashboard and tasks pages
This commit is contained in:
AbdBarho
2023-01-24 23:12:19 +01:00
committed by GitHub
12 changed files with 194 additions and 121 deletions
+2 -1
View File
@@ -14,5 +14,6 @@
"sign_in": "Sign In",
"sign_out": "Sign Out",
"terms_of_service": "Terms of Service",
"title": "Open Assistant"
"title": "Open Assistant",
"more_information": "More Information"
}
+8
View File
@@ -0,0 +1,8 @@
{
"grab_a_task": "Grab a task!",
"create": "Create",
"evaluate": "Evaluate",
"label": "Label",
"dashboard": "Dashboard",
"go": "Go"
}
+79
View File
@@ -0,0 +1,79 @@
{
"write_initial_prompt": "Write your prompt here...",
"default": {
"unchanged_title": "No changes",
"unchanged_message": "Are you sure you would like to continue?"
},
"random": {
"label": "I'm feeling lucky",
"desc": "Help us improve Open Assistant by starting a random task."
},
"create_initial_prompt": {
"label": "Create Initial Prompts",
"desc": "Write initial prompts to help Open Assistant to try replying to diverse messages.",
"overview": "Create an initial message to send to the assistant",
"instruction": "Provide the initial prompts"
},
"reply_as_user": {
"label": "Reply as User",
"desc": "Chat with Open Assistant and help improve it's responses as you interact with it.",
"overview": "Given the following conversation, provide an adequate reply",
"instruction": "Provide the user's reply"
},
"reply_as_assistant": {
"label": "Reply as Assistant",
"desc": "Help Open Assistant improve its responses to conversations with other users.",
"overview": "Given the following conversation, provide an adequate reply"
},
"rank_user_replies": {
"label": "Rank User Replies",
"desc": "Help Open Assistant improve its responses to conversations with other users.",
"overview": "Given the following User replies, sort them from best to worst, best being first, worst being last.",
"unchanged_title": "Order Unchanged",
"unchanged_message": "You have not changed the order of the prompts. Are you sure you would like to continue?"
},
"rank_assistant_replies": {
"label": "Rank Assistant Replies",
"desc": "Score prompts given by Open Assistant based on their accuracy and readability.",
"overview": "Given the following Assistant replies, sort them from best to worst, best being first, worst being last.",
"unchanged_title": "Order Unchanged",
"unchanged_message": "You have not changed the order of the prompts. Are you sure you would like to continue?"
},
"rank_initial_prompts": {
"label": "Rank Initial Prompts",
"desc": "Score prompts given by Open Assistant based on their accuracy and readability.",
"overview": "Given the following initial prompts, sort them from best to worst, best being first, worst being last.",
"unchanged_title": "Order Unchanged",
"unchanged_message": "You have not changed the order of the prompts. Are you sure you would like to continue?"
},
"label_initial_prompt": {
"label": "Label Initial Prompt",
"desc": "Provide labels for a prompt.",
"overview": "Provide labels for the following prompt"
},
"label_prompter_reply": {
"label": "Label Prompter Reply",
"desc": "Provide labels for a prompt.",
"overview": "Given the following discussion, provide labels for the final prompt."
},
"label_assistant_reply": {
"label": "Label Assistant Reply",
"desc": "Provide labels for a prompt.",
"overview": "Given the following discussion, provide labels for the final prompt."
},
"classify_initial_prompt": {
"label": "Classify Initial Prompt",
"desc": "Provide labels for a prompt.",
"overview": "Read the following prompt and then answer the question about it."
},
"classify_prompter_reply": {
"label": "Classify Prompter Reply",
"desc": "Provide labels for a prompt.",
"overview": "Read the following conversation and then answer the question about the last reply in the discussion."
},
"classify_assistant_reply": {
"label": "Classify Assistant Reply",
"desc": "Provide labels for a prompt.",
"overview": "Read the following conversation and then answer the question about the last reply in the discussion."
}
}
@@ -12,7 +12,9 @@ import {
} from "@chakra-ui/react";
import { HelpCircle } from "lucide-react";
import Link from "next/link";
import { useTranslation } from "next-i18next";
import { useMemo } from "react";
import { getTypeSafei18nKey } from "src/lib/i18n";
import { TaskType } from "src/types/Task";
import { TaskCategory, TaskCategoryLabels, TaskInfo, TaskInfos } from "../Tasks/TaskTypes";
@@ -22,6 +24,7 @@ export interface TasksOptionProps {
}
export const TaskOption = ({ content }: TasksOptionProps) => {
const { t } = useTranslation(["dashboard", "tasks"]);
const backgroundColor = useColorModeValue("white", "gray.700");
const taskInfoMap = useMemo(
@@ -41,7 +44,7 @@ export const TaskOption = ({ content }: TasksOptionProps) => {
<div key={category}>
<Flex>
<Heading size="lg" className="pb-4">
{TaskCategoryLabels[category]}
{t(TaskCategoryLabels[category])}
</Heading>
<Spacer />
<ExternalLink href="https://projects.laion.ai/Open-Assistant/" isExternal>
@@ -52,7 +55,7 @@ export const TaskOption = ({ content }: TasksOptionProps) => {
{taskTypes
.map((taskType) => taskInfoMap[taskType])
.map((item) => (
<Link key={category + item.label} href={item.pathname}>
<Link key={category + item.id} href={item.pathname}>
<GridItem
bg={backgroundColor}
borderRadius="xl"
@@ -60,8 +63,8 @@ export const TaskOption = ({ content }: TasksOptionProps) => {
className="flex flex-col justify-between h-full"
>
<Flex className="p-6 pb-10" flexDir="column" gap="3">
<Heading size="md">{item.label}</Heading>
<Text size="sm">{item.desc}</Text>
<Heading size="md">{t(getTypeSafei18nKey(`tasks:${item.id}.label`))}</Heading>
<Text size="sm">{t(getTypeSafei18nKey(`tasks:${item.id}.desc`))}</Text>
</Flex>
<Text
fontWeight="bold"
@@ -69,7 +72,7 @@ export const TaskOption = ({ content }: TasksOptionProps) => {
borderBottomRadius="xl"
className="px-6 py-2 transition-colors duration-300 bg-blue-500 hover:bg-blue-600"
>
Go -&gt;
{t("go")} -&gt;
</Text>
</GridItem>
</Link>
+13 -8
View File
@@ -1,10 +1,12 @@
import { Box, Stack, Text, useColorModeValue } from "@chakra-ui/react";
import { useTranslation } from "next-i18next";
import { useState } from "react";
import { MessageTable } from "src/components/Messages/MessageTable";
import { TrackedTextarea } from "src/components/Survey/TrackedTextarea";
import { TwoColumnsWithCards } from "src/components/Survey/TwoColumnsWithCards";
import { TaskSurveyProps } from "src/components/Tasks/Task";
import { TaskHeader } from "src/components/Tasks/TaskHeader";
import { getTypeSafei18nKey } from "src/lib/i18n";
export const CreateTask = ({
task,
@@ -14,14 +16,15 @@ export const CreateTask = ({
onReplyChanged,
onValidityChanged,
}: TaskSurveyProps<{ text: string }>) => {
const { t, i18n } = useTranslation(["tasks", "common"]);
const cardColor = useColorModeValue("gray.50", "gray.800");
const titleColor = useColorModeValue("gray.800", "gray.300");
const [inputText, setInputText] = useState("");
const textChangeHandler = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
const text = event.target.value;
const isTextBlank = !text || /^\s*$/.test(text) ? true : false;
onReplyChanged({ text });
const isTextBlank = !text || /^\s*$/.test(text);
if (!isTextBlank) {
onValidityChanged("VALID");
setInputText(text);
@@ -36,22 +39,24 @@ export const CreateTask = ({
<TwoColumnsWithCards>
<>
<TaskHeader taskType={taskType} />
{task.conversation ? (
{!!task.conversation && (
<Box mt="4" borderRadius="lg" bg={cardColor} className="p-3 sm:p-6">
<MessageTable messages={task.conversation.messages} highlightLastMessage />
</Box>
) : null}
)}
</>
<>
<Stack spacing="4">
<Text fontSize="xl" fontWeight="bold" color={titleColor}>
{taskType.instruction}
</Text>
{!!i18n.exists(`task.${taskType.id}.instruction`) && (
<Text fontSize="xl" fontWeight="bold" color={titleColor}>
{t(getTypeSafei18nKey(`${taskType.id}.instruction`))}
</Text>
)}
<TrackedTextarea
text={inputText}
onTextChange={textChangeHandler}
thresholds={{ low: 20, medium: 40, goal: 50 }}
textareaProps={{ placeholder: "Write your prompt here...", isDisabled, isReadOnly: !isEditable }}
textareaProps={{ placeholder: t("tasks:write_initial_prompt"), isDisabled, isReadOnly: !isEditable }}
/>
</Stack>
</>
+5 -5
View File
@@ -1,3 +1,4 @@
import { useTranslation } from "next-i18next";
import { useRef, useState } from "react";
import { TaskControls } from "src/components/Survey/TaskControls";
import { CreateTask } from "src/components/Tasks/CreateTask";
@@ -6,6 +7,7 @@ import { LabelTask } from "src/components/Tasks/LabelTask";
import { TaskCategory, TaskInfo, TaskInfos } from "src/components/Tasks/TaskTypes";
import { UnchangedWarning } from "src/components/Tasks/UnchangedWarning";
import { post } from "src/lib/api";
import { getTypeSafei18nKey } from "src/lib/i18n";
import { TaskContent, TaskReplyValidity } from "src/types/Task";
import useSWRMutation from "swr/mutation";
@@ -23,6 +25,7 @@ export interface TaskSurveyProps<T> {
}
export const Task = ({ frontendId, task, trigger, mutate }) => {
const { t } = useTranslation("tasks");
const [taskStatus, setTaskStatus] = useState<TaskStatus>("NOT_SUBMITTABLE");
const replyContent = useRef<TaskContent>(null);
const [showUnchangedWarning, setShowUnchangedWarning] = useState(false);
@@ -111,7 +114,6 @@ export const Task = ({ frontendId, task, trigger, mutate }) => {
case TaskCategory.Create:
return (
<CreateTask
key={task.id}
task={task}
taskType={taskType}
isEditable={edit_mode}
@@ -123,7 +125,6 @@ export const Task = ({ frontendId, task, trigger, mutate }) => {
case TaskCategory.Evaluate:
return (
<EvaluateTask
key={task.id}
task={task}
taskType={taskType}
isEditable={edit_mode}
@@ -135,7 +136,6 @@ export const Task = ({ frontendId, task, trigger, mutate }) => {
case TaskCategory.Label:
return (
<LabelTask
key={task.id}
task={task}
taskType={taskType}
isEditable={edit_mode}
@@ -160,8 +160,8 @@ export const Task = ({ frontendId, task, trigger, mutate }) => {
/>
<UnchangedWarning
show={showUnchangedWarning}
title={taskType.unchanged_title || "No changes"}
message={taskType.unchanged_message || "Are you sure you would like to continue?"}
title={t(getTypeSafei18nKey(`${taskType.id}.unchanged_title`)) || t("default.unchanged_title")}
message={t(getTypeSafei18nKey(`${taskType.id}.unchanged_message`)) || t("default.unchanged_message")}
continueButtonText={"Continue anyway"}
onClose={() => setShowUnchangedWarning(false)}
onContinueAnyway={() => {
@@ -1,6 +1,8 @@
import { HStack, IconButton, Link, Stack, Text, useColorModeValue } from "@chakra-ui/react";
import { HelpCircle } from "lucide-react";
import { useTranslation } from "next-i18next";
import type { TaskInfo } from "src/components/Tasks/TaskTypes";
import { getTypeSafei18nKey } from "src/lib/i18n";
interface TaskHeaderProps {
/**
@@ -13,20 +15,21 @@ interface TaskHeaderProps {
* Presents the Task label, instructions, and help link
*/
const TaskHeader = ({ taskType }: TaskHeaderProps) => {
const { t } = useTranslation(["tasks", "common"]);
const labelColor = useColorModeValue("gray.600", "gray.400");
const titleColor = useColorModeValue("gray.800", "gray.300");
return (
<Stack spacing="1">
<HStack>
<Text fontSize="xl" fontWeight="bold" color={titleColor}>
{taskType.label}
{t(getTypeSafei18nKey(`${taskType.id}.label`))}
</Text>
<Link href={taskType.help_link} isExternal>
<IconButton variant="ghost" aria-label="More Information" icon={<HelpCircle size="1em" />} />
</Link>
</HStack>
<Text fontSize="md" color={labelColor}>
{taskType.overview}
{t(getTypeSafei18nKey(`${taskType.id}.overview`))}
</Text>
</Stack>
);
+56 -87
View File
@@ -1,181 +1,150 @@
import { TaskType } from "src/types/Task";
export enum TaskCategory {
Random = "Random",
Create = "Create",
Evaluate = "Evaluate",
Label = "Label",
Random = "Random",
}
export enum TaskUpdateType {
MessageRanking = "message_ranking",
Random = "random",
TextLabels = "text_labels",
TextReplyToMessage = "text_reply_to_message",
}
export interface TaskInfo {
label: string;
desc: string;
category: TaskCategory;
help_link: string;
id: string;
mode?: string;
pathname: string;
type: string;
help_link: string;
mode?: string;
overview?: string;
instruction?: string;
update_type: string;
unchanged_title?: string;
unchanged_message?: string;
}
export const TaskCategoryLabels: { [key in TaskCategory]: string } = {
[TaskCategory.Random]: "Grab a task!",
[TaskCategory.Create]: "Create",
[TaskCategory.Evaluate]: "Evaluate",
[TaskCategory.Label]: "Label",
[TaskCategory.Random]: "grab_a_task",
[TaskCategory.Create]: "create",
[TaskCategory.Evaluate]: "evaluate",
[TaskCategory.Label]: "label",
};
export const TaskInfos: TaskInfo[] = [
// general/random
{
label: "I'm feeling lucky",
desc: "Help us improve Open Assistant by starting a random task.",
id: "random",
category: TaskCategory.Random,
pathname: "/tasks/random",
help_link: "https://projects.laion.ai/Open-Assistant/docs/guides/prompting",
type: "random",
update_type: "random",
type: TaskType.random,
update_type: TaskUpdateType.Random,
},
// create
{
label: "Create Initial Prompts",
desc: "Write initial prompts to help Open Assistant to try replying to diverse messages.",
id: "create_initial_prompt",
category: TaskCategory.Create,
pathname: "/create/initial_prompt",
help_link: "https://projects.laion.ai/Open-Assistant/docs/guides/prompting",
type: "initial_prompt",
overview: "Create an initial message to send to the assistant",
instruction: "Provide the initial prompt",
update_type: "text_reply_to_message",
type: TaskType.initial_prompt,
update_type: TaskUpdateType.TextReplyToMessage,
},
{
label: "Reply as User",
desc: "Chat with Open Assistant and help improve its responses as you interact with it.",
id: "reply_as_user",
category: TaskCategory.Create,
pathname: "/create/user_reply",
help_link: "https://projects.laion.ai/Open-Assistant/docs/tasks/reply_as_user",
type: "prompter_reply",
overview: "Given the following conversation, provide an adequate reply",
instruction: "Provide the user's reply",
update_type: "text_reply_to_message",
type: TaskType.prompter_reply,
update_type: TaskUpdateType.TextReplyToMessage,
},
{
label: "Reply as Assistant",
desc: "Help Open Assistant improve its responses to conversations with other users.",
id: "reply_as_assistant",
category: TaskCategory.Create,
pathname: "/create/assistant_reply",
help_link: "https://projects.laion.ai/Open-Assistant/docs/tasks/reply_as_assistant",
type: "assistant_reply",
overview: "Given the following conversation, provide an adequate reply",
instruction: "Provide the assistant's reply",
update_type: "text_reply_to_message",
type: TaskType.assistant_reply,
update_type: TaskUpdateType.TextReplyToMessage,
},
// evaluate
{
label: "Rank User Replies",
id: "rank_user_replies",
category: TaskCategory.Evaluate,
desc: "Help Open Assistant improve its responses to conversations with other users.",
pathname: "/evaluate/rank_user_replies",
help_link: "https://projects.laion.ai/Open-Assistant/docs/guides/prompting",
overview: "Given the following User replies, sort them from best to worst, best being first, worst being last.",
type: "rank_prompter_replies",
update_type: "message_ranking",
unchanged_title: "Order Unchanged",
unchanged_message: "You have not changed the order of the prompts. Are you sure you would like to continue?",
type: TaskType.rank_prompter_replies,
update_type: TaskUpdateType.MessageRanking,
},
{
label: "Rank Assistant Replies",
desc: "Score prompts given by Open Assistant based on their accuracy and readability.",
id: "rank_assistant_replies",
category: TaskCategory.Evaluate,
pathname: "/evaluate/rank_assistant_replies",
help_link: "https://projects.laion.ai/Open-Assistant/docs/guides/prompting",
overview:
"Given the following Assistant replies, sort them from best to worst, best being first, worst being last.",
type: "rank_assistant_replies",
update_type: "message_ranking",
unchanged_title: "Order Unchanged",
unchanged_message: "You have not changed the order of the prompts. Are you sure you would like to continue?",
type: TaskType.rank_assistant_replies,
update_type: TaskUpdateType.MessageRanking,
},
{
label: "Rank Initial Prompts",
desc: "Score prompts given by Open Assistant based on their accuracy and readability.",
id: "rank_initial_prompts",
category: TaskCategory.Evaluate,
pathname: "/evaluate/rank_initial_prompts",
help_link: "https://projects.laion.ai/Open-Assistant/docs/guides/prompting",
overview: "Given the following initial prompts, sort them from best to worst, best being first, worst being last.",
type: "rank_initial_prompts",
update_type: "message_ranking",
unchanged_title: "Order Unchanged",
unchanged_message: "You have not changed the order of the prompts. Are you sure you would like to continue?",
type: TaskType.rank_initial_prompts,
update_type: TaskUpdateType.MessageRanking,
},
// label (full)
{
label: "Label Initial Prompt",
desc: "Provide labels for a prompt.",
id: "label_initial_prompt",
category: TaskCategory.Label,
pathname: "/label/label_initial_prompt",
help_link: "https://projects.laion.ai/Open-Assistant/docs/guides/prompting",
overview: "Provide labels for the following prompt",
type: "label_initial_prompt",
type: TaskType.label_initial_prompt,
mode: "full",
update_type: "text_labels",
update_type: TaskUpdateType.TextLabels,
},
{
label: "Label Prompter Reply",
desc: "Provide labels for a prompt.",
id: "label_prompter_reply",
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.",
type: "label_prompter_reply",
type: TaskType.label_prompter_reply,
mode: "full",
update_type: "text_labels",
update_type: TaskUpdateType.TextLabels,
},
{
label: "Label Assistant Reply",
desc: "Provide labels for a prompt.",
id: "label_assistant_reply",
category: TaskCategory.Label,
pathname: "/label/label_assistant_reply",
help_link: "https://projects.laion.ai/Open-Assistant/docs/tasks/label_assistant_reply",
overview: "Given the following discussion, provide labels for the final prompt.",
type: "label_assistant_reply",
type: TaskType.label_assistant_reply,
mode: "full",
update_type: "text_labels",
update_type: TaskUpdateType.TextLabels,
},
// label (simple)
{
label: "Classify Initial Prompt",
desc: "Provide labels for a prompt.",
id: "classify_initial_prompt",
category: TaskCategory.Label,
pathname: "/label/label_initial_prompt",
help_link: "https://projects.laion.ai/Open-Assistant/docs/guides/prompting",
overview: "Read the following prompt and then answer the question about it.",
type: "label_initial_prompt",
type: TaskType.label_initial_prompt,
mode: "simple",
update_type: "text_labels",
update_type: TaskUpdateType.TextLabels,
},
{
label: "Classify Prompter Reply",
desc: "Provide labels for a prompt.",
id: "classify_prompter_reply",
category: TaskCategory.Label,
pathname: "/label/label_prompter_reply",
help_link: "https://projects.laion.ai/Open-Assistant/docs/guides/prompting",
overview: "Read the following conversation and then answer the question about the last reply in the discussion.",
type: "label_prompter_reply",
type: TaskType.label_prompter_reply,
mode: "simple",
update_type: "text_labels",
update_type: TaskUpdateType.TextLabels,
},
{
label: "Classify Assistant Reply",
desc: "Provide labels for a prompt.",
id: "classify_assistant_reply",
category: TaskCategory.Label,
pathname: "/label/label_assistant_reply",
help_link: "https://projects.laion.ai/Open-Assistant/docs/guides/prompting",
overview: "Read the following conversation and then answer the question about the last reply in the discussion.",
type: "label_assistant_reply",
type: TaskType.label_assistant_reply,
mode: "simple",
update_type: "text_labels",
update_type: TaskUpdateType.TextLabels,
},
];
+1
View File
@@ -0,0 +1 @@
export const getTypeSafei18nKey = (key: string) => key as unknown as TemplateStringsArray;
+4 -3
View File
@@ -12,8 +12,9 @@ import useSWR from "swr";
const Dashboard = () => {
const {
t,
i18n: { language },
} = useTranslation();
} = 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
@@ -36,7 +37,7 @@ const Dashboard = () => {
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">
@@ -54,6 +55,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[];
+6 -7
View File
@@ -11,23 +11,22 @@ const Leaderboard = () => {
return (
<>
<Head>
<title>{`${t("leaderboard:leaderboard")} - ${t("common:title")}`}</title>
<title>{`${t("leaderboard")} - ${t("common:title")}`}</title>
<meta name="description" content="Leaderboard Rankings" charSet="UTF-8" />
</Head>
<Box display="flex" flexDirection="column">
<Heading fontSize="2xl" fontWeight="bold" pb="4">
{t("leaderboard:leaderboard")}
{t("leaderboard")}
</Heading>
<Card>
<CardBody>
<Tabs isFitted isLazy>
<TabList>
<Tab>{t("leaderboard:daily")}</Tab>
<Tab>{t("leaderboard:weekly")}</Tab>
<Tab>{t("leaderboard:monthly")}</Tab>
<Tab>{t("leaderboard:overall")}</Tab>
<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} />
+7 -3
View File
@@ -1,15 +1,19 @@
import "i18next";
import type common from "../public/locales/en/common.json";
import type index from "../public/locales/en/index.json";
import type leaderboard from "../public/locales/en/leaderboard.json";
import type common from "public/locales/en/common.json";
import type dashboard from "public/locales/en/dashboard.json";
import type index from "public/locales/en/index.json";
import type leaderboard from "public/locales/en/leaderboard.json";
import type tasks from "public/locales/en/tasks.json";
declare module "i18next" {
interface CustomTypeOptions {
resources: {
common: typeof common;
dashboard: typeof dashboard;
index: typeof index;
leaderboard: typeof leaderboard;
tasks: typeof tasks;
};
}
}