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


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

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

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

    1. declare(strict_types=1);
    2. namespace App\Extends;
    3. use WebSocket\Client;
    4. use IteratorAggregate;
    5. use Generator;
    6. class XingHuoClient
    7. {
    8. protected $client;
    9. public function client(){
    10. $apikey = '';//自己填写真实内容
    11. $apiSecret = '';//自己填写真实内容
    12. $addr = '';//自己填写真实内容
    13. $authUrl = $this->assembleAuthUrl("GET",$addr,$apikey,$apiSecret);
    14. //创建ws连接对象
    15. $this->client = new Client($authUrl);
    16. return $this;
    17. }
    18. public function send($uid, array $message)
    19. {
    20. if($this->client){
    21. $data = $this->getBody($uid, $message);
    22. $this->client->send($data);
    23. $response = new XingResponseIterator($this->client);
    24. return $response;
    25. }else{
    26. throw new \Exception('星火客户端异常');
    27. }
    28. }
    29. //构造参数体
    30. protected function getBody($uid, $message){
    31. //...省略内容
    32. return $json_string;
    33. }
    34. //鉴权方法
    35. public function assembleAuthUrl($method, $addr, $apiKey, $apiSecret) {
    36. //...省略内容
    37. return $authAddr;
    38. }
    39. }
    40. class XingResponseIterator implements IteratorAggregate {
    41. protected $client;
    42. public function __construct($client) {
    43. $this->client = $client;
    44. }
    45. public function getIterator(): Generator {
    46. if($this->client){
    47. while(true){
    48. $response = $this->client->receive();
    49. $resp = json_decode($response,true);
    50. $code = $resp["header"]["code"];
    51. if(0 == $code){
    52. $status = $resp["header"]["status"];
    53. if($status != 2){
    54. yield $resp['payload'];
    55. }else{
    56. yield $resp['payload'];
    57. break;
    58. }
    59. }else{
    60. //TODO:记录错误日志或报警
    61. break;
    62. }
    63. }
    64. }else{
    65. return [];
    66. }
    67. }
    68. }

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

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

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

  • 相关阅读:
    C#语言async, await 简单介绍与实例(入门级)
    2021-07-15-2021年全球10大最佳单板计算机开发板(SBC)(第1-3名)
    openGauss学习笔记-92 openGauss 数据库管理-内存优化表MOT管理-内存表特性-使用MOT-MOT使用MOT SQL覆盖和限制
    QT多线程项目中子线程无法修改主线程的ui组件
    【C++】函数模版和类模版详解
    Matlab 实用代码集
    英文网站的优化怎么判断是否到位
    matlab画图常用函数image、imagesc、imshow区别
    结合对称加密、非对称加密浅析HTTPS协议
    Go语言学习(三)-- 派生数据类型
  • 原文地址:https://blog.csdn.net/jinborui2/article/details/132970863