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配置也在这篇文章里有所讲解,保证服务端及时输出内容到客户端。

相关推荐
未来之窗软件服务9 小时前
跨平台 WebSocket 服务器的设计与实现 —— 基于.NET 8 的跨操作系统解决方案linux,macos,windows——开发工具
linux·服务器·websocket·仙盟创梦ide·东方仙盟
何双新1 天前
基于Tornado的WebSocket实时聊天系统:从零到一构建与解析
python·websocket·tornado
陈琦鹏1 天前
轻松管理 WebSocket 连接!easy-websocket-client
前端·vue.js·websocket
小王子10241 天前
Django实时通信实战:WebSocket与ASGI全解析(下)
python·websocket·django
IT布道2 天前
解决angular与jetty websocket 每30s自动断连的问题
websocket·angular.js·jetty
程序员编程指南2 天前
Qt 网络编程进阶:WebSocket 通信
c语言·网络·c++·qt·websocket
@CodeMaster3 天前
websocket是什么?怎么用?
网络·websocket·网络协议