'Cn8zlXvVB5DwjcA9h40z9fprHDoc3Jqv97SwrInpmyYiilkeRdKvpD63cWqTYHfz','url' => 'http://mmbiz.qpic.cn/mmbiz_jpg/QHFVW13lONaQJxK9QbHU9CtrvTS2ModZnUyeAvuVN67t8XP85DxVJwDJf2YxCTalrsr17jS080xM6xQv5yGiaEQ/0?wx_fmt=jpeg'];//默认头像 //期刊接口地址 protected $sJournalUrl = 'http://journalapi.tmrjournals.com/public/index.php';//'http://zmzm.journal.dev.com'; // //期刊官网 protected $sJournalUsx = 'https://www.tmrjournals.com'; //投稿系统 protected $sSubmissionUrl = 'https://submission.tmrjournals.com/'; //文章图片icon地址 protected $sArticleIcon = '/public/articleicon/'; //期刊图片icon地址 protected $sJournalIcon = '/public/journalicon/'; //期刊编辑二维码地址 protected $sJournalEditorQrcode = '/public/journaleditorqrcode/'; //作者头像地址 protected $sUserIcon = '/public/usericon/'; //默认头像 protected $sDefaultUserIcon = '/static/img/userImg.f3d9bc3b.jpg'; //默认公众号配置 protected $aWechatConfig = [ 'issn' => 'default', 'wechat_name' => 'TMR Publishing Group', 'wechat_app_id' => 'wxda4cc30fe32e6313', 'wechat_app_secret' => 'd5e6002b8b48de46f64dc9a02312f944' ]; //生成AI文章状态 protected $sGenerateStatusName = 'generate_status_article_id'; public function __construct(\think\Request $request = null) { parent::__construct($request); } /** * @title 生成公微 * @param aSearch array 模版内容 * @param iTemplateId 模版ID */ public function create($aParam = []){ //获取参数 $aParam = empty($aParam) ? $this->request->post() : $aParam; $iArticleId = empty($aParam['article_id']) ? 0 : $aParam['article_id']; if(empty($iArticleId)){ return json_encode(array('status' => 2,'msg' => 'Please select an article'.json_encode($aParam) )); } $iPArticleId = empty($aParam['p_article_id']) ? 0 : $aParam['p_article_id']; if(!empty($iPArticleId)){ //获取官网ID $aWhere = ['p_article_id' => $iPArticleId]; $aProductionArticle = Db::name('production_article')->field('w_article_id')->where($aWhere)->find(); if(empty($aProductionArticle['w_article_id'])){ return json_encode(['status' => 2,'msg' => 'The article was not successfully pushed']); } $iArticleId = $aProductionArticle['w_article_id']; } //媒体类型 $iMediaType = empty($aParam['media_type']) ? 1 : $aParam['media_type']; //获取文章是否生成AI内容 $aResult = json_decode($this->getArticle($iArticleId),true); $iStatus = empty($aResult['status']) ? 0 : $aResult['status']; if($iStatus != 1){ return json_encode($aResult); } //获取数据 $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']); } //期刊数据 $aJournal = empty($aArticleContent['journal']) ? [] : $aArticleContent['journal']; if(empty($aJournal)){ return json_encode(['status' => 3,'msg' => 'The journal to which the article belongs does not exist or has been closed']); } //查询AI内容是否生成 $aWhere = ['is_delete' => 2,'article_id' => $iArticleId]; $aAiArticle = Db::name('ai_article')->where($aWhere)->find(); $iId = empty($aAiArticle['ai_article_id']) ? 0 : $aAiArticle['ai_article_id']; if(empty($aAiArticle)){ //插入t_ai_article数据 $sIssn = empty($aJournal['issn']) ? '' : $aJournal['issn']; $aInsert = ['title_english' => $aArticle['title'],'article_id' => $iArticleId,'create_time' => time(),'journal_issn' => $sIssn,'journal_id' => $aArticle['journal_id'],'article_type' => $aArticle['type'],'media_type' => $iMediaType,'journal_issn' => empty($aJournal['issn']) ? '' :$aJournal['issn']]; $iId = Db::name('ai_article')->insertGetId($aInsert); if($iId === false){ return json_encode(['status' => 4,'msg' => 'Data insertion failed']); } $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']); } //请求OPENAI return $this->createForOpenAi($aArticleContent,$aAiArticle); } /** * @title 请求OPENAI生成内容 * @param article_id 文章ID * @param model 接口模型 * @param stream 是否流式输出 true是false否 */ public function createForOpenAi($aArticleContent = [],$aAiArticle = []){ $iId = empty($aAiArticle['ai_article_id']) ? 0 : $aAiArticle['ai_article_id']; $iArticleId = empty($aAiArticle['article_id']) ? 0 : $aAiArticle['article_id']; //文章数据 $aArticle = empty($aArticleContent['article']) ? [] : $aArticleContent['article']; //期刊数据 $aJournal = empty($aArticleContent['journal']) ? [] : $aArticleContent['journal']; //子期刊数据 $aJournalStage = empty($aArticleContent['journal_stage']) ? [] : $aArticleContent['journal_stage']; //通讯作者 $aAuthor = empty($aArticleContent['author']) ? [] : $aArticleContent['author']; //查询文章内容 $oOpenAi = new OpenAi; //请求OPENAI生成微信公众号文章内容 $aSearch = []; $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'] ?? ''); $aSearch['{#journal_content#}'] = trim(trim($aSearch['{#journal_content#}'],'.'),'。'); $aSearch['article_id'] = $iArticleId; $aSearch['prompt_article_type'] = empty($aArticle['type']) ? 'default' : $aArticle['type']; //获取问答内容 $oOpenAi = new OpenAi; $aMessage = $oOpenAi->buildWechatPrompt($aSearch); if(empty($aMessage)){ return json_encode(['status' => 5,'msg' => 'AI Q&A content not obtained']); } //请求OPENAI接口 $aParam = ['messages' => $aMessage,'model' => empty($aParam['api_model']) ? 'gpt-4.1' : $aParam['api_model'],'redis_id' => empty($aSearch['article_id']) ? 0 : $aSearch['article_id']]; return $oOpenAi->createWechatContent($aParam); } /** * 处理文章引用 * @param string $html * @return string */ private function _cite($aArticle = [],$aJournal = [],$aJournalStage = []){ $no = empty($aJournalStage['stage_no']) ? ':' : '(' . $aJournalStage['stage_no'] . '):'; $jabbr = empty($aJournal['jabbr']) ? '' : $aJournal['jabbr']; $stage_year = empty($aJournalStage['stage_year']) ? '' : $aJournalStage['stage_year']; $stage_vol = empty($aJournalStage['stage_vol']) ? '' : $aJournalStage['stage_vol']; $sCite = ''; if ($aArticle['journal_id'] == 22) { $sCite = $aArticle['abbr'] . '. ' . $aArticle['title'] . '[J]. ' . choiseJabbr($aArticle['article_id'],$jabbr) . ',' . $stage_year . ',' . $stage_vol . $no . $aArticle['npp'] . '. doi:' . $aArticle['doi']; } else { $sCite = $aArticle['abbr'] . '. ' . $aArticle['title'] . '. ' . choiseJabbr($aArticle['article_id'], $jabbr) . '. ' . $stage_year . ';' . $stage_vol . $no . $aArticle['npp'] . '. doi:' . $aArticle['doi']; } return $sCite; } /** * 接口请求获取Journal数据库文章信息 * @param article_id 文章ID */ public function getArticle($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' => 3,'msg' => $aResult['msg'] ?? '操作异常']); } //获取接口内容 $aContent = empty($aResult['data']) ? [] : $aResult['data']; //查询生产环境的文章信息 $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]); } /** * 获取Ai生成文章信息 * @param article_id 文章ID * @param $iSelectAuthor 是否查询作者 1是2否 */ public function getAiArticle($aParam = []){ $aParam = empty($aParam) ? $this->request->post() : $aParam; //文章ID $iArticleId = empty($aParam['article_id']) ? '' : $aParam['article_id']; if(empty($iArticleId)){ return json_encode(['status' => 2,'msg' => 'Please select the article to be generated']); } //是否查询作者 1是2否 $iSelectAuthor = empty($aParam['is_select_author']) ? 2 : $aParam['is_select_author']; //查询AI生成的文章内容 $aWhere = ['is_delete' => 2];//,'is_generate' => 1 if(!empty($iArticleId)){ $aWhere['article_id'] = $iArticleId; } $aAiArticle = Db::name('ai_article')->where($aWhere)->find(); if(empty($aAiArticle)){ return json_encode(['status' => 1,'msg' => 'data is null','data' => ['ai_article' => []]]); } $iArticleId = empty($aAiArticle['article_id']) ? 0 : $aAiArticle['article_id']; //查询文章通讯作者 $aAiAuthor = []; if($iSelectAuthor == 2){ $aResult = json_decode($this->getArticle($iArticleId),true); //获取数据 $aArticleContent = empty($aResult['data']) ? [] : $aResult['data']; //通讯作者 $aAuthor = empty($aArticleContent['author']) ? [] : $aArticleContent['author']; if(!empty($aAuthor)){ $aAiAuthor = $this->_dealAuthor($aAuthor); if(!empty($aAiAuthor)){ foreach ($aAiAuthor as $key => $value) { $aAiAuthor[$key]['icon_path'] = empty($value['icon']) ? $this->sDefaultUserIcon : $this->sUserIcon.$value['icon']; } } } } //查询结论 $aWhere = ['article_id' => $iArticleId,'is_delete' => 2]; $aArticleResult = DB::name('ai_article_results')->field('id,title,content')->where($aWhere)->select(); return json_encode(['status' => 1,'msg' => 'success','data' => ['ai_article' => $aAiArticle,'ai_article_author' => $aAiAuthor,'ai_article_results' => $aArticleResult]]); } /** * @title 处理作者数据 * @param article_id 文章ID * @param content 内容 */ protected function _dealAuthor($aAuthor = array()){ //返回数组 if(empty($aAuthor)){ return []; } //根据邮箱查询作者信息 $aArticleId = array_unique(array_column($aAuthor, 'article_id')); $iArticleId = $aArticleId[0]; $aEmail = array_unique(array_column($aAuthor, 'email')); $aWhere = ['email' => ['in',$aEmail]]; $aUser = Db::name('user')->field('user_id,realname,email,localname,icon')->where($aWhere)->select(); if(empty($aUser)){ return []; } //查询作者详情 $aUserId = array_column($aUser, 'user_id'); $aWhere = ['reviewer_id' => ['in',$aUserId]]; $aUserInfo = DB::name('user_reviewer_info')->field('reviewer_id,technical,introduction,company')->where($aWhere)->select(); if(empty($aUserInfo)){ return []; } //数据处理 $aUserInfo = array_column($aUserInfo, null,'reviewer_id'); $aAuthor = array_column($aAuthor, null,'email'); $aInfo = []; foreach ($aUser as $key => $value) { //姓名 $sName = empty($aAuthor[$value['email']]['author_name']) ? '' : $aAuthor[$value['email']]['author_name']; $sName = empty($sName) ? $value['localname'] : $sName; $sName = empty($sName) ? $value['realname'] : $sName; //单位 $sCompany = empty($aAuthor[$value['email']]['company']) ? '' : $aAuthor[$value['email']]['company']; $sCompany1 = empty($aUserInfo[$value['user_id']]['company']) ? '' : $aUserInfo[$value['user_id']]['company']; $sCompany = empty($sCompany) ? $sCompany1 : $sCompany; //职称 $sTechnical = empty($aUserInfo[$value['user_id']]['technical']) ? '' : $aUserInfo[$value['user_id']]['technical']; //简介 $sIntroduction = empty($aUserInfo[$value['user_id']]['introduction']) ? '' : $aUserInfo[$value['user_id']]['introduction']; $aInfo[] = ['user_id' => $value['user_id'],'email' => $value['email'],'author_name' => $sName,'technical' => $sTechnical,'introduction' => $sIntroduction,'company' => $sCompany,'article_id' => $iArticleId,'create_time' => time(),'icon' => $value['icon']]; } return $aInfo; } /** * 基础HTML过滤 * @param string $html * @return string */ private function basic_html_filter($html) { // 移除所有HTML标签及PHP标签 $text = empty($html) ? '' : strip_tags($html); // 转换HTML实体 $text = html_entity_decode($text, ENT_QUOTES | ENT_HTML5, 'UTF-8'); // 合并连续空白字符 $text = preg_replace('/\s+/u', ' ', $text); return trim($text); } /** * @title AI生成稿件内容入库 * @param article_id 文章ID * @param content 内容 */ public function updateAiArticle($aParam = array()){ //返回数组 $aResult = ['status' => 1,'msg' => 'AI article updated successfully','data' => []]; //获取参数 $aParam = empty($aParam) ? $this->request->post() : $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']); } //更新AI文章内容 $oArticle = new \app\common\Article; $aResult = json_decode($oArticle->updateAiArticle($aParam),true); $iStatus = empty($aResult['status']) ? 0 : $aResult['status']; if($iStatus != 1){ return json_encode($aResult); } //结论信息 $aResultInfo = empty($aParam['results']) ? [] : $aParam['results']; $aResultInfo = is_array( $aResultInfo) ? $aResultInfo : json_decode($aResultInfo,true); //更新作者信息 $aAuthorList = empty($aParam['author_list']) ? []: $aParam['author_list']; $aAuthorList = is_array( $aAuthorList) ? $aAuthorList: json_decode($aAuthorList,true); if(empty($aAuthorList) && empty($aResultInfo)){ return json_encode($aResult); } //根据邮箱查询作者信息 if(!empty($aAuthorList)){ $aAuthorList = array_column($aAuthorList, null,'email'); $aEmail = array_keys($aAuthorList); if(empty($aEmail)){ return json_encode($aResult); } $aUserParam = ['email' => ['in',$aEmail]]; $aUserInfo = Db::name('user')->field('email,user_id')->where($aUserParam)->select(); if(empty($aUserInfo)){ return json_encode($aResult); } //查询用户附表 $aUserId = array_column($aUserInfo, 'user_id'); $aWhere = ['reviewer_id' => ['in',$aUserId]]; $aUserReviewer = Db::name('user_reviewer_info')->where($aWhere)->column('reviewer_id'); //更新用户信息 Db::startTrans(); foreach ($aUserInfo as $key => $value) { $aUser = empty($aAuthorList[$value['email']]) ? [] : $aAuthorList[$value['email']]; if(empty($aUser)){ continue; } //更新作者名字 if(isset($aUser['author_name'])){ $aUpdate = ['localname' => $aUser['author_name']]; Db::name('user')->where('user_id',$value['user_id'])->update($aUpdate); } //更新作者简介和单位 $aUpdateReviewer = []; if(isset($aUser['technical'])){ $aUpdateReviewer['technical'] = $aUser['technical']; } if(isset($aUser['introduction'])){ $aUpdateReviewer['introduction'] = $aUser['introduction']; } if(isset($aUser['company'])){ $aUpdateReviewer['company'] = $aUser['company']; } if(isset($aUpdateReviewer)){ if(in_array($value['user_id'], $aUserReviewer)){//更新 Db::name('user_reviewer_info')->where('reviewer_id',$value['user_id'])->limit(1)->update($aUpdateReviewer); } if(!in_array($value['user_id'], $aUserReviewer)){//插入 $aUpdateReviewer['reviewer_id'] = $value['user_id']; Db::name('user_reviewer_info')->insert($aUpdateReviewer); } } } Db::commit(); } //更新结论 if(!empty($aResultInfo)){ Db::startTrans(); foreach ($aResultInfo as $key => $value) { //记录ID $iRecordId = empty($value['record_id']) ? 0 : $value['record_id']; if(empty($iRecordId)){ continue; } //标题 $sTitle = empty($value['title']) ? '' : $value['title']; //内容 $sContent = empty($value['content']) ? '' : $value['content']; if(empty($sTitle) && empty($sContent)){ continue; } if(!empty($sTitle)){ $aUpdate['title'] = $sTitle; } if(!empty($sContent)){ $aUpdate['content'] = $sContent; } if(!empty($aUpdate)){ $aUpdate['update_time'] = time(); $aWhere = ['article_id' => $iArticleId,'id' => $iRecordId]; $result = DB::name('ai_article_results')->where($aWhere)->limit(1)->update($aUpdate); } } Db::commit(); } // $aResult['data'] = $aParam; return json_encode($aResult); } /** * 文章内容选择模版生成数据 * @param article_id 文章ID * @param template_id 模版ID * @param $iIsSync 是否同步素材到微信 1是2否 */ public function getTemplateContent($aParam = [],$iIsSync = 2){ //获取参数 $aParam = empty($aParam) ? $this->request->post() : $aParam; //文章ID $iArticleId = empty($aParam['article_id']) ? '' : $aParam['article_id']; //模版ID $iIsSync = empty($aParam['is_sync']) ? 2 : $aParam['is_sync']; //必填参数验证 if(empty($iArticleId)){ return json_encode(['status' => 2, 'msg' => 'Please select an article']); } //获取AI生成文章内容 $aAiContent = json_decode($this->getAiArticle(['article_id' => $iArticleId,'is_select_author' => 1]),true); $aAiContent = empty($aAiContent['data']) ? [] : $aAiContent['data']; $aAiArticle = empty($aAiContent['ai_article']) ? [] : $aAiContent['ai_article']; //判断是否生成AI内容 if(empty($aAiArticle)){ return json_encode(['status' => 3, 'msg' => 'The article content of WeChat official account has not been generated']); } //获取文章内容 $aResult = json_decode($this->getArticle($iArticleId),true); //获取数据 $aArticleContent = empty($aResult['data']) ? [] : $aResult['data']; if(empty($aArticleContent)){ return json_encode($aResult); } //文章数据 $aArticle = empty($aArticleContent['article']) ? [] : $aArticleContent['article']; if(empty($aArticle)){ return json_encode(['status' => 4,'msg' => 'Article data is empty']); } //期刊数据 $aJournal = empty($aArticleContent['journal']) ? [] : $aArticleContent['journal']; if(empty($aJournal)){ return json_encode(['status' => 4,'msg' => 'Journal data is empty']); } //子期刊数据 $aJournalStage = empty($aArticleContent['journal_stage']) ? [] : $aArticleContent['journal_stage']; //通讯作者 $aAuthor = empty($aArticleContent['author']) ? [] : $aArticleContent['author']; //文章图片 $sArticleIcon = trim($this->sJournalUsx,'/').$this->sArticleIcon.$aArticle['article_icon']; //期刊图片 $sJournalStageIcon = empty($aJournalStage['stage_icon']) ? '' : '/public/'.$aJournalStage['stage_icon']; $sJournalIcon = empty($aJournal['journal_icon']) ? '' : $this->sJournalIcon.$aJournal['journal_icon']; $sJournalIcon = empty($sJournalStageIcon) ? $sJournalIcon : $sJournalStageIcon; $sJournalIcon = trim($this->sJournalUsx,'/').$sJournalIcon; //期刊编辑二维码 $sEditorQrcode = empty($aJournal['editor_qrcode']) ? '' : $aJournal['editor_qrcode']; $sEditorQrcode = trim($this->sSubmissionUrl,'/').$this->sJournalEditorQrcode.$sEditorQrcode; //获取期刊二维码 $oMaterial = new Material; $aJournal['icon'] = $sJournalIcon; $aJournal['journal_stage_id'] = empty($aArticle['journal_stage_id']) ? 0 : $aArticle['journal_stage_id']; $aJournalQrCode = $oMaterial->createJournalQrCode($aJournal); $sJournalCode = empty($aJournalQrCode['qrcode_url']) ? '' : $this->sSubmissionUrl.'public/qrcode/'.$aJournalQrCode['qrcode_url']; $aAiArticle['journal_qrcode'] = $sJournalCode; //文章二维码 $aArticleQrCode = $oMaterial->createArticleQrCode($aArticle); $sArticleCode = empty($aArticleQrCode['qrcode_url']) ? '' : $this->sSubmissionUrl.'public/qrcode/'.$aArticleQrCode['qrcode_url']; $aAiArticle['article_qrcode'] = $sArticleCode; //文章cite $aAiArticle['cite'] = $this->_cite($aArticle,$aJournal,$aJournalStage); // //上传素材到微信 if($iIsSync == 1){ //查询参数组装 $aQueryParam = ['article_id' => $iArticleId,'journal_id' => $aArticle['journal_id']]; //组装作者数据 if(!empty($aAuthor)){ $aAuthor = $this->_dealAuthor($aAuthor); $aQueryParam['author_info'] = $aAuthor; } //获取素材信息 $oMaterial = new Material; $aReturnDataResult = json_decode($oMaterial->getMaterial($aQueryParam),true); $aReturnData = empty($aReturnDataResult['data']) ? [] : $aReturnDataResult['data']; //文章图片 $aDataInfo = empty($aReturnData['ai_article_material']) ? [] : $aReturnData['ai_article_material']; $aAiArticle['article_icon'] = empty($aDataInfo['media_url']) ? $sArticleIcon : $aDataInfo['media_url']; //文章二维码图片 $aDataInfo = empty($aReturnData['ai_article_qrcode']) ? [] : $aReturnData['ai_article_qrcode']; $aAiArticle['article_qrcode'] = empty($aDataInfo['media_url']) ? $sArticleIcon : $aDataInfo['media_url']; //期刊图片 $aDataInfo = empty($aReturnData['ai_journal_material']) ? [] : $aReturnData['ai_journal_material']; $aAiArticle['journal_icon'] = empty($aDataInfo['media_url']) ? $sJournalIcon : $aDataInfo['media_url']; //期刊二维码图片 $aDataInfo = empty($aReturnData['ai_journal_qrcode']) ? [] : $aReturnData['ai_journal_qrcode']; $aAiArticle['journal_qrcode'] = empty($aDataInfo['media_url']) ? $sJournalIcon : $aDataInfo['media_url']; //期刊编辑二维码 $aDataInfo = empty($aReturnData['ai_journal_editor_material']) ? [] : $aReturnData['ai_journal_editor_material']; $aAiArticle['editor_qrcode'] = empty($aDataInfo['media_url']) ? $sEditorQrcode : $aDataInfo['media_url']; //作者图片上传 $aDataInfo = empty($aReturnData['ai_author_material']) ? [] : $aReturnData['ai_author_material']; if(!empty($aDataInfo) && $aAuthor){ $aDataInfo = array_column($aDataInfo, null,'email'); foreach ($aAuthor as $key => $value) { $aAuthorData = empty($aDataInfo[$value['email']]) ? [] : $aDataInfo[$value['email']]; if(empty($aAuthorData)){ continue; } $aAuthor[$key]['icon'] = empty($aAuthorData['media_url']) ? $value['icon'] : $aAuthorData['media_url']; } } }else{ //处理文章图片地址数据 $aAiArticle['article_icon'] = $sArticleIcon; //处理文章期刊图片地址数据 $aAiArticle['journal_icon'] = $sJournalIcon; //期刊编辑二维码图片地址数据 $aAiArticle['editor_qrcode'] = $sEditorQrcode; //作者信息处理 if(!empty($aAuthor)){ $aAuthor = $this->_dealAuthor($aAuthor); } } //期刊访问地址 $journal_usx = trim($this->sJournalUsx,'/').'/'; if(!empty($aJournal['journal_usx'])){ //地址 $journal_usx .= $aJournal['journal_usx']??''.'/'; } $aAiArticle['journal_usx_url'] = trim($journal_usx); //处理期刊内容 if(empty($aJournal['journal_content'])){ $aJournal['journal_content'] = empty($aJournal['journal_content']) ? $aJournal['journal_content_english'] : $aJournal['journal_content']; } $aAiArticle += $aJournal; //获取模版信息 $sJournalIssn = empty($aJournal['issn']) ? 'default' : $aJournal['issn'];//期刊issn $sArticleType = empty($aArticle['type']) ? 'default' : $aArticle['type'];//文章类型 if(in_array($sArticleType, ['review','Mini Review'])){ $sArticleType = "Review"; } $sTemplatePath = ROOT_PATH."public/ArticleTemplate/".$sJournalIssn."/".$sArticleType; if (!is_dir($sTemplatePath)) {//默认模版信息 $sTemplatePath = ROOT_PATH."public/ArticleTemplate/default/".$sArticleType; } //index模版目录 $sTemplateIndexPath = $sTemplatePath.'/index.html'; // 验证文件有效性 if (!file_exists($sTemplateIndexPath)) { return json_encode(['status' => 4, 'msg' => 'Article template does not exist']); } if (!is_readable($sTemplateIndexPath)) { return json_encode(['status' => 5, 'msg' => 'The article template is unreadable']); } //获取模版内容 $sTemplate = file_get_contents($sTemplateIndexPath); //数据处理 $aSearch = []; foreach ($aAiArticle as $key => $value) { if(is_array($value)){ continue; } $aSearch['{###'.$key.'###}'] = empty($value) ? '' : $value; } //处理通讯作者信息数据 $aAuthorInfo = json_decode($this->dealTemplateAuthor($aAuthor,$sTemplatePath),true); $aAuthorInfo = empty($aAuthorInfo['data']) ? [] : $aAuthorInfo['data']; $aSearch['{###author_summary###}'] = empty($aAuthorInfo['author_info']) ? '' : $aAuthorInfo['author_info']; $aSearch['{###author_string###}'] = empty($aAuthorInfo['author_string']) ? '' : ',通讯作者为'.$aAuthorInfo['author_string']; //处理往期推荐数据 $aPreviousRecommend = json_decode($this->dealTemplatePreviousRecommend($aArticle,$sTemplatePath),true); $aSearch['{###previous_recommend_summary###}'] = empty($aPreviousRecommend['data']) ? '' : $aPreviousRecommend['data']; //处理期刊主题数据 $sJournalTopic = empty($aJournal['journal_topic']) ? '' : $aJournal['journal_topic']; $aTopic = json_decode($this->dealTemplateTopic($sJournalTopic,$sTemplatePath),true); $aSearch['{###topic_name_summary###}'] = empty($aTopic['data']) ? '' : $aTopic['data']; //公众号名字处理 $aSearch['{###wechat_name###}'] = empty($aSearch['{###wechat_name###}']) ? '“'.$aSearch['{###journal_title###}'].'“' : '“'.$aSearch['{###wechat_name###}'].'“'; //是否显示文章来源 //查询app_id和app_secret $sIssn = empty($aJournal['issn']) ? '' : $aJournal['issn']; $aTougaoJournal = Db::name('journal')->field('wechat_app_id,wechat_app_secret')->where('issn',$sIssn)->find(); if(!empty($aJournal)){ $wechat_app_id = empty($aTougaoJournal['wechat_app_id']) ? '' : $aTougaoJournal['wechat_app_id']; $aJournal['wechat_app_id'] = empty($aJournal['wechat_app_id']) ? $wechat_app_id : $aJournal['wechat_app_id']; $wechat_app_secret = empty($aTougaoJournal['wechat_app_secret']) ? '' : $aTougaoJournal['wechat_app_secret']; $aJournal['wechat_app_secret'] = empty($aJournal['wechat_app_secret']) ? $wechat_app_secret : $aJournal['wechat_app_secret']; } $aSearch['{###article_from###}'] = ''; if(empty($aJournal['wechat_app_id']) || empty($aJournal['wechat_app_secret'])){//获取默认推送公众号 $sTemplateFromPath = $sTemplatePath.'/article_from.html'; //获取默认推送公众号配置 $aWechatConfig = $this->aWechatConfig; if (file_exists($sTemplateFromPath) && is_readable($sTemplateFromPath)) { $sTemplateFromPath = file_get_contents($sTemplateFromPath); $aSearch['{###article_from###}'] = str_replace('{###journal_title###}', $aJournal['wechat_name']??$aWechatConfig['wechat_name'], $sTemplateFromPath); } $aSearch['{###wechat_name###}'] = '“'.$aWechatConfig['wechat_name'].'“'; } //模版替换变量 if(empty($aSearch)){ return json_encode(['status' => 6, 'msg' => '模版内容不能为空']); } $aSearch['{###jabbr###}'] = trim(trim($aSearch['{###jabbr###}'],'.'),'。'); //期刊封面 $aSearch['{###journal_icon_info###}'] = $aSearch['{###journal_icon_details###}'] = ''; if(!empty($sJournalIcon)){ $sTemplateJournalInfo = $sTemplatePath.'/journal_icon_info.html'; if(file_exists($sTemplateJournalInfo) && is_readable($sTemplateJournalInfo)) { $sTemplateJournalInfo = file_get_contents($sTemplateJournalInfo); $aSearch['{###journal_icon_info###}'] = str_replace('{###journal_icon###}', $aAiArticle['journal_icon']??'', $sTemplateJournalInfo); } $sTemplateJournalInfo = $sTemplatePath.'/journal_icon_details.html'; if(file_exists($sTemplateJournalInfo) && is_readable($sTemplateJournalInfo)) { $sTemplateJournalInfo = file_get_contents($sTemplateJournalInfo); $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'); return json_encode(['status' => 1, 'msg' => '模版生成成功','data' => ['template' => $sTemplate]]); } /** * 处理模版通讯作者 * @param article_id 文章ID */ private function dealTemplateAuthor($aAuthor = [],$sTemplatePath = ''){ //必填字段判断 if(empty($aAuthor) || empty($sTemplatePath)){ return json_encode(['status' => 2,'msg' => 'Corresponding author or template does not exist']); } //获取通讯作者模版 $sAuthorTemplatePathAuthor = $sTemplatePath.'/author.html'; if (!file_exists($sAuthorTemplatePathAuthor)) { return json_encode(['status' => 3, 'msg' => 'Corresponding author template does not exist','data' => '']); } if (!is_readable($sAuthorTemplatePathAuthor)) { return json_encode(['status' => 4, 'msg' => 'The corresponding author template is unreadable','data' => '']); } $sAuthorTemplate = file_get_contents($sAuthorTemplatePathAuthor); //默认头像 $aLogo = $this->aLogo; //数据处理 $aTranslate = $aAuthorSerachInfo = $aTranslateAuthorList = []; //通讯作者信息 $sAuthorInfo = ''; foreach ($aAuthor as $key => $value) { //所属单位处理 if(!empty($value['company'])){ $value['company'] =str_replace(',', ',', $value['company']); $aCompany = explode(',', $value['company']); } $value['company'] = empty($aCompany[0]) ? $value['company'] : trim($aCompany[0],','); $sAuthorInfo .= $value['company'].$value['author_name'].$value['technical'].','; if(empty($value['introduction'])){//简介为空不处理 continue; } $aTranslateAuthorList[$value['email']] = [ 'author_name' => empty($value['author_name']) ? '' : $value['author_name'], 'technical' => empty($value['technical']) ? '' : $value['technical'], 'introduction' => empty($value['introduction']) ? '' : $value['introduction'], 'company' => empty($value['company']) ? '' : $value['company'] ]; $aAuthorSerachInfo[] = $value; } //请求AI翻译 if(!empty($sAuthorInfo)){ $aTranslate = array_merge(['author_info' => trim($sAuthorInfo,',')],$aTranslate); } 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($aAuthorSerachInfo)){ foreach ($aAuthorSerachInfo as $key => $value) { $aInfo = empty($aTranslate[$value['email']]) ? [] : $aTranslate[$value['email']]; $value['author_name'] = empty($aInfo['author_name']) ? $value['author_name'] : $aInfo['author_name']; $value['technical'] = empty($aInfo['technical']) ? $value['technical'] : $aInfo['technical']; $value['introduction'] = empty($aInfo['introduction']) ? $value['introduction'] : $aInfo['introduction']; $value['company'] = empty($aInfo['company']) ? $value['company'] : $aInfo['company']; $aAuthorSerach = []; foreach ($value as $k => $val) { if($k == 'icon'){//头像拼接处理 $sIconInfo = empty($val) ? $aLogo['url'] : $val; $aParsedUrl = parse_url($sIconInfo); if(empty($aParsedUrl['scheme'])){ $aAuthorSerach['{###icon_path###}'] = trim($this->sSubmissionUrl,'/').$this->sUserIcon.$val; }else{ $aAuthorSerach['{###icon_path###}'] = $sIconInfo; } $aAuthorSerach['{###icon_path###}'] = trim($aAuthorSerach['{###icon_path###}'],'/'); }else{ $aAuthorSerach['{###'.$k.'###}'] = trim($val,'/'); } } $aAuthorSerachInfo[$key] = str_replace(array_keys($aAuthorSerach), array_values($aAuthorSerach), $sAuthorTemplate); } } //通讯作者列表 //获取通讯作者汇总模版 $sAuthorTemplatePath = $sTemplatePath.'/author_summary.html'; if (!file_exists($sAuthorTemplatePath)) { return json_encode(['status' => 3, 'msg' => 'Corresponding author template does not exist','data' => '']); } if (!is_readable($sAuthorTemplatePath)) { return json_encode(['status' => 4, 'msg' => 'The corresponding author template is unreadable','data' => '']); } $sAuthorTemplate = file_get_contents($sAuthorTemplatePath); //数据处理内容替换 $sInfo = empty($aAuthorSerachInfo) ? '' : implode("\n", $aAuthorSerachInfo); $sAuthorTemplate = empty($sInfo) ? '' : str_replace('{###author_info###}', $sInfo, $sAuthorTemplate); //通讯作者字符串处理 $sAuthorInfo = empty($aTranslate['author_info']) ? '' : $aTranslate['author_info']; return json_encode(['status' => 1,'msg' => 'success','data' => ['author_info' => $sAuthorTemplate,'author_string' => trim($sAuthorInfo,';')]]); } /** * 处理期刊主题模版 * @param article_id 文章ID */ private function dealTemplateTopic($sTopic = '',$sTemplatePath = ''){ if(empty($sTemplatePath)){ return json_encode(['status' => 2,'template does not exist']); } if(empty($sTopic)){ return json_encode(['status' => 2,'topic does not exist']); } //获取主题模版 $sTemplatePathTopic = $sTemplatePath.'/topic.html'; if (!file_exists($sTemplatePathTopic)) { return json_encode(['status' => 4, 'msg' => 'Corresponding author template does not exist']); } if (!is_readable($sTemplatePathTopic)) { return json_encode(['status' => 5, 'msg' => 'The corresponding author template is unreadable']); } $sTemplate = file_get_contents($sTemplatePathTopic); //数据处理 $sTopic = trim($sTopic); $aTopic = empty($sTopic) ? [] : explode(',', $sTopic); $aSearchInfo = []; if(!empty($aTopic)){ foreach ($aTopic as $key => $value) { $aSerach['{###topic_name###}'] = empty($value) ? '' : strip_tags($value); $aSearchInfo[] = str_replace(array_keys($aSerach), array_values($aSerach), $sTemplate); } } //获取期刊主题汇总模版 $sTemplatePath = $sTemplatePath.'/topic_summary.html'; if (!file_exists($sTemplatePath)) { return json_encode(['status' => 4, 'msg' => 'Corresponding author template does not exist']); } if (!is_readable($sTemplatePath)) { return json_encode(['status' => 5, 'msg' => 'The corresponding author template is unreadable']); } $sTemplate = file_get_contents($sTemplatePath); //模版数据替换 $sTopicName = empty($aSearchInfo) ? '' : implode("\n", $aSearchInfo); $sTemplate = empty($sTopicName) ? '' : str_replace('{###topic_name###}', $sTopicName, $sTemplate); return json_encode(['status' => 1,'msg' => 'success','data' => $sTemplate]); } /** * 处理往期推荐 * @param article_id 文章ID */ private function dealTemplatePreviousRecommend($aArticle=[],$sTemplatePath = ''){ if(empty($sTemplatePath)){ return json_encode(['status' => 2,'template does not exist']); } //获取往期推荐模版 $sTemplatePathRecommend = $sTemplatePath.'/previous_recommend.html'; if (!file_exists($sTemplatePathRecommend)) { return json_encode(['status' => 3, 'msg' => 'Corresponding author template does not exist']); } if (!is_readable($sTemplatePathRecommend)) { return json_encode(['status' => 4, 'msg' => 'The corresponding author template is unreadable']); } $sTemplate = file_get_contents($sTemplatePathRecommend); //判断是否关联文章 if(empty($aArticle['related'])){ return json_encode(['status' => 6, 'msg' => 'Unrelated articles']); } //获取关联文章信息 $aWhere = ['article_id' => ['in',json_decode($aArticle['related'],true)],'is_delete' => 2]; $aRecommend = Db::name('ai_article')->field('article_id')->where($aWhere)->select(); $aSearchInfo = []; if(!empty($aRecommend)){ $aId = array_column($aRecommend, 'article_id'); //查询是否推送到微信公众号并且已发布 $aWhere['is_publish'] = 1; $aWechatArticle = Db::name('ai_wechat_article')->field('article_id,media_url')->where($aWhere)->select(); if(empty($aWechatArticle)){ return json_encode(['status' => 6, 'msg' => 'No article published on WeChat official account was found']); } //查询文章图片 $aWhere = ['article_id' => ['in',$aId],'is_delete' => 2]; $aArticleMaterial = Db::name('ai_article_material')->where($aWhere)->column('article_id,media_url'); foreach ($aWechatArticle as $key => $value) { $aSearch['{###wechat_url###}'] = $value['media_url']; $sIcon = empty($aArticleMaterial[$value['article_id']]) ? '' : $aArticleMaterial[$value['article_id']]; $aSearch['{###wechat_media_url###}'] = $sIcon; $aSearchInfo[] = str_replace(array_keys($aSearch), array_values($aSearch), $sTemplate); } } //获取往期推荐汇总模版 $sTemplatePath = $sTemplatePath.'/previous_recommend_summary.html'; if (!file_exists($sTemplatePath)) { return json_encode(['status' => 3, 'msg' => 'Corresponding author template does not exist']); } if (!is_readable($sTemplatePath)) { return json_encode(['status' => 4, 'msg' => 'The corresponding author template is unreadable']); } $sTemplate = file_get_contents($sTemplatePath); //数据处理内容替换 $sInfo = empty($aSearchInfo) ? '' : implode("\n", $aSearchInfo); $sTemplate = empty($sInfo) ? '' : str_replace('{###previous_recommend###}', $sInfo, $sTemplate); return json_encode(['status' => 1,'msg' => 'success','data' => $sTemplate]); } /** * 文章同步到微信公众号草稿箱 * @param article_id 文章ID */ public function syncWechat($aParam = []){ //获取参数 $aParam = empty($aParam) ? $this->request->post() : $aParam; //文章ID $iArticleId = empty($aParam['article_id'] ) ? '' : $aParam['article_id']; //必填参数验证 if(empty($iArticleId)){ return json_encode(['status' => 2, 'msg' => 'Please select an article']); } //判断草稿箱是否上传 $oMaterial = new Material; $aLog = json_decode($oMaterial->getWechatLog(['article_id' => $iArticleId,'type' => 2,'status' =>1]),true); if(!empty($aLog['data'])){ return json_encode(['status' => 1,'msg' => 'Already uploaded to draft box','data' => []]); } //判断文章类型 $article_type = empty($aParam['article_type']) ? 'news' : $aParam['article_type']; if(!in_array($article_type, ['news','newspic'])){ return json_encode(['status' => 6,'msg' => "The article type does not match"]); } //查询文章是否存在 $aWhere = ['article_id' => $iArticleId,'is_delete' => 2]; $aAiArticle = Db::name('ai_article')->field('ai_article_id,title_chinese as title,journal_issn,digest,article_type')->where($aWhere)->find(); if(empty($aAiArticle)){ return json_encode(['status' => 3, 'msg' => 'The article does not exist']); } $sWechatId = empty($aAiArticle['journal_issn']) ? '' : $aAiArticle['journal_issn']; if(empty($sWechatId)){ return json_encode(['status' => 2, 'msg' => 'Please select the WeChat official account to push']); } //获取模版 $sTemplate = empty($aAiArticle['article_type']) ? 'default' : $aAiArticle['article_type'];//文章类型 if(in_array($sTemplate, ['review','Mini Review'])){ $sTemplate = "Review"; } //查询期刊微信公众号配置 $aJournalInfo = Db::name('journal')->field('wechat_app_id,wechat_app_secret')->where('issn',$sWechatId)->find(); if(empty($aJournalInfo['wechat_app_id']) || empty($aJournalInfo['wechat_app_secret'])){ //获取默认配置 $aJournalInfo = $this->aWechatConfig; $sWechatId = $aJournalInfo['issn'] ?? 'default'; } //查询该模版是否推送到微信公众号 $aWhere['wechat_id'] = $sWechatId; $aWhere['template_id'] = $sTemplate; $aWhere['wechat_id'] = $aAiArticle['journal_issn']; $aWechatArticle = Db::name('ai_wechat_article')->where($aWhere)->find(); if(!empty($aWechatArticle)){ return json_encode(['status' => 4, 'msg' => 'Already uploaded to draft box']); } //数据处理-标题 $sTitle = empty($aAiArticle['title']) ? '' : $aAiArticle['title']; $sTitle = mb_convert_encoding($sTitle, 'UTF-8', 'auto'); $aAiArticle['title'] = $this->truncateByBytes($sTitle); //数据处理-摘要 $sDigest = empty($aAiArticle['digest']) ? '' : $aAiArticle['digest']; $sDigest = mb_convert_encoding($sDigest, 'UTF-8', 'auto'); $aAiArticle['digest'] = $this->truncateByBytes($sDigest, 120); //是否打开评论,0不打开(默认),1打开 $aParam['need_open_comment'] = empty($aParam['need_open_comment']) ? 1 : $aParam['need_open_comment']; //是否粉丝才可评论,0所有人可评论(默认),1粉丝才可评论 $aParam['only_fans_can_comment'] = empty($aParam['only_fans_can_comment']) ? 1 : $aParam['only_fans_can_comment']; //查询文章封面 $aMaterial = Db::name('ai_article_material')->field('media_id as thumb_media_id')->where('article_id',$iArticleId)->find(); if(!empty($aMaterial)){ $aAiArticle += $aMaterial; } $aParam += $aAiArticle; //获取模版生成内容 $aTemplateParam = ['article_id' => $iArticleId,'template_id' => $sTemplate,'is_sync' => 1,'wechat_id' => $sWechatId]; $aTemplateParam += $aJournalInfo; $aResult = json_decode($this->getTemplateContent($aTemplateParam,1),true); $sMsg = empty($aResult['msg']) ? 'The content is empty' : $aResult['msg']; $aData = empty($aResult['data']) ? [] : $aResult['data']; if(empty($aData['template'])){ return json_encode(['status' => 4, 'msg' => $sMsg]); } //请求微信公众号接口推送 $aParam['content'] = $aData['template']; $aParam += $aJournalInfo; $oWechat = new Wechat; $aResult = json_decode($oWechat->addDraft($aParam),true); $aData = empty($aResult['data']) ? [] : $aResult['data']; //插入操作日志 $iStatus = empty($aResult['status']) ? 0 : $aResult['status']; $sMsg = empty($aResult['msg']) ? '' : $aResult['msg']; if ($iStatus != 1) { $iStatus = 2; $sMsg = empty($sMsg) ? '草稿箱推送失败' : $sMsg; } //插入日志记录 $oMaterial = new Material; $aLogInfo = ['article_id' => $iArticleId,'type' => 2,'msg' =>$sMsg,'status' => $iStatus,'create_time' => time()]; $result = json_decode($oMaterial->addWechatLog($aLogInfo),true); if(empty($aData)){ return json_encode($aResult); } //插入记录表 $aParam = ['media_id' => $aData['media_id'],'update_time' => time(),'template_id' => $sTemplate,'template_content' => $aParam['content'],'article_id' => $iArticleId,'article_type' => $article_type,'need_open_comment' => $aParam['need_open_comment'],'only_fans_can_comment' => $aParam['only_fans_can_comment'],'create_time' => time(),'wechat_id' => $sWechatId,'ai_article_id' => $aAiArticle['ai_article_id']]; $result = Db::name('ai_wechat_article')->insert($aParam); if($result === false){ return json_encode(['status' => 5,'msg' => "Article data insertion failed"]); } //写入发布队列 // Queue::later(60,'app\api\job\WechatPublishDraft@fire', ['article_id' => $iArticleId], 'WechatDraftPublish'); return json_encode(['status' => 1,'msg' => 'Upload draft box successfully','data' => []]); } /** * 字符串处理 * @param article_id 文章ID */ private function truncateByBytes($str, $maxLength = 64) { $totalChars = mb_strlen($str, 'UTF-8'); if($totalChars >= $maxLength){ return mb_substr($str,0,$maxLength); } return $str; } /** * 获取Ai生成文章状态 * @param article_id 文章ID */ public function getAiArticleStatus(){ $aParam = $this->request->post(); //AI生成文章ID $iArticleId = empty($aParam['article_id']) ? '' : $aParam['article_id']; if(empty($iArticleId)){ return json_encode(['status' => 2,'msg' => 'Please select the article to be generated']); } //返回数据定义 $aResult = ['generate_status' => 3,'draft_status' => 2,'publish_status' => -1]; //查询AI生成的文章内容 $aWhere = ['is_delete' => 2]; if(!empty($iArticleId)){ $aWhere['article_id'] = $iArticleId; } $aAiArticle = Db::name('ai_article')->field('is_generate')->where($aWhere)->find(); // 生成状态 $aMsg = [1 => 'The data has been generated, please proceed with the next steps',2 => 'AI content generation in progress',3 => 'AI content not generated',4 => 'The article has been pushed to the draft box',6 => 'The article has been pushed to the draft box']; $iStatus = empty($aAiArticle['is_generate']) ? 3 : $aAiArticle['is_generate']; $sMsg = empty($aMsg[$iStatus]) ? 'illegal request' : $aMsg[$iStatus]; $aResult['generate_status'] = $iStatus; if(!empty($aAiArticle)){ $iStatus = 2; $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']; //判断是否上传素材 $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($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($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']; //查询微信接口获取发布状态 if($aDraft['publish_status'] == 1){ $aReturnData = json_decode($this->queryStatus($aDraft),true); $aData = empty($aReturnData['data']['data']) ? [] : $aReturnData['data']['data']; } $iStatus = empty($aData['publish_status']) ? $aDraft['publish_status'] : $aData['publish_status']; $aResult['publish_status'] = $iStatus; } } $sMsg = empty($aMsg[$iStatus]) ? 'illegal request' : $aMsg[$iStatus]; return json_encode(['status' => 1,'msg' => $sMsg,'data' => $aResult]); } /** * 获取公众号信息 */ public function getWechatLists(){ $aWhere = ['state' => 0,'wechat_app_id' => ['<>',''],'wechat_app_secret' => ['<>','']]; $aJournal = Db::name('journal')->field('issn,wechat_name')->where($aWhere)->select(); return json_encode(['status' => 1,'msg' => 'success','data' => $aJournal]); } /** * 公众号文章发布 */ public function publishDraft($aParam = []){ //获取参数 $aParam = empty($aParam) ? $this->request->post() : $aParam; //文章ID $iArticleId = empty($aParam['article_id'] ) ? '' : $aParam['article_id']; //必填参数验证 if(empty($iArticleId)){ return json_encode(['status' => 2, 'msg' => 'Please select an article']); } //查询文章是否存在 $aWhere = ['article_id' => $iArticleId,'is_delete' => 2]; $aAiArticle = Db::name('ai_article')->field('article_type')->where($aWhere)->find(); if(empty($aAiArticle)){ return json_encode(['status' => 3, 'msg' => 'The article does not exist']); } //查询是否上传到草稿箱 $aWhere = ['article_id' => $iArticleId,'template_id' => $aAiArticle['article_type']]; $aWechatArticle = Db::name('ai_wechat_article')->field('id,is_publish,media_id,publish_status,wechat_id')->where($aWhere)->find(); $sMediaId = empty($aWechatArticle['media_id']) ? '' : $aWechatArticle['media_id']; if(empty($sMediaId)){ return json_encode(['status' => 3, 'msg' => 'The article was not found in the draft box of WeChat official account']); } $iId = empty($aWechatArticle['id']) ? 0 : $aWechatArticle['id']; //推送公众号Id $sWechatId = empty($aWechatArticle['wechat_id']) ? '' : $aWechatArticle['wechat_id']; //判断是否发布 if($aWechatArticle['publish_status'] != '-1'){ return json_encode(['status' => 5, 'msg' => 'The article has been published, please confirm']); } //查询期刊微信公众号配置 $aJournalInfo = Db::name('journal')->field('wechat_app_id,wechat_app_secret')->where('issn',$sWechatId)->find(); if(empty($aJournalInfo['wechat_app_id']) || empty($aJournalInfo['wechat_app_secret'])){ //获取默认配置 $aJournalInfo = $this->aWechatConfig; } $aJournalInfo['media_id'] = $sMediaId; //调用发布接口 $oWechat = new Wechat; $aResult = json_decode($oWechat->publishDraft($aJournalInfo),true); $iStatus = empty($aResult['status']) ? 0 : $aResult['status']; $sMsg = empty($aResult['msg']) ? '' : $aResult['msg']; if ($iStatus != 1) { $iStatus = 2; $sMsg = empty($sMsg) ? '发布失败' : $sMsg; } //插入日志记录 $oMaterial = new Material; $aLogInfo = ['article_id' => $iArticleId,'type' => 3,'msg' =>$sMsg,'status' => $iStatus,'create_time' => time()]; $result = json_decode($oMaterial->addWechatLog($aLogInfo),true); if($iStatus != 1){ return json_encode($aResult); } //更新数据表 //更新文章表publish_id $aData = empty($aResult['data']) ? [] : $aResult['data']; $aUpdate = ['update_time' => time(),'is_publish' => 1,'publish_id' => $aData['publish_id'],'publish_status' => 1]; $result = Db::name('ai_wechat_article')->where('id',$iId)->limit(1)->update($aUpdate); if($result === false){ return json_encode(['status' => 5,'msg' => "Failed to update the status of the published article"]); } //发布成功查询状态 $iDelaySeconds = 30;//4 * 3600; // 30秒数 Queue::later($iDelaySeconds,'app\api\job\WechatQueryStatus@fire', ['article_id' => $iArticleId], 'WechatQueryStatus'); return json_encode(['status' => 1,'msg' => 'Draft box article successfully published','data' => []]); } /** * CURL 查询文章的发布状态 * @param $sToken Token * @param article_id array 文章ID */ public function queryStatus($aParam = []){ //获取参数 $aParam = empty($aParam) ? $this->request->post() : $aParam; //查询条件 $aWhere = ['is_publish' => 1,'publish_id' => ['<>',''],'publish_status' => 1,'is_delete' => 2]; //文章ID if(!empty($aParam['article_id'])){ $aWhere['article_id'] = $aParam['article_id']; } //模版ID if(!empty($aParam['template_id'])){ $aWhere['template_id'] = $aParam['template_id']; } //推送公众号Id if(!empty($aParam['wechat_id'])){ $aWhere['wechat_id'] = $aParam['wechat_id']; } //查询待发布文章信息 $aWechatArticle = Db::name('ai_wechat_article')->where($aWhere)->field('id,article_id,template_id,wechat_id,publish_id')->select(); if(empty($aWechatArticle)){ return json_encode(['status' => 2,'msg' => 'No articles requiring synchronization status were found'],true); } //查询期刊微信公众号配置 $aIssn = array_unique(array_column($aWechatArticle, 'wechat_id')); if(empty($aIssn)){ return json_encode(['status' => 3,'msg' => 'Official account information is empty']); } $aWhere = ['issn' => ['in',$aIssn]]; $aJournalInfo = Db::name('journal')->field('issn,wechat_app_id,wechat_app_secret')->where($aWhere)->select(); if(!empty($aJournalInfo)){ $aJournalInfo = array_column($aJournalInfo, null,'issn'); } //循环处理 $oWechat = new Wechat; $aInsert = []; Db::startTrans(); foreach ($aWechatArticle as $key => $value) { if(empty($value['wechat_id']) || empty($value['publish_id'])){ continue; } //账号信息 $aAccount = empty($aJournalInfo[$value['wechat_id']]) ? [] : $aJournalInfo[$value['wechat_id']]; if(empty($aAccount['wechat_app_id']) || empty($aAccount['wechat_app_secret'])){ $aAccount = $this->aWechatConfig; } $aAccount['publish_id'] = $value['publish_id']; $aResult = json_decode($oWechat->queryStatus($aAccount),true); $aData = empty($aResult['data']) ? [] : $aResult['data']; if(empty($aData)){ continue; } //日志记录 $aData = $this->dealStatusData($aData); $aLog = empty($aData['log']) ? [] : $aData['log']; if(!empty($aLog)){ $aInsert[] = $aData['log']; } //更新状态 $aDetail = empty($aData['article_detail']) ? [] : $aData['article_detail']; $iStatus = isset($aLog['publish_status']) ? $aLog['publish_status'] : $value['publish_status']; //微信文章链接 $sUrl = empty($aDetail[0]['article_url']) ? '' : $aDetail[0]['article_url']; $updateResult = Db::name('ai_wechat_article')->where('id',$value['id'])->limit(1)->update(['publish_status' => $iStatus,'wechat_article_url' => $sUrl,'update_time' => time()]); } //插入日志表 if(!empty($aInsert)){ $insertResult = Db::name('wechat_article_publish_log')->insertAll($aInsert); } Db::commit(); return json_encode(['status' => 1,'msg' => 'success']); } /** * 发布日志数据处理 * @param $sToken Token * @param article_id array 文章ID */ private function dealStatusData($aParam = []){ //log日志需要参数 $aField = ['publish_id' => '','publish_status' => '' ,'article_id' => '' ,'article_detail' => '' ,'fail_idx' => '']; $aDetail = []; foreach ($aParam as $key => $value) { if($key == 'article_detail'){ $aDetail = empty($value) ? [] : $value; $aDetail = empty($aDetail['item']) ? [] : $aDetail['item']; } $aField[$key] = empty($value) ? '' : $value; $aField[$key] = is_array($aField[$key]) ? json_encode($aField[$key]) : $aField[$key]; } $aField['create_time'] = time(); return ['article_detail' => $aDetail,'log' => $aField]; } /** * 上传素材 * @param $sToken Token * @param article_id array 文章ID */ public function uploadMaterial($aParam = []){ //获取参数 $aParam = empty($aParam) ? $this->request->post() : $aParam; //文章ID $iArticleId = empty($aParam['article_id']) ? '' : $aParam['article_id']; //必填参数验证 if(empty($iArticleId)){ return json_encode(['status' => 2, 'msg' => 'Please select an article']); } //判断素材是否上传 $oMaterial = new Material; $aLog = json_decode($oMaterial->getWechatLog(['article_id' => $iArticleId,'type' => 1,'status' =>1]),true); if(!empty($aLog['data'])){ $aLog = json_decode($oMaterial->getWechatLog(['article_id' => $iArticleId,'type' => 2,'status' =>1]),true); if(empty($aLog['data'])){ //推送到草稿箱 Queue::push('app\api\job\WechatDraft@fire', ['article_id' => $iArticleId], 'WechatDraft'); return json_encode(['status' => 1,'msg' => 'The article material has been pushed into the draft box queue','data' => []]); } return json_encode(['status' => 1,'msg' => 'The material has been uploaded','data' => []]); } //获取AI生成文章内容 $aAiContent = json_decode($this->getAiArticle(['article_id' => $iArticleId,'is_select_author' => 1]),true); $aAiContent = empty($aAiContent['data']) ? [] : $aAiContent['data']; $aAiArticle = empty($aAiContent['ai_article']) ? [] : $aAiContent['ai_article']; //判断是否生成AI内容 if(empty($aAiArticle)){ return json_encode(['status' => 3, 'msg' => 'The article content of WeChat official account has not been generated']); } //获取文章内容 $aResult = json_decode($this->getArticle($iArticleId),true); //获取数据 $aArticleContent = empty($aResult['data']) ? [] : $aResult['data']; if(empty($aArticleContent)){ return json_encode($aResult); } //文章数据 $aArticle = empty($aArticleContent['article']) ? [] : $aArticleContent['article']; if(empty($aArticle)){ return json_encode(['status' => 4,'msg' => 'Article data is empty']); } //期刊数据 $aJournal = empty($aArticleContent['journal']) ? [] : $aArticleContent['journal']; if(empty($aJournal)){ return json_encode(['status' => 4,'msg' => 'Journal data is empty']); } //通讯作者 $aAuthor = empty($aArticleContent['author']) ? [] : $aArticleContent['author']; //文章图片 $sArticleIcon = trim($this->sJournalUsx,'/').$this->sArticleIcon.$aArticle['article_icon']; //子期刊数据 $aJournalStage = empty($aArticleContent['journal_stage']) ? [] : $aArticleContent['journal_stage']; //期刊图片 $sJournalStageIcon = empty($aJournalStage['stage_icon']) ? '' : '/public/'.$aJournalStage['stage_icon']; $sJournalIcon = empty($aJournal['journal_icon']) ? '' : $this->sJournalIcon.$aJournal['journal_icon']; $sJournalIcon = empty($sJournalStageIcon) ? $sJournalIcon : $sJournalStageIcon; $sJournalIcon = trim($this->sJournalUsx,'/').$sJournalIcon; //期刊编辑二维码 $editor_qrcode = empty($aJournal['editor_qrcode']) ? '' : $aJournal['editor_qrcode']; $sEditorQrcode = trim($this->sSubmissionUrl,'/').$this->sJournalEditorQrcode.$editor_qrcode; //获取期刊二维码 $oMaterial = new Material; $aJournal['journal_stage_id'] = empty($aArticle['journal_stage_id']) ? 0 : $aArticle['journal_stage_id']; $aJournalQrCode = $oMaterial->createJournalQrCode($aJournal); $sJournalCode = empty($aJournalQrCode['qrcode_url']) ? '' : $this->sSubmissionUrl.'public/qrcode/'.$aJournalQrCode['qrcode_url']; $aAiArticle['journal_qrcode'] = $sJournalCode; //文章二维码 $aArticleQrCode = $oMaterial->createArticleQrCode($aArticle); $sArticleCode = empty($aArticleQrCode['qrcode_url']) ? '' : $this->sSubmissionUrl.'public/qrcode/'.$aArticleQrCode['qrcode_url']; $aAiArticle['article_qrcode'] = $sArticleCode; // //上传素材到微信 //组装文章数据 $aWechatConfig = $this->aWechatConfig; $sWechatAppId = empty($aJournal['wechat_app_id']) ? $aWechatConfig['wechat_app_id'] : $aJournal['wechat_app_id']; $sWechatAppSecret = empty($aJournal['wechat_app_secret']) ? $aWechatConfig['wechat_app_secret'] : $aJournal['wechat_app_secret']; $aUpload['article_info'] = ['icon' => $sArticleIcon]; //组装期刊数据 $aUpload['journal_info'] = ['icon' => $sJournalIcon,'editor_qrcode' => $editor_qrcode,'journal_stage_id' => $aArticle['journal_stage_id']]; //组装作者数据 if(!empty($aAuthor)){ $aUpload['author_info'] = $this->_dealAuthor($aAuthor); } //上传微信公众号用到的素材 $aUpload += ['article_id' => $iArticleId,'journal_id' => $aArticle['journal_id'],'wechat_app_id' => $sWechatAppId,'wechat_app_secret' => $sWechatAppSecret]; $aResult = $oMaterial->uploadMaterial($aUpload); return $aResult; } /** * 获取文章对应模版 */ private function writeFile($sContent,$sPath = ''){ $chunkSize = 1024 * 1024; // 例如,每次写入1MB $file = fopen($sPath, "w"); for ($i = 0; $i < strlen($sContent); $i += $chunkSize) { $chunk = substr($sContent, $i, $chunkSize); fwrite($file, $chunk); } 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+\s*/i', '', $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]); } }