websocket请求通过IteratorAggregate实现流式输出

对接国内讯飞星火模型,官方文档接口采用的是websocket跟国外chatgpt有些差异。

虽然官网给出一个简单demo通过while(true),websocket的receive()可以实现逐条接受并输出给前端,但是通用和灵活度不高。不能兼容现有项目框架的流式输出。故模仿openai,采用IteratorAggregate接口实现迭代器可遍历获取响应结果。

IteratorAggregate只有一个需要实现的方法getIterator()实现起来简单方便,基本代码如下

php 复制代码
<?php
declare(strict_types=1);

namespace App\Extends;

use WebSocket\Client;
use IteratorAggregate;
use Generator;

class XingHuoClient
{
    protected $client;

    public function client(){
        $apikey = '';//自己填写真实内容
        $apiSecret = '';//自己填写真实内容
        $addr = '';//自己填写真实内容
        $authUrl = $this->assembleAuthUrl("GET",$addr,$apikey,$apiSecret);
        //创建ws连接对象
        $this->client = new Client($authUrl);
        return $this;
    }

    public function send($uid, array $message)
    {
        if($this->client){
            $data = $this->getBody($uid, $message);
            $this->client->send($data);
            $response = new XingResponseIterator($this->client);
            return $response;
        }else{
            throw new \Exception('星火客户端异常');
        }
    }

    //构造参数体
    protected function getBody($uid, $message){
        //...省略内容
        return $json_string;
    }

    //鉴权方法
    public function assembleAuthUrl($method, $addr, $apiKey, $apiSecret) {
        //...省略内容
        return $authAddr;
    }
}

class XingResponseIterator implements IteratorAggregate {

    protected $client;

    public function __construct($client) {
        $this->client = $client;
    }

    public function getIterator(): Generator {
        if($this->client){
            while(true){
                $response = $this->client->receive();
                $resp = json_decode($response,true);
                $code = $resp["header"]["code"];
                if(0 == $code){
                    $status = $resp["header"]["status"];
                    if($status != 2){
                        yield $resp['payload'];
                    }else{
                        yield $resp['payload'];
                        break;
                    }
                }else{
                    //TODO:记录错误日志或报警

                    break;
                }
            }
        }else{
            return [];
        }
    }
}

前提引入composer require textalk/websocket包用于socket请求星火接口,大部分内容还是官网提供的demo,主要是增加了XingResponseIterator 。

php 复制代码
$stream = xinghuo()->client()->send($uid, $messages);//xinghuo()是封装的XingHuoClient对象
foreach($stream as $response){
    //处理数据,格式化数据,统计,记录等操作,输出内容到响应流,此处不做细讲
}

输出形式可以分流式输出,以openai为例参考:

https://github.com/orhanerday/open-ai

https://packagist.org/packages/hhxsv5/php-sse

前端浏览器使用的是EventSource对象。

可以使用chunk形式,存在客户端不支持eventSource对象的情况可以选择使用,参考我的另一篇文章

https://blog.csdn.net/jinborui2/article/details/132325824

以及一些nginx配置和php配置也在这篇文章里有所讲解,保证服务端及时输出内容到客户端。

相关推荐
半桶水专家4 小时前
用go实现创建WebSocket服务器
服务器·websocket·golang
FeelTouch Labs5 小时前
Netty实现WebSocket Server是否开启压缩深度分析
网络·websocket·网络协议
代码魔法师Sunny3 天前
4.WebSocket 配置与Nginx 的完美结合
websocket·网络协议
kunkun1013 天前
关于Websocket
网络·websocket·网络协议
flying robot4 天前
websocket的使用
websocket
azheng2225 天前
WebSocket消息帧的组成结构
websocket
._Ha!n.5 天前
WebSocket实现消息实时推送
网络·websocket·网络协议
蜀中孤鹰6 天前
由浅入深逐步理解spring boot中如何实现websocket
spring boot·后端·websocket
测试界的酸菜鱼6 天前
C# 如何处理 WebSocket 连接异常
开发语言·websocket·c#
布兰妮甜6 天前
WebSocket详解:从前端到后端的全栈理解
前端·websocket·网络协议