aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDhravya Shah <[email protected]>2024-08-02 14:24:44 -0700
committerGitHub <[email protected]>2024-08-02 14:24:44 -0700
commit40055ace3f96c3e036d4a4ca68060cb30132def8 (patch)
treea2fd7064730adae69c5cf70faedc766d624ea5bf
parentMerge branch 'main' of github.com:supermemoryai/supermemory (diff)
parentfix: wrong icon for speaker-x (diff)
downloadsupermemory-40055ace3f96c3e036d4a4ca68060cb30132def8.tar.xz
supermemory-40055ace3f96c3e036d4a4ca68060cb30132def8.zip
Merge pull request #204 from krakenftw/textospeech
Textospeech
-rw-r--r--apps/web/app/(dash)/chat/chatWindow.tsx71
-rw-r--r--apps/web/wrangler.toml22
2 files changed, 60 insertions, 33 deletions
diff --git a/apps/web/app/(dash)/chat/chatWindow.tsx b/apps/web/app/(dash)/chat/chatWindow.tsx
index 662c7217..a691c0ce 100644
--- a/apps/web/app/(dash)/chat/chatWindow.tsx
+++ b/apps/web/app/(dash)/chat/chatWindow.tsx
@@ -6,7 +6,7 @@ import QueryInput from "./chatQueryInput";
import { cn } from "@repo/ui/lib/utils";
import { motion } from "framer-motion";
import { useRouter } from "next/navigation";
-import { ChatHistory, sourcesZod } from "@repo/shared-types";
+import { type ChatHistory, sourcesZod } from "@repo/shared-types";
import {
Accordion,
AccordionContent,
@@ -23,7 +23,11 @@ import { codeLanguageSubset } from "@/lib/constants";
import { toast } from "sonner";
import Link from "next/link";
import { createChatObject } from "@/app/actions/doers";
-import { ClipboardIcon, SpeakerWaveIcon } from "@heroicons/react/24/outline";
+import {
+ ClipboardIcon,
+ SpeakerWaveIcon,
+ SpeakerXMarkIcon,
+} from "@heroicons/react/24/outline";
function ChatWindow({
q,
@@ -51,6 +55,8 @@ function ChatWindow({
}) {
const [layout, setLayout] = useState<"chat" | "initial">("chat");
const [chatHistory, setChatHistory] = useState<ChatHistory[]>(initialChat);
+ const [speakingIdx, setSpeakingIdx] = useState<number | null>(null);
+ const speechSynth: SpeechSynthesis = window.speechSynthesis;
const removeJustificationFromText = (text: string) => {
// remove everything after the first "<justification>" word
@@ -66,12 +72,31 @@ function ChatWindow({
return text;
};
+ const handleTTS = (text: string, idx: number) => {
+ if (speakingIdx != null) return stopTTS();
+ if (!text) return;
+ const utterThis: SpeechSynthesisUtterance = new SpeechSynthesisUtterance(
+ text,
+ );
+ utterThis.lang = "en-US";
+ speechSynth.speak(utterThis);
+ setSpeakingIdx(idx);
+ utterThis.onend = () => {
+ setSpeakingIdx(null);
+ };
+ };
+
+ const stopTTS = () => {
+ speechSynth.cancel();
+ setSpeakingIdx(null);
+ };
+
const router = useRouter();
const getAnswer = async (
query: string,
spaces: string[],
- proMode: boolean = false,
+ proMode = false,
) => {
if (query.trim() === "from_loading" || query.trim().length === 0) {
return;
@@ -305,25 +330,6 @@ function ChatWindow({
</Markdown>
<div className="mt-3 relative -left-2 flex items-center gap-1">
- {/* speak response */}
- <button
- onClick={() => {
- const utterThis: SpeechSynthesisUtterance =
- new SpeechSynthesisUtterance(
- chat.answer.parts
- .map((part) => part.text)
- .join(""),
- );
- const speechSynth: SpeechSynthesis =
- window.speechSynthesis;
- utterThis.lang = "en-US";
- utterThis.rate = 1;
- speechSynth.speak(utterThis);
- }}
- className="group h-8 w-8 flex justify-center items-center active:scale-75 duration-200"
- >
- <SpeakerWaveIcon className="size-[18px] group-hover:text-primary" />
- </button>
{/* copy response */}
<button
onClick={() =>
@@ -337,6 +343,27 @@ function ChatWindow({
>
<ClipboardIcon className="size-[18px] group-hover:text-primary" />
</button>
+ {/* speak response */}
+ <button
+ disabled={
+ speakingIdx !== null && speakingIdx !== idx
+ }
+ onClick={() => {
+ handleTTS(
+ chat.answer.parts
+ .map((part) => part.text)
+ .join(""),
+ idx,
+ );
+ }}
+ className="group h-8 w-8 flex justify-center items-center active:scale-75 duration-200"
+ >
+ {speakingIdx === idx ? (
+ <SpeakerXMarkIcon className="size-[18px] group-hover:text-primary" />
+ ) : (
+ <SpeakerWaveIcon className="size-[18px] group-hover:text-primary group-disabled:text-gray-600" />
+ )}
+ </button>
</div>
</div>
</div>
diff --git a/apps/web/wrangler.toml b/apps/web/wrangler.toml
index 7f3fa047..675038c6 100644
--- a/apps/web/wrangler.toml
+++ b/apps/web/wrangler.toml
@@ -5,13 +5,13 @@ pages_build_output_dir = ".vercel/output/static"
kv_namespaces = [
- { binding = "CANVAS_SNAPS", id = "6df98c892b3744ccb0c631d9f60d6697" },
- { binding = "RECOMMENDATIONS", id = "83bc7055226c4657948141c2ff9a5425" }
+ { binding = "CANVAS_SNAPS", id = "24c7048fa9064e7787dd58760b21dc8d" },
+ { binding = "RECOMMENDATIONS", id = "abfd16f09b0b4300908115a5a177429e" }
]
env.production.kv_namespaces = [
- { binding = "CANVAS_SNAPS", id = "6df98c892b3744ccb0c631d9f60d6697" },
- { binding = "RECOMMENDATIONS", id = "83bc7055226c4657948141c2ff9a5425" }
+ { binding = "CANVAS_SNAPS", id = "24c7048fa9064e7787dd58760b21dc8d" },
+ { binding = "RECOMMENDATIONS", id = "abfd16f09b0b4300908115a5a177429e" }
]
[ai]
@@ -22,26 +22,26 @@ mode = "smart"
[[r2_buckets]]
binding = "STORAGE"
-bucket_name = "dev-r2-anycontext"
+bucket_name = "supermemory-r2"
[[d1_databases]]
binding = "DATABASE"
-database_name = "dev-d1-anycontext"
-database_id = "fc562605-157a-4f60-b439-2a24ffed5b4c"
+database_name = "supermemory-db-preview"
+database_id = "b09e126c-8179-4927-876a-6a03ee94334b"
[[env.production.d1_databases]]
binding = "DATABASE"
-database_name = "prod-d1-supermemory"
-database_id = "f527a727-c472-41d4-8eaf-3d7ba0f2f395"
+database_name = "supermemory-db-prod"
+database_id = "0dea4084-3629-4aea-938c-da478a32f5cd"
[env.preview.ai]
binding = "AI"
[[env.preview.d1_databases]]
binding = "DATABASE"
-database_name = "dev-d1-anycontext"
-database_id = "fc562605-157a-4f60-b439-2a24ffed5b4c"
+database_name = "supermemory-db-preview"
+database_id = "b09e126c-8179-4927-876a-6a03ee94334b"
[env.production.ai]
binding = "AI" \ No newline at end of file