公共方法
This commit is contained in:
@@ -3,6 +3,8 @@ namespace app\common;
|
||||
use think\Cache;
|
||||
use think\Db;
|
||||
use think\Queue;
|
||||
use app\common\Article;
|
||||
use app\common\QueueRedis;
|
||||
class OpenAi
|
||||
{
|
||||
protected $sApiKey = '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';
|
||||
@@ -65,20 +67,21 @@ class OpenAi
|
||||
];
|
||||
//定义redis连接
|
||||
private $redis;
|
||||
private $oQueueRedis;
|
||||
public function __construct()
|
||||
{
|
||||
|
||||
// 初始化 Redis 连接
|
||||
$config = \think\Config::get('queue');
|
||||
$this->redis = new \Redis();
|
||||
$this->redis->connect($config['host'], $config['port']);
|
||||
|
||||
if (!empty($config['password'])) {
|
||||
$this->redis->auth($config['password']);
|
||||
}
|
||||
|
||||
$this->redis->select($config['select']);
|
||||
// 初始化 Redis 连接
|
||||
// $this->redis = Cache::store('redis')->handler();
|
||||
$this->redis->select($config['select']);
|
||||
|
||||
$this->oQueueRedis = QueueRedis::getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -341,205 +344,6 @@ class OpenAi
|
||||
curl_close($this->curl);
|
||||
return json_encode(['status' => 1,'msg' => 'success','data' => $aContent]);
|
||||
}
|
||||
/**
|
||||
* 对接OPENAI接口-并行CURL请求【重要维度单独询问】
|
||||
*/
|
||||
public function curlMultiOpenAIImportant($aSearch = [],$timeout = 120, $iChunkSize = 2) {
|
||||
// 入参校验
|
||||
if (empty($aSearch)) {
|
||||
return json_encode(['status' => 2, 'msg' => 'Parameter is empty']);
|
||||
}
|
||||
//提问问题类型
|
||||
$sKey = empty($aSearch['question']) ? '' : $aSearch['question'];
|
||||
if (empty($sKey)) {
|
||||
return json_encode(['status' => 2, 'msg' => 'Please select the type of question']);
|
||||
}
|
||||
//获取问题
|
||||
$aQuestion = $this->$sKey;
|
||||
if (empty($aQuestion)) {
|
||||
return json_encode(['status' => 2, 'msg' => 'question is empty']);
|
||||
}
|
||||
|
||||
//分批处理(核心优化:控制并发量)
|
||||
$aChunk = array_chunk($aQuestion, $iChunkSize); // 按批次拆分,每批最多5个请求
|
||||
//定义空数组用于接收数据
|
||||
$aEmptyData = $aLog = $aReturnData = [];
|
||||
//分批次处理开始
|
||||
foreach ($aChunk as $iChunkKey => $item) {
|
||||
// 初始化多curl句柄
|
||||
$oCurlMulti = curl_multi_init();
|
||||
$aCurl = [];
|
||||
// 批量初始化请求
|
||||
foreach ($item as $key => $value) {
|
||||
// 跳过无效参数
|
||||
if (empty($value)) {
|
||||
$aLog[] = [
|
||||
'content' => $iChunkKey.'-'.$key.':Invalid parameter'
|
||||
];
|
||||
continue;
|
||||
}
|
||||
//问题处理-变量替换
|
||||
$aQuestionInfo = $this->buildReviewPromptImportant($aSearch,$value);
|
||||
if(empty($aQuestionInfo)){
|
||||
$aLog[] = [
|
||||
'content' => $iChunkKey.'-'.$key.':The problem is empty:'.json_encode($value)
|
||||
];
|
||||
continue;
|
||||
}
|
||||
// 核心配置优化
|
||||
$oCurl = curl_init();
|
||||
curl_setopt_array($oCurl, [
|
||||
CURLOPT_URL => $this->sUrl,
|
||||
CURLOPT_HTTPHEADER => [
|
||||
'Content-Type: application/json',
|
||||
'Authorization: Bearer ' . $this->sApiKey,
|
||||
'Expect:',
|
||||
],
|
||||
CURLOPT_PROXY => $this->proxy,
|
||||
// SSL验证优化:若代理证书不可信,临时关闭(生产环境需配置信任证书)
|
||||
CURLOPT_SSL_VERIFYPEER => true, // 调试时设为false,生产环境设为true
|
||||
CURLOPT_SSL_VERIFYHOST => 2, // 调试时设为0,生产环境设为2
|
||||
CURLOPT_POST => true,
|
||||
CURLOPT_POSTFIELDS => json_encode($aQuestionInfo),
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
// 超时优化:延长响应超时,新增连接超时
|
||||
CURLOPT_TIMEOUT => $timeout, // 总超时(秒),建议60-120
|
||||
CURLOPT_CONNECTTIMEOUT => 20, // 连接超时(秒),避免无限等待
|
||||
CURLOPT_LOW_SPEED_LIMIT => 1024, // 最低速度(字节/秒),低于此值触发超时
|
||||
CURLOPT_LOW_SPEED_TIME => 30, // 持续低速时间(秒),超过则终止
|
||||
]);
|
||||
curl_multi_add_handle($oCurlMulti, $oCurl);
|
||||
$aCurl[$key] = $oCurl;
|
||||
}
|
||||
// 空请求处理
|
||||
if (empty($aCurl)) {
|
||||
curl_multi_close($oCurlMulti);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 核心优化:修复curl_multi循环逻辑,确保所有请求完成
|
||||
$active = null;
|
||||
$mrc = CURLM_OK;
|
||||
// 第一阶段:处理瞬时可完成的请求
|
||||
do {
|
||||
$mrc = curl_multi_exec($oCurlMulti, $active);
|
||||
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
|
||||
|
||||
// 第二阶段:等待所有活跃请求完成(关键优化)
|
||||
while ($active > 0 && $mrc == CURLM_OK) {
|
||||
// 等待事件(超时1秒,避免CPU空转)
|
||||
if (curl_multi_select($oCurlMulti, 1.0) != -1) {
|
||||
// 处理就绪的请求
|
||||
do {
|
||||
$mrc = curl_multi_exec($oCurlMulti, $active);
|
||||
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
|
||||
} else {
|
||||
// 无事件时,检查是否超时(防止无限阻塞)
|
||||
$timedOut = false;
|
||||
foreach ($aCurl as $oCurl) {
|
||||
$startTime = curl_getinfo($oCurl, CURLINFO_STARTTRANSFER_TIME);
|
||||
if ($startTime > 0 && (microtime(true) - $startTime) > $timeout) {
|
||||
$timedOut = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($timedOut) break; // 超时则强制退出
|
||||
}
|
||||
}
|
||||
|
||||
// 处理当前批次结果
|
||||
foreach ($aCurl as $key => $oCurl) {
|
||||
// 1. 捕获curl错误(连接失败、超时等)
|
||||
$sError = curl_error($oCurl);
|
||||
if (!empty($sError)) {
|
||||
$aLog[] = [
|
||||
'content' => "Curl error: {$sError}"
|
||||
];
|
||||
$aEmptyData[] = $key;
|
||||
curl_multi_remove_handle($oCurlMulti, $oCurl);
|
||||
curl_close($oCurl);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 2. 获取HTTP状态码(关键优化:处理OpenAI的API错误)
|
||||
$httpCode = curl_getinfo($oCurl, CURLINFO_HTTP_CODE);
|
||||
$sContent = curl_multi_getcontent($oCurl);
|
||||
// 3. 处理非200状态码(如限流、服务不可用)
|
||||
if ($httpCode != 200) {
|
||||
$errorMsg = "HTTP {$httpCode}: " . (empty($sContent) ? 'No response' : $sContent);
|
||||
// 记录关键错误日志(便于调试)
|
||||
$aLog[] = [
|
||||
'http_code' => $httpCode,
|
||||
'content' => $errorMsg,
|
||||
];
|
||||
$aEmptyData[] = $key;
|
||||
curl_multi_remove_handle($oCurlMulti, $oCurl);
|
||||
curl_close($oCurl);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 4. 解析响应内容(原逻辑优化)
|
||||
$aResult = json_decode($sContent, true);
|
||||
if (json_last_error() != JSON_ERROR_NONE) {
|
||||
$aLog[] = [
|
||||
'content' => "Invalid JSON: {$sContent}",
|
||||
];
|
||||
$aEmptyData[] = $key;
|
||||
curl_multi_remove_handle($oCurlMulti, $oCurl);
|
||||
curl_close($oCurl);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 5. 提取OpenAI的content(简化判断逻辑)
|
||||
$aOpenAiContent = empty($aResult['choices'][0]['message']['content']) ? '' : $aResult['choices'][0]['message']['content'];
|
||||
if (empty($aOpenAiContent)) {
|
||||
$aLog[] = [
|
||||
'content' => "OPENAI returns empty content",
|
||||
];
|
||||
$aEmptyData[] = $key;
|
||||
curl_multi_remove_handle($oCurlMulti, $oCurl);
|
||||
curl_close($oCurl);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 6. 处理业务解析(原extractAndParse逻辑)
|
||||
$aData = $this->extractAndParse($aOpenAiContent);
|
||||
$aContent = empty($aData['data']) ? [] : $aData['data'];
|
||||
$sMsg = empty($aData['msg']) ? 'Success' : $aData['msg'];
|
||||
if (empty($aContent)) {
|
||||
$aEmptyData[] = $key;
|
||||
}
|
||||
$aLog[] = [
|
||||
'content' => $sMsg,
|
||||
];
|
||||
$aReturnData += $aContent;
|
||||
// 释放资源
|
||||
curl_multi_remove_handle($oCurlMulti, $oCurl);
|
||||
curl_close($oCurl);
|
||||
}
|
||||
|
||||
// 关闭当前批次的multi句柄
|
||||
curl_multi_close($oCurlMulti);
|
||||
// 批次间隔(核心优化:避免触发OpenAI限流)
|
||||
if ($iChunkKey < count($aChunk) - 1) {
|
||||
usleep(1000000); // 批次间间隔1秒(根据OpenAI配额调整)
|
||||
}
|
||||
}
|
||||
$aParam = [
|
||||
'status' => 1,
|
||||
'msg' => 'success',
|
||||
'data' => empty($aReturnData) ? [] : $aReturnData,
|
||||
'empty_data' => empty($aEmptyData) ? [] : $aEmptyData,
|
||||
'log_data' => empty($aLog) ? [] : $aLog,
|
||||
'open_ai_id' => empty($aSearch['open_ai_id']) ? 0 : $aSearch['open_ai_id']
|
||||
];
|
||||
|
||||
//日志记录
|
||||
$this->addLog($aParam);
|
||||
|
||||
return json_encode($aParam);
|
||||
}
|
||||
|
||||
/**
|
||||
* CURL 发送请求到 OpenAI【流式】
|
||||
* @param $messages 内容
|
||||
@@ -557,7 +361,7 @@ class OpenAi
|
||||
//超时设置
|
||||
$timeout = empty($aParam['timeout']) ? 300 : $aParam['timeout'];
|
||||
//接口地址
|
||||
$sUrl = $this->sUrl;
|
||||
$sUrl = empty($aParam['url']) ? $this->sUrl : $aParam['url'];
|
||||
|
||||
//组装数据
|
||||
$data = [
|
||||
@@ -624,8 +428,7 @@ class OpenAi
|
||||
/**
|
||||
* 解析流式响应
|
||||
*/
|
||||
private function parseMedicalStreamResponse($streamContent)
|
||||
{
|
||||
private function parseMedicalStreamResponse($streamContent){
|
||||
$fullContent = '';
|
||||
$lines = explode("\n", $streamContent);
|
||||
foreach ($lines as $line) {
|
||||
@@ -639,57 +442,10 @@ class OpenAi
|
||||
return $fullContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录处理进度【Redis】
|
||||
*/
|
||||
private function recordProcessingStart($key,$totalQuestions)
|
||||
{
|
||||
$this->redis->hMSet($key, [
|
||||
'status' => 'processing',
|
||||
'total' => $totalQuestions,
|
||||
'completed' => 0,
|
||||
'start_time' => time()
|
||||
]);
|
||||
$this->redis->expire($key, 86400); // 24小时过期
|
||||
}
|
||||
/**
|
||||
* 更新处理进度【Redis】
|
||||
*/
|
||||
private function updateProcessingProgress($key,$iId,$completed)
|
||||
{
|
||||
|
||||
$this->redis->hSet($key, 'completed', $completed);
|
||||
//完成进度
|
||||
$iProgress = round(($completed / $this->redis->hGet($key, 'total')) * 100, 2);
|
||||
if($iProgress == 100){
|
||||
$this->recordProcessingComplete($key,$iId);
|
||||
}
|
||||
$this->redis->hSet($key, 'progress', $iProgress);
|
||||
}
|
||||
/**
|
||||
* 记录处理完成【Redis】
|
||||
*/
|
||||
private function recordProcessingComplete($key,$iId)
|
||||
{
|
||||
$this->redis->hSet($key, 'status', 'completed');
|
||||
$this->redis->hSet($key, 'end_time', time());
|
||||
$this->wechatGegnerate(['article_id' => $iId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存分块进度【Redis】
|
||||
*/
|
||||
private function saveChunkProgress($key, $chunkIndex, $content)
|
||||
{
|
||||
$this->redis->hset($key, "chunk_{$chunkIndex}", $content);
|
||||
$this->redis->expire($key, 86400); // 进度保存24小时
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信公众号-生成公微内容(CURL)
|
||||
*/
|
||||
public function createWechatContent($aParam = [])
|
||||
{
|
||||
public function createWechatContent($aParam = []){
|
||||
//主键ID
|
||||
$iId = empty($aParam['redis_id']) ? 0 : $aParam['redis_id'];
|
||||
if(empty($iId)){
|
||||
@@ -703,7 +459,7 @@ class OpenAi
|
||||
//记录处理开始
|
||||
$iNum = count($aMessage);
|
||||
$sRedisKey = 'ai_create_article_'.$iId;
|
||||
$this->recordProcessingStart($sRedisKey,$iNum);
|
||||
$this->oQueueRedis->recordProcessingStart($sRedisKey,$iNum);
|
||||
//定义空数组
|
||||
$aChunkResult = $aFail = [];
|
||||
foreach ($aMessage as $key => $value) {
|
||||
@@ -733,72 +489,64 @@ class OpenAi
|
||||
$iMaxNum = empty($aParam['count_num']) ? 0 : $aParam['count_num'];
|
||||
//请求OPENAI
|
||||
$aResult = $this->curlOpenAIStream($aParam);
|
||||
|
||||
//更新处理进度
|
||||
$iIndex = empty($aParam['chunkIndex']) ? 0 : $aParam['chunkIndex'];
|
||||
$sRedisKey = 'ai_create_article_'.$iId;
|
||||
$this->updateProcessingProgress($sRedisKey,$iId,$iIndex + 1);
|
||||
|
||||
$iProgress = $this->oQueueRedis->updateProcessingProgress($sRedisKey,$iIndex + 1);
|
||||
//保存内容
|
||||
$sRedisKey = 'ai_create_article_progress_'.$iId;
|
||||
$this->saveChunkProgress($sRedisKey, $iIndex,$aResult);
|
||||
$this->oQueueRedis->saveChunkProgress($sRedisKey, $iIndex,$aResult);
|
||||
|
||||
//更新入库
|
||||
$aReturnData = json_decode($aResult,true);
|
||||
$aDataInfo =empty($aReturnData['data']) ? [] : $aReturnData['data'];
|
||||
$aData = empty($aDataInfo) ? [] : $this->extractAndParse($aDataInfo);
|
||||
$aData = empty($aData['data']) ? [] : $aData['data'];
|
||||
if(!empty($aData)){
|
||||
if(!empty($aData)){//更新AI审稿记录表
|
||||
if($iProgress >= 100){
|
||||
$aData['is_generate'] = 1;
|
||||
}
|
||||
$aData['article_id'] = $iId;
|
||||
$this->updateAiArticle($aData);
|
||||
$this->updateAiContent($aData);
|
||||
}
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取期刊内容
|
||||
* 微信公众号-更新AI生成内容
|
||||
*/
|
||||
public function getJournalPaperArt($aParam = []){
|
||||
private function updateAiContent($aParam = []){
|
||||
|
||||
//判断文章ID
|
||||
$sIssn = empty($aParam['issn']) ? [] : $aParam['issn'];
|
||||
if(empty($sIssn)){
|
||||
return json_encode(['status' => 2,'msg' => 'Please select an article']);
|
||||
}
|
||||
//接口获取期刊内容
|
||||
$sUrl = $this->sTmrUrl."/api/Supplementary/getJournalPaperArt";
|
||||
$aParam = ['issn' => $sIssn];
|
||||
$aResult = object_to_array(json_decode(myPost($sUrl,$aParam),true));
|
||||
return json_encode($aResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文章文件内容
|
||||
*/
|
||||
|
||||
public function getFileContent($aParam = []){
|
||||
|
||||
//判断文章ID
|
||||
$iArticleId = empty($aParam['article_id']) ? [] : $aParam['article_id'];
|
||||
//文章ID
|
||||
$iArticleId = empty($aParam['article_id']) ? 0 : $aParam['article_id'];
|
||||
if(empty($iArticleId)){
|
||||
return json_encode(['status' => 2,'msg' => 'Please select an article']);
|
||||
return json_encode(['status' => 2,'msg' => 'Please select the article to be modified']);
|
||||
}
|
||||
//更新生成状态
|
||||
$oArticle = new Article;
|
||||
$aResult = json_decode($oArticle->updateAiArticle($aParam),true);
|
||||
$iStatus = empty($aResult['status']) ? 0 : $aResult['status'];
|
||||
$sMsg = empty($aResult['msg']) ? '更新状态失败' : $aResult['msg'];
|
||||
//是否生成
|
||||
$is_generate = empty($aParam['is_generate']) ? 2 : $aParam['is_generate'];
|
||||
|
||||
//获取文件内容
|
||||
$aWhere = ['article_id' => $iArticleId,'type_name' => 'manuscirpt'];
|
||||
$aFile = Db::name('article_file')->field('file_url')->where($aWhere)->order('ctime desc')->limit(1)->find();
|
||||
if(empty($aFile['file_url'])){
|
||||
return json_encode(['status' => 2,'msg' => 'No Manuscript']);
|
||||
//内容生成完成推送上传素材队列
|
||||
if($is_generate == 1){
|
||||
if($iStatus == 1){
|
||||
//四小时后推送上传素材并推送草稿箱
|
||||
$iDelaySeconds = 4 * 3600; // 4小时的秒数
|
||||
Queue::later($iDelaySeconds,'app\api\job\WechatMaterial@fire', ['article_id' => $iArticleId], 'WechatMaterial');
|
||||
$sMsg = '文章AI内容生成成功';
|
||||
}else{
|
||||
$iStatus = 2;
|
||||
}
|
||||
//插入日志记录
|
||||
$oMaterial = new Material;
|
||||
$aLogInfo = ['article_id' => $iArticleId,'type' => 5,'msg' =>$sMsg,'status' => $iStatus,'create_time' => time()];
|
||||
$result = $oMaterial->addWechatLog($aLogInfo);
|
||||
}
|
||||
|
||||
//接口获取上传文件
|
||||
$sUrl = $this->sJavaUrl."api/typeset/readDocx";
|
||||
$aParam['fileRoute'] = $this->sFileUrl.$aFile['file_url'];
|
||||
$aResult = object_to_array(json_decode(myPost($sUrl,$aParam)));
|
||||
return json_encode($aResult);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 添加接口访问日志
|
||||
*/
|
||||
@@ -819,87 +567,13 @@ class OpenAi
|
||||
return DB::name('openapi_log')->insertGetId($aInsert);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新AI生成内容入库
|
||||
* @param $messages 内容
|
||||
* @param $model 模型类型
|
||||
*/
|
||||
private function updateAiArticle($aParam = []){
|
||||
//文章ID
|
||||
$iArticleId = empty($aParam['article_id']) ? 0 : $aParam['article_id'];
|
||||
|
||||
//查询内容是否存在
|
||||
$aWhere = ['is_delete' => 2];
|
||||
if(empty($iArticleId)){
|
||||
return json_encode(['status' => 2,'msg' => 'Please select the article to be modified']);
|
||||
}
|
||||
$aWhere['article_id'] = $iArticleId;
|
||||
$aAiArticle = Db::name('ai_article')->field('ai_article_id')->where($aWhere)->find();
|
||||
if(empty($aAiArticle)){
|
||||
return json_encode(['status' => 3,'msg' => 'he article content of WeChat official account has not been generated']);
|
||||
}
|
||||
$iAiArticleId = $aAiArticle['ai_article_id'];
|
||||
|
||||
//必填参数验证
|
||||
$aFields = ['article_id','title_english','title_chinese','journal_issn','covered','digest','research_result','content','highlights','discussion','prospect','research_background','discussion_results','research_method','overview','summary','is_generate'];
|
||||
$sFiled = '';
|
||||
$aUpdateParam = [];
|
||||
foreach($aFields as $val){
|
||||
if(!isset($aParam[$val])){
|
||||
continue;
|
||||
}
|
||||
if(is_array($aParam[$val])){
|
||||
$aParam[$val] = implode(";",$aParam[$val]);
|
||||
}
|
||||
$aUpdateParam[$val] = empty($aParam[$val]) ? '' : addslashes($aParam[$val]);
|
||||
}
|
||||
if(empty($aUpdateParam)){
|
||||
return json_encode(['status' => 1,'msg' => 'No data currently being processed']);
|
||||
}
|
||||
//执行入库
|
||||
$aUpdateParam['update_time'] = time();
|
||||
$result = Db::name('ai_article')->where('ai_article_id',$iAiArticleId)->limit(1)->update($aUpdateParam);
|
||||
if($result === false){
|
||||
return json_encode(['status' => 4,'msg' => 'UPDATEING AI article failed']);
|
||||
}
|
||||
return json_encode(['status' => 1,'msg' => 'No data currently being processed']);
|
||||
}
|
||||
|
||||
private function wechatGegnerate($aParam = []){
|
||||
|
||||
//文章ID
|
||||
$iArticleId = empty($aParam['article_id']) ? 0 : $aParam['article_id'];
|
||||
if(empty($iArticleId)){
|
||||
return json_encode(['status' => 2,'msg' => 'Please select the article to be modified']);
|
||||
}
|
||||
//更新生成状态
|
||||
$aParam['is_generate'] = 1;
|
||||
$aResult = json_decode($this->updateAiArticle($aParam),true);
|
||||
$iStatus = empty($aResult['status']) ? 0 : $aResult['status'];
|
||||
$sMsg = empty($aResult['msg']) ? '更新状态失败' : $aResult['msg'];
|
||||
if($iStatus == 1){
|
||||
//四小时后推送上传素材并推送草稿箱
|
||||
$iDelaySeconds = 4 * 3600; // 4小时的秒数
|
||||
Queue::later($iDelaySeconds,'app\api\job\WechatMaterial@fire', ['article_id' => $iArticleId], 'WechatMaterial');
|
||||
$sMsg = '文章AI内容生成成功';
|
||||
}else{
|
||||
$iStatus = 2;
|
||||
}
|
||||
|
||||
//插入日志记录
|
||||
$oMaterial = new Material;
|
||||
$aLogInfo = ['article_id' => $iArticleId,'type' => 5,'msg' =>$sMsg,'status' => $iStatus,'create_time' => time()];
|
||||
$result = json_decode($oMaterial->addWechatLog($aLogInfo),true);
|
||||
return json_encode($aResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从文本中提取被```json```和```包裹的JSON内容并解析
|
||||
* @param string $text 包含JSON代码块的文本
|
||||
* @param bool $assoc 是否返回关联数组(默认true)
|
||||
* @return array|object 解析后的JSON数据,失败时返回null
|
||||
*/
|
||||
private function extractAndParse($text, $assoc = true){
|
||||
public function extractAndParse($text, $assoc = true){
|
||||
|
||||
// 使用正则表达式提取JSON代码块
|
||||
preg_match('/```json\s*(\{.*?\})\s*```/s', $text, $matches);
|
||||
|
||||
Reference in New Issue
Block a user