GPTバーチャルライブデモシリーズ(1)|GPTが生放送室にアクセスし、キャスターと視聴者のインタラクションを実現

まとめ

ChatGPT と Metaverse はどちらも、現在のデジタル分野で非常に人気のあるテクノロジおよびアプリケーションです。2 つの利点と特性を組み合わせることで、より多くのアプリケーション シナリオとビジネス モデルを検討できます。たとえば、自然言語インタラクションに Metaverse で ChatGPT を使用すると、よりインテリジェントでパーソナライズされたサービスとサポートをユーザーに提供できます。また、ChatGPT で Metaverse を仮想現実体験に使用すると、より現実的で豊かで多様なインタラクティブ エクスペリエンスをユーザーに提供できます。
次に、Metaverse と ChatGPT の利点を組み合わせて GPT 仮想ライブ ブロードキャストのデモを開発し、Douyin プラットフォームにプッシュします。

NodeJS は ChatGPT とインスタント ZIM にアクセスします

前回の記事「ChatGPT4.0を使って誰でもアバターバーチャルヒューマン生放送ができる」では主にChatGPT+を使ってアバターを構築してバーチャルヒューマン生放送を行う方法を紹介しました。紙面の都合上、コードの特定の実装については十分に詳しく説明しません。多くの読者からコード関連の問題について質問を受けました。次に、著者がコードの実装を 2 つの部分に分けて詳しく説明します。

  1. NodeJS は ChatGPT とインスタント ZIM にアクセスします
  2. ChatGPT とインスタント アバター バーチャル ヒューマン ドッキング ライブ ブロードキャスト

この記事では主に、ChatGPT にアクセスし、後で Avatar と接続する機能を実現する方法を説明します。

具体的なプロセスを説明する前に、GPT 仮想ライブ ブロードキャスト デモ全体の実装フローチャートを確認してみましょう。この記事で共有する内容は、下図の右側の実装ロジックです。

ここに画像の説明を挿入

1 基本原則

ChatGPT はプレーンテキストの対話ですが、それをアバターの仮想人物とどのように接続するのでしょうか?
まず事前分布が分かります。

  • つまり、アバターにはテキスト駆動の機能があり、アバターにテキストを入力すると、アバターは口の形をレンダリングし、テキストに従って音声をブロードキャストします。
  • ライブ放送室の視聴者から送信された集中砲火メッセージをキャプチャした後、OpenAI の ChatGPT サーバーに送信します
  • ChatGPT からの返信を受信した後、その返信内容はアバター音声を通じてブロードキャストされ、
    視聴者の観点から見ると、これは ChatGPT と同じ IQ を持つ仮想人物とのライブ インタラクションとなります。

2 この記事で使用するツール

3 ドッキングチャットGPT

ここで推奨される主なライブラリは 2 つあります。

  • チャットgpt-api
  • チャットチャット

chatgpt-api は bing ベースの chatgpt4.0 をカプセル化し、chatgpt は openAI の公式 chatgpt3.5 に基づいています。bing アカウントの作成方法、Cookie 値の取得方法、および apiKey の取得方法の詳細については、別の記事「ChatGPT4.0 を使用して誰でもアバター バーチャル ヒューマン ライブ ブロードキャストを行うことができます」を参照してください。

3.1 chatgpt-api

インストール:

npm i @waylaidwanderer/chatgpt-api

Bing は中国本土に対して chatgpt を公開していないため、プロキシが必要となるため、プロキシ アドレスを一緒にパッケージ化する必要があります。コードは以下のように表示されます。


import {
    
     BingAIClient } from '@waylaidwanderer/chatgpt-api';

export class BingGPT {
    
    
    /*
    * http_proxy, apiKey
    **/
    constructor(http_proxy, userCookie) {
    
    
        this.api = this.init(http_proxy, userCookie);
        this.conversationSignature = "";
        this.conversationId = "";
        this.clientId = "";
        this.invocationId = "";
    }
    init(http_proxy, userCookie) {
    
    
       console.log(http_proxy, userCookie)
        const options = {
    
     
            host: 'https://www.bing.com', 
            userToken: userCookie,
            // If the above doesn't work, provide all your cookies as a string instead
            cookies: '',
            // A proxy string like "http://<ip>:<port>"
            proxy: http_proxy,
            // (Optional) Set to true to enable `console.debug()` logging
            debug: false,
        };

        return new BingAIClient(options);
    }
    //
    //此处省略chat函数......
    //
} 

