AI审稿功能开发

This commit is contained in:
chengxl
2025-07-01 16:34:27 +08:00
parent 4df77f0490
commit 83c46c6c7e

View File

@@ -4,7 +4,7 @@ namespace app\api\controller;
use app\api\controller\Base; use app\api\controller\Base;
use think\Db; use think\Db;
use app\common\OpenAi;
/** /**
* @title AI审核文章 * @title AI审核文章
* @description 对接OPENAI接口 * @description 对接OPENAI接口
@@ -12,69 +12,6 @@ use think\Db;
class Aireview extends Base class Aireview extends Base
{ {
protected $sApiKey;
protected $proxy;
protected $sUrl;
protected $curl;
protected $sResponesData;
protected $sError;
protected $timeout = 60;
public function __construct(\think\Request $request = null) {
// 从配置读取敏感信息(非硬编码)
$this->sApiKey = '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';
$this->proxy = '';
$this->sUrl = 'https://api.openai.com/v1/chat/completions';
parent::__construct($request);
}
/**
* CURL 发送请求到 OpenAI
* @param $messages 内容
* @param $model 模型类型
*/
protected function curlOpenAI($messages, $model = 'gpt-4o'){
$sUrl = $this->sUrl;
$data = [
'model' => $model,
'messages' => $messages,
'temperature' => 0.7
];
$this->curl = curl_init();
// 通用配置
curl_setopt($this->curl, CURLOPT_URL, $sUrl);
// 设置头信息
curl_setopt($this->curl, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer ' . $this->sApiKey
]);
curl_setopt($this->curl, CURLOPT_PROXY,$this->proxy);
curl_setopt($this->curl, CURLOPT_SSL_VERIFYPEER,true);
curl_setopt($this->curl, CURLOPT_SSL_VERIFYHOST,2);
curl_setopt($this->curl, CURLOPT_POST, true); //设置为POST方式
curl_setopt($this->curl, CURLOPT_POSTFIELDS,json_encode($data));
curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, TRUE) ; // 获取数据返回
// curl_setopt($this->curl, CURLOPT_TIMEOUT, $this->timeout);
$result = curl_exec($this->curl);
//请求失败
if (curl_errno($this->curl)){
$this->sError = curl_errno($this->curl);
curl_close($this->curl);
return FALSE;
}
$this->sResponesData = json_decode($result);
curl_close($this->curl);
return TRUE;
}
/** /**
* @title AI审核文章 * @title AI审核文章
* @param article_id 文章ID * @param article_id 文章ID
@@ -88,77 +25,67 @@ class Aireview extends Base
//获取参数 //获取参数
$aParam = $this->request->post(); $aParam = $this->request->post();
if(empty($aParam['article_id'])){ $iArticleId = empty($aParam['article_id']) ? '' : $aParam['article_id'];
exit(json_encode(array('status' => 2,'msg' => 'Please select an article' ))); if(empty($iArticleId)){
return json_encode(array('status' => 2,'msg' => 'Please select an article' ));
} }
// if(empty($aParam['abstrart'])){
// exit(json_encode(array('status' => 2,'msg' => 'abstrart cannot be empty' )));
// }
// if(empty($aParam['keywords'])){
// exit(json_encode(array('status' => 2,'msg' => 'keywords cannot be empty' )));
// }
//查询文章 //查询文章
$aArticle = Db::table('t_article')->field('article_id,abstrart,keywords,journal_id')->where('article_id',$aParam['article_id'])->find(); $aWhere = ['article_id' => $aParam['article_id']];
$aArticle = Db::name('article')->field('article_id,abstrart,keywords,journal_id')->where('article_id',$aParam['article_id'])->find();
if(empty($aArticle)){ if(empty($aArticle)){
exit(json_encode(array('status' => 3,'msg' => 'No articles requiring review were found' ))); return json_encode(array('status' => 3,'msg' => 'No articles requiring review were found' ));
} }
//获取文章评测内容 //获取文章评测内容
$aAiReview = Db::table('t_article_ai_review')->field('article_id,content')->where('article_id',$aParam['article_id'])->find(); $aAiReview = Db::table('t_article_ai_review')->where('article_id',$aParam['article_id'])->find();
if(!empty($aAiReview)){ if(!empty($aAiReview)){
exit(json_encode(array('status' => 1,'msg' => 'AI has been reviewed','data' => $aAiReview))); return json_encode(array('status' => 1,'msg' => 'AI has been reviewed','data' => $aAiReview));
} }
$aParam['abstrart'] = empty($aParam['abstrart']) ? $aArticle['abstrart'] : $aParam['abstrart'];//简介
$aParam['keywords'] = empty($aParam['keywords']) ? $aArticle['keywords'] : $aParam['keywords'];//关键词
//根据期刊ID查询期刊信息 //根据期刊ID查询期刊信息
$aJournal = Db::table('t_journal')->field('zname')->where('journal_id',$aArticle['journal_id'])->find(); $aJournal = Db::table('t_journal')->field('zname')->where('journal_id',$aArticle['journal_id'])->find();
if(empty($aJournal)){ if(empty($aJournal)){
exit(json_encode(array('status' => 4,'msg' => 'This article is not associated with a journal' ))); return json_encode(array('status' => 4,'msg' => 'This article is not associated with a journal' ));
}
//组织参数
$sContent = '';
$sContent .= '摘要:'.$aParam['abstrart'];
$sContent .= '关键词:'.$aParam['keywords'];
$sContent .= '以上这篇文章是否符合'.$aJournal['zname'].'?是否具有科学前沿性和创新性?请返回中文解释';
$messages = [
[
'role' => 'user', //角色platform平台;developer:开发者user:用户;guideline:模型规范“指南”部分:连接https://model-spec.openai.com/2025-02-12.html#chain_of_command
'content' => $sContent
]
];
//请求接口
$sModel = $aParam['api_model'] ?? 'gpt-4o';
$result = $this->curlOpenAI($messages,$sModel);
if($result == FALSE){
exit(json_encode(array('status' => 4,'msg' => 'Interface request failed'.$this->sError)));
} }
//查询文章内容
$aWhere['type'] = 0;
$aWhere['content'] = ['<>',''];
$aWhere['state'] = 0;
$aArticleMain = Db::table('t_article_main')->where($aWhere)->column('content');
//获取提问AI的内容
$aSearch = [];
$aSearch['{abstrart}'] = empty($aArticle['abstrart']) ? '' : $aArticle['abstrart'];//简介
$aSearch['{keywords}'] = empty($aArticle['keywords']) ? '' : $aArticle['keywords'];//关键词
$aSearch['{content}'] = empty($aArticleMain) ? '' : strip_tags(implode('', array_unique($aArticleMain)));//文章内容
$aSearch['{journal_name}'] = empty($aJournal['zname']) ? '' : $aJournal['zname'];//期刊名
//获取问答内容
$oOpenAi = new OpenAi;
$aMessage = $oOpenAi->buildReviewArticlePrompt($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']];
$aResult = json_decode($oOpenAi->curlOpenAI($aParam),true);
$iStatus = empty($aResult['status']) ? 0 : $aResult['status'];
if($iStatus != 1){
return json_encode($aResult);
}
//处理返回信息 //处理返回信息
$data = $this->sResponesData; $aData = empty($aResult['data']) ? [] : $aResult['data'];
if(!is_object($data)){ if(empty($aData)){
exit(json_encode(array('status' => 5,'msg' => 'There is a misunderstanding in the data returned by the interface'))); return json_encode(['status' => 6,'msg' => 'OPENAI returns empty content']);
} }
$data = object_to_array($data); if(empty($aData)){
$aChoices = $data['choices'] ?? []; return json_encode(array('status' => 10,'msg' => 'OPENAI did not return data'));
if(empty($aChoices)){
exit(json_encode(array('status' => 6,'msg' => 'OPENAI did not return data')));
} }
$aChoicesInfo = $aChoices[0] ?? [];
$aMessage = $aChoicesInfo['message'] ?? [];
if(empty($aMessage['content'])){
exit(json_encode(array('status' => 7,'msg' => 'OPENAI returns empty data')));
}
//执行数据入库 //执行数据入库
$param = []; $aData['article_id'] = $iArticleId;
$param['content'] = addslashes($aMessage['content']); $aResult = $this->addAiReview($aData);
$param['article_id'] = $aParam['article_id']; return json_encode($aResult);
$aResult = $this->addAiReview($param);
exit(json_encode($aResult));
} }
@@ -171,25 +98,40 @@ class Aireview extends Base
protected function addAiReview($aParam = array()){ protected function addAiReview($aParam = array()){
//返回数组 //返回数组
$aResult = ['status' => 1,'msg' => 'AI review successful','data' => $aParam]; $aResult = ['status' => 1,'msg' => 'AI review successful'];
//必填参数验证 //必填参数验证
$aFields = ['article_id','content']; $aFields = ['journal_scope','attribute','contradiction','unreasonable','ethics','academic','conclusion','fund_number','hotspot','submit_direction','overall_evaluation','article_id','references_past_three','references_past_five','references_ratio_JCR1','references_ratio_JCR2','registration_assessment','cite_rate'];
$bStatus = true; $aInsert = ['create_time' => date('Y-m-d H:i:s')];
foreach($aFields as $val){ foreach($aFields as $val){
if(empty($aParam[$val])){ $aValue = empty($aParam[$val]) ? [] : $aParam[$val];
$aResult = ['status' => 2,'msg' => $val.'cannot be empty']; if(!isset($aValue)){
$bStatus = false; continue;
break;
} }
if(is_array($aValue)){
foreach ($aValue as $key => $value) {
$sField = $val.'_'.$key;
$aInsert[$sField] = empty($value) ? '' : addslashes($value);
}
}else{
$aInsert[$val] = empty($aValue) ? '' : addslashes($aValue);
} }
if($bStatus == false){
return $aResult;
} }
//执行入库 //执行入库
$aParam['create_time'] = date('Y-m-d H:i:s'); if(empty($aInsert['article_id'])){
if(!Db::name('article_ai_review')->insert($aParam)){ return ['status' => 2,'msg' => 'Please select the article to be reviewed'];
}
//判断是否生成
$aAiReview = Db::table('t_article_ai_review')->where('article_id',$aInsert['article_id'])->find();
if(!empty($aAiReview)){
return json_encode(array('status' => 1,'msg' => 'AI has been reviewed','data' => $aAiReview));
}
$aInsert['content'] = $aInsert['article_id'];
if(!Db::name('article_ai_review')->insert($aInsert)){
$aResult = ['status' => 2,'msg' => 'Failed to add AI audit content']; $aResult = ['status' => 2,'msg' => 'Failed to add AI audit content'];
} }
$aResult['data'] = $aInsert;
return $aResult; return $aResult;
} }
@@ -202,42 +144,16 @@ class Aireview extends Base
//获取参数 //获取参数
$aParam = $this->request->post(); $aParam = $this->request->post();
if(empty($aParam['article_id'])){ if(empty($aParam['article_id'])){
exit(json_encode(array('status' => 2,'msg' => 'Please select an article' ))); return json_encode(array('status' => 2,'msg' => 'Please select an article' ));
} }
//查询文章 //查询文章
$aArticle = Db::table('t_article')->field('article_id')->where('article_id',$aParam['article_id'])->find(); $aArticle = Db::table('t_article')->field('article_id')->where('article_id',$aParam['article_id'])->find();
if(empty($aArticle)){ if(empty($aArticle)){
exit(json_encode(array('status' => 3,'msg' => 'No articles requiring review were found' ))); return json_encode(array('status' => 3,'msg' => 'No articles requiring review were found' ));
} }
//查询文章审核内容 //查询文章审核内容
$aAiReview = Db::table('t_article_ai_review')->field('content')->where('article_id',$aParam['article_id'])->find(); $aAiReview = Db::table('t_article_ai_review')->where('article_id',$aParam['article_id'])->find();
exit(json_encode(array('status' => 1,'msg' => 'Successfully obtained article review content','data' => $aAiReview))); return json_encode(array('status' => 1,'msg' => 'Successfully obtained article review content','data' => $aAiReview));
}
public function test(){
//获取参数
$aParam = $this->request->post();
if(empty($aParam['content'])){
exit(json_encode(array('status' => 2,'msg' => '请输入需要验证的字符串' )));
}
if(!$this->checkMinChars($aParam['content'],200)){
exit(json_encode(array('status' => 3,'msg' => '字符串长度未满足配置' )));
}
exit(json_encode(array('status' => 1,'msg' => '验证成功' )));
}
/**
* 验证字符长度
* @param $str 字符串
* @param $num 字符长度
* @return void
*/
private function checkMinChars($str = '',$num = 200) {
// 过滤非汉字和英文的字符(保留汉字、大小写字母)
$filteredStr = preg_replace('/[^\x{4e00}-\x{9fa5}a-zA-Z0-9]/u', '', $str);
// 计算有效字符总数汉字按1个字符计英文和数字同理
$total = mb_strlen($filteredStr, 'UTF-8');
return $total >= $num;
} }
} }