3v324v23's picture
Зафиксирована рабочая версия TEN-Agent для HuggingFace Space
87337b1
"use client"
import * as React from "react"
import { cn } from "@/lib/utils"
import { ICameraVideoTrack, ILocalVideoTrack, IMicrophoneAudioTrack } from "agora-rtc-sdk-ng"
import { useAppSelector, useAppDispatch } from "@/common/hooks"
import { isVoiceGenderSupported, VideoSourceType } from "@/common/constant"
import { ITextItem, EMessageType, IChatItem } from "@/types"
import { rtcManager, IUserTracks, IRtcUser } from "@/manager"
import {
setRoomConnected,
addChatItem,
setVoiceType,
setOptions,
} from "@/store/reducers/global"
import AgentVoicePresetSelect from "@/components/Agent/VoicePresetSelect"
import AgentView from "@/components/Agent/View"
import MicrophoneBlock from "@/components/Agent/Microphone"
import CameraBlock from "@/components/Agent/Camera"
import VideoBlock from "@/components/Agent/Camera"
let hasInit: boolean = false
export default function RTCCard(props: { className?: string }) {
const { className } = props
const dispatch = useAppDispatch()
const options = useAppSelector((state) => state.global.options)
const voiceType = useAppSelector((state) => state.global.voiceType)
const selectedGraphId = useAppSelector((state) => state.global.graphName)
const { userId, channel } = options
const [videoTrack, setVideoTrack] = React.useState<ICameraVideoTrack>()
const [audioTrack, setAudioTrack] = React.useState<IMicrophoneAudioTrack>()
const [screenTrack, setScreenTrack] = React.useState<ILocalVideoTrack>()
const [remoteuser, setRemoteUser] = React.useState<IRtcUser>()
const [videoSourceType, setVideoSourceType] = React.useState<VideoSourceType>(VideoSourceType.CAMERA)
React.useEffect(() => {
if (!options.channel) {
return
}
if (hasInit) {
return
}
init()
return () => {
if (hasInit) {
destory()
}
}
}, [options.channel])
const init = async () => {
console.log("[rtc] init")
rtcManager.on("localTracksChanged", onLocalTracksChanged)
rtcManager.on("textChanged", onTextChanged)
rtcManager.on("remoteUserChanged", onRemoteUserChanged)
await rtcManager.createCameraTracks()
await rtcManager.createMicrophoneTracks()
await rtcManager.join({
channel,
userId,
})
dispatch(
setOptions({
...options,
appId: rtcManager.appId ?? "",
token: rtcManager.token ?? "",
}),
)
await rtcManager.publish()
dispatch(setRoomConnected(true))
hasInit = true
}
const destory = async () => {
console.log("[rtc] destory")
rtcManager.off("textChanged", onTextChanged)
rtcManager.off("localTracksChanged", onLocalTracksChanged)
rtcManager.off("remoteUserChanged", onRemoteUserChanged)
await rtcManager.destroy()
dispatch(setRoomConnected(false))
hasInit = false
}
const onRemoteUserChanged = (user: IRtcUser) => {
console.log("[rtc] onRemoteUserChanged", user)
setRemoteUser(user)
}
const onLocalTracksChanged = (tracks: IUserTracks) => {
console.log("[rtc] onLocalTracksChanged", tracks)
const { videoTrack, audioTrack, screenTrack } = tracks
setVideoTrack(videoTrack)
setScreenTrack(screenTrack)
if (audioTrack) {
setAudioTrack(audioTrack)
}
}
const onTextChanged = (text: IChatItem) => {
console.log("[rtc] onTextChanged", text)
dispatch(
addChatItem(text),
)
}
const onVoiceChange = (value: any) => {
dispatch(setVoiceType(value))
}
const onVideoSourceTypeChange = async (value: VideoSourceType) => {
await rtcManager.switchVideoSource(value)
setVideoSourceType(value)
}
return (
<>
<div className={cn("flex-shrink-0", "overflow-y-auto", className)}>
<div className="flex h-full w-full flex-col">
{/* -- Agent */}
<div className="w-full">
<div className="flex w-full items-center justify-between p-2">
<h2 className="mb-2 text-xl font-semibold">Audio & Video</h2>
{
isVoiceGenderSupported(selectedGraphId) ?
<AgentVoicePresetSelect /> :
null}
</div>
<AgentView audioTrack={remoteuser?.audioTrack} />
</div>
{/* -- You */}
<div className="w-full space-y-2 px-2">
<MicrophoneBlock audioTrack={audioTrack} />
<VideoBlock
cameraTrack={videoTrack}
screenTrack={screenTrack}
videoSourceType={videoSourceType}
onVideoSourceChange={onVideoSourceTypeChange}
/>
</div>
</div>
</div>
</>
)
}