Merge remote-tracking branch 'origin/master'

This commit is contained in:
wangjinlei
2025-07-25 17:28:13 +08:00
21 changed files with 2595 additions and 1762 deletions

View File

@@ -18,9 +18,6 @@ class Aiarticle extends Base
{
protected $aLogo = ['media_id' => 'Cn8zlXvVB5DwjcA9h40z9fprHDoc3Jqv97SwrInpmyYiilkeRdKvpD63cWqTYHfz','url' => 'http://mmbiz.qpic.cn/mmbiz_jpg/QHFVW13lONaQJxK9QbHU9CtrvTS2ModZnUyeAvuVN67t8XP85DxVJwDJf2YxCTalrsr17jS080xM6xQv5yGiaEQ/0?wx_fmt=jpeg'];//默认头像
//数据表必填字段[ai_article]
protected $aAiFileds = ['article_id','title_english','title_chinese','journal_issn','covered','digest','research_result','content','highlights','discussion','prospect','research_background','discussion_results','research_method','overview','summary'];
//期刊接口地址
protected $sJournalUrl = 'http://journalapi.tmrjournals.com/public/index.php';//'http://zmzm.journal.dev.com'; //
//期刊官网
@@ -53,59 +50,10 @@ class Aiarticle extends Base
}
/**
* @title 请求OPENAI
* @title 生成公微
* @param aSearch array 模版内容
* @param iTemplateId 模版ID
*/
private function _createContentForOpenAI($aSearch = [],$sArticleType = 'default',$isTranslate = 2){
if(empty($aSearch) || empty($sArticleType)){
return json_encode(array('status' => 2,'msg' => 'Please select a template or enter the content you want to consult'));
}
//组织参数
if(in_array($sArticleType, ['Mini Review','Review'])){
$sArticleType = 'Review';
}else{
$sArticleType = 'default';
}
if($isTranslate == 1){
$sArticleType = 1;
}
//获取问答内容
$oOpenAi = new OpenAi;
if($sArticleType == 'default'){
$aMessage = $oOpenAi->buildDefaultPrompt($aSearch);
if(empty($aMessage)){
return json_encode(['status' => 5,'msg' => 'AI Q&A content not obtained']);
}
$aParam = ['messages' => $aMessage,'model' => empty($aParam['api_model']) ? 'gpt-4.1' : $aParam['api_model'],'redis_id' => empty($aSearch['article_id']) ? 0 : $aSearch['article_id']];
$aResult = json_decode($oOpenAi->createWechatContent($aParam),true);
}
if($sArticleType == 'Review'){
$aMessage = $oOpenAi->buildReviewPrompt($aSearch);
if(empty($aMessage)){
return json_encode(['status' => 5,'msg' => 'AI Q&A content not obtained']);
}
$aParam = ['messages' => $aMessage,'model' => empty($aParam['api_model']) ? 'gpt-4.1' : $aParam['api_model'],'redis_id' => empty($aSearch['article_id']) ? 0 : $aSearch['article_id']];
$aResult = json_decode($oOpenAi->createWechatContent($aParam),true);
}
if($sArticleType == 1){
$aMessage = $oOpenAi->buildTranslatePrompt($aSearch);
if(empty($aMessage)){
return json_encode(['status' => 5,'msg' => 'AI Q&A content not obtained']);
}
$aParam = ['messages' => $aMessage,'model' => empty($aParam['api_model']) ? 'gpt-4.1' : $aParam['api_model']];
$aResult = json_decode($oOpenAi->curlOpenAI($aParam),true);
}
//请求OPENAI接口
$iStatus = empty($aResult['status']) ? 0 : $aResult['status'];
if($iStatus != 1){
return json_encode($aResult);
}
return json_encode(array('status' => 1,'msg' => 'Content is being generated, please wait'));
}
public function create($aParam = []){
//获取参数
@@ -157,8 +105,7 @@ class Aiarticle extends Base
return json_encode(['status' => 5,'msg' => 'The data has been generated, please proceed with the next steps']);
}
//请求OPENAI
$aResult = json_decode($this->createForOpenAi($aArticleContent,$aAiArticle),true);
return json_encode($aResult);
return $this->createForOpenAi($aArticleContent,$aAiArticle);
}
@@ -198,12 +145,17 @@ class Aiarticle extends Base
$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#}'],'.'),'。');
//写入Redis 标识已经开始请求OPENAI处理
$sArticleType = empty($aArticle['type']) ? 'default' : $aArticle['type'];
$aSearch['article_id'] = $iArticleId;
$aResult = $this->_createContentForOpenAI($aSearch,$sArticleType);
return $aResult;
$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);
}
/**
@@ -277,7 +229,7 @@ class Aiarticle extends Base
//是否查询作者 1是2否
$iSelectAuthor = empty($aParam['is_select_author']) ? 2 : $aParam['is_select_author'];
//查询AI生成的文章内容
$aWhere = ['is_delete' => 2];
$aWhere = ['is_delete' => 2,'is_generate' => 1];
if(!empty($iArticleId)){
$aWhere['article_id'] = $iArticleId;
}
@@ -390,118 +342,74 @@ class Aiarticle extends Base
//获取参数
$aParam = empty($aParam) ? $this->request->post() : $aParam;
//主键ID
$iAiArticleId = empty($aParam['ai_article_id']) ? 0 : $aParam['ai_article_id'];
//文章ID
$iArticleId = empty($aParam['article_id']) ? 0 : $aParam['article_id'];
//查询内容是否存在
$aWhere = ['is_delete' => 2];
if(empty($iArticleId) && 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);
}
if(!empty($iArticleId)){
$aWhere['article_id'] = $iArticleId;
}
if(!empty($iAiArticleId)){
$aWhere['ai_article_id'] = $iAiArticleId;
}
$aAiArticle = Db::name('ai_article')->where($aWhere)->find();
if(empty($aAiArticle)){
return json_encode(['status' => 3,'msg' => 'he article content of WeChat official account has not been generated']);
}
//必填参数验证
$aFields = $this->aAiFileds;
$sFiled = '';
$aUpdateParam = [];
foreach($aFields as $val){
if(!isset($aParam[$val])){
continue;
}
if(is_array($aParam[$val])){
$aParam[$val] = implode(";",$aParam[$val]);
}
$aUpdateParam[$val] = empty($aParam[$val]) ? '' : addslashes(strip_tags($aParam[$val]));
}
if(empty($aUpdateParam)){
return json_encode(['status' => 1,'msg' => 'No data currently being processed']);
}
Db::startTrans();
//执行入库
$aUpdateParam['update_time'] = time();
$aUpdateParam['is_generate'] = 1;
$result = Db::name('ai_article')->where('ai_article_id',$iAiArticleId)->limit(1)->update($aUpdateParam);
if($result === false){
$aResult = json_encode(['status' => 3,'msg' => 'UPDATEING AI article failed']);
}
$aResult['data'] = $aUpdateParam;
//更新作者信息
$aAuthorList = empty($aParam['author_list']) ? []: $aParam['author_list'];
$aAuthorList = is_array( $aAuthorList) ? $aAuthorList: json_decode($aAuthorList,true);
if(!empty($aAuthorList)){
$aAuthorList = array_column($aAuthorList, null,'email');
//根据邮箱查询作者信息
$aEmail = array_keys($aAuthorList);
if(empty($aAuthorList)){
return json_encode($aResult);
}
$aUserInfo = $aUserReviewer = [];
if(!empty($aEmail)){
$aUserParam = ['email' => ['in',$aEmail]];
$aUserInfo = Db::name('user')->field('email,user_id')->where($aUserParam)->select();
if(!empty($aUserInfo)){
$aUserId = array_column($aUserInfo, 'user_id');
//查询用户附表
$aWhere = ['reviewer_id' => ['in',$aUserId]];
$aUserReviewer = Db::name('user_reviewer_info')->where($aWhere)->column('reviewer_id');
//根据邮箱查询作者信息
$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);
}
}
//更新用户信息
if(!empty($aUserInfo)){
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();
$aResult['data'] = $aUpdateParam;
$aResult['data'] = $aParam;
return json_encode($aResult);
}
@@ -695,11 +603,11 @@ class Aiarticle extends Base
//处理通讯作者信息数据
$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'];
@@ -741,12 +649,6 @@ class Aiarticle extends Base
}
$aSearch['{###jabbr###}'] = trim(trim($aSearch['{###jabbr###}'],'.'),'。');
// $aSearch['{###free_year###}'] = date('Y');
// $aSearch['{###covered###}'] = '内容涵盖'.str_replace('研究涵盖', '', $aSearch['{###covered###}']);
if(!empty($aSearch['{###covered###}']) && strpos($aSearch['{###covered###}'], '涵盖') === false){
$aSearch['{###covered###}'] = '内容涵盖'.str_replace('研究涵盖', '', $aSearch['{###covered###}']);
}
//期刊封面
$aSearch['{###journal_icon_info###}'] = $aSearch['{###journal_icon_details###}'] = '';
if(!empty($sJournalIcon)){
@@ -761,7 +663,8 @@ class Aiarticle extends Base
$aSearch['{###journal_icon_details###}'] = str_replace('{###journal_icon###}', $aAiArticle['journal_icon']??'', $sTemplateJournalInfo);
}
}
$aSearch['{###covered###}'] = empty($aSearch['{###covered###}']) ? '' : '内容涵盖'.$aSearch['{###covered###}'];
$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]]);
@@ -788,58 +691,70 @@ class Aiarticle extends Base
}
$sAuthorTemplate = file_get_contents($sAuthorTemplatePathAuthor);
//处理模版变量
$aAuthorSerachInfo = [];
$sAuthorInfo = '';
//默认头像
$aLogo = $this->aLogo;
//请求AI翻译
$sContent = '';
$aSearch['{#content#}'] = json_encode($aAuthor);
$aResult = json_decode($this->_createContentForOpenAI($aSearch,1,1),true);
$aContent = empty($aResult['data']) ? [] : array_column($aResult['data'], null,'email');
//数据处理
$aTranslate = $aAuthorSerachInfo = $aTranslateAuthorList = [];
//通讯作者信息
$sAuthorInfo = '';
foreach ($aAuthor as $key => $value) {
//请求AI翻译
$aInfo = empty($aContent[$value['email']]) ? [] : $aContent[$value['email']];
//替换模版
$aAuthorSerach = [];
//所属单位处理
$value['company'] = empty($aInfo['company']) ? $value['company'] : $aInfo['company'];
if(!empty($value['company'])){
$value['company'] =str_replace('', ',', $value['company']);
$aCompany = explode(',', $value['company']);
}
$value['company'] = empty($aCompany[0]) ? $value['company'] : trim($aCompany[0],',');
//简介处理
$value['introduction'] = empty($aInfo['introduction']) ? $value['introduction'] : $aInfo['introduction'];
//职称处理
$value['technical'] = empty($aInfo['technical']) ? $value['technical'] : $aInfo['technical'];
$sAuthorInfo .= $value['company'].$value['author_name'].$value['technical'].',';
if(empty($value['introduction'])){//简介为空不处理
$sTechnical = empty($value['technical']) ? '老师' : $value['technical'];
$sAuthorInfo .= $value['company'].$value['author_name'].$sTechnical.',';
continue;
}
//缓缓处理进行模版替换
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[] = str_replace(array_keys($aAuthorSerach), array_values($aAuthorSerach), $sAuthorTemplate);
$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';
@@ -855,7 +770,7 @@ class Aiarticle extends Base
$sAuthorTemplate = empty($sInfo) ? '' : str_replace('{###author_info###}', $sInfo, $sAuthorTemplate);
//通讯作者字符串处理
$sAuthorInfo = trim($sAuthorInfo,',');
$sAuthorInfo = empty($aTranslate['author_info']) ? '' : $aTranslate['author_info'];
return json_encode(['status' => 1,'msg' => 'success','data' => ['author_info' => $sAuthorTemplate,'author_string' => trim($sAuthorInfo,';')]]);
}

View File

@@ -5,6 +5,7 @@ namespace app\api\controller;
use app\api\controller\Base;
use think\Db;
use app\common\OpenAi;
use app\common\Article;
/**
* @title AI审核文章
* @description 对接OPENAI接口
@@ -53,7 +54,7 @@ class Aireview extends Base
}
//实例化公共方法
$oOpenAi = new OpenAi;
$oArticle = new Article;
if($aArticle['state'] > 4 ){
//查询文章内容
$aWhere['type'] = 0;
@@ -70,7 +71,7 @@ class Aireview extends Base
}
}else{
$aFile = json_decode($oOpenAi->getFileContent(['article_id' => $iArticleId]),true);
$aFile = json_decode($oArticle->getFileContent(['article_id' => $iArticleId]),true);
$aFile = empty($aFile['data']) ? [] : $aFile['data'];
$aArticleMain = empty($aFile['mains']) ? [] : $aFile['mains'];
}
@@ -92,7 +93,7 @@ class Aireview extends Base
$aSearch['{journal_name}'] = '传统医学研究';
}
//查询期刊内容
$aJournalPaperArt = json_decode($oOpenAi->getJournalPaperArt($aJournal),true);
$aJournalPaperArt = json_decode($oArticle->getJournalPaperArt($aJournal),true);
$sJournalContent = empty($aJournalPaperArt['data']) ? '' : implode('', $aJournalPaperArt['data']);
$sJournalContent = empty($sJournalContent) ? $aJournal['scope'] : $sJournalContent;
$aSearch['{scope}'] = $sJournalContent;//期刊范围
@@ -222,12 +223,14 @@ class Aireview extends Base
}
//查询文章
$aArticle = Db::table('t_article')->field('article_id,abstrart,keywords,journal_id,title,state')->where('article_id',$aParam['article_id'])->find();
$aArticle = Db::name('article')->field('article_id,abstrart,keywords,journal_id,title,state')->where('article_id',$aParam['article_id'])->find();
if(empty($aArticle)){
return json_encode(array('status' => 3,'msg' => 'No articles requiring review were found' ));
}
//查询文章审核内容
$aAiReview = Db::table('t_article_ai_review')->where('article_id',$aParam['article_id'])->find();
return json_encode(array('status' => 1,'msg' => 'Successfully obtained article review content','data' => $aAiReview,'article_data' => $aArticle));
$oAireview = new \app\common\Aireview;
$aAireview = $oAireview->get($aParam);
$aAireview = empty($aAireview['data']) ? [] : $aAireview['data'];
return json_encode(array('status' => 1,'msg' => 'Successfully obtained article review content','data' => $aAireview,'article_data' => $aArticle));
}
}