Open main menu
首页
专栏
课程
分类
归档
Chat
Sci-Hub
谷歌学术
Libgen
GitHub镜像
登录/注册
搜索
关闭
Previous
Previous
Next
Next
GPT Demo 分享|日不落直播间接入虚拟人AI互动
sockstack
/
272
/
2023-11-06 23:54:33
<p><span style="color: red; font-size: 18px">ChatGPT 可用网址,仅供交流学习使用,如对您有所帮助,请收藏并推荐给需要的朋友。</span><br><a href="https://ckai.xyz/?sockstack§ion=detail" target="__blank">https://ckai.xyz</a><br><br></p> <article class="baidu_pl"><div id="article_content" class="article_content clearfix"> <link rel="stylesheet" href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/editerView/kdoc_html_views-1a98987dfd.css"> <link rel="stylesheet" href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/editerView/ck_htmledit_views-25cebea3f9.css"> <div id="content_views" class="markdown_views prism-atom-one-dark"> <svg xmlns="http://www.w3.org/2000/svg" style="display: none;"><path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path></svg><h1> <a id="_0"></a>摘要</h1> <p>虚拟人和数字人是人工智能技术在现实生活中的具体应用,它们可以为人们的生活和工作带来便利和创新。在直播间场景里,虚拟人和数字人可用于直播主播、智能客服、营销推广等。接入GPT的虚拟人像是加了超强buff,具备更强大的自然语言处理能力和智能对话能力,可以实现更加智能化、自然化的人机交互。</p> <ul> <li>直播主播:虚拟人可以作为直播间的主播角色,通过与粉丝的对话和互动,提高粉丝的互动效果和兴趣</li> <li>代替客服:数字人可以作为客服角色,通通过自然语言处理和智能对话,解决客户的问题,并提高客户满意度。</li> <li>营销推广:虚拟人可以作为品牌形象进行推广,数字人可以通过客观数据进行精准营销,提高粉丝的黏性和忠诚度。</li> </ul> <h1> <a id="_8"></a>前言</h1> <p>续上一篇文章《「GPT实战」GPT接入直播间实现虚拟人互动》 ,我们实现了ChatGPT与ZIM的对接。使得加入聊天群组就相当于加入了直播间,实时与ChatGPT文字互动。但还缺了点什么:直播间可不是只有文字,还有主播!接下来进入本文主题:如何接入虚拟人直播。</p> <p>虚拟主播我们可以通过即构Avatar进行个人化定制,之前在他们《官网》体验过Avatar Demo,一键可以打造多元化风格,支持Q版、二次元、动漫、拟人等多种风格,即构自研虚拟形象引擎强大AI驱动能力,四种驱动方式:表情驱动、声音驱动、文本驱动、肢体驱动。根据本期Demo需求定制了拟人版本的主播小姐姐。即构AvatarQ版形象软萌可爱含丰富的服饰和妆容素材库,推荐大家去体验。即构Avatar的文本驱动方式刚好符合咱们的业务需求。</p> <p><img referrerpolicy="no-referrer" src="https://img-blog.csdnimg.cn/img_convert/ccd2d4c07d37642a281330abc20a90d6.png" alt="微信图片_20230529131522.png"></p> <h1> <a id="1_ZIM_17"></a>1 加入ZIM房间,实时收发消息</h1> <p>加入ZIM房间跟上一篇文章介绍的nodejs版原理一致:</p> <blockquote> <ol> <li>先登录ZIM</li> <li>加入房间或创建房间</li> <li>发送弹幕</li> <li>监听房间消息,如果来自ChatGPT则朗读</li> </ol> </blockquote> <h2> <a id="11_ZIM_24"></a>1.1 创建ZIM对象</h2> <p>首先引入ZIM库后,可以调用ZIM的create函数创建ZIM对象,然后调用ZIM对象的setEventHandler函数,将ZIMEventHandler对象传入。ZIMEventHandler主要用于处理一些回调事件如用户上线等回调事件。</p> <pre><code class="prism language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ZIMMngr</span> <span class="token punctuation">{<!-- --></span><span class="token comment">/*** 创建ZIM对象*/</span><span class="token keyword">private</span> <span class="token class-name">ZIM</span> <span class="token function">createZIM</span><span class="token punctuation">(</span><span class="token class-name">Application</span> app<span class="token punctuation">,</span> <span class="token class-name">ZIMEventHandler</span> handler<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token comment">// 创建 ZIM 对象,传入 APPID 与 Android 中的 Application</span><span class="token class-name">ZIM</span> zim <span class="token operator">=</span> ZIM<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token class-name">KeyCenter</span><span class="token punctuation">.</span>APP_ID<span class="token punctuation">,</span> app<span class="token punctuation">)</span><span class="token punctuation">;</span>zim<span class="token punctuation">.</span><span class="token function">setEventHandler</span><span class="token punctuation">(</span>handler<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">return</span> zim<span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token comment">//其他代码略...</span> <span class="token punctuation">}</span> </code></pre> <h2> <a id="12__41"></a>1.2 群聊-登录、创建房间、加入房间</h2> <p>登录即构服务首选需要token,生成token算法在附件源码已经给出,直接调用即可。但是需要注意,在这个Demo中直接在客户端上生成了,这是非常危险的操作,因为你的密钥和appid暴露出来了,黑客可以通过密钥和appid蹭你的额度费用。因此,建议把token计算放在服务器端生成。</p> <p>ZIM的createRoom函数用于创建房间,需要提供房间号;joinRoom函数用于加入房间,同样也需要提供房间号。具体代码如下所示:</p> <pre><code class="prism language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ZIMMngr</span> <span class="token punctuation">{<!-- --></span><span class="token comment">//其他代码略....</span><span class="token comment">/*** 登录zim*/</span><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">login</span><span class="token punctuation">(</span><span class="token class-name">String</span> userId<span class="token punctuation">,</span> <span class="token class-name">CB</span> cb<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token class-name">String</span> token <span class="token operator">=</span> <span class="token class-name">ZIMMngr</span><span class="token punctuation">.</span><span class="token function">getToken</span><span class="token punctuation">(</span>userId<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token class-name">ZIMMngr</span><span class="token punctuation">.</span><span class="token function">login</span><span class="token punctuation">(</span>zim<span class="token punctuation">,</span> token<span class="token punctuation">,</span> userId<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">ZIMLoggedInCallback</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token annotation punctuation">@Override</span><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">onLoggedIn</span><span class="token punctuation">(</span><span class="token class-name">ZIMError</span> errorInfo<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token keyword">if</span> <span class="token punctuation">(</span>errorInfo<span class="token punctuation">.</span><span class="token function">getCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token class-name">ZIMErrorCode</span><span class="token punctuation">.</span>SUCCESS<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token class-name">Log</span><span class="token punctuation">.</span><span class="token function">e</span><span class="token punctuation">(</span>TAG<span class="token punctuation">,</span> <span class="token string">"login error:"</span> <span class="token operator">+</span> errorInfo<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>cb<span class="token punctuation">.</span><span class="token function">complete</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token string">"登录失败"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{<!-- --></span>cb<span class="token punctuation">.</span><span class="token function">complete</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token comment">/*** 加入房间*/</span><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">joinRoom</span><span class="token punctuation">(</span><span class="token class-name">String</span> roomId<span class="token punctuation">,</span> <span class="token class-name">CB</span> cb<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>zim<span class="token punctuation">.</span><span class="token function">joinRoom</span><span class="token punctuation">(</span>roomId<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">ZIMRoomJoinedCallback</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token annotation punctuation">@Override</span><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">onRoomJoined</span><span class="token punctuation">(</span><span class="token class-name">ZIMRoomFullInfo</span> roomInfo<span class="token punctuation">,</span> <span class="token class-name">ZIMError</span> errorInfo<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token class-name">Log</span><span class="token punctuation">.</span><span class="token function">e</span><span class="token punctuation">(</span>TAG<span class="token punctuation">,</span> <span class="token string">">>"</span> <span class="token operator">+</span> errorInfo<span class="token punctuation">.</span>code<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span>errorInfo<span class="token punctuation">.</span>code <span class="token operator">==</span> <span class="token class-name">ZIMErrorCode</span><span class="token punctuation">.</span>ROOM_DOES_NOT_EXIST<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>cb<span class="token punctuation">.</span><span class="token function">complete</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token string">"房间不存在!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>errorInfo<span class="token punctuation">.</span>code <span class="token operator">==</span> <span class="token class-name">ZIMErrorCode</span><span class="token punctuation">.</span>SUCCESS <span class="token operator">||</span> errorInfo<span class="token punctuation">.</span>code <span class="token operator">==</span> <span class="token class-name">ZIMErrorCode</span><span class="token punctuation">.</span>THE_ROOM_ALREADY_EXISTS<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>cb<span class="token punctuation">.</span><span class="token function">complete</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">,</span> roomInfo<span class="token punctuation">.</span>baseInfo<span class="token punctuation">.</span>roomName<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token comment">/*** 创建房间*/</span><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">createRoom</span><span class="token punctuation">(</span><span class="token class-name">String</span> masterId<span class="token punctuation">,</span> <span class="token class-name">String</span> roomId<span class="token punctuation">,</span> <span class="token class-name">String</span> roomName<span class="token punctuation">,</span> <span class="token class-name">CB</span> cb<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token class-name">ZIMRoomInfo</span> groupInfo <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ZIMRoomInfo</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>groupInfo<span class="token punctuation">.</span>roomID <span class="token operator">=</span> roomId<span class="token punctuation">;</span>groupInfo<span class="token punctuation">.</span>roomName <span class="token operator">=</span> roomName<span class="token punctuation">;</span>zim<span class="token punctuation">.</span><span class="token function">createRoom</span><span class="token punctuation">(</span>groupInfo<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">ZIMRoomCreatedCallback</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token annotation punctuation">@Override</span><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">onRoomCreated</span><span class="token punctuation">(</span><span class="token class-name">ZIMRoomFullInfo</span> roomInfo<span class="token punctuation">,</span> <span class="token class-name">ZIMError</span> errorInfo<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token keyword">if</span> <span class="token punctuation">(</span>errorInfo<span class="token punctuation">.</span>code <span class="token operator">==</span> <span class="token class-name">ZIMErrorCode</span><span class="token punctuation">.</span>SUCCESS<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token function">inviteJoinRoom</span><span class="token punctuation">(</span>masterId<span class="token punctuation">,</span> roomId<span class="token punctuation">,</span> CHATGPT_ID<span class="token punctuation">,</span> cb<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//这里把chagpt的用户id硬编码</span><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{<!-- --></span><span class="token class-name">Log</span><span class="token punctuation">.</span><span class="token function">e</span><span class="token punctuation">(</span>TAG<span class="token punctuation">,</span> <span class="token string">"创建房间失败:"</span> <span class="token operator">+</span> errorInfo<span class="token punctuation">.</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span>cb<span class="token punctuation">.</span><span class="token function">complete</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token string">"房号已存在,请更换一个房间号!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre> <h2> <a id="13__110"></a>1.3 即时通讯实现收发消息</h2> <p>接下来实现消息收发,主动发送消息与监听接收消息。注意,这里因为我们只关注弹幕消息,因此非弹幕消息过滤。发送消息封装两类:</p> <ul> <li>P2P</li> <li>ROOM</li> </ul> <p>注意,因为我们这里只用弹幕消息,因此ROOM消息只表示弹幕消息。</p> <pre><code class="prism language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ZIMMngr</span> <span class="token punctuation">{<!-- --></span><span class="token comment">//定义属性略....</span><span class="token comment">/*** 收到房间消息*/</span><span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">onRcvMsg</span><span class="token punctuation">(</span><span class="token class-name">ArrayList</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">ZIMMessage</span><span class="token punctuation">></span></span> messageList<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token keyword">if</span> <span class="token punctuation">(</span>mListener <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token keyword">return</span><span class="token punctuation">;</span><span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">ZIMMessage</span> zimMessage <span class="token operator">:</span> messageList<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token keyword">if</span> <span class="token punctuation">(</span>zimMessage <span class="token keyword">instanceof</span> <span class="token class-name">ZIMBarrageMessage</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token comment">//只看弹幕消息</span><span class="token class-name">ZIMBarrageMessage</span> zimTextMessage <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">ZIMBarrageMessage</span><span class="token punctuation">)</span> zimMessage<span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span>zimMessage<span class="token punctuation">.</span><span class="token function">getTimestamp</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator"><</span> <span class="token keyword">this</span><span class="token punctuation">.</span>startTime<span class="token punctuation">)</span><span class="token keyword">continue</span><span class="token punctuation">;</span><span class="token class-name">String</span> fromUID <span class="token operator">=</span> zimTextMessage<span class="token punctuation">.</span><span class="token function">getSenderUserID</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token class-name">ZIMConversationType</span> ztype <span class="token operator">=</span> zimTextMessage<span class="token punctuation">.</span><span class="token function">getConversationType</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token class-name">String</span> toUID <span class="token operator">=</span> zimTextMessage<span class="token punctuation">.</span><span class="token function">getConversationID</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token class-name">Msg<span class="token punctuation">.</span>MsgType</span> type <span class="token operator">=</span> <span class="token class-name">Msg<span class="token punctuation">.</span>MsgType</span><span class="token punctuation">.</span>P2P<span class="token punctuation">;</span> <span class="token class-name">String</span> data <span class="token operator">=</span> zimTextMessage<span class="token punctuation">.</span>message<span class="token punctuation">;</span> <span class="token class-name">Msg</span> msg <span class="token operator">=</span> <span class="token class-name">Msg</span><span class="token punctuation">.</span><span class="token function">parseMsg</span><span class="token punctuation">(</span>data<span class="token punctuation">,</span> fromUID<span class="token punctuation">,</span> toUID<span class="token punctuation">,</span> ztype <span class="token operator">==</span> <span class="token class-name">ZIMConversationType</span><span class="token punctuation">.</span>ROOM<span class="token punctuation">)</span><span class="token punctuation">;</span>mListener<span class="token punctuation">.</span><span class="token function">onRcvMsg</span><span class="token punctuation">(</span>msg<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token comment">/*** 发送zim消息* */</span><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">sendMsg</span><span class="token punctuation">(</span><span class="token class-name">Msg</span> msg<span class="token punctuation">,</span> <span class="token class-name">CB</span> cb<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token comment">//p2p消息则发送Text,room发送弹幕类型消息</span><span class="token class-name">ZIMMessage</span> zimMsg <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span><span class="token class-name">ZIMConversationType</span> type<span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span>msg<span class="token punctuation">.</span>type <span class="token operator">==</span> <span class="token class-name">Msg<span class="token punctuation">.</span>MsgType</span><span class="token punctuation">.</span>P2P<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token class-name">ZIMTextMessage</span> m <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ZIMTextMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>m<span class="token punctuation">.</span>message <span class="token operator">=</span> msg<span class="token punctuation">.</span>msg<span class="token punctuation">;</span>zimMsg <span class="token operator">=</span> m<span class="token punctuation">;</span>type <span class="token operator">=</span> <span class="token class-name">ZIMConversationType</span><span class="token punctuation">.</span>PEER<span class="token punctuation">;</span><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{<!-- --></span><span class="token class-name">ZIMBarrageMessage</span> m <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ZIMBarrageMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>m<span class="token punctuation">.</span>message <span class="token operator">=</span> msg<span class="token punctuation">.</span>msg<span class="token punctuation">;</span>zimMsg <span class="token operator">=</span> m<span class="token punctuation">;</span>type <span class="token operator">=</span> <span class="token class-name">ZIMConversationType</span><span class="token punctuation">.</span>ROOM<span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token class-name">ZIMMessageSendConfig</span> config <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ZIMMessageSendConfig</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 消息优先级,取值为 低:1 默认,中:2,高:3</span>config<span class="token punctuation">.</span>priority <span class="token operator">=</span> <span class="token class-name">ZIMMessagePriority</span><span class="token punctuation">.</span>LOW<span class="token punctuation">;</span><span class="token comment">// 设置消息的离线推送配置</span><span class="token class-name">ZIMPushConfig</span> pushConfig <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ZIMPushConfig</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>pushConfig<span class="token punctuation">.</span>title <span class="token operator">=</span> <span class="token string">"离线推送的标题"</span><span class="token punctuation">;</span>pushConfig<span class="token punctuation">.</span>content <span class="token operator">=</span> <span class="token string">"离线推送的内容"</span><span class="token punctuation">;</span>config<span class="token punctuation">.</span>pushConfig <span class="token operator">=</span> pushConfig<span class="token punctuation">;</span> zim<span class="token punctuation">.</span><span class="token function">sendMessage</span><span class="token punctuation">(</span>zimMsg<span class="token punctuation">,</span> msg<span class="token punctuation">.</span>toUID<span class="token punctuation">,</span> type<span class="token punctuation">,</span> config<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">ZIMMessageSentCallback</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token annotation punctuation">@Override</span><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">onMessageAttached</span><span class="token punctuation">(</span><span class="token class-name">ZIMMessage</span> message<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token punctuation">}</span> <span class="token annotation punctuation">@Override</span><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">onMessageSent</span><span class="token punctuation">(</span><span class="token class-name">ZIMMessage</span> message<span class="token punctuation">,</span> <span class="token class-name">ZIMError</span> errorInfo<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> cb<span class="token punctuation">.</span><span class="token function">complete</span><span class="token punctuation">(</span>errorInfo<span class="token punctuation">.</span>code <span class="token operator">==</span> <span class="token class-name">ZIMErrorCode</span><span class="token punctuation">.</span>SUCCESS<span class="token punctuation">,</span> errorInfo<span class="token punctuation">.</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// 其他代码略....</span> <span class="token punctuation">}</span> </code></pre> <p>上面代码只挑选了关键函数, 更多关于即构ZIM接口与官方Demo可以点击参考这里,或者参考附录源码。</p> <h1> <a id="2_Avatar_186"></a>2 创建虚拟形象-即构Avatar</h1> <p>接下来需要创建虚拟形象,读者可以参考官方文档获取更多详细信息。</p> <p>需要注意的是,通过官方封装的ZegoCharacterHelper可以非常简单的创建<code>Avatar</code>。创建虚拟形象封装到setCharacter函数中,在程序初始化期间,需要执行initRes函数,将资源拷贝到SDCard。作为演示,这里是将Assets里面的相关资源拷贝到SDCard。在实际项目中,建议将资源存放在服务器端,通过离线下载的方式存储到SDCard。这样既可以降低安装包的大小,也更灵活。</p> <pre><code class="prism language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">AvatarMngr</span> <span class="token keyword">implements</span> <span class="token class-name">ZegoAvatarServiceDelegate</span> <span class="token punctuation">{<!-- --></span><span class="token comment">//属性定义略.... </span><span class="token comment">/*** 设置虚拟形象如衣服、头发、性别等*/</span><span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">setCharacter</span><span class="token punctuation">(</span><span class="token class-name">User</span> user<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token comment">// 创建 helper 简化调用</span><span class="token comment">// base.bundle 是头模, human.bundle 是全身人模</span>mCharacterHelper <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ZegoCharacterHelper</span><span class="token punctuation">(</span><span class="token class-name">FileUtils</span><span class="token punctuation">.</span><span class="token function">getPhonePath</span><span class="token punctuation">(</span>mApp<span class="token punctuation">,</span> <span class="token string">"human.bundle"</span><span class="token punctuation">,</span> <span class="token string">"assets"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>mCharacterHelper<span class="token punctuation">.</span><span class="token function">setExtendPackagePath</span><span class="token punctuation">(</span><span class="token class-name">FileUtils</span><span class="token punctuation">.</span><span class="token function">getPhonePath</span><span class="token punctuation">(</span>mApp<span class="token punctuation">,</span> <span class="token string">"Packages"</span><span class="token punctuation">,</span> <span class="token string">"assets"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 设置形象配置</span>mCharacterHelper<span class="token punctuation">.</span><span class="token function">setDefaultAvatar</span><span class="token punctuation">(</span><span class="token class-name">ZegoCharacterHelper</span><span class="token punctuation">.</span>MODEL_ID_FEMALE<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 角色上屏, 必须在 UI 线程, 必须设置过avatar形象后才可调用(用 setDefaultAvatar 或者 setAvatarJson 都可以)</span>mCharacterHelper<span class="token punctuation">.</span><span class="token function">setCharacterView</span><span class="token punctuation">(</span>user<span class="token punctuation">.</span>avatarView<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token punctuation">{<!-- --></span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>mCharacterHelper<span class="token punctuation">.</span><span class="token function">setViewport</span><span class="token punctuation">(</span><span class="token class-name">ZegoAvatarViewState</span><span class="token punctuation">.</span>half<span class="token punctuation">)</span><span class="token punctuation">;</span>mCharacterHelper<span class="token punctuation">.</span><span class="token function">setPackage</span><span class="token punctuation">(</span><span class="token string">"ZEGO_Girl_Hair_0001"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>mCharacterHelper<span class="token punctuation">.</span><span class="token function">setPackage</span><span class="token punctuation">(</span><span class="token string">"ZEGO_Girl_Tshirt_0001_0002"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>mCharacterHelper<span class="token punctuation">.</span><span class="token function">setPackage</span><span class="token punctuation">(</span><span class="token string">"facepaint5"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>mCharacterHelper<span class="token punctuation">.</span><span class="token function">setPackage</span><span class="token punctuation">(</span><span class="token string">"irises2"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">updateUser</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">initRes</span><span class="token punctuation">(</span><span class="token class-name">Application</span> app<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token comment">// 先把资源拷贝到SD卡,注意:线上使用时,需要做一下判断,避免多次拷贝。资源也可以做成从网络下载。</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token class-name">FileUtils</span><span class="token punctuation">.</span><span class="token function">checkFile</span><span class="token punctuation">(</span>app<span class="token punctuation">,</span> <span class="token string">"AIModel.bundle"</span><span class="token punctuation">,</span> <span class="token string">"assets"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token class-name">FileUtils</span><span class="token punctuation">.</span><span class="token function">copyAssetsDir2Phone</span><span class="token punctuation">(</span>app<span class="token punctuation">,</span> <span class="token string">"AIModel.bundle"</span><span class="token punctuation">,</span> <span class="token string">"assets"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token class-name">FileUtils</span><span class="token punctuation">.</span><span class="token function">checkFile</span><span class="token punctuation">(</span>app<span class="token punctuation">,</span> <span class="token string">"base.bundle"</span><span class="token punctuation">,</span> <span class="token string">"assets"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token class-name">FileUtils</span><span class="token punctuation">.</span><span class="token function">copyAssetsDir2Phone</span><span class="token punctuation">(</span>app<span class="token punctuation">,</span> <span class="token string">"base.bundle"</span><span class="token punctuation">,</span> <span class="token string">"assets"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token class-name">FileUtils</span><span class="token punctuation">.</span><span class="token function">checkFile</span><span class="token punctuation">(</span>app<span class="token punctuation">,</span> <span class="token string">"human.bundle"</span><span class="token punctuation">,</span> <span class="token string">"assets"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token class-name">FileUtils</span><span class="token punctuation">.</span><span class="token function">copyAssetsDir2Phone</span><span class="token punctuation">(</span>app<span class="token punctuation">,</span> <span class="token string">"human.bundle"</span><span class="token punctuation">,</span> <span class="token string">"assets"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token class-name">FileUtils</span><span class="token punctuation">.</span><span class="token function">checkFile</span><span class="token punctuation">(</span>app<span class="token punctuation">,</span> <span class="token string">"Packages"</span><span class="token punctuation">,</span> <span class="token string">"assets"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token class-name">FileUtils</span><span class="token punctuation">.</span><span class="token function">copyAssetsDir2Phone</span><span class="token punctuation">(</span>app<span class="token punctuation">,</span> <span class="token string">"Packages"</span><span class="token punctuation">,</span> <span class="token string">"assets"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token comment">//...</span><span class="token comment">//其他代码略....</span><span class="token comment">//...</span> <span class="token punctuation">}</span> </code></pre> <p>除了衣服、首饰、发型等"装饰类"形象定义,还可以捏脸,这里不详细描述,建议读者前往官网查看。即构Avatar官网。</p> <h1> <a id="4__238"></a>4 直播间虚拟人与粉丝互动聊天</h1> <p>创建完虚拟人后,接下来将收到的ChatGPT消息朗读出来,使虚拟主播嘴巴动起来,互动玩法更好。首先执行initTextApi函数,初始化本地文字驱动引擎。接下来就可以调用ZegoTextAPI的playTextExpression函数,驱动虚拟人语音播报文字内容。</p> <pre><code class="prism language-java"><span class="token comment">/*** 朗读文字(嘴唇+语音) */</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">playText</span><span class="token punctuation">(</span><span class="token class-name">String</span> text<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token keyword">if</span> <span class="token punctuation">(</span>mTextApi <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token keyword">return</span><span class="token punctuation">;</span>mTextApi<span class="token punctuation">.</span><span class="token function">playTextExpression</span><span class="token punctuation">(</span>text<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token class-name">Log</span><span class="token punctuation">.</span><span class="token function">e</span><span class="token punctuation">(</span>TAG<span class="token punctuation">,</span> <span class="token string">">>>>已播放"</span> <span class="token operator">+</span> text<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">/*** 初始化文本驱动接口 */</span> <span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">initTextApi</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>mTextApi <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ZegoTextAPI</span><span class="token punctuation">(</span>mCharacterHelper<span class="token punctuation">.</span><span class="token function">getCharacter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>mTextApi<span class="token punctuation">.</span><span class="token function">setTextExpressionCallback</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">ITextExpressionCallback</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token comment">/*** 文本驱动播放启动时,回调*/</span><span class="token annotation punctuation">@Override</span><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">onStart</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token class-name">Log</span><span class="token punctuation">.</span><span class="token function">d</span><span class="token punctuation">(</span>TAG<span class="token punctuation">,</span> <span class="token string">"text drive start"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token comment">/*** 文本驱动播放出错时,回调* @param errorCode 错误码,详情请参考 [常见错误码 - 文本驱动](https://doc-zh.zego.im/article/14884#2)。*/</span><span class="token annotation punctuation">@Override</span><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">onError</span><span class="token punctuation">(</span><span class="token keyword">int</span> errorCode<span class="token punctuation">,</span> <span class="token class-name">String</span> msg<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token punctuation">}</span><span class="token comment">/*** 文本驱动播放结束时,回调*/</span><span class="token annotation punctuation">@Override</span><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">onEnd</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token class-name">Log</span><span class="token punctuation">.</span><span class="token function">d</span><span class="token punctuation">(</span>TAG<span class="token punctuation">,</span> <span class="token string">"text drive end"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre> <p>文本驱动部分代码比较简单,也反映了官方对这块封装的比较好。播报文字主要借助即构avatar的文本能力,读者可以查看官方文档描述:官方文档。仔细阅读可以发现,关键核心代码非常少,附件里面的其他代码主要是开发App非核心代码。</p> <p>本文演示了从0开发、无须服务端开发完成的基于ChatGPT的虚拟人直播,任何人下载该App即可加入直播间。一些小伙伴可能并不需要开发一个虚拟人直播平台,而是想着在抖音、快手、视频号等平台实现虚拟人直播。这里提供一个实现思路:</p> <ol> <li>复用本文代码,可以实现ChatGPT回复、并将回复的文字驱动虚拟人</li> <li>使用直播伴侣等工具录制虚拟人,推流到抖音平台</li> <li>去github找开源工具,实时爬取直播间的弹幕</li> <li>读取到弹幕后,调用ChatGPT得到回复,再回到第1步。</li> </ol> <p>未来想象方面,虚拟人接入GPT可以实现更加智能化、个性化的服务,可以预见的是,未来的虚拟人将更加人性化,通过情感计算等技术,可以实现更加真实、自然的人机交互。虚拟人还可以与物理机器人结合,成为未来的机器人助手,为人们的生活和工作提供更加便利的服务。</p> <h1> <a id="5_Github_292"></a>5 Github源码</h1> <p>供一个实现思路:</p> <ol> <li>复用本文代码,可以实现ChatGPT回复、并将回复的文字驱动虚拟人</li> <li>使用直播伴侣等工具录制虚拟人,推流到抖音平台</li> <li>去github找开源工具,实时爬取直播间的弹幕</li> <li>读取到弹幕后,调用ChatGPT得到回复,再回到第1步。</li> </ol> <p>未来想象方面,虚拟人接入GPT可以实现更加智能化、个性化的服务,可以预见的是,未来的虚拟人将更加人性化,通过情感计算等技术,可以实现更加真实、自然的人机交互。虚拟人还可以与物理机器人结合,成为未来的机器人助手,为人们的生活和工作提供更加便利的服务。</p> <h1> <a id="5_Github_301"></a>5 Github源码</h1> <ol><li>ChatGPT虚拟直播源码</li></ol> </div> <link href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/editerView/markdown_views-98b95bb57c.css" rel="stylesheet"> <link href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/style-c216769e99.css" rel="stylesheet"> </div> <div id="treeSkill"></div> </article>
GPT Demo 分享|日不落直播间接入虚拟人AI互动
作者
sockstack
许可协议
CC BY 4.0
发布于
2023-11-06
修改于
2024-12-21
上一篇:软件:常用 Linux 软件汇总,值得收藏
下一篇:chatgpt赋能python:如何在Python中创建模块:完整指南
尚未登录
登录 / 注册
文章分类
博客重构之路
5
Spring Boot简单入门
4
k8s 入门教程
0
MySQL 知识
1
NSQ 消息队列
0
ThinkPHP5 源码分析
5
使用 Docker 从零开始搭建私人代码仓库
3
日常开发汇总
4
标签列表
springboot
hyperf
swoole
webman
php
多线程
数据结构
docker
k8s
thinkphp
mysql
tailwindcss
flowbite
css
前端