From c7b4539c49e4b99b6433a4d12297379f7295f001 Mon Sep 17 00:00:00 2001 From: chengxl Date: Thu, 7 Aug 2025 16:14:26 +0800 Subject: [PATCH] =?UTF-8?q?redis=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- application/api/controller/Aiarticle.php | 235 ++++++++++++++++------- application/common/Material.php | 2 +- application/common/OpenAi.php | 2 +- 3 files changed, 172 insertions(+), 67 deletions(-) diff --git a/application/api/controller/Aiarticle.php b/application/api/controller/Aiarticle.php index bdfde04..bb1f44b 100644 --- a/application/api/controller/Aiarticle.php +++ b/application/api/controller/Aiarticle.php @@ -74,7 +74,6 @@ class Aiarticle extends Base $aArticleContent = empty($aResult['data']) ? [] : $aResult['data']; //文章数据 $aArticle = empty($aArticleContent['article']) ? [] : $aArticleContent['article']; - if(empty($aArticle)){ return json_encode(['status' => 3,'msg' => 'The content of the article is empty']); } @@ -98,7 +97,6 @@ class Aiarticle extends Base } $aAiArticle = array_merge(['ai_article_id' => $iId,'article_id' => $iArticleId,'is_generate' => 2],$aInsert); } - //判断是否生成 if(!empty($aAiArticle['is_generate']) && $aAiArticle['is_generate'] == 1){ return json_encode(['status' => 5,'msg' => 'The data has been generated, please proceed with the next steps']); @@ -134,12 +132,10 @@ class Aiarticle extends Base $aAuthor = empty($aArticleContent['author']) ? [] : $aArticleContent['author']; //查询文章内容 - $aMain = empty($aArticleContent['main']) ? [] : $aArticleContent['main'];; - $sContent = empty($aMain) ? '' : implode(',', $aMain); - + $oOpenAi = new OpenAi; //请求OPENAI生成微信公众号文章内容 $aSearch = []; - $aSearch['{#content#}'] = $this->basic_html_filter($sContent); + $aSearch['main_content'] = empty($aArticleContent) ? [] : $aArticleContent; $aSearch['{#abstract#}'] = $this->basic_html_filter($aArticle['abstract']); $aSearch['{#title_chinese#}'] = $this->basic_html_filter($aArticle['title']); $aSearch['{#journal_content#}'] = $this->basic_html_filter($aJournal['journal_content'] ?? ''); @@ -184,30 +180,60 @@ class Aiarticle extends Base */ public function getArticle($iArticleId = ''){ - $aParam = $this->request->post(); - $iArticleId = empty($iArticleId) ? $aParam['article_id'] : $iArticleId; + //文章ID + $iArticleId = empty($iArticleId) ? 0 : $iArticleId; + if(empty($iArticleId)){ + return json_encode(['status' => 2,'msg' => 'article id is null']); + } //接口请求地址 $sUrl = $this->sJournalUrl.'/wechat/Article/getArticle'; - //请求接口 $aParam['article_id'] = $iArticleId; $aResult = object_to_array(json_decode(myPost($sUrl, $aParam))); $iStatus = empty($aResult['status']) ? 0 : $aResult['status']; if($iStatus != 1){ - return json_encode(['status' => 0,'msg' => $aResult['msg'] ?? '操作异常']); + return json_encode(['status' => 3,'msg' => $aResult['msg'] ?? '操作异常']); } - + //获取接口内容 $aContent = empty($aResult['data']) ? [] : $aResult['data']; - if(!empty($aContent['journal'])){ - $aJournal = $aContent['journal']; - //查询期刊主题 - $aWhere['issn'] = $aJournal['issn']; - $aJournalInfo = Db::name('journal')->field('journal_topic')->where($aWhere)->find(); - $aContent['journal']+=$aJournalInfo; + //查询生产环境的文章信息 + $aParam = ['w_article_id' => $iArticleId,'state' => ['in',[0,2]]]; + $aProductionArticle = Db::name('production_article')->field('article_id,title,abstract,journal_id,journal_stage_id,abbr,npp,doi,icon as article_icon,related,type')->where($aParam)->find(); + if(empty($aProductionArticle)){ + return json_encode(['status' => 4,'msg' => 'The production article data is empty']); } + + //查询文章内容 + $iArticleId = empty($aProductionArticle['article_id']) ? 0 : $aProductionArticle['article_id']; + $aParam = ['article_id' => $iArticleId,'state' => 0,'type' => ['in',[0,1]],'content' => ['<>','']]; + $aMain = Db::name('article_main')->field('am_id,article_id,content,sort,is_h1,is_h2,type,ami_id,amt_id')->where($aParam)->order('sort asc ')->select(); + //查询文章内容里的一级标题 + $aParam['is_h1'] = 1; + $aMainH1 = Db::name('article_main')->field('am_id,content,sort')->where($aParam)->order('sort asc ')->select(); + if(!empty($aMainH1)){ + //数据处理一级标题内容 + $aMainH1Info = array_column($aMainH1,'sort', 'am_id'); + // 提取纯标题数组(保持原顺序) + $aMainContent = array_column($aMainH1, 'content'); + // 提取纯am_id数组(保持原顺序) + $aAmId = array_column($aMainH1, 'am_id'); + // 初始化结果数组 + $aMainH1 = []; + // 处理前4个标题对应的ID区间 + for ($i = 0; $i < count($aMainContent) - 1; $i++) { + $title = $aMainContent[$i]; + $currentId = $aAmId[$i]; + $nextId = $aAmId[$i + 1]; + $aMainH1[$title] = ['range' => "{$aMainH1Info[$currentId]},{$aMainH1Info[$nextId]}"]; + } + // 处理最后一个ID(单独添加) + $aMainH1[end($aMainContent)] = ['range' => $aMainH1Info[end($aAmId)]]; + } + // 拼接成最终字符串 + $aContent += ['main' => $aMain,'main_h1' => $aMainH1]; return json_encode(['status' => 1,'msg' => 'success','data' => $aContent]); } @@ -498,7 +524,6 @@ class Aiarticle extends Base // //上传素材到微信 if($iIsSync == 1){ - //查询参数组装 $aQueryParam = ['article_id' => $iArticleId,'journal_id' => $aArticle['journal_id']]; //组装作者数据 @@ -540,8 +565,7 @@ class Aiarticle extends Base } }else{ - - //处理文章图片地址数据 + //处理文章图片地址数据 $aAiArticle['article_icon'] = $sArticleIcon; //处理文章期刊图片地址数据 $aAiArticle['journal_icon'] = $sJournalIcon; @@ -552,7 +576,6 @@ class Aiarticle extends Base if(!empty($aAuthor)){ $aAuthor = $this->_dealAuthor($aAuthor); } - } //期刊访问地址 $journal_usx = trim($this->sJournalUsx,'/').'/'; @@ -597,7 +620,7 @@ class Aiarticle extends Base if(is_array($value)){ continue; } - $aSearch['{###'.$key.'###}'] = empty($value) ? '' : htmlspecialchars(strip_tags($value)); + $aSearch['{###'.$key.'###}'] = empty($value) ? '' : $value; } //处理通讯作者信息数据 @@ -646,7 +669,6 @@ class Aiarticle extends Base if(empty($aSearch)){ return json_encode(['status' => 6, 'msg' => '模版内容不能为空']); } - $aSearch['{###jabbr###}'] = trim(trim($aSearch['{###jabbr###}'],'.'),'。'); //期刊封面 $aSearch['{###journal_icon_info###}'] = $aSearch['{###journal_icon_details###}'] = ''; @@ -662,10 +684,24 @@ class Aiarticle extends Base $aSearch['{###journal_icon_details###}'] = str_replace('{###journal_icon###}', $aAiArticle['journal_icon']??'', $sTemplateJournalInfo); } } + + //涵盖范围 $aSearch['{###covered###}'] = empty($aSearch['{###covered###}']) ? '' : '内容涵盖'.$aSearch['{###covered###}']; + //处理研究结果 + $aResearchResults = json_decode($this->dealTemplateResearchResults(['article_id' => $iArticleId,'template_path' => $sTemplatePath,'is_sync' => $iIsSync]),true); + $aSearch['{###discussion_results###}'] = empty($aResearchResults['data']) ? '' : implode('', $aResearchResults['data']); + //处理研究结论 + $aSearch['{###research_conclusion###}'] = ''; + if(!empty($aAiArticle['conclusion'])){ + $sConclusionTemplatePath = $sTemplatePath.'/research_conclusion.html'; + if (file_exists($sConclusionTemplatePath) && is_readable($sConclusionTemplatePath)) { + $sConclusionTemplatePath = file_get_contents($sConclusionTemplatePath); + $aSearch['{###research_conclusion###}'] = str_replace('{###conclusion###}', $aAiArticle['conclusion'], $sConclusionTemplatePath); + } + } $sTemplate = str_replace(array_keys($aSearch), array_values($aSearch), $sTemplate); - // $this->writeFile($sTemplate,ROOT_PATH.'public/template_info.html'); + $this->writeFile($sTemplate,ROOT_PATH.'public/template_info.html'); return json_encode(['status' => 1, 'msg' => '模版生成成功','data' => ['template' => $sTemplate]]); } @@ -722,12 +758,12 @@ class Aiarticle extends Base if(!empty($aTranslateAuthorList)){ $aTranslate = array_merge($aTranslateAuthorList,$aTranslate); } - if(!empty($aTranslate)){ - $aSearch['{#content#}'] = json_encode($aTranslate); - $oOpenAi = new OpenAi; - $aTranslate = $oOpenAi->buildTranslatePrompt($aSearch); - $aTranslate = empty($aTranslate['data']) ? [] : $aTranslate['data']; - } + // if(!empty($aTranslate)){ + // $aSearch['{#content#}'] = json_encode($aTranslate); + // $oOpenAi = new OpenAi; + // $aTranslate = $oOpenAi->buildTranslatePrompt($aSearch); + // $aTranslate = empty($aTranslate['data']) ? [] : $aTranslate['data']; + // } //翻译内容处理 if(!empty($aAuthorSerachInfo)){ foreach ($aAuthorSerachInfo as $key => $value) { @@ -1059,32 +1095,32 @@ class Aiarticle extends Base if(!empty($aAiArticle)){ $aMsg = [1 => 'The article has been pushed to the draft box',2 => 'Not pushed to the draft box',3 => 'Material upload in progress',4 => 'Material upload completed']; - //获取Redis内容,判断是否上传素材成功 - $oMaterial = new Material; - $sUploadInfo = $oMaterial->getStepForRedis($iArticleId); - $sErrorInfo = ''; - if(!empty($sUploadInfo) && $sUploadInfo != 'finish'){ - $iStatus = 3;//素材上传中 - $sErrorInfo = $oMaterial->getErrorForRedis($iArticleId); - if(!empty($sErrorInfo)){ - $iStatus = 5; - return json_encode(['status' => 5,'msg' => $sErrorInfo]); - } + //判断是否上传素材 + $oMaterial = new Material; + $aLogParam = ['article_id' => $iArticleId,'type' => 1]; + $aLog = json_decode($oMaterial->getWechatLog($aLogParam),true); + $aLog = empty($aLog['data']) ? [] : $aLog['data']; + if(empty($aLog)){ + $iStatus = 6;//未上传 + return json_encode(['status' => $iStatus,'msg' => 'Material not uploaded']); } - if(!empty($sUploadInfo) && $sUploadInfo == 'finish'){ + if(!empty($aLog) && $aLog['status_name'] == 'processing'){ + $iStatus = 3;//素材上传中 + } + if(!empty($aLog) && $aLog['status_name'] == 'fail'){ + $iStatus = 5;//失败 + return json_encode(['status' => $iStatus,'msg' => empty($aLog['msg']) ? 'fail' : $aLog['msg']]); + } + if(!empty($aLog) && $aLog['status_name'] == 'finish'){ $iStatus = 4;//素材上传完成 } //判断是否推送到草稿箱 - if(empty($sUploadInfo) || $iStatus == 4){ - if(!empty($aParam['template_id'])){ - $aWhere['template_id'] = $aParam['template_id']; - } + if(!empty($aLog) && $iStatus == 4){ $aDraft = Db::name('ai_wechat_article')->field('is_publish,publish_status,article_id,template_id,wechat_id')->where($aWhere)->find(); $iStatus = empty($aDraft) ? 2 : 1; } $aResult['draft_status'] = $iStatus; - if(!empty($aDraft)){ $aMsg = [0 => 'Article successfully published', 1 => 'Article is being published',2 => 'Original article creation failed', 3 => 'Article conventional failure', 4 => 'WeChat official account platform review failed', 5 => 'After success, the user deletes all articles', 6 => 'After success, the system will ban all articles','-1' => 'Draft box article not published']; @@ -1396,24 +1432,9 @@ class Aiarticle extends Base } //上传微信公众号用到的素材 $aUpload += ['article_id' => $iArticleId,'journal_id' => $aArticle['journal_id'],'wechat_app_id' => $sWechatAppId,'wechat_app_secret' => $sWechatAppSecret]; - $aResult = json_decode($oMaterial->uploadMaterial($aUpload),true); - $iStatus = empty($aResult['status']) ? 0 : $aResult['status']; - $sMsg = empty($aResult['msg']) ? '' : $aResult['msg']; - if ($iStatus != 1) { - $iStatus = 2; - $sMsg = empty($sMsg) ? '素材上传失败' : $sMsg; - } - //插入日志记录 - $aLogInfo = ['article_id' => $iArticleId,'type' => 1,'msg' =>$sMsg,'status' => $iStatus,'create_time' => time()]; - $result = json_decode($oMaterial->addWechatLog($aLogInfo),true); - - //素材上传成功调用上传草稿箱的任务 - if($iStatus == 1){ - //1分钟后推送草稿箱 - $iDelaySeconds = 60;//4 * 3600; // 1分钟的秒数 - Queue::later($iDelaySeconds,'app\api\job\WechatDraft@fire', ['article_id' => $iArticleId], 'WechatDraft'); - } - return json_encode(['status' => $iStatus,'msg' => $sMsg,'data' => $aLogInfo]); + $aResult = $oMaterial->uploadMaterial($aUpload); + return $aResult; + } /** @@ -1431,4 +1452,88 @@ class Aiarticle extends Base fclose($file); } + + /** + * 处理文章研究结果 + * @param article_id 文章ID + */ + private function dealTemplateResearchResults($aParam = []){ + + $sTemplatePath = empty($aParam['template_path']) ? 0 : $aParam['template_path']; + if(empty($sTemplatePath)){ + return json_encode(['status' => 2,'msg' => 'template does not exist']); + } + $iArticleId = empty($aParam['article_id']) ? 0 : $aParam['article_id']; + if(empty($iArticleId)){ + return json_encode(['status' => 2,'msg' => 'Please select an article']); + } + //是否上传到微信草稿箱 + $iIsSync = empty($aParam['is_sync']) ? 2 : $aParam['is_sync']; + + //获取主题模版 + $sTemplatePathInfo = $sTemplatePath.'/research_results.html'; + //获取主题模版-图片 + $sTemplateImagePathInfo = $sTemplatePath.'/research_results_image.html'; + if (!file_exists($sTemplatePathInfo)) { + return json_encode(['status' => 4, 'msg' => 'Corresponding author template does not exist']); + } + if (!is_readable($sTemplatePathInfo)) { + return json_encode(['status' => 5, 'msg' => 'The corresponding author template is unreadable']); + } + $sTemplate = file_get_contents($sTemplatePathInfo); + $sTemplateImagePathInfo = file_get_contents($sTemplateImagePathInfo); + //查询数据 + $aWhere = ['article_id' => $iArticleId]; + $aResult = Db::name('ai_article_results')->field('title,content,current_am_id,next_am_id,ami_id')->where($aWhere)->select(); + if(empty($aResult)){ + return json_encode(['status' => 1,'msg' => 'data is null']); + } + $aAmiId = array_unique(array_column($aResult, 'ami_id')); + $aAmiId = empty($aAmiId) ? [] : explode(',', implode(',', $aAmiId)); + if(!empty($aAmiId)){ + //查询图片内容 + $aParam = ['state' => 0,'ami_id' => ['in',$aAmiId]]; + $aMainImage = Db::name('article_main_image')->field('ami_id,url,title,note')->where($aParam)->select(); + $aMainImage = empty($aMainImage) ? [] : array_column($aMainImage, null,'ami_id'); + } + //查询研究结果相关的微信素材 + if($iIsSync == 1){ + //获取研究结果图片 + $aWhere = ['article_id' => $iArticleId,'is_delete' => 2]; + $aResultsMaterial = Db::name('ai_results_material')->field('ami_id,media_id,media_url')->where($aWhere)->select(); + $aResultsMaterial = empty($aResultsMaterial) ? [] : array_column($aResultsMaterial, null,'ami_id'); + } + //数据处理https://submission.tmrjournals.com/public/articleImage/ + foreach ($aResult as $key => $value) { + $aSerach['{###title###}'] = empty($value['title']) ? '' : $value['title']; + $aSerach['{###content###}'] = empty($value['content']) ? '' : $value['content']; + $aSerach['{###image_info###}'] = ''; + if(!empty($value['ami_id'])){ + $aAmiId = explode(',', $value['ami_id']); + $aImageInfo = []; + foreach ($aAmiId as $k => $val) { + $aMainImageInfo = empty($aMainImage[$val]) ? [] : $aMainImage[$val]; + if(empty($aMainImageInfo['url'])){ + continue; + } + $aImageSerach['{###image_url###}'] = trim($this->sSubmissionUrl,'/').'/public/articleImage/'.$aMainImageInfo['url']; + if($iIsSync == 1){ + $aImageSerach['{###image_url###}'] = empty($aResultsMaterial[$val]['media_url']) ? '' : $aResultsMaterial[$val]['media_url']; + } + $aImageSerach['{###image_url###}'] = trim($this->sSubmissionUrl,'/').'/public/articleImage/'.$aMainImageInfo['url']; + $sTitle = empty($aMainImageInfo['title']) ? strip_tags($aMainImageInfo['note']) : strip_tags($aMainImageInfo['title']); + $aImageSerach['{###image_title###}'] = ''; + if(!empty($sTitle)){ + $sTitle = preg_replace('/Figure \d+.*?/', '', $sTitle); + $aTitle = explode('.', $sTitle); + $aImageSerach['{###image_title###}'] = empty($aTitle[0]) ? $sTitle : strip_tags($aTitle[0]); + } + $aImageInfo[] = str_replace(array_keys($aImageSerach), array_values($aImageSerach), $sTemplateImagePathInfo); + } + $aSerach['{###image_info###}'] = empty($aImageInfo) ? '' : implode(',', $aImageInfo); + } + $aSearchInfo[] = str_replace(array_keys($aSerach), array_values($aSerach), $sTemplate); + } + return json_encode(['status' => 1,'msg' => 'success','data' => $aSearchInfo]); + } } diff --git a/application/common/Material.php b/application/common/Material.php index 034189d..989bf2c 100644 --- a/application/common/Material.php +++ b/application/common/Material.php @@ -470,7 +470,7 @@ class Material $aInsert['create_time'] = $iTime; $response = Db::name('ai_journal_editor_material')->insertGetId($aInsert); }else{ - $aWhere['author_id'] = $aMaterial['author_id']; + $aWhere['author_id'] = $aMaterial['id']; $aInsert['update_time'] = $iTime; $response = Db::name('ai_journal_editor_material')->where($aWhere)->limit(1)->update($aInsert); } diff --git a/application/common/OpenAi.php b/application/common/OpenAi.php index 0411ddd..6e519c1 100644 --- a/application/common/OpenAi.php +++ b/application/common/OpenAi.php @@ -619,7 +619,7 @@ class OpenAi curl_setopt($this->curl, CURLOPT_PROXY, $this->proxy); curl_setopt($this->curl, CURLOPT_SSL_VERIFYPEER, true); curl_setopt($this->curl, CURLOPT_SSL_VERIFYHOST, 2); - curl_setopt($this->curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); // 强制TLS版本 + // curl_setopt($this->curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); // 强制TLS版本 // 核心传输配置 - 解决数据截断 curl_setopt($this->curl, CURLOPT_POST, true);