上記のコードは VPN と BingAIClient のカプセル化を完了しますが、チャット インターフェイスが欠けているため、チャット機能を追加してチャット機能を完成させます。

//调用chatpgt 
chat(text, cb) {
    
    
    var res=""
    var that = this;
    console.log("正在向bing发送提问", text ) 
    this.api.sendMessage(text, {
    
     
        toneStyle: 'balanced',
        onProgress: (token) => {
    
     
            if(token.length==2 && token.charCodeAt(0)==55357&&token.charCodeAt(1)==56842){
    
    
                cb(true, res);
            } 
            res+=token;
        }
    }).then(function(response){
    
     
        that.conversationSignature = response.conversationSignature;
        that.conversationId = response.conversationId;
        that.clientId = response.clientId;
        that.invocationId = response.invocationId;
    }) ;  

}

使用するときは次のように呼び出します。

var bing = new BingGPT(HTTP_PROXY, BING_USER_COOKIE);
bing.chat("这里传入提问内容XXXX?", function(succ, response){
    
    
    if(succ)
        console.log("回复内容:", response)
})

bing ベースの chatgpt4.0 は主にブラウザをシミュレートすることによってブロックされることに注意してください。ブラウザ側にはボット対策の検出機能がたくさんあるため、簡単にスタックしてしまいます。ここで著者は、これはユーザー自身の体験に限定されており、製品インターフェイスとしての使用には適していないことを示唆しています。製品にパッケージ化する必要がある場合は、次のセクションの 2.2 の内容を使用することをお勧めします。

3.2 チャットポイント

インストール:

npm install chatgpt

前のセクション 2.1 と同様に、openAI ベースの chatgpt3.5 を使用するにはラダーが必要です。chatgpt ライブラリにはプロキシ機能が組み込まれていないため、プロキシ ライブラリを自分でインストールできます。

npm install https-proxy-agent node-fetch

次に、プロキシと chatgpt ライブラリが統合され、1 つのクラスにカプセル化されます。

import {
    
     ChatGPTAPI } from "chatgpt";
import proxy from "https-proxy-agent";
import nodeFetch from "node-fetch";

export class ChatGPT {
    
    
  
    constructor(http_proxy, apiKey) {
    
    
        this.api = this.init(http_proxy, apiKey);
        this.conversationId = null;
        this.ParentMessageId = null;
    }
    init(http_proxy, apiKey) {
    
    
        console.log(http_proxy, apiKey)
        return new ChatGPTAPI({
    
    
            apiKey: apiKey,
            fetch: (url, options = {
     
     }) => {
    
    
                const defaultOptions = {
    
    
                    agent: proxy(http_proxy),
                };

                const mergedOptions = {
    
    
                    ...defaultOptions,
                    ...options,
                };

                return nodeFetch(url, mergedOptions);
            },
        });
    }
    //...
    //此处省略chat函数
    //...
} 

ChatGPTAPI のカプセル化が完了したら、チャット インターフェイスを追加します。

//调用chatpgt 
chat(text, cb) {
    
    
    let that = this
    console.log("正在向ChatGPT发送提问:", text)
    that.api.sendMessage(text, {
    
    
        conversationId: that.ConversationId,
        parentMessageId: that.ParentMessageId
    }).then(
        function (res) {
    
    
            that.ConversationId = res.conversationId
            that.ParentMessageId = res.id
            cb && cb(true, res.text)
        }
    ).catch(function (err) {
    
    
        console.log(err)
        cb && cb(false, err);
    });
}

使い方はとても簡単です:

var chatgpt =  new ChatGPT(HTTP_PROXY, API_KEY);
chatgpt.chat("这里传入提问内容XXXX?", function(succ, response){
    
    
    if(succ)
        console.log("回复内容:", response)
})

chatgpt ライブラリは主に openAI の公式インターフェイスに基づいており、比較的安定しているため、この方法で使用することをお勧めします。

3.3 2 つのライブラリを一緒にパッケージ化する

より柔軟で使いやすくするために、chatgpt3.5 と chatgpt4.0 を自由に切り替えてください。上記の 2 つのライブラリを 1 つのインターフェイスにカプセル化します。

