From e475ba38eac6bb2743749a8440bfac892fcd8f82 Mon Sep 17 00:00:00 2001 From: Arjun Komath Date: Sat, 2 Mar 2024 23:06:07 +1100 Subject: [PATCH 1/3] Add AI proof read --- .../ai-prood-read-dialog.component.tsx | 153 ++++++++++++++++++ .../components/forms/post-form.component.tsx | 32 +++- 2 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 apps/web/components/dialogs/ai-prood-read-dialog.component.tsx diff --git a/apps/web/components/dialogs/ai-prood-read-dialog.component.tsx b/apps/web/components/dialogs/ai-prood-read-dialog.component.tsx new file mode 100644 index 0000000..045f1d6 --- /dev/null +++ b/apps/web/components/dialogs/ai-prood-read-dialog.component.tsx @@ -0,0 +1,153 @@ +import { SpinnerWithSpacing } from "@changes-page/ui"; +import { convertMarkdownToPlainText } from "@changes-page/utils"; +import { Dialog, Transition } from "@headlessui/react"; +import { LightningBoltIcon } from "@heroicons/react/solid"; +import { Fragment, useCallback, useEffect, useRef, useState } from "react"; +import { getStreamingUrl } from "../../utils/useAiAssistant"; +import { notifyError } from "../core/toast.component"; + +export default function AiProofReadDialog({ open, setOpen, content }) { + const [loading, setLoading] = useState(false); + const [result, setResult] = useState(null); + const cancelButtonRef = useRef(null); + + const proofRead = useCallback(async (text) => { + setLoading(true); + + const { url } = await getStreamingUrl( + "wf_5a7eaceda859ee21c07771aaaecc9826" + ); + + const response = await fetch(url, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + content: text, + }), + }); + + if (!response.ok) { + notifyError("Too many requests"); + } + + const data = response.body; + if (!data) { + return; + } + + const reader = data.getReader(); + const decoder = new TextDecoder(); + let done = false; + + setLoading(false); + + while (!done) { + const { value, done: doneReading } = await reader.read(); + done = doneReading; + const chunkValue = decoder.decode(value); + setResult((prev) => (prev ?? "") + chunkValue); + } + }, []); + + useEffect(() => { + if (open && content) { + setLoading(true); + setResult(null); + + proofRead(convertMarkdownToPlainText(content)).catch(() => { + setLoading(false); + setOpen(false); + notifyError("Failed to process request, please contact support."); + }); + } + }, [open, content]); + + return ( + + +
+ + + + + {/* This element is to trick the browser into centering the modal contents. */} + + +
+
+
+
+ + + +
+
+
+
+ {loading && } + +

+ {result} +

+
+
+
+
+
+
+
+ +
+ +
+
+
+
+
+
+ ); +} diff --git a/apps/web/components/forms/post-form.component.tsx b/apps/web/components/forms/post-form.component.tsx index e90990a..faf695f 100644 --- a/apps/web/components/forms/post-form.component.tsx +++ b/apps/web/components/forms/post-form.component.tsx @@ -26,6 +26,7 @@ import { PrimaryButton } from "../core/buttons.component"; import MarkdownEditor from "../core/editor.component"; import { notifyError, notifySuccess } from "../core/toast.component"; import AiExpandConceptPromptDialogComponent from "../dialogs/ai-expand-concept-prompt-dialog.component"; +import AiProofReadDialog from "../dialogs/ai-prood-read-dialog.component"; import AiSuggestTitlePromptDialogComponent from "../dialogs/ai-suggest-title-prompt-dialog.component"; import DateTimePromptDialog from "../dialogs/date-time-prompt-dialog.component"; import SwitchComponent from "./switch.component"; @@ -75,6 +76,7 @@ export default function PostFormComponent({ const [promptSchedule, setPromptSchedule] = useState(false); const [promptTitleSuggestions, setPromptTitleSuggestions] = useState(false); const [promptExpandConcept, setPromptExpandConcept] = useState(false); + const [promptProofRead, setPromptProofRead] = useState(false); // // For email notifications const [emailNotified, setEmailNotified] = useState(false); @@ -181,6 +183,14 @@ export default function PostFormComponent({ } }, [formik.values.content]); + const proofRead = useCallback(() => { + if (formik.values.content) { + setPromptProofRead(true); + } else { + notifyError("Content cannot be empty"); + } + }, [formik.values.content]); + if (loading) { return ; } @@ -327,7 +337,7 @@ export default function PostFormComponent({ > @@ -353,6 +363,17 @@ export default function PostFormComponent({ Expand concept + + + @@ -625,6 +646,15 @@ export default function PostFormComponent({ ); }} /> + + { + setPromptProofRead(open); + track("AiProofRead"); + }} + /> ); } From e54db48933431e8a6382c14f313f8877c35a6e6a Mon Sep 17 00:00:00 2001 From: Arjun Komath Date: Mon, 4 Mar 2024 21:06:09 +1100 Subject: [PATCH 2/3] Consistent name --- .../web/components/dialogs/ai-prood-read-dialog.component.tsx | 2 +- apps/web/components/forms/post-form.component.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/web/components/dialogs/ai-prood-read-dialog.component.tsx b/apps/web/components/dialogs/ai-prood-read-dialog.component.tsx index 045f1d6..cd70f2d 100644 --- a/apps/web/components/dialogs/ai-prood-read-dialog.component.tsx +++ b/apps/web/components/dialogs/ai-prood-read-dialog.component.tsx @@ -6,7 +6,7 @@ import { Fragment, useCallback, useEffect, useRef, useState } from "react"; import { getStreamingUrl } from "../../utils/useAiAssistant"; import { notifyError } from "../core/toast.component"; -export default function AiProofReadDialog({ open, setOpen, content }) { +export default function AiProofReadDialogComponent({ open, setOpen, content }) { const [loading, setLoading] = useState(false); const [result, setResult] = useState(null); const cancelButtonRef = useRef(null); diff --git a/apps/web/components/forms/post-form.component.tsx b/apps/web/components/forms/post-form.component.tsx index faf695f..d2623bc 100644 --- a/apps/web/components/forms/post-form.component.tsx +++ b/apps/web/components/forms/post-form.component.tsx @@ -26,7 +26,7 @@ import { PrimaryButton } from "../core/buttons.component"; import MarkdownEditor from "../core/editor.component"; import { notifyError, notifySuccess } from "../core/toast.component"; import AiExpandConceptPromptDialogComponent from "../dialogs/ai-expand-concept-prompt-dialog.component"; -import AiProofReadDialog from "../dialogs/ai-prood-read-dialog.component"; +import AiProofReadDialogComponent from "../dialogs/ai-prood-read-dialog.component"; import AiSuggestTitlePromptDialogComponent from "../dialogs/ai-suggest-title-prompt-dialog.component"; import DateTimePromptDialog from "../dialogs/date-time-prompt-dialog.component"; import SwitchComponent from "./switch.component"; @@ -647,7 +647,7 @@ export default function PostFormComponent({ }} /> - { From bb01de86e919d480af11756bb609d190ba7d3267 Mon Sep 17 00:00:00 2001 From: Arjun Komath Date: Mon, 4 Mar 2024 21:06:14 +1100 Subject: [PATCH 3/3] 1.1.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 27ce5f1..e62e48b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "changes-page", - "version": "1.0.0", + "version": "1.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "changes-page", - "version": "1.0.0", + "version": "1.1.0", "license": "MIT" } } diff --git a/package.json b/package.json index edf7127..579a90b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "changes-page", - "version": "1.0.0", + "version": "1.1.0", "scripts": { "build": "pnpm --filter './packages/*' -r build", "dev:page": "pnpm --filter './apps/page' -r dev",