Files
tougao/application/api/controller/Aiarticle.php
2025-09-29 17:50:32 +08:00

1597 lines
75 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace app\api\controller;
use app\api\controller\Base;
use think\Controller;
use think\Db;
use app\common\QrCodeImage;
use app\common\Wechat;
use app\common\Material;
use think\Cache;
use think\Queue;
use app\common\OpenAi;
/**
* @title 数据库接口
* @description 数据库接口
* @group 数据库接口
*/
class Aiarticle extends Base
{
protected $aLogo = ['media_id' => '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'] . '. <i>' . choiseJabbr($aArticle['article_id'], $jabbr) . '</i>. ' . $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]);
}
}