まず、さまざまな構成を保存するためのファイル KeyCenter.js を作成します。

const HTTP_PROXY = "http://127.0.0.1:xxxx";//本地vpn代理端口
//openAI的key, 
const API_KEY = "sk-xxxxxxxxxxxxxxxxxxxxxxxxx";
//bing cookie
const BING_USER_COOKIE = 'xxxxxxxxxxxxxxxxxxxxxxxx--BA';

module.exports = {
    
     
    HTTP_PROXY: HTTP_PROXY,
    API_KEY: API_KEY,
    BING_USER_COOKIE:BING_USER_COOKIE
}

上記の関連する設定内容はリーダーによって置き換えられる必要があることに注意してください。

次に、chatGPT の 2 つの異なるバージョンをカプセル化します。

const KEY_CENTER = require("../KeyCenter.js");
var ChatGPTObj = null, BingGPTObj = null;
//初始化chatgpt
function getChatGPT(onInitedCb) {
    
    
    if (ChatGPTObj != null) {
    
    
        onInitedCb(true, ChatGPTObj);
        return;
    }
    (async () => {
    
    
        let {
    
     ChatGPT } = await import("./chatgpt.mjs");
        return new ChatGPT(KEY_CENTER.HTTP_PROXY, KEY_CENTER.API_KEY);
    })().then(function (obj) {
    
    
        ChatGPTObj = obj;
        onInitedCb(true, obj);
    }).catch(function (err) {
    
    
        onInitedCb(false, err);
    });
}

function getBingGPT(onInitedCb){
    
    
    if(BingGPTObj!=null) {
    
    
        onInitedCb(true, BingGPTObj);
        return;
    }
    (async () => {
    
    
        let {
    
     BingGPT } = await import("./binggpt.mjs");
        return new BingGPT(KEY_CENTER.HTTP_PROXY, KEY_CENTER.BING_USER_COOKIE);
    })().then(function (obj) {
    
    
        BingGPTObj = obj;
        onInitedCb(true, obj);
    }).catch(function (err) {
    
    
        console.log(err)
        onInitedCb(false, err);
    });
}

上記の 2 つの関数getBingGPTと、getChatGPTそれぞれに対応する2.1节カプセル2.2节化されたバージョン。バージョンを切り替えるときに、対応する関数を直接呼び出すこともできますが、エレガントさが足りないと思います。さまざまなオブジェクトをメンテナンスする必要があるため、まだ十分に快適には使用できません。さらにカプセル化することが最善であり、呼び出し時に 1 行のコードを使用することが最善です。次に、さらにカプセル化して、次のコードを追加します。

//调用chatgpt聊天
function chatGPT(text, cb) {
    
    
    getChatGPT(function (succ, obj) {
    
    
        if (succ) {
    
    
            obj.chat(text, cb);
        } else {
    
    
            cb && cb(false, "chatgpt not inited!!!");
        }
    })
}

function chatBing(text, cb){
    
    
    getBingGPT(function (succ, obj) {
    
    
        if (succ) {
    
    
            obj.chat(text, cb);
        } else {
    
    
            cb && cb(false, "chatgpt not inited!!!");
        }
    })

}

module.exports = {
    
    
    chatGPT: chatGPT,
    chatBing:chatBing
} 

上記のコードを追加すると、さらに快適になります。bing の chatgpt4.0 を使用したい場合は、chatBing 関数を呼び出すだけです。openAI の公式 chatgpt3.5 を使用したい場合は、chatGPT 関数を呼び出すだけです。

4 ドッキングアバター

4.1 基本的な考え方

さて、セクション 2 では、chatgpt のカプセル化について説明します。バージョンが異なれば、chatgpt との会話を実現するために異なる関数を呼び出すだけで済みます。次に、chatGPTのテキスト会話内容をAvatarに渡すにはどうすればよいでしょうか?Instant Avatar は、Instant によって発売された仮想画像製品で、インスタント メッセージング ZIM や音声およびビデオ通話 RTC など、Instant 内の他の製品と接続できます。これは扱いが簡単で、ZIM または RTC を使用するだけです。

インスタント ZIM はリアルタイムのテキスト コンテンツに非常に便利なので、ここでは主にインスタント ZIM を使用して実装します。つまり、ZIM グループ チャット メッセージは安定性と信頼性が高く、遅延が少なく、世界中のどの地域でも確実に到着するためのアクセス サービス ノードを備えています。

