diff --git a/client/app/components/chat.tsx b/client/app/components/chat.tsx
index 38fcc6fe951..b5940491363 100644
--- a/client/app/components/chat.tsx
+++ b/client/app/components/chat.tsx
@@ -7,7 +7,14 @@ import {
import { ChatInput } from "~/components/ui/chat/chat-input";
import { ChatMessageList } from "~/components/ui/chat/chat-message-list";
import { AnimatePresence, motion } from "framer-motion";
-import { Copy, CornerDownLeft, Mic, Paperclip } from "lucide-react";
+import {
+ Copy,
+ CornerDownLeft,
+ Mic,
+ Paperclip,
+ Speaker,
+ Volume2,
+} from "lucide-react";
import { useEffect, useRef, useState } from "react";
import { Content, UUID } from "@elizaos/core";
import { useMutation, useQueryClient } from "@tanstack/react-query";
@@ -15,6 +22,7 @@ import { apiClient } from "~/lib/api";
import { cn, moment } from "~/lib/utils";
import { Avatar, AvatarImage } from "./ui/avatar";
import CopyButton from "./copy-button";
+import ChatTtsButton from "./ui/chat/chat-tts-button";
interface ExtraContentFields {
user: string;
@@ -169,13 +177,33 @@ export default function Page({ agentId }: { agentId: UUID }) {
}
>
{message?.text}
+
+ {/* Attachments */}
+ {/* */}
-
+
{message?.text &&
!message?.isLoading ? (
-
+
+
+
+
) : null}
{message?.createdAt ? (
diff --git a/client/app/components/ui/button.tsx b/client/app/components/ui/button.tsx
index ef511cf2bf9..b6d51c6c5d8 100644
--- a/client/app/components/ui/button.tsx
+++ b/client/app/components/ui/button.tsx
@@ -24,7 +24,7 @@ const buttonVariants = cva(
default: "h-9 px-4 py-2",
sm: "h-8 rounded-md px-3 text-xs",
lg: "h-10 rounded-md px-8",
- icon: "h-9 w-9",
+ icon: "size-[30px] rounded-md",
},
},
defaultVariants: {
diff --git a/client/app/components/ui/chat/chat-bubble.tsx b/client/app/components/ui/chat/chat-bubble.tsx
index 9957632021a..a82cec89e87 100644
--- a/client/app/components/ui/chat/chat-bubble.tsx
+++ b/client/app/components/ui/chat/chat-bubble.tsx
@@ -135,7 +135,7 @@ const ChatBubbleTimestamp: React.FC
= ({
className,
...props
}) => (
-
+
{timestamp}
);
diff --git a/client/app/components/ui/chat/chat-tts-button.tsx b/client/app/components/ui/chat/chat-tts-button.tsx
new file mode 100644
index 00000000000..40e5adc7b17
--- /dev/null
+++ b/client/app/components/ui/chat/chat-tts-button.tsx
@@ -0,0 +1,43 @@
+import { DotSquare, Ellipsis, StopCircle, Volume2 } from "lucide-react";
+import { Button } from "../button";
+import { useMutation } from "@tanstack/react-query";
+import { useState } from "react";
+import { apiClient } from "~/lib/api";
+
+export default function ChatTtsButton({ agentId, text }: { agentId: string; text: string }) {
+ const [playing, setPlaying] = useState
(false);
+ const mutation = useMutation({
+ mutationKey: ["tts", text],
+ mutationFn: () => apiClient.speak(agentId, text),
+ onSuccess: () => {
+ setPlaying(true);
+ },
+ });
+
+ const execute = () => {
+ if (mutation?.isPending) return;
+ if (playing) {
+ setPlaying(false);
+ }
+
+ mutation.mutate();
+ };
+
+ const iconClass = "text-muted-foreground size-4";
+ return (
+
+ );
+}
diff --git a/client/app/lib/api.ts b/client/app/lib/api.ts
index bd7652901cb..3c355b64e50 100644
--- a/client/app/lib/api.ts
+++ b/client/app/lib/api.ts
@@ -50,10 +50,19 @@ export const apiClient = {
method: "POST",
body: {
text: message,
- user: 'user'
+ user: "user",
},
}),
getAgents: () => fetcher({ url: "/agents" }),
getAgent: (agentId: string): Promise<{ id: UUID; character: Character }> =>
fetcher({ url: `/agents/${agentId}` }),
+
+ speak: (agentId: string, text: string) =>
+ fetcher({
+ url: `/${agentId}/speak`,
+ method: "POST",
+ body: {
+ text,
+ },
+ }),
};
diff --git a/client/app/root.tsx b/client/app/root.tsx
index 58760505a50..952c831dbfa 100644
--- a/client/app/root.tsx
+++ b/client/app/root.tsx
@@ -1,6 +1,5 @@
import {
Links,
- LiveReload,
Meta,
Outlet,
Scripts,
@@ -50,9 +49,8 @@ export function Layout({ children }: { children: React.ReactNode }) {
-
-
-
+
+
@@ -61,10 +59,10 @@ export function Layout({ children }: { children: React.ReactNode }) {
-
-
-
-
+
+
+
+