一、交互数智人实践教程概述
2. 创建视频流:使用形象资产 ID 或数智人平台项目 ID 创建视频流,指定视频流协议和驱动类型。
3. 检测会话状态:循环检查会话状态,直到会话状态变为已就绪(SessionStatus=1)。
4. 开启会话:调用 API 以开启会话。
5. 创建长链接通道:建立长链接通道,以便进行持续的通信。启动两个线程,一个用于定期获取下行信息,另一个用于定期发送心跳指令,以保持连接活跃。
6. 发送驱动指令:根据不同的场景(参见这篇档:1.数智人绑定对话服务场景、2.直播场景、3.用户自行接入大模型场景、4.音频驱动场景),发送相应的驱动指令,详细的适用场景与驱动指令的关系参考驱动指令说明。
7. 关闭长连接通道和会话:根据不同场景的情况关闭长连接通道和会话。
其中步骤需要根据不同的场景来选择不同的驱动指令,其他步骤的逻辑基本一致。以下是该流程的代码 Demo(目前只提供 go 语言版本):
Gopackage mainimport ( "encoding/base64" "fmt" "io" "log" "os" "strings" "time" uuid "github.com/satori/go.uuid" "k8s.io/apimachinery/pkg/util/rand")func main() { //第一步:初始化api调用对象 var api = NewVHApi( "your appkey", //your appkey "your accesstoken", //your accesstoken "https://gw.tvs.qq.com", //http domain "wss://gw.tvs.qq.com") //wss domain //第二步:使用形象资产ID或数智人项目ID创建视频流(使用形象资产ID可以指定音色相关参数,对话场景这些也没有明确;使用数智人项目ID里面包含了音色信息以及对话服务配置) //这里使用数智人项目ID创建视频流,以webrtc协议为例 createSessionRsp, err := api.CreateSession(CreateSessionReq{ UserId: "your user id", VirtualmanProjectId: "your virtualman project id", Protocol: "webrtc", //可选:webrtc、rtmp、trtc DriverType: 1, //drivetype=1代表支持文本驱动指令;drivetype=3代表支持音频和文本驱动指令 }) if err != nil { log.Fatalf("err:%v", err) } fmt.Println("获取流播放地址", createSessionRsp.PlayStreamAddr) for { var userInput string fmt.Print("是否成功复制地址(输入'y'确定): ") fmt.Scanln(&userInput) if strings.ToLower(userInput) == "y" { break } } //第三步:循环检测会话状态直到SessionStatus=1(已就绪) sessionStatus := createSessionRsp.SessionStatus for sessionStatus != 1 { time.Sleep(time.Second * 1) statSessionRsp, err := api.StatSession() if err != nil { log.Fatalf("err:%v", err) } sessionStatus = statSessionRsp.SessionStatus }
//第四步:开启会话 _, err = api.StartSession() if err != nil { log.Fatalf("err:%v", err) } //第五步:创建长链接通道 err = api.CommandChannel() if err != nil { log.Fatalf("err:%v", err) } // 开启协程每过3s获取下行信息 go func() { for { time.Sleep(time.Second * 3) fmt.Println("\\n—–开始调用长连接下行信息—–") api.ReadWssMessage() } }() //开启协程每过1分钟发送心跳指令 go func() { for { time.Sleep(time.Minute * 1) fmt.Println("\\n—–开始调用长连接发送心跳指令—–") api.SendHeartBeatCommand() } }() //第六步:发送驱动指令 //根据不同的场景选择不同的函数发送驱动指令,如大模型对话,调用以下函数(更多场景请见下文) largeModelDialogue() //第七步:关闭长连接通道和会话 //90s后关闭长连接通道(根据自己的场景来选择断连时间) time.Sleep(time.Second * 90) api.CloseSession()}
二、数智人绑定对话服务实践教程
数智人绑定的对话服务目前主要有如下两种配置:
1. 云小微对话(客服机器人对话)
2. 腾讯行业大模型对话
注意:说明:
注意:请到数智人的项目创建与管理绑定数智人对话服务,只能使用数智人平台项目创建会话方式。
对话服务推荐采用文本驱动指令(WebSocket 长连接),以下是这两种配置的代码示例:
Go// 客服机器人对话func robotDialogue() { fmt.Println("\\n—–云小微对话(客服机器人对话)—–") err := api.SendTextDriveWssCommand(TextDriveWssCommand{ Data: &TextWssData{ Text: "微信简介", //根据客服机器人问答知识库回答 ChatCommand: "", //使用客服对话or大模型对话 }, }) if err != nil { log.Fatalf("err:%v", err) }}
Go// 腾讯行业大模型对话func largeModelDialogue() { fmt.Println("\\n—–腾讯行业大模型对话—–") err := api.SendTextDriveWssCommand(TextDriveWssCommand{ Data: &TextWssData{ Text: "你是谁", //可以在模型管理里面自定义配置问答 ChatCommand: "", //使用客服对话or大模型对话 ChatRoundId: strings.Replace(uuid.NewV4().String(), "-", "", -1)[:32], //使用腾讯行业大模型对话服务的数智人项目需要传入此字段,用于区分多轮对话 }, }) if err != nil { log.Fatalf("err:%v", err) }}
三、直播场景实践教程
直播场景推荐使用直播数智人服务,实践教程可直接参考直播数智人服务 API 文档。
四、用户自行接入大模型实践教程
用户自行接入大模型: 指用户自行接入了 ChatGPT、腾讯混元等大模型,输出通常为流式文本。
该场景推荐使用流式文本驱动指令中的非子句模式(isSentence=false),非子句模式下服务端会对客户端发送的文本重新组句,能很好的配合大模型的流式输出,用户接入大模型的场景完整 Demo 参考ASR/ChatGPT/数智人 整合 demo。
以下是该场景对应的代码示例:
Go// 用户自行接入大模型来驱动数智人的场景func SendNotSentenceStreamText() { //模拟大模型的返回结果 rspText := "我是一个数智人,我在测试发送流式文本非子句模式。" //模拟大模型生成流式文本 streamChan := streamResponse(rspText, time.Millisecond*500) reqId := strings.Replace(uuid.NewV4().String(), "-", "", -1)[:32] seq := 1 for char := range streamChan { api.SendStreamTextDriveWssCommand(StreamTextDriveWssCommand{ ReqId: reqId, Data: &StreamTextWssData{ Text: char, Seq: seq, }, }) seq++ } // 发送final数据包 api.SendStreamTextDriveWssCommand(StreamTextDriveWssCommand{ ReqId: reqId, Data: &StreamTextWssData{ Seq: 1, IsFinal: true, }, })}
func streamResponse(text string, delay time.Duration) <-chan string { ch := make(chan string) go func() { for _, char := range text { //模拟大模型流式返回延时 time.Sleep(delay) ch <- string(char) } close(ch) }() return ch}
五、音频驱动场景实践教程
用户可以使用音频文件来驱动数智人,以下是该场景对应的代码示例:
Gofunc SendAudio() { /* 音频格式:格式-PCM,采样率-16kHz,采样位深-16bits,声道-单声道。 1.如果是麦克风实时收音发送,每录制160ms(5120B)的数据即可发出,中间不需要间隔等待;如果是读取离线音频文件发送,片包大小为160ms(5120B),片包发送间隔为120ms。 2.最后一个片包大小按实际发送(需小于160ms)。 3.当数据包发送完毕后,必须再发送一个IsFinal=true的空数据包(Audio字段填空串)结束当次音频驱动使数字人回到静默状态。 4.发送音频实时率要介于[0.75,1],小于0.75会触发限速,大于1会导致画面卡顿。比如160ms音频片包大小,发送间隔不能低于120ms,不能高于160ms。 */ chunkSize := 5120 //块大小-5120B sleepBase := 120 //间隔ms seq := 1 reqId := strings.Replace(uuid.NewV4().String(), "-", "", -1)[:32] //读取音频二进制文件 voiceFile, err := os.Open("your_audio_file.pcm") if err != nil { log.Fatalf("err:%v", err) } defer voiceFile.Close() buffer := make([]byte, chunkSize) for { n, err := voiceFile.Read(buffer) if err != nil && err != io.EOF { fmt.Println("Error reading file:", err) break } if n == 0 { // 文件读取完毕 break } err = api.SendVoiceDriveCommand(VoiceDriveCommand{ ReqId: reqId, Data: &VoiceData{ Audio: base64.StdEncoding.EncodeToString(buffer), //声音二进制数据编码Base64后的值。 Seq: seq, IsFinal: false, }, }) if err != nil { log.Fatalf("err:%v", err) } seq++ // 递增序列号 // 等待120ms到160ms的随机时间 sleepDuration := time.Duration(sleepBase+rand.Intn(41)) * time.Millisecond time.Sleep(sleepDuration) } // 发送final数据包 api.SendVoiceDriveCommand(VoiceDriveCommand{ ReqId: reqId, Data: &VoiceData{ Seq: seq, IsFinal: true, }, })}
六、完整 Demo 列表
| Demo 内容 | Demo 概述 | 语言 | 最新版这篇件名 | Demo 下载链接 |
| ASR/ChatGPT/数智人 整合 demo | 本 Demo 展示了如何通过ASR/ChatGPT,与数智人进行交互。 | python | asr_chatgpt_vh_demo_20241212.zip | 点击下载 |