特にZIMのグループチャットには弾幕機能があり、チャットメッセージの送信に比べて弾幕メッセージの送信は保存されないため、生放送ルームでのコメント機能に適しています。

4.2 コードの実装

つまり、構造体が提供する公式のjs版ライブラリは主にブラウザベースとなっており、DOMやlocalStorageなどのブラウザの機能を利用する必要があります。そして、ここでは主に NodeJS に基づいており、ブラウザ環境はありません。したがって、必要なライブラリをいくつかインストールする必要がありますが、関連するライブラリは package.json にすでに記録されているので、次のコマンドを直接実行するだけです。

npm install

4.2.1 模擬ブラウザ環境の作成

まず、ブラウザ環境のシミュレーションを実行し、fake-indexeddb、jsdom、node-localstorage ライブラリを通じてブラウザ環境とローカル ストレージ環境をシミュレートします。WebSocket、XMLHttpRequest などのグローバル オブジェクトを作成します。

var fs = require('fs');
//先清理缓存
fs.readdirSync('./local_storage').forEach(function (fileName) {
    
    
    fs.unlinkSync('./local_storage/' + fileName);
});

const KEY_CENTER = require("../KeyCenter.js");
const APPID = KEY_CENTER.APPID, SERVER_SECRET = KEY_CENTER.SERVER_SECRET;
const generateToken04 = require('./TokenUtils.js').generateToken04;
var LocalStorage = require('node-localstorage').LocalStorage;
localStorage = new LocalStorage('./local_storage');
var indexedDB = require("fake-indexeddb/auto").indexedDB;
const jsdom = require("jsdom");
const {
    
     JSDOM } = jsdom;
const dom = new JSDOM(``, {
    
    
    url: "http://localhost/",
    referrer: "http://localhost/",
    contentType: "text/html",
    includeNodeLocations: true,
    storageQuota: 10000000
});
window = dom.window;
document = window.document;
navigator = window.navigator;
location = window.location;
WebSocket = window.WebSocket;
XMLHttpRequest = window.XMLHttpRequest;

4.2.2 ZIM オブジェクトの作成

近々正式にダウンロードされるindex.jsをインポートし、ZIMクラスを取得してインスタンス化し、この処理をcreateZIM関数にカプセル化します。なお、ログインにはトークンが必要ですが、セキュリティ上の理由からトークンはサーバー側で生成することを推奨します。次に、メッセージの受信をリッスンするための登録、トークンの有効期限の監視、リセットなどの初期化プロセス全体を initZego 関数にカプセル化します。

const ZIM = require('./index.js').ZIM; 

function newToken(userId) {
    
    
    const token = generateToken04(APPID, userId, SERVER_SECRET, 60 * 60 * 24, '');
    return token;
}
/**
 * 创建ZIM对象
*/
function createZIM(onError, onRcvMsg, onTokenWillExpire) {
    
    
    var zim = ZIM.create(APPID);
    zim.on('error', onError);
    zim.on('receivePeerMessage', function (zim, msgObj) {
    
    
        console.log("收到P2P消息")
        onRcvMsg(false, zim, msgObj)
    });
    // 收到群组消息的回调
    zim.on('receiveRoomMessage', function (zim, msgObj) {
    
    
        console.log("收到群组消息")
        onRcvMsg(true, zim, msgObj)
    });

    zim.on('tokenWillExpire', onTokenWillExpire);

    return zim;
}
/*
*初始化即构ZIM
*/
function initZego(onError, onRcvMsg, myUID) {
    
    
    var token = newToken(myUID);
    var startTimestamp = new Date().getTime();
    function _onError(zim, err) {
    
    
        onError(err);
    }
    function _onRcvMsg(isFromGroup, zim, msgObj) {
    
    
        var msgList = msgObj.messageList;
        var fromConversationID = msgObj.fromConversationID;
        msgList.forEach(function (msg) {
    
    
            if (msg.timestamp - startTimestamp >= 0) {
    
     //过滤掉离线消息
                var out = parseMsg(zim, isFromGroup, msg.message, fromConversationID)
                if (out)
                    onRcvMsg(out); 
            }
        })

    }
    function onTokenWillExpire(zim, second) {
    
    
        token = newToken(userId);
        zim.renewToken(token);
    }
    var zim = createZIM(_onError, _onRcvMsg, onTokenWillExpire);
    login(zim, myUID, token, function (succ, data) {
    
    
        if (succ) {
    
    
            console.log("登录成功!")

        } else {
    
    
            console.log("登录失败!", data)
        }
    })
    return zim;
}

