This commit is contained in:
poipiii
2022-12-27 16:42:01 +08:00
82 changed files with 1184 additions and 316 deletions
+7 -26
View File
@@ -1,33 +1,14 @@
import Link from "next/link";
import Image from "next/image";
function BackgroundIllustration(props) {
export function AuthLayout({ children }) {
return (
<svg viewBox="0 0 1090 1090" aria-hidden="true" fill="none" preserveAspectRatio="none" {...props}>
<circle cx={545} cy={545} r="544.5" />
<circle cx={545} cy={545} r="480.5" />
<circle cx={545} cy={545} r="416.5" />
<circle cx={545} cy={545} r="352.5" />
</svg>
);
}
export function AuthLayout({ title, subtitle, children }) {
return (
<main className="flex min-h-full overflow-hidden pt-16 sm:py-28">
<div className="mx-auto flex w-full max-w-2xl flex-col px-4 sm:px-6">
<Link href="/" aria-label="Home">
{/* logo */}
<main className="flex items-center justify-center min-h-full overflow-hidden pt-16 sm:py-28 subpixel-antialiased">
<div className="flex items-center w-full max-w-2xl flex-col px-4 sm:px-6">
<Link href="/" aria-label="Home" className="flex items-center text-3xl font-bold text-black">
<Image src="/images/logos/logo.svg" width="100" height="100" alt="Open Assistant Logo" /> Open Assistant
</Link>
<div className="relative mt-12 sm:mt-16">
<BackgroundIllustration
width="1090"
height="1090"
className="absolute -top-7 left-1/2 -z-10 h-[788px] -translate-x-1/2 stroke-gray-300/30 [mask-image:linear-gradient(to_bottom,white_20%,transparent_75%)] sm:-top-9 sm:h-auto"
/>
<h1 className="text-center text-2xl font-medium tracking-tight text-gray-900">{title}</h1>
{subtitle && <p className="mt-3 text-center text-lg text-gray-600">{subtitle}</p>}
</div>
<div className="-mx-4 mt-10 flex-auto bg-white py-10 px-4 shadow-2xl shadow-gray-900/10 sm:mx-0 sm:flex-none sm:rounded-2xl sm:p-24">
<div className="flex-auto items-center justify-center w-full py-10 px-4 sm:mx-0 sm:flex-none sm:rounded-2xl sm:p-20">
{children}
</div>
</div>
+96
View File
@@ -0,0 +1,96 @@
import React from "react";
import { signOut, useSession } from "next-auth/react";
import Image from "next/image";
import { Popover } from "@headlessui/react";
import { AnimatePresence, motion } from "framer-motion";
import { FaCog, FaSignOutAlt, FaGithub } from "react-icons/fa";
export function Avatar() {
const { data: session } = useSession();
if (!session) {
return <></>;
}
if (session && session.user) {
const email = session.user.email;
const accountOptions = [
{
name: "Account Settings",
href: "#",
desc: "Account Settings",
icon: FaCog,
//For future use
},
];
return (
<Popover className="relative">
{({ open }) => (
<>
<Popover.Button aria-label="Toggle Account Options" className="flex">
<div className="flex items-center gap-4 p-1 lg:pr-6 rounded-full bg-white border border-slate-300/70 hover:bg-gray-200/50 transition-colors duration-300">
<Image
src="/images/temp-avatars/av1.jpg"
alt="Profile Picture"
width="40"
height="40"
className="rounded-full"
></Image>
<p className="hidden lg:flex">{email}</p>
{/* Will be changed to username once it is implemented */}
</div>
</Popover.Button>
<AnimatePresence initial={false}>
{open && (
<>
<Popover.Panel
static
as={motion.div}
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
exit={{
opacity: 0,
y: -10,
transition: { duration: 0.2 },
}}
className="absolute right-0 mt-3 w-screen max-w-xs p-4 rounded-md bg-white border border-slate-300/70"
>
<div className="flex flex-col gap-1">
{accountOptions.map((item) => (
<a
key={item.name}
href={item.href}
aria-label={item.desc}
className="flex items-center rounded-md hover:bg-gray-200/50"
>
<div className="p-4">
<item.icon aria-hidden="true" />
</div>
<div>
<p>{item.name}</p>
</div>
</a>
))}
<a
className="flex items-center rounded-md hover:bg-gray-100 cursor-pointer"
onClick={() => signOut()}
>
<div className="p-4">
<FaSignOutAlt />
</div>
<div>
<p>Sign Out</p>
</div>
</a>
</div>
</Popover.Panel>
</>
)}
</AnimatePresence>
</>
)}
</Popover>
);
}
}
export default Avatar;
+2 -2
View File
@@ -12,7 +12,7 @@ export function CallToAction() {
<h2 className="text-3xl font-medium tracking-tight text-white sm:text-4xl">Join Us</h2>
<p className="mt-4 text-lg text-gray-300">
All open source projects begin with people like you. Open source is the belief that if we collaborate we can
together gift our knoweledge and technology to the world for the benefit of humanity. Are you in? Find us
together gift our knowledge and technology to the world for the benefit of humanity. Are you in? Find us
here:
</p>
<div className="mt-8 flex justify-center">
@@ -27,7 +27,7 @@ export function CallToAction() {
d="M524.531,69.836a1.5,1.5,0,0,0-.764-.7A485.065,485.065,0,0,0,404.081,32.03a1.816,1.816,0,0,0-1.923.91,337.461,337.461,0,0,0-14.9,30.6,447.848,447.848,0,0,0-134.426,0,309.541,309.541,0,0,0-15.135-30.6,1.89,1.89,0,0,0-1.924-.91A483.689,483.689,0,0,0,116.085,69.137a1.712,1.712,0,0,0-.788.676C39.068,183.651,18.186,294.69,28.43,404.354a2.016,2.016,0,0,0,.765,1.375A487.666,487.666,0,0,0,176.02,479.918a1.9,1.9,0,0,0,2.063-.676A348.2,348.2,0,0,0,208.12,430.4a1.86,1.86,0,0,0-1.019-2.588,321.173,321.173,0,0,1-45.868-21.853,1.885,1.885,0,0,1-.185-3.126c3.082-2.309,6.166-4.711,9.109-7.137a1.819,1.819,0,0,1,1.9-.256c96.229,43.917,200.41,43.917,295.5,0a1.812,1.812,0,0,1,1.924.233c2.944,2.426,6.027,4.851,9.132,7.16a1.884,1.884,0,0,1-.162,3.126,301.407,301.407,0,0,1-45.89,21.83,1.875,1.875,0,0,0-1,2.611,391.055,391.055,0,0,0,30.014,48.815,1.864,1.864,0,0,0,2.063.7A486.048,486.048,0,0,0,610.7,405.729a1.882,1.882,0,0,0,.765-1.352C623.729,277.594,590.933,167.465,524.531,69.836ZM222.491,337.58c-28.972,0-52.844-26.587-52.844-59.239S193.056,219.1,222.491,219.1c29.665,0,53.306,26.82,52.843,59.239C275.334,310.993,251.924,337.58,222.491,337.58Zm195.38,0c-28.971,0-52.843-26.587-52.843-59.239S388.437,219.1,417.871,219.1c29.667,0,53.307,26.82,52.844,59.239C470.715,310.993,447.538,337.58,417.871,337.58Z"
/>
</svg>
<span className="text-lg ml-3">DISCORD</span>
<span className="text-lg ml-3">Discord</span>
</button>
</a>
+1 -7
View File
@@ -12,13 +12,7 @@ export function Footer() {
<div>
<div className="flex items-center text-gray-900">
<Link href="/" aria-label="Home" className="flex items-center">
<Image
src="/images/logos/CHAT-THOUGHT-LOGO.svg"
className="mx-auto object-fill"
width="50"
height="50"
alt="logo"
/>
<Image src="/images/logos/logo.svg" className="mx-auto object-fill" width="50" height="50" alt="logo" />
</Link>
<div className="ml-4">
+15 -22
View File
@@ -4,7 +4,9 @@ import { AnimatePresence, motion } from "framer-motion";
import Image from "next/image";
import Link from "next/link";
import { signOut, useSession } from "next-auth/react";
import { FaUser, FaSignOutAlt } from "react-icons/fa";
import { Avatar } from "./Avatar";
import { Container } from "./Container";
import { NavLinks } from "./NavLinks";
@@ -40,15 +42,13 @@ function MobileNavLink({ children, ...props }) {
function AccountButton() {
const { data: session } = useSession();
if (session) {
return (
<Button variant="outline" onClick={() => signOut()}>
Log out
</Button>
);
return;
}
return (
<Link href="/auth/signin" aria-label="Home" className="flex items-center">
<Button variant="outline">Log in</Button>
<Link href="/auth/signup" aria-label="Home" className="flex items-center">
<Button variant="outline" leftIcon={<FaUser />}>
Log in
</Button>
</Link>
);
}
@@ -57,28 +57,22 @@ export function Header() {
return (
<header>
<nav>
<Container className="relative z-50 flex justify-between py-8">
<Container className="relative bg-white z-10 flex justify-between py-8">
<div className="relative z-10 flex items-center gap-16">
<Link href="/" aria-label="Home" className="flex items-center">
<Image
src="/images/logos/CHAT-THOUGHT-LOGO.svg"
className="mx-auto object-fill"
width="50"
height="50"
alt="logo"
/>
<Image src="/images/logos/logo.svg" className="mx-auto object-fill" width="50" height="50" alt="logo" />
<span className="text-2xl font-bold ml-3">Open Assistant</span>
</Link>
<div className="hidden lg:flex lg:gap-10">
<NavLinks />
</div>
</div>
<div className="flex items-center gap-6">
<div className="flex items-center gap-4">
<Popover className="lg:hidden">
{({ open }) => (
<>
<Popover.Button
className="relative z-10 -m-2 inline-flex items-center rounded-lg stroke-gray-900 p-2 hover:bg-gray-200/50 hover:stroke-gray-600 active:stroke-gray-900 [&:not(:focus-visible)]:focus:outline-none"
className="relative z-10 inline-flex items-center rounded-lg stroke-gray-900 p-2 hover:bg-gray-200/50 hover:stroke-gray-600 active:stroke-gray-900 [&:not(:focus-visible)]:focus:outline-none"
aria-label="Toggle site navigation"
>
{({ open }) => (open ? <ChevronUpIcon className="h-6 w-6" /> : <MenuIcon className="h-6 w-6" />)}
@@ -92,7 +86,7 @@ export function Header() {
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="fixed inset-0 z-0 bg-gray-300/60 backdrop-blur"
className="fixed inset-0 z-1 bg-gray-300/60 backdrop-blur"
/>
<Popover.Panel
static
@@ -104,15 +98,13 @@ export function Header() {
y: -32,
transition: { duration: 0.2 },
}}
className="absolute inset-x-0 top-0 z-0 origin-top rounded-b-2xl bg-gray-50 px-6 pb-6 pt-32 shadow-2xl shadow-gray-900/20"
className="absolute inset-x-0 top-0 z-0 origin-top rounded-b-2xl bg-white px-6 pb-6 pt-32 shadow-2xl shadow-gray-900/20"
>
<div className="space-y-4">
<MobileNavLink href="#join-us">Join Us</MobileNavLink>
<MobileNavLink href="#faqs">FAQs</MobileNavLink>
</div>
<div className="mt-8 flex flex-col gap-4">
<AccountButton />
</div>
<div className="mt-8 flex flex-col gap-4"></div>
</Popover.Panel>
</>
)}
@@ -121,6 +113,7 @@ export function Header() {
)}
</Popover>
<AccountButton />
<Avatar />
</div>
</Container>
</nav>
+1 -1
View File
@@ -71,7 +71,7 @@ export function Hero() {
<BackgroundIllustration className="absolute left-1/2 top-4 h-[1026px] w-[1026px] -translate-x-1/3 stroke-gray-300/70 [mask-image:linear-gradient(to_bottom,white_20%,transparent_75%)] sm:top-16 sm:-translate-x-1/2 lg:-top-16 lg:ml-12 xl:-top-14 xl:ml-0" />
<div className="-mx-4 h-[448px] px-9 [mask-image:linear-gradient(to_bottom,white_60%,transparent)] sm:mx-0 lg:absolute lg:-inset-x-10 lg:-top-10 lg:-bottom-20 lg:h-auto lg:px-0 lg:pt-10 xl:-bottom-32">
<Image
src="/images/logos/CHAT-THOUGHT-CONVO.svg"
src="/images/logos/logo.svg"
className="mx-auto mr-6 object-fill"
width="450"
height="450"
+45
View File
@@ -0,0 +1,45 @@
import { useSession } from "next-auth/react";
import { Footer } from "../components/Footer";
import { Header } from "../components/Header";
import Head from "next/head";
import Link from "next/link";
export default function Error() {
const { data: session } = useSession();
if (!session) {
return (
<>
<Head>
<title>Open Assistant</title>
<meta name="404" content="Sorry, this page doesn't exist." />
</Head>
<Header />
<main className="flex h-3/4 items-center justify-center overflow-hidden subpixel-antialiased text-xl">
{"Sorry, the page you're looking for does not exist."}
</main>
<Footer />
</>
);
}
return (
<>
<Head>
<title>Open Assistant</title>
<meta
name="description"
content="Conversational AI for everyone. An open source project to create a chat enabled GPT LLM run by LAION and contributors around the world."
/>
</Head>
<Header />
<main>
<h2>Open Chat Gpt</h2>
<p>You are logged in</p>
<Link href="/grading/grade-output">~Rate a prompt and output now~</Link>
</main>
<Footer />
</>
);
}
+24 -1
View File
@@ -1,12 +1,35 @@
import { ChakraProvider } from "@chakra-ui/react";
import { SessionProvider } from "next-auth/react";
import { Inter } from "@next/font/google";
import { extendTheme } from "@chakra-ui/react";
import "../styles/globals.css";
import "focus-visible";
const inter = Inter({
subsets: ["latin"],
variable: "--font-inter",
});
const theme = extendTheme({
styles: {
global: {
body: {
bg: "white",
},
main: {
fontFamily: "Inter",
},
header: {
fontFamily: "Inter",
},
},
},
});
function MyApp({ Component, pageProps: { session, ...pageProps } }) {
return (
<ChakraProvider>
<ChakraProvider theme={theme}>
<SessionProvider session={session}>
<Component {...pageProps} />
</SessionProvider>
+3 -1
View File
@@ -37,7 +37,9 @@ export const authOptions: AuthOptions = {
adapter: PrismaAdapter(prisma),
providers,
pages: {
signIn: "/auth/signin",
signIn: "/auth/signup",
verifyRequest: "/auth/verify",
// error: "/auth/error", -Will be used later
},
session: {
strategy: "jwt",
-62
View File
@@ -1,62 +0,0 @@
import { Button, Input } from "@chakra-ui/react";
import Head from "next/head";
import { FaDiscord, FaGithub, FaMagic } from "react-icons/fa";
import { getCsrfToken, getProviders, signIn } from "next-auth/react";
import { useRef } from "react";
import { AuthLayout } from "src/components/AuthLayout";
export default function Signin({ csrfToken, providers }) {
const { discord, email } = providers;
const emailEl = useRef(null);
const signinWithEmail = () => {
signIn(email.id, { callbackUrl: "/", email: emailEl.current.value });
};
return (
<>
<Head>
<title>Log in</title>
</Head>
<AuthLayout title="Log In" subtitle={<></>}>
<div className="space-y-6 w-100 flex flex-col justify-center items-center ">
{discord && (
<Button
leftIcon={<FaDiscord />}
colorScheme="blue"
size="lg"
w="36"
onClick={() => signIn(discord.id, { callbackUrl: "/" })}
>
Discord
</Button>
)}
<Button w="36" leftIcon={<FaGithub />} colorScheme="blue" size="lg">
Github
</Button>
{email && (
<div>
<Input variant="outline" placeholder="Email Address" ref={emailEl} />
<Button w="36" leftIcon={<FaMagic />} colorScheme="blue" size="lg" onClick={signinWithEmail}>
Email
</Button>
</div>
)}
</div>
</AuthLayout>
</>
);
}
export async function getServerSideProps(context) {
const csrfToken = await getCsrfToken();
const providers = await getProviders();
return {
props: {
csrfToken,
providers,
},
};
}
+103
View File
@@ -0,0 +1,103 @@
import { Button, Input, Stack } from "@chakra-ui/react";
import Head from "next/head";
import { FaDiscord, FaEnvelope, FaGithub } from "react-icons/fa";
import { getCsrfToken, getProviders, signIn } from "next-auth/react";
import { useRef } from "react";
import Link from "next/link";
import { AuthLayout } from "src/components/AuthLayout";
export default function Signin({ csrfToken, providers }) {
const { discord, email, github } = providers;
const emailEl = useRef(null);
const signinWithEmail = () => {
signIn(email.id, { callbackUrl: "/", email: emailEl.current.value });
};
return (
<>
<Head>
<title>Sign Up - Open Assistant</title>
<meta name="Sign Up" content="Sign up to access Open Assistant" />
</Head>
<AuthLayout>
<Stack spacing="2">
{email && (
<Stack>
<Input variant="outline" size="lg" placeholder="Email Address" ref={emailEl} />
<Button
size={"lg"}
leftIcon={<FaEnvelope />}
colorScheme="gray"
onClick={signinWithEmail}
// isDisabled="false"
>
Continue with Email
</Button>
</Stack>
)}
{discord && (
<Button
bg="#5865F2"
_hover={{ bg: "#4A57E3" }}
_active={{
bg: "#454FBF",
}}
size="lg"
leftIcon={<FaDiscord />}
color="white"
onClick={() => signIn(discord, { callbackUrl: "/" })}
// isDisabled="false"
>
Continue with Discord
</Button>
)}
{github && (
<Button
bg="#333333"
_hover={{ bg: "#181818" }}
_active={{
bg: "#101010",
}}
size={"lg"}
leftIcon={<FaGithub />}
colorScheme="blue"
// isDisabled="false"
>
Continue with Github
</Button>
)}
</Stack>
<div className="pt-10 text-center">
By signing up you agree to our <br></br>
<Link href="#" aria-label="Terms of Service" className="hover:underline underline-offset-4">
<b>Terms of Service</b>
</Link>{" "}
and{" "}
<Link href="#" aria-label="Terms of Use" className="hover:underline underline-offset-4">
<b>Privacy Policy</b>
</Link>
.
</div>
<hr className="mt-14 mb-4 h-px bg-gray-200 border-0" />
<div className="text-center">
Already have an account?{" "}
<Link href="#" aria-label="Log In" className="hover:underline underline-offset-4">
<b>Log In</b>
</Link>
</div>
</AuthLayout>
</>
);
}
export async function getServerSideProps(context) {
const csrfToken = await getCsrfToken();
const providers = await getProviders();
return {
props: {
csrfToken,
providers,
},
};
}
+38
View File
@@ -0,0 +1,38 @@
import Head from "next/head";
import { getCsrfToken, getProviders, signIn } from "next-auth/react";
import Link from "next/link";
import { AuthLayout } from "src/components/AuthLayout";
export default function Verify() {
return (
<>
<Head>
<title>Sign Up - Open Assistant</title>
<meta name="Sign Up" content="Sign up to access Open Assistant" />
</Head>
<AuthLayout>
<h1 className="text-lg">A sign-in link has been sent to your email address.</h1>
<hr className="mt-14 mb-4 h-px bg-gray-200 border-0" />
<Link
href="#"
aria-label="Log In"
className="flex justify-center font-medium text-black hover:underline underline-offset-4"
>
Already have an account? Log In
</Link>
</AuthLayout>
</>
);
}
export async function getServerSideProps(context) {
const csrfToken = await getCsrfToken();
const providers = await getProviders();
return {
props: {
csrfToken,
providers,
},
};
}
+9 -8
View File
@@ -2,6 +2,7 @@ import { useSession } from "next-auth/react";
import Head from "next/head";
import Link from "next/link";
import { Button, Input, Stack } from "@chakra-ui/react";
import { CallToAction } from "../components/CallToAction";
import { Faq } from "../components/Faq";
@@ -25,7 +26,7 @@ export default function Home() {
/>
</Head>
<Header />
<main>
<main className="z-0">
<Hero />
<CallToAction />
@@ -45,13 +46,13 @@ export default function Home() {
/>
</Head>
<Header />
<main>
<h2>Open Chat Gpt</h2>
<p>You are logged in</p>
<Link href="/grading/grade-output">~Rate a prompt and output now~</Link>
<Link href="/leaderboard/score-leaderboard">~view the score leaderboard~</Link>
<main className="h-3/4 z-0 bg-white flex flex-col items-center justify-center gap-2">
<Button size="lg" colorScheme="blue" className="drop-shadow">
<Link href="/grading/grade-output">Rate a prompt and output now</Link>
</Button>
<Button size="lg" colorScheme="blue" className="drop-shadow">
<Link href="/summarize/story">Summarize a story</Link>
</Button>
</main>
<Footer />
</>
+118
View File
@@ -0,0 +1,118 @@
// TODO(#65): Unify and simplify the task paths
import { Textarea } from "@chakra-ui/react";
import { useRef, useState } from "react";
import useSWRMutation from "swr/mutation";
import useSWRImmutable from "swr/immutable";
import fetcher from "src/lib/fetcher";
import poster from "src/lib/poster";
const SummarizeStory = () => {
// Use an array of tasks that record the sequence of steps until a task is
// deemed complete.
const [tasks, setTasks] = useState([]);
const inputRef = useRef<HTMLTextAreaElement>(null);
// Fetch the very fist task. We can ignore everything except isLoading
// because the onSuccess handler will update `tasks` when ready.
const { isLoading } = useSWRImmutable("/api/new_task/summarize_story", fetcher, {
onSuccess: (data) => {
console.log(data);
setTasks([data]);
},
});
// Every time we submit an answer to the latest task, let the backend handle
// all the interactions then add the resulting task to the queue. This ends
// when we hit the done task.
const { trigger, isMutating } = useSWRMutation("/api/update_task", poster, {
onSuccess: async (data) => {
const newTask = await data.json();
// This is the more efficient way to update a react state array.
setTasks((oldTasks) => [...oldTasks, newTask]);
},
});
// Trigger a mutation that updates the current task. We should probably
// signal somewhere that this interaction is being processed.
const submitResponse = (task: { id: string }) => {
const text = inputRef.current.value.trim();
trigger({
id: task.id,
content: {
update_type: "text_reply_to_post",
text,
},
});
};
/**
* TODO: Make this a nicer loading screen.
*/
if (tasks.length == 0) {
return <div className=" p-6 h-full mx-auto bg-slate-100 text-gray-800">Loading...</div>;
}
return (
<div className=" p-6 h-full mx-auto bg-slate-100 text-gray-800">
{/* Instrunction and Output panels */}
<section className="mb-8 lt-lg:mb-12 ">
<div className="grid lg:gap-x-12 lg:grid-cols-2">
{/* Instruction panel */}
<div className="rounded-lg shadow-lg h-full block bg-white">
<div className="p-6">
<h5 className="text-lg font-semibold">Instruction</h5>
<p className="text-lg py-1">Summarize the following story</p>
<div className="bg-slate-800 p-6 rounded-xl text-white whitespace-pre-wrap">{tasks[0].task.story}</div>
</div>
</div>
{/* Output panel */}
<div className="mt-6 lg:mt-0 rounded-lg shadow-lg h-full block bg-white">
<div className="flex justify-center p-6">
<Textarea name="summary" placeholder="Summary" ref={inputRef} />
</div>
</div>
</div>
</section>
{/* Info & controls */}
<section className="mb-8 p-4 rounded-lg shadow-lg bg-white flex flex-row justify-items-stretch ">
<div className="flex flex-col justify-self-start text-gray-700">
<div>
<span>
<b>Prompt</b>
</span>
<span className="ml-2">{tasks[0].id}</span>
</div>
<div>
<span>
<b>Output</b>
</span>
<span className="ml-2">Submit your answer</span>
</div>
</div>
{/* Skip / Submit controls */}
<div className="flex justify-center ml-auto">
<button
type="button"
className="mr-2 inline-flex items-center rounded-md border border-transparent bg-indigo-100 px-4 py-2 text-sm font-medium text-indigo-700 hover:bg-indigo-200 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
>
Skip
</button>
<button
type="button"
onClick={() => submitResponse(tasks[0])}
className="inline-flex items-center rounded-md border border-transparent bg-indigo-600 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
>
Submit
</button>
</div>
</section>
</div>
);
};
export default SummarizeStory;