File size: 2,421 Bytes
efc9173
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import React, { useState } from "react";
import {
  useDaily,
  useParticipantIds,
  useAppMessage,
  DailyAudio,
} from "@daily-co/daily-react";
import { IconLogout, IconLoader2 } from "@tabler/icons-react";

import VideoTile from "@/components/VideoTile";
import { Button } from "@/components/ui/button";
import UserInputIndicator from "@/components/UserInputIndicator";
import WaveText from "@/components/WaveText";

interface StoryProps {
  handleLeave: () => void;
}

const Story: React.FC<StoryProps> = ({ handleLeave }) => {
  const daily = useDaily();
  const participantIds = useParticipantIds({ filter: "remote" });
  const [storyState, setStoryState] = useState<"user" | "assistant">(
    "assistant"
  );

  useAppMessage({
    onAppMessage: (e) => {
      if (!daily || !e.data?.cue) return;

      // Determine the UI state from the cue sent by the bot
      if (e.data?.cue === "user_turn") {
        // Delay enabling local mic input to avoid feedback from LLM
        setTimeout(() => daily.setLocalAudio(true), 500);
        setStoryState("user");
      } else {
        daily.setLocalAudio(false);
        setStoryState("assistant");
      }
    },
  });

  return (
    <div className="w-full flex flex-col flex-1 self-stretch">
      {/* Absolute elements */}
      <div className="absolute top-20 w-full text-center z-50">
        <WaveText active={storyState === "user"} />
      </div>
      <header className="flex absolute top-0 w-full z-50 p-6 justify-end">
        <Button variant="secondary" onClick={() => handleLeave()}>
          <IconLogout size={21} className="mr-2" />
          Exit
        </Button>
      </header>
      <div className="absolute inset-0 bg-gray-800 bg-opacity-90 z-10 fade-in"></div>

      {/* Static elements */}
      <div className="relative z-20 flex-1 flex items-center justify-center">
        {participantIds.length >= 1 ? (
          <VideoTile
            sessionId={participantIds[0]}
            inactive={storyState === "user"}
          />
        ) : (
          <span className="p-3 rounded-full bg-gray-900/60 animate-pulse">
            <IconLoader2
              size={42}
              stroke={2}
              className="animate-spin text-white z-20 self-center"
            />
          </span>
        )}
        <DailyAudio />
      </div>
      <UserInputIndicator active={storyState === "user"} />
    </div>
  );
};

export default Story;