openAI 通过php方式 发送请求,流数据形式传输,php 实现chatGPT功能

书接上文,如何在PHP中对接openAI接口

  • PHP调用OpenAI API的方法
    • js文件

PHP调用OpenAI API的方法

此处使用的框架是 symfony ,可自行根据自己框架开发,大同小异,框架无所谓,主要是功能!
先上代码

<?php
namespace LdWxappPlugin\Api\Resource\Chatapi;
use ApiBundle\Api\ApiRequest;
use ApiBundle\Api\Resource\AbstractResource;
use ApiBundle\Api\Annotation\ApiConf;
use AppBundle\Common\ArrayToolkit;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
class ChatapiConversation extends AbstractResource
{protected $host = 'http://*.*.*.*'; // 服务器地址protected $uri = '/v1/chat/completions'; // 调用的接口地址protected $authKey = 'Basic c2VjcmV********'; // api鉴权的keyprotected $message = '';protected $sources = [];protected $conversationId = ''; protected $currentMessage='';/*** @var array|mixed*/private $document;/*** @param ApiRequest $request* @param $conversationId 会话id*/// 前端输入完信息,发送时调用的请求public function add(ApiRequest $request,$conversationId){$this->verifySend();$this->conversationId = $conversationId;//刷新缓冲区ob_implicit_flush(true);ob_end_flush();$response = new StreamedResponse();// 设置响应头,指定Content-Type为text/event-stream$response->headers->set('Content-Type', 'text/event-stream');$response->headers->set('Cache-Control', 'no-cache');$response->headers->set('Charset', 'UTF-8');$response->headers->set('X-Accel-Buffering', 'no');$params = $request->request->all();$aiParams = $this->filterAiParams($params);//插入用户消息$this->getChatApiConversationService()->addUserMessage($this->conversationId,$aiParams);// 设置响应内容生成器$response->setCallback(function () use ($request,$aiParams) {$this->forwardAiRequest($aiParams);});// 发送响应$response->send();}public function update(ApiRequest $request,$conversationId,$flag){$params = $request->request->all();$message = $params['messages']['0']['content'] ?? '';$result = $this->getChatApiConversationService()->addAiMessage($conversationId,['message'=>$message],'');if ($result){return ['status'=>'success','message'=>'补充消息成功','code'=> 1,"data"=>['messageId'=>$result['id']] ];} else {return ['status'=>'fail','message'=>'补充消息成功','code'=> 0];}}/*** @param $chunk* @return string*/public function formatAiResponse($chunk){if($chunk == "Internal Server Error"){throw new BadRequestHttpException("AI好像开小差了~请联系客服");}//替换掉data:$chunkJsonStr = trim(str_replace('data:','',$chunk));$isComplete = json_decode($this->currentMessage,true);if($isComplete == null){$this->currentMessage .= $chunkJsonStr;} else {$this->currentMessage = $chunkJsonStr;}if($chunkJsonStr !='[DONE]'){//这里会出现单条消息超限多条消息拼接的情况,$chunkArr = json_decode($this->currentMessage,true);if (!$chunkArr){return null;}$this->currentMessage = '';$originMessage = $chunkArr['choices'][0]['delta']['content'] ?? '';//拼接当前条消息数据$this->message .= $originMessage;//赋值引用文档if($chunkArr['choices'][0]['sources']){$this->document = $chunkArr['choices'][0]['sources'];}//重新拼装前端结构$customChunkArr = ["status"=>"going","content"=>$originMessage];return "data: ".json_encode($customChunkArr,JSON_UNESCAPED_UNICODE)."\n\n";} else {//传输结束,这里处理数据入库$this->message$sources = $this->getTaskByPageLabel($this->document);$insertData = ['message' => $this->message,"sourceFrom" => json_encode($sources,JSON_UNESCAPED_UNICODE)];//这里判断是否当前课程学员//先查出当前会话对应goods$conversation = $this->getChatApiService()->findByConversationId($this->conversationId);$isMember = false;$id = $conversation[0]['goodsId'] ?? 0;if($id !== 0){//查询当goods_$goodsApiRequest = new ApiRequest("/api/goods/{$id}", 'GET', []);try{$goods = $this->container->get('api_resource_kernel')->handleApiRequest($goodsApiRequest);$isMember = $goods['isMember'];}catch(\Exception $e){$catchFlag = 1;}}//根据taskId查询task$originData = json_encode(['message'=>$this->message,'sources'=>$this->document],JSON_UNESCAPED_UNICODE);$result = $this->getChatApiConversationService()->addAiMessage($this->conversationId,$insertData,$originData);return "data: ".json_encode(["status"=>"done","finishData"=>['id'=>$result['id'],"sourceFrom"=>$sources,"isMember"=>$isMember]],JSON_UNESCAPED_UNICODE)."\n\n";}}//前置验证protected function verifySend(){$userId = $this->getCurrentUser()->getId();if (!$userId){//登录验证throw new BadRequestHttpException("请先登录");}$factory = $this->biz->offsetGet('ratelimiter.factory');$rateLimiter = $factory('chat_send_message', 5, 60);$remained = $rateLimiter->check($userId);if (!$remained) {throw new BadRequestHttpException("发送过于频繁请于1分钟后重试");}}public function filterAiParams($params){if(!$params['messages'] || $params['conversationId']){throw new BadRequestHttpException("缺失必要参数");}$params['stream'] = true;$params['use_context'] = true;$params['include_sources'] = true;return $params;}public function forwardAiRequest($params){$curl = curl_init();curl_setopt_array($curl, array(CURLOPT_URL => $this->host.$this->uri,CURLOPT_RETURNTRANSFER => true,CURLOPT_ENCODING => '',CURLOPT_MAXREDIRS => 10,CURLOPT_TIMEOUT => 0,CURLOPT_FOLLOWLOCATION => true,CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,CURLOPT_CUSTOMREQUEST => 'POST',CURLOPT_POSTFIELDS => json_encode($params),CURLOPT_HTTPHEADER => array('Accept: application/json','Authorization: '.$this->authKey,'Content-Type: application/json'),// 启用流式传输模式));curl_setopt($curl, CURLOPT_BUFFERSIZE, 16384);curl_setopt($curl, CURLOPT_WRITEFUNCTION, function ($ch, $chunk) {// 处理接收到的流式数据$echoStream = $this->formatAiResponse($chunk);if ($echoStream != null){echo $echoStream;}flush();return strlen($chunk);});$response = curl_exec($curl);curl_close($curl);// echo $response;}//根据map,page_label获取taskprotected function getTaskByPageLabel($sources){$tasks = [];if($sources){foreach ($sources as $source){$pageLabel = $source['document']['doc_metadata']['page_label'] ?? 0;$score = $source['score'] ?? 0;if ($pageLabel && $score>0.5){$task = self::getPageTaskMap()[$pageLabel];$taskInfo = $this->getTaskService()->getTask($task['taskId']);$task['courseId'] = $taskInfo['courseId'];$tasks[] = $task;}}}return array_unique($tasks);}//page与task映射map,先写死实现功能static protected function getPageTaskMap(){//page_label => taskInforeturn  [1 => ['taskId'=>51147,'taskTitle'=>"课时1:课程概述、特点及说明",],2 => ['taskId'=>51148,'taskTitle'=>"课时2:资产配置概述、均值方差模型配置法的 GPT 应用",],3 => ['taskId'=>51148,'taskTitle'=>"课时2:资产配置概述、均值方差模型配置法的 GPT 应用",],4 => ['taskId'=>51148,'taskTitle'=>"课时2:资产配置概述、均值方差模型配置法的 GPT 应用",],5 => ['taskId'=>51149,'taskTitle'=>"课时3:Black-Litterman 策略、风险平价策略介绍及GPT 应用",],6 => ['taskId'=>51149,'taskTitle'=>"课时3:Black-Litterman 策略、风险平价策略介绍及GPT 应用",],7 => ['taskId'=>51149,'taskTitle'=>"课时3:Black-Litterman 策略、风险平价策略介绍及GPT 应用",],8 => ['taskId'=>51150,'taskTitle'=>"课时4:Black-Litterman 策略、风险平价策略介绍及GPT 应用",],9 => ['taskId'=>51150,'taskTitle'=>"课时4:Black-Litterman 策略、风险平价策略介绍及GPT 应用",],10 => ['taskId'=>51151,'taskTitle'=>"课时5:基金分类、标签体系、收益风险指标分析",],11 => ['taskId'=>51151,'taskTitle'=>"课时5:基金分类、标签体系、收益风险指标分析",],12 => ['taskId'=>51152,'taskTitle'=>"课时6:基金投资体验分析和投资风格分析",],13 => ['taskId'=>51152,'taskTitle'=>"课时6:基金投资体验分析和投资风格分析",],14 => ['taskId'=>51152,'taskTitle'=>"课时6:基金投资体验分析和投资风格分析",],15 => ['taskId'=>51153,'taskTitle'=>"课时7:基金插件工具介绍及营销文案编写",],16 => ['taskId'=>51154,'taskTitle'=>"课时8:历史事件复盘",],17 => ['taskId'=>51155,'taskTitle'=>"课时9:近期市场、经济复盘",],18 => ['taskId'=>51156,'taskTitle'=>"课时10:未来经济展望",],20 => ['taskId'=>51157,'taskTitle'=>"课时11:PPI 时间序列预测",],21 => ['taskId'=>51158,'taskTitle'=>"课时12:周期划分到策略适配",],22 => ['taskId'=>51174,'taskTitle'=>"课时13:金融数据分析简介",],23 => ['taskId'=>51175,'taskTitle'=>"课时14:调研问卷分析案例",],24 => ['taskId'=>51175,'taskTitle'=>"课时14:调研问卷分析案例",],25 => ['taskId'=>51176,'taskTitle'=>"课时15:金融客户机器学习分群案例",],26 => ['taskId'=>51176,'taskTitle'=>"课时15:金融客户机器学习分群案例",],27 => ['taskId'=>51177,'taskTitle'=>"课时16:财经公众号内容提取案例",],28 => ['taskId'=>51178,'taskTitle'=>"课时17:筛选符合减持新规的股票",],29 => ['taskId'=>51159,'taskTitle'=>"课时18:数据提取:基金历史业绩(附 Noteable 插件介绍)",],30 => ['taskId'=>51159,'taskTitle'=>"课时18:数据提取:基金历史业绩(附 Noteable 插件介绍)",],31 => ['taskId'=>51160,'taskTitle'=>"课时19:数据提取:基金基础信息",],32 => ['taskId'=>51161,'taskTitle'=>"课时20:数据提取:基金基础信息",],33 => ['taskId'=>51162,'taskTitle'=>"课时21:数据分析:持仓数据图表化",],34 => ['taskId'=>51163,'taskTitle'=>"课时22:数据分析:持仓数据分析",],35 => ['taskId'=>51163,'taskTitle'=>"课时22:数据分析:持仓数据分析",],36 => ['taskId'=>51164,'taskTitle'=>"课时23:数据分析:文字描述生成",],37 => ['taskId'=>51165,'taskTitle'=>"课时24:数据分析:大类资产配比计算及增配建议",],38 => ['taskId'=>51166,'taskTitle'=>"课时25:数据分析:基金持仓行业分布",],39 => ['taskId'=>51167,'taskTitle'=>"课时26:内容生成:宏观经济与市场分析(及 KeyMate插件介绍)",],40 => ['taskId'=>51167,'taskTitle'=>"课时26:内容生成:宏观经济与市场分析(及 KeyMate插件介绍)",],41 => ['taskId'=>51168,'taskTitle'=>"课时27:内容生成:行业分析",],42 => ['taskId'=>51169,'taskTitle'=>"课时28:内容生成:基金分析",],43 => ['taskId'=>51170,'taskTitle'=>"课时29:风格适配:结构化 Prompt",],44 => ['taskId'=>51171,'taskTitle'=>"课时30:风风格适配:Custom Instructions",],45 => ['taskId'=>51172,'taskTitle'=>"课时31:风风格适配:Custom Instructions",],46 => ['taskId'=>51173,'taskTitle'=>"课时 32: 资产配置报告展示",],47 => ['taskId'=>51173,'taskTitle'=>"课时 32: 资产配置报告展示",],];}protected function getTaskService(){return $this->service('Task:TaskService');}private function getProductService(){return $this->service('Product:ProductService');}public function getGoodsService(){return $this

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/630643.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue学习笔记8--插槽<slot></slot>

一、作用 让父组件可以向子组件指定的位置插入html结构&#xff0c;&#xff0c;也是一种组件间通信的方式&#xff0c;适用于父组件》子组件。二、分类&#xff1a; 默认插槽具名插槽作用域插槽 三、使用方法 1. 默认插槽 父组件中&#xff1a; <Category><div…

uni-app qiun-data-charts无法显示tooltip

如下代码无法使得图表展示tooltip <template><view style"overflow: hidden; background-color: #fff;box-sizing: border-box; border-radius: 5px; box-shadow: 4px 2px 6px #ccc;padding: 10px; position:relative;"><view style"font-weigh…

Ubuntu20.4 Mono C# gtk 编程习练笔记(二)

界面设计习练后&#xff0c;下面写一些程序设计心得。 程序结构 先看一下程序总体结构&#xff0c;先在program.cs中找到main入口&#xff0c;在命名空间下是MainClass类&#xff0c;Main函数进入后首先建立应用程序环境 Application.Init&#xff0c;然后对MainWindow进行实…

【嘉立创EDA-PCB设计指南】3.网络表概念解读+板框绘制

前言&#xff1a;本文对网络表概念解读板框绘制&#xff08;确定PCB板子轮廓&#xff09; 网络表概念解读 在本专栏的上一篇文章【嘉立创EDA-PCB设计指南】2&#xff0c;将设计的原理图转为了PCB&#xff0c;在PCB界面下出现了所有的封装&#xff0c;以及所有的飞线属性&…

What is `StringEscapeUtils.escapeHtml4` does?

StringEscapeUtils.escapeHtml4 作用是将特殊字符转换为它们对应的HTML实体形式&#xff0c;从而防止这些字符在网页中被解析为HTML标签或脚本&#xff0c;有助于防止跨站脚本攻击&#xff08;XSS, Cross-Site Scripting&#xff09; 依赖 <!--org.apache.commons.text.St…

【开源】基于JAVA语言的智慧家政系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、系统展示四、核心代码4.1 查询家政服务4.2 新增单条服务订单4.3 新增留言反馈4.4 小程序登录4.5 小程序数据展示 五、免责说明 一、摘要 1.1 项目介绍 基于微信小程序JAVAVueSpringBootMySQL的智慧家政系统&#xff0…

【Docker】安装 Nginx 容器并部署前后端分离项目

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是Java方文山&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的专栏《Docker实战》。&#x1f3af;&#x1f3af; &…

GRU门控循环单元神经网络的MATLAB实现(含源代码)

在深度学习领域&#xff0c;循环神经网络&#xff08;RNN&#xff09;因其在处理序列数据方面的卓越能力而受到广泛关注。GRU&#xff08;门控循环单元&#xff09;作为RNN的一种变体&#xff0c;以其在捕捉时间序列长距离依赖关系方面的高效性而备受推崇。在本文中&#xff0c…

SpringBoot 中使用 Quartz 创建定时任务

文章目录 一、使用示例二、运行原理 一、使用示例 自定义 job&#xff1a; Slf4j public class MyJob extends QuartzJobBean {Overrideprotected void executeInternal(JobExecutionContext context) throws JobExecutionException {log.info("MyJob start...");l…

JavaWeb后端——Maven

maven主要服务于基于Java平台的项目构建、依赖管理和项目信息管理 maven项目对象模型简称POM&#xff0c; maven解决问题&#xff1a; 1. 添加第三方jar包&#xff0c;maven将 jar 包放在本地仓库中统一管理&#xff0c;使用时用坐标的方式引用即可 2. 解决 jar 包之间的依…

Facebook与环境保护:社交媒体的可持续发展

在当今社会&#xff0c;科技发展日新月异&#xff0c;而社交媒体作为数字时代的代表之一&#xff0c;正面临着巨大的责任与机遇。随着全球环境问题的凸显&#xff0c;社交媒体平台如Facebook也逐渐认识到自身在环保可持续发展中的角色。本文将深入探讨Facebook在环境保护方面的…

统计学-R语言-5.3

文章目录 前言分位数统计量的标准误总结 前言 本篇文章即为概率与分布的最后一篇文章。 分位数 分位数函数是累积分布函数的反函数。 p-分位数是具有这样性质的一个值&#xff1a;小于或等于它的概率为p。 根据定义&#xff0c;中位数即50%分位数。 分位数通常用于置信区间的…

vite 打包优化

✨专栏介绍 在当今数字化时代&#xff0c;Web应用程序已经成为了人们生活和工作中不可或缺的一部分。而要构建出令人印象深刻且功能强大的Web应用程序&#xff0c;就需要掌握一系列前端技术。前端技术涵盖了HTML、CSS和JavaScript等核心技术&#xff0c;以及各种框架、库和工具…

【机器学习实例讲解】机器学习-鸢尾花数据集多分类第02课

问题定义与理解&#xff1a; 明确机器学习任务的目标&#xff0c;是分类、回归、聚类、强化学习还是其他类型的问题。 确定业务背景和需求&#xff0c;了解所处理数据的现实意义。 数据收集&#xff1a; 根据任务目标从各种来源获取原始数据&#xff0c;可以是数据库、文件、…

SQL 查询两个时间段是否有交集的情况 三种写法

mysql 写法 其他一样 数据库的字段 start_time, end_time 输入的字段 a,b 第一种 SELECT * FROM test_table WHERE(start_time > a AND start_time < b)OR (start_time < a AND end_time > b)OR (end_time > a AND end_time < b) 第二种 SELECT * FROM …

Spring5深入浅出篇:Spring与工厂设计模式简介

Spring5深入浅出篇:Spring与工厂设计模式简介 什么是Spring Spring是⼀个轻量级的JavaEE解决⽅案&#xff0c;整合众多优秀的设计模式轻量级 1. 对于运⾏环境是没有额外要求的开源 tomcat resion jetty收费 weblogic websphere 2. 代码移植性⾼不需要实现额外接⼝JavaEE的解…

Bing AI:探索人工智能搜索引擎Bing Chat工具

Microsoft 更新了其搜索引擎 Bing&#xff0c;采用了由 OpenAI 的 GPT-4 模型提供支持的人工智能 &#xff08;AI&#xff09; 技术。 这意味着您现在可以与 Bing 聊天。而且&#xff0c;除了常规的链接列表外&#xff0c;搜索引擎还可以汇总互联网上的数据来回答您的问题。 …

架构篇04-复杂度来源:高性能

文章目录 单机复杂度集群的复杂度小结 从本篇开始&#xff0c;我们一起深入分析架构设计复杂度的 6 个来源&#xff0c;先来聊聊复杂度的来源之一高性能。 对性能孜孜不倦的追求是整个人类技术不断发展的根本驱动力。例如计算机&#xff0c;从电子管计算机到晶体管计算机再到集…

VL171 VL170配合LDR6020的type-c母座显示器方案

兼容基于VASEL控制引脚的10 Gbps USB3.2 Gen2和AM所有4通道视频&#xff0c;包括DP1.4 8.1 Gbps VL171配合LDR6020实现的type-c桌面显示器方案电路LDR6020是一个DRP的PD芯片&#xff0c;PD芯片与主机通讯完之后&#xff0c;通过PD芯片去控制VL171实现正反插与USB信号和DP信号的…

31 3D日历组件

效果演示 实现了一个3D文字旋转的效果&#xff0c;当鼠标悬停在容器上时&#xff0c;最后一个文字会旋转630度&#xff0c;而其他文字会逐渐旋转到水平面上方。 Code <div class"container"><div class"text" style"--j:0;"><sp…