Add a thinking visual feedback
This commit is contained in:
@@ -12,6 +12,7 @@ export default function AudioRecorder() {
|
|||||||
const messages = useConversation((state) => state.messages);
|
const messages = useConversation((state) => state.messages);
|
||||||
const addMessage = useConversation((state) => state.addMessage);
|
const addMessage = useConversation((state) => state.addMessage);
|
||||||
const setMessageResult = useConversation((state) => state.setMessageResult);
|
const setMessageResult = useConversation((state) => state.setMessageResult);
|
||||||
|
const setThinking = useConversation((state) => state.setThinking);
|
||||||
|
|
||||||
const handleRecordClick = () => {
|
const handleRecordClick = () => {
|
||||||
if (isRecording) {
|
if (isRecording) {
|
||||||
@@ -23,6 +24,7 @@ export default function AudioRecorder() {
|
|||||||
|
|
||||||
const fetchConversation = useCallback(
|
const fetchConversation = useCallback(
|
||||||
async (audioBlob: Blob) => {
|
async (audioBlob: Blob) => {
|
||||||
|
setThinking(true);
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append("audio", audioBlob, "audio.ogg");
|
formData.append("audio", audioBlob, "audio.ogg");
|
||||||
formData.append("messages", JSON.stringify(messages));
|
formData.append("messages", JSON.stringify(messages));
|
||||||
@@ -32,6 +34,7 @@ export default function AudioRecorder() {
|
|||||||
method: "POST",
|
method: "POST",
|
||||||
body: formData,
|
body: formData,
|
||||||
});
|
});
|
||||||
|
setThinking(false);
|
||||||
|
|
||||||
const result = JSON.parse((await response.headers.get("result")) || "{}");
|
const result = JSON.parse((await response.headers.get("result")) || "{}");
|
||||||
const userMessage = JSON.parse((await response.headers.get("usermessage")) || "{}");
|
const userMessage = JSON.parse((await response.headers.get("usermessage")) || "{}");
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { Canvas } from "@react-three/fiber";
|
|||||||
import { Leva } from "leva";
|
import { Leva } from "leva";
|
||||||
|
|
||||||
import { Avatar } from "./Avatar";
|
import { Avatar } from "./Avatar";
|
||||||
|
import Thinking from "./Thinking";
|
||||||
|
|
||||||
function Experience() {
|
function Experience() {
|
||||||
return (
|
return (
|
||||||
@@ -14,6 +15,7 @@ function Experience() {
|
|||||||
{/* <Canvas shadows camera={{ position: [0, 0, 1], fov: 30 }}> */}
|
{/* <Canvas shadows camera={{ position: [0, 0, 1], fov: 30 }}> */}
|
||||||
<Canvas shadows camera={{ position: [0, 0, 1], fov: 30 }}>
|
<Canvas shadows camera={{ position: [0, 0, 1], fov: 30 }}>
|
||||||
<Environment preset="warehouse" />
|
<Environment preset="warehouse" />
|
||||||
|
<Thinking />
|
||||||
<Avatar />
|
<Avatar />
|
||||||
</Canvas>
|
</Canvas>
|
||||||
</>
|
</>
|
||||||
|
|||||||
28
src/components/Thinking.tsx
Normal file
28
src/components/Thinking.tsx
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import { useFrame } from "@react-three/fiber";
|
||||||
|
import React, { useRef } from "react";
|
||||||
|
|
||||||
|
import { useConversation } from "@/lib/store";
|
||||||
|
|
||||||
|
function Thinking() {
|
||||||
|
const thinking = useConversation((state) => state.thinking);
|
||||||
|
const haloRef = useRef();
|
||||||
|
|
||||||
|
// Animate the halo rotation if active
|
||||||
|
useFrame((state, delta) => {
|
||||||
|
if (thinking && haloRef.current) {
|
||||||
|
haloRef.current.rotation.z += delta; // Rotate around Z-axis
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Render nothing if not active
|
||||||
|
if (!thinking) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<mesh ref={haloRef} position={[0, 0.1, -1]}>
|
||||||
|
<ringGeometry args={[0.3, 0.4, 16]} />
|
||||||
|
<meshBasicMaterial color="#00FFFF" transparent opacity={0.7} side={2} />
|
||||||
|
</mesh>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Thinking;
|
||||||
@@ -14,13 +14,17 @@ interface MessageType {
|
|||||||
interface ConversationState {
|
interface ConversationState {
|
||||||
messageResult: MessageResultType | null;
|
messageResult: MessageResultType | null;
|
||||||
messages: MessageType[];
|
messages: MessageType[];
|
||||||
|
thinking: boolean;
|
||||||
setMessageResult: (message: MessageResultType | null) => void;
|
setMessageResult: (message: MessageResultType | null) => void;
|
||||||
addMessage: (message: MessageType) => void;
|
addMessage: (message: MessageType) => void;
|
||||||
|
setThinking: (thinking: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useConversation = create<ConversationState>()((set) => ({
|
export const useConversation = create<ConversationState>()((set) => ({
|
||||||
messageResult: null,
|
messageResult: null,
|
||||||
messages: [],
|
messages: [],
|
||||||
|
thinking: false,
|
||||||
setMessageResult: (messageResult) => set({ messageResult }),
|
setMessageResult: (messageResult) => set({ messageResult }),
|
||||||
addMessage: (message) => set((state) => ({ messages: [...state.messages, message] })),
|
addMessage: (message) => set((state) => ({ messages: [...state.messages, message] })),
|
||||||
|
setThinking: (thinking) => set({ thinking }),
|
||||||
}));
|
}));
|
||||||
|
|||||||
Reference in New Issue
Block a user