4.2.3 ログイン、ルームの作成、ルームへの参加、ルームからの退出

zim オブジェクトの login 関数を呼び出してログインを完了し、ログイン関数にカプセル化します。zim オブジェクトの joinRoom を呼び出してルームへの参加を完了し、joinRoom 関数にカプセル化します。完了するには、zim オブジェクトの LeaveRoom 関数を呼び出します。ルームから出て、それを LeaveRoom 関数にカプセル化します。

/**
 * 登录即构ZIM
*/
function login(zim, userId, token, cb) {
    
    
    var userInfo = {
    
     userID: userId, userName: userId };

    zim.login(userInfo, token)
        .then(function () {
    
    
            cb(true, null);
        })
        .catch(function (err) {
    
    
            cb(false, err);
        });
}
/**
 * 加入房间
*/
function joinRoom(zim, roomId, cb = null) {
    
    
    zim.joinRoom(roomId)
        .then(function ({
     
      roomInfo }) {
    
    

            cb && cb(true, roomInfo);
        })
        .catch(function (err) {
    
    
            cb && cb(false, err);
        });
}
/**
 * 离开房间
*/
function leaveRoom(zim, roomId) {
    
    

    zim.leaveRoom(roomId)
        .then(function ({
     
      roomID }) {
    
    
            // 操作成功
            console.log("已离开房间", roomID)
        })
        .catch(function (err) {
    
    
            // 操作失败
            console.log("离开房间失败", err)
        });
}

4.2.4 メッセージの送信と解析

メッセージの送信は、1 対 1 の送信とルームへの送信に分けられ、以下の sendMsg 関数に示すように、ここでは isGroup パラメーターによって制御されます。受信したメッセージUIDと送信内容をsendMsgパラメータとして使用し、最終的にカプセル化してZIMのsendMessage関数を呼び出すことでメッセージ送信が完了します。

メッセージを受信した後、送信されたメッセージのコンテンツが json オブジェクトであることがアプリケーションに設定されるため、コンテンツを解析する必要があります。具体的な json 形式については、完全なソース コードを参照してください。説明は省略します。詳しくはこちら。

/**
 * 发送消息
*/
function sendMsg(zim, isGroup, msg, toUID, cb) {
    
     
    var type = isGroup ? 1 : 0; // 会话类型,取值为 单聊:0,房间:1,群组:2
    var config = {
    
    
        priority: 1, // 设置消息优先级,取值为 低:1(默认),中:2,高:3
    }; 
    var messageTextObj = {
    
     type: 20, message: msg, extendedData: '' };
    var notification = {
    
    
        onMessageAttached: function (message) {
    
     
            console.log("已发送", message)
        }
    } 
    zim.sendMessage(messageTextObj, toUID, type, config, notification)
        .then(function ({
     
      message }) {
    
    
            // 发送成功
            cb(true, null);
        })
        .catch(function (err) {
    
    
            // 发送失败
            cb(false, err)
        }); 
}
/**
 * 解析收到的消息
*/
function parseMsg(zim, isFromGroup, msg, fromUid) {
    
    
    //具体实现略
}

4.2.5 エクスポートインターフェイス

上記の実装では、キー関数のエクスポートが他のビジネス コールに公開されます。

module.exports = {
    
    
    initZego: initZego,
    sendMsg: sendMsg,
    joinRoom: joinRoom
}

上記のコードは主に以下をカプセル化します。

  1. インスタント ZIM 初期化
  2. メッセージを送ります
  3. 部屋に参加する

これまでのところ、chatgpt メッセージをルームに送信し、ルームに参加し、ルーム内で集中メッセージを受信する機能があります。

インスタント ZIM インターフェイスと公式デモの詳細については、ここをクリックしてください。インスタント ZIM の詳細については、ここをクリックしてください。

Avatar が chatgpt コンテンツをブロードキャストする方法については、次の記事で実装します。

5つの関連コード

  1. NodejsはchatgptとインスタントZIMにアクセスします

おすすめ

転載: blog.csdn.net/RTC_SDK_220704/article/details/130865916