Skip to content

Commit

Permalink
feat: replace form with react-hook-form and persist
Browse files Browse the repository at this point in the history
  • Loading branch information
JimmyLv committed Mar 13, 2023
1 parent 2db0ef9 commit a71638f
Show file tree
Hide file tree
Showing 6 changed files with 210 additions and 65 deletions.
142 changes: 98 additions & 44 deletions components/PromptOptions.tsx
Original file line number Diff line number Diff line change
@@ -1,59 +1,113 @@
import React from "react";
import { SwitchTimestamp } from "~/components/SwitchTimestamp";
import { Label } from "~/components/ui/label";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "~/components/ui/select";
import { Switch } from "~/components/ui/switch";
import { UseFormReturn } from "react-hook-form/dist/types/form";
import { PROMPT_LANGUAGE_MAP } from "~/utils/constants/language";
import { Slider } from "./ui/slider";

export function PromptOptions(props: {
checked: boolean;
onCheckedChange: (checked: boolean) => void;
export function PromptOptions({
register,
getValues,
}: {
// TODO: add types
getValues: UseFormReturn["getValues"];
register: any;
}) {
return (
<div className="mt-6 grid grid-cols-4 items-center gap-4 ">
<SwitchTimestamp
checked={props.checked}
onCheckedChange={props.onCheckedChange}
/>
<div className="mt-10 grid grid-cols-3 items-center gap-x-10 gap-y-6">
<label className="relative inline-flex cursor-pointer items-center">
<input
type="checkbox"
value=""
className="peer sr-only"
{...register("showTimestamp")}
/>
<div className="peer h-6 w-11 rounded-full bg-gray-200 after:absolute after:top-[2px] after:left-[2px] after:h-5 after:w-5 after:rounded-full after:border after:border-gray-300 after:bg-white after:transition-all after:content-[''] peer-checked:bg-sky-400 peer-checked:after:translate-x-full peer-checked:after:border-white peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-sky-300 dark:border-gray-600 dark:bg-gray-700 dark:peer-focus:ring-sky-800"></div>
<span className="ml-3 text-sm font-medium text-gray-900 dark:text-gray-300">
是否显示时间戳
</span>
</label>
<label className="relative inline-flex cursor-pointer items-center">
<input
type="checkbox"
value=""
className="peer sr-only"
{...register("showEmoji")}
/>
<div className="peer h-6 w-11 rounded-full bg-gray-200 after:absolute after:top-[2px] after:left-[2px] after:h-5 after:w-5 after:rounded-full after:border after:border-gray-300 after:bg-white after:transition-all after:content-[''] peer-checked:bg-sky-400 peer-checked:after:translate-x-full peer-checked:after:border-white peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-sky-300 dark:border-gray-600 dark:bg-gray-700 dark:peer-focus:ring-sky-800"></div>
<span className="ml-3 text-sm font-medium text-gray-900 dark:text-gray-300">
是否显示Emoji
</span>
</label>
<div>
<Switch
id="emoji-mode"
checked={true}
// onCheckedChange={props.onCheckedChange}
<label
htmlFor="outputLanguage"
className="mb-2 block text-sm font-medium text-gray-900 dark:text-white"
>
输出语言
</label>
<select
id="outputLanguage"
className="block w-full rounded-md border border-gray-300 bg-gray-50 text-sm text-gray-900 focus:border-sky-500 focus:ring-sky-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder-gray-400 dark:focus:border-sky-500 dark:focus:ring-sky-500"
{...register("outputLanguage")}
>
{Object.keys(PROMPT_LANGUAGE_MAP).map((k: string) => (
<option value={PROMPT_LANGUAGE_MAP[k]}>{k}</option>
))}
</select>
</div>

<div>
<label
htmlFor="sentenceNumber"
className="mb-2 block text-sm font-medium text-gray-900 dark:text-white"
>
要点个数
<span className="text-gray-500">({getValues("sentenceNumber")})</span>
</label>
<input
id="sentenceNumber"
type="range"
min={3}
max={10}
step={1}
className="h-2 w-full cursor-pointer accent-black rounded-lg bg-gray-200 dark:bg-gray-700"
{...register("sentenceNumber")}
/>
<Label htmlFor="emoji-mode">
是否显示Emoji <span className="text-gray-500">(beta)</span>
</Label>
</div>
<div>
<Slider id="detail-slider" defaultValue={[400]} max={1000} step={10} />
<Label htmlFor="detail-slider">
详细程度 <span className="text-gray-500">(beta)</span>
</Label>
<label
htmlFor="outlineLevel"
className="mb-2 block text-sm font-medium text-gray-900 dark:text-white"
>
大纲层级
<span className="text-gray-500">({getValues("outlineLevel")})</span>
</label>
<input
id="outlineLevel"
type="range"
min={1}
max={5}
step={1}
className="h-2 w-full cursor-pointer accent-black rounded-lg bg-gray-200 dark:bg-gray-700"
{...register("outlineLevel")}
/>
</div>
<div>
<Slider id="sentence-slider" defaultValue={[5]} max={10} step={1} />
<Label htmlFor="sentence-slider">
要点个数 <span className="text-gray-500">(beta)</span>
</Label>
<label
htmlFor="detailLevel"
className="mb-2 block text-sm font-medium text-gray-900 dark:text-white"
>
详细程度
<span className="text-gray-500">({getValues("detailLevel")})</span>
</label>
<input
id="detailLevel"
type="range"
min={300}
max={1000}
step={10}
className="h-2 w-full accent-black cursor-pointer rounded-lg bg-gray-200 dark:bg-gray-700"
{...register("detailLevel")}
/>
</div>
<Select>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="总结语言" />
</SelectTrigger>
<SelectContent>
{Object.keys(PROMPT_LANGUAGE_MAP).map((k: string) => (
<SelectItem value={PROMPT_LANGUAGE_MAP[k]}>{k}</SelectItem>
))}
</SelectContent>
</Select>
</div>
);
}
53 changes: 53 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
},
"repository": "https://github.com/JimmyLv/BibiGPT.git",
"dependencies": {
"@hookform/resolvers": "^2.9.11",
"@next/font": "^13.1.5",
"@radix-ui/react-dialog": "^1.0.2",
"@radix-ui/react-label": "^2.0.0",
Expand Down Expand Up @@ -46,6 +47,8 @@
"react": "18.2.0",
"react-bilibili-embed-renderer": "^1.2.1",
"react-dom": "18.2.0",
"react-hook-form": "^7.43.5",
"react-hook-form-persist": "^3.0.0",
"react-hot-toast": "^2.4.0",
"react-type-animation": "^2.1.2",
"react-use": "^17.4.0",
Expand Down
59 changes: 38 additions & 21 deletions pages/[...slug].tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { zodResolver } from "@hookform/resolvers/zod";
import getVideoId from "get-video-id";
import type { NextPage } from "next";
import { useSearchParams } from "next/navigation";
import { useRouter } from "next/router";
import React, { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import useFormPersist from "react-hook-form-persist";
import { useAnalytics } from "~/components/context/analytics";
import { PromptOptions } from "~/components/PromptOptions";
import { SubmitButton } from "~/components/SubmitButton";
Expand All @@ -17,6 +20,7 @@ import { useSummarize } from "~/hooks/useSummarize";
import { VideoService } from "~/lib/types";
import { extractPage, extractUrl } from "~/utils/extractUrl";
import { getVideoIdFromUrl } from "~/utils/getVideoIdFromUrl";
import { VideoConfigSchema, videoConfigSchema } from "~/utils/schemas/video";

export const Home: NextPage<{
showSingIn: (show: boolean) => void;
Expand All @@ -29,13 +33,40 @@ export const Home: NextPage<{
// TODO: add mobx or state manager
const [currentVideoId, setCurrentVideoId] = useState<string>("");
const [currentVideoUrl, setCurrentVideoUrl] = useState<string>("");
const [shouldShowTimestamp, setShouldShowTimestamp] =
useLocalStorage<boolean>("should-show-timestamp");
const [userKey, setUserKey] = useLocalStorage<string>("user-openai-apikey");
const { loading, summary, resetSummary, summarize } =
useSummarize(showSingIn);
const { toast } = useToast();
const { analytics } = useAnalytics();
const {
register,
handleSubmit,
control,
trigger,
getValues,
watch,
setValue,
formState: { errors },
} = useForm<VideoConfigSchema>({
defaultValues: {
showTimestamp: false,
showEmoji: true,
detailLevel: 600,
sentenceNumber: 5,
outlineLevel: 1,
outputLanguage: "Simplified Chinese",
},
resolver: zodResolver(videoConfigSchema),
});
useFormPersist("video-config-storage", {
watch,
setValue,
storage: typeof window !== "undefined" ? window.localStorage : undefined, // default window.sessionStorage
// exclude: ['baz']
});
// const formValues = getValues();
const shouldShowTimestamp = getValues("showTimestamp");
console.log("========formValues========", shouldShowTimestamp);

useEffect(() => {
licenseKey && setUserKey(licenseKey);
Expand Down Expand Up @@ -87,6 +118,9 @@ export const Home: NextPage<{
}
};
const generateSummary = async (url?: string) => {
const formValues = getValues();
console.log("=======formValues=========", formValues);

resetSummary();
validateUrlFromAddressBar(url);

Expand All @@ -96,7 +130,7 @@ export const Home: NextPage<{
setCurrentVideoId(id);
await summarize(
{ videoId: id, service: VideoService.Youtube },
{ userKey, shouldShowTimestamp }
{ userKey, shouldShowTimestamp: shouldShowTimestamp }
);
return;
}
Expand Down Expand Up @@ -125,20 +159,6 @@ export const Home: NextPage<{
setUserKey(e.target.value);
};

function handleShowTimestamp(checked: boolean) {
resetSummary();
setShouldShowTimestamp(checked);
analytics
.track(`ShowTimestamp Clicked`, {
videoId: currentVideoId,
// todo: add video service
shouldShowTimestamp: checked,
})
.then((res) => console.log("tracked!", res))
.catch(console.error);
// throw new Error("Sentry Frontend Error");
}

const handleInputChange = async (e: any) => {
const value = e.target.value;
// todo: 兼容?query参数
Expand Down Expand Up @@ -169,10 +189,7 @@ export const Home: NextPage<{
placeholder={"输入 bilibili.com 视频链接,按下「回车」"}
/>
<SubmitButton loading={loading} />
<PromptOptions
checked={shouldShowTimestamp}
onCheckedChange={handleShowTimestamp}
/>
<PromptOptions getValues={getValues} register={register} />
</form>
{summary && (
<SummaryResult
Expand Down
Loading

1 comment on commit a71638f

@vercel
Copy link

@vercel vercel bot commented on a71638f Mar 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.