AI相关调整
This commit is contained in:
@@ -21,193 +21,213 @@ class Aireview extends Base
|
||||
* @param model 接口模型
|
||||
* @param stream 是否流式输出 true是false否
|
||||
*/
|
||||
public function review(){
|
||||
public function review($aParam = []){
|
||||
|
||||
|
||||
//获取参数
|
||||
$aParam = $this->request->post();
|
||||
$aParam = empty($aParam) ? $this->request->post() : $aParam;
|
||||
$iArticleId = empty($aParam['article_id']) ? '' : $aParam['article_id'];
|
||||
if(empty($iArticleId)){
|
||||
return json_encode(array('status' => 2,'msg' => 'Please select an article' ));
|
||||
}
|
||||
|
||||
|
||||
//问题等级
|
||||
$sQuestionLevel = empty($aParam['question_level']) ? 'C' : $aParam['question_level'];
|
||||
//需要处理的AI问题字段
|
||||
$sQuestionFields = empty($aParam['queue_fields']) ? 'hotspot' : $aParam['queue_fields'];
|
||||
$aQuestionFields = explode(',', $sQuestionFields);
|
||||
//查询文章及AI审稿
|
||||
$aWhere = ['article_id' => $aParam['article_id']];
|
||||
$aResult = json_decode($this->get($aWhere),true);
|
||||
|
||||
//文章信息
|
||||
$aArticle = empty($aResult['article_data']) ? [] : $aResult['article_data'];
|
||||
if(empty($aArticle)){
|
||||
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' ));
|
||||
}
|
||||
|
||||
//AI审稿信息
|
||||
// //AI审稿信息
|
||||
$aAiReview = empty($aResult['data']) ? [] : $aResult['data'];
|
||||
if(!empty($aAiReview)){
|
||||
if(!empty($aAiReview['is_finish']) && $aAiReview['is_finish'] == 1){
|
||||
return json_encode(array('status' => 1,'msg' => 'AI has been reviewed','data' => $aAiReview));
|
||||
}
|
||||
|
||||
//根据期刊ID查询期刊信息
|
||||
$aJournal = Db::table('t_journal')->field('title,scope,issn,journal_id')->where('journal_id',$aArticle['journal_id'])->find();
|
||||
if(empty($aJournal)){
|
||||
return json_encode(array('status' => 4,'msg' => 'This article is not associated with a journal' ));
|
||||
}
|
||||
|
||||
//实例化公共方法
|
||||
$oArticle = new Article;
|
||||
if($aArticle['state'] > 4 ){
|
||||
//查询文章内容
|
||||
$aWhere['type'] = 0;
|
||||
$aWhere['content'] = ['<>',''];
|
||||
$aWhere['state'] = 0;
|
||||
$aArticleMain = Db::table('t_article_main')->where($aWhere)->column('content');
|
||||
//查询参考文献
|
||||
$aWhere = ['state' => ['in',[0,2]],'article_id' => $iArticleId];
|
||||
$aProductionArticle = Db::name('production_article')->field('p_article_id')->where($aWhere)->find();
|
||||
if(!empty($aProductionArticle)){
|
||||
$aWhere = ['state' => 0,'p_article_id' => $aProductionArticle['p_article_id']];
|
||||
$aRefer = Db::name('production_article_refer')->field('refer_content')->where($aWhere)->column('refer_content');
|
||||
$aArticleMain = empty($aRefer) ? $aArticleMain : array_merge($aRefer,$aArticleMain);
|
||||
$oHelperFunction = new \app\common\HelperFunction;
|
||||
//根据期刊ID查询期刊信息
|
||||
$aJournalIssn = [];
|
||||
$sIssn = $sScope = '';
|
||||
if(in_array('journal_scope', $aQuestionFields)){
|
||||
$aWhere = ['journal_id' => $aArticle['journal_id'],'state' => 0];
|
||||
$aJournal = Db::table('t_journal')->field('title as targeted_journals,scope as journal_scope,issn')->where($aWhere)->find();
|
||||
if(empty($aJournal)){
|
||||
return json_encode(array('status' => 4,'msg' => 'This article is not associated with a journal' ));
|
||||
}
|
||||
}else{
|
||||
|
||||
$aFile = json_decode($oArticle->getFileContent(['article_id' => $iArticleId]),true);
|
||||
$aFile = empty($aFile['data']) ? [] : $aFile['data'];
|
||||
$aArticleMain = empty($aFile['mains']) ? [] : $aFile['mains'];
|
||||
$aArticle += $aJournal;
|
||||
$sIssn = empty($aJournal['issn']) ? '' : $aJournal['issn'];
|
||||
$sScope = empty($aJournal['journal_scope']) ? '' : $aJournal['journal_scope'];
|
||||
$aJournalIssn = array_merge($aJournalIssn,[$sIssn]);
|
||||
}
|
||||
//获取提问AI的内容
|
||||
$aSearch = [];
|
||||
$title = empty($aArticle['title']) ? '' : $aArticle['title'];//简介
|
||||
$abstrart = empty($aArticle['abstrart']) ? '' : $aArticle['abstrart'];//简介
|
||||
$keywords = empty($aArticle['keywords']) ? '' : $aArticle['keywords'];//关键词
|
||||
$aSearch['{title}'] = $title;
|
||||
$aSearch['{abstrart}'] = $abstrart;
|
||||
$aSearch['{keywords}'] = $keywords;
|
||||
//文章内容
|
||||
$sContent = empty($aArticleMain) ? '' : implode('', array_unique($aArticleMain));
|
||||
$sContent = preg_replace('/[\r\n]+/', '', $sContent);
|
||||
$sContent = preg_replace('/ +/', ' ', $sContent); // 合并连续空格
|
||||
$aSearch['{content}'] = $sContent;
|
||||
$aSearch['{journal_name}'] = empty($aJournal['title']) ? '' : $aJournal['title'];//期刊名
|
||||
if($aJournal['journal_id'] == 1){
|
||||
$aSearch['{journal_name}'] = '传统医学研究';
|
||||
if(in_array('other_journal', $aQuestionFields)){
|
||||
$aWhere = ['journal_id' => ['<>',$aArticle['journal_id']],'state' => 0];
|
||||
$aJournalOther = Db::table('t_journal')->field('title as targeted_journals,scope as journal_scope,issn')->where($aWhere)->select();
|
||||
if(!empty($aJournalOther)){
|
||||
$aJournalIssn = array_merge($aJournalIssn,array_column($aJournalOther, 'issn'));
|
||||
}
|
||||
}
|
||||
//查询期刊范围
|
||||
if(!empty($aJournalIssn)){
|
||||
//查询期刊内容
|
||||
$oArticle = new Article;
|
||||
$aJournalPaperArt = json_decode($oArticle->getJournalPaperArt(['issn' => $aJournalIssn]),true);
|
||||
$aJournalPaperArt = empty($aJournalPaperArt['data']) ? [] : $aJournalPaperArt['data'];
|
||||
$aArticle['journal_scope'] = empty($aJournalPaperArt[$sIssn]) ? $sScope : $oHelperFunction->filterAllTags($aJournalPaperArt[$sIssn]);
|
||||
if(!empty($aJournalPaperArt[$sIssn])){
|
||||
unset($aJournalPaperArt[$sIssn]);
|
||||
}
|
||||
$aArticle['other_journal'] = empty($aJournalPaperArt) ? '' : json_encode($aJournalPaperArt,JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
//查询期刊内容
|
||||
$aJournalPaperArt = json_decode($oArticle->getJournalPaperArt($aJournal),true);
|
||||
$sJournalContent = empty($aJournalPaperArt['data']) ? '' : implode('', $aJournalPaperArt['data']);
|
||||
$sJournalContent = empty($sJournalContent) ? $aJournal['scope'] : $sJournalContent;
|
||||
$aSearch['{scope}'] = $sJournalContent;//期刊范围
|
||||
|
||||
//获取重要维度的问答信息
|
||||
//获取文章的领域
|
||||
if($sQuestionFields == 'hotspot'){
|
||||
$oArticle = new Article;
|
||||
$aArticleField = $oArticle->getArticleField(['article_id' => $iArticleId]);
|
||||
$aArticleField = empty($aArticleField['data']) ? [] : $aArticleField['data'];
|
||||
if(empty($aArticleField)){
|
||||
return json_encode(array('status' => 4,'msg' => 'Domain where article not found:'.$sQuestionFields));
|
||||
}
|
||||
//数据处理
|
||||
$aArticleFieldData = [];
|
||||
foreach ($aArticleField as $key => $value) {
|
||||
$aArticleFieldData[] = getMajorStr($value['major_id']);
|
||||
}
|
||||
$aArticle['hotspot'] = json_encode($aArticleFieldData,JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
//获取提问AI话术
|
||||
$oOpenAi = new OpenAi;
|
||||
//请求OPENAI接口-重要维度单独请求获取答案
|
||||
$aSearch['question'] = 'aArticleImportantPrompt';
|
||||
$aSearch['open_ai_id'] = $iArticleId;
|
||||
$aResult = json_decode($oOpenAi->curlMultiOpenAIImportant($aSearch),true);
|
||||
$iStatus = empty($aResult['status']) ? 0 : $aResult['status'];
|
||||
if($iStatus != 1){
|
||||
return json_encode($aResult);
|
||||
}
|
||||
//处理返回信息
|
||||
$aData = empty($aResult['data']) ? [] : $aResult['data'];
|
||||
if(empty($aData)){
|
||||
return json_encode(['status' => 6,'msg' => 'OPENAI returns empty content']);
|
||||
}
|
||||
//执行数据入库
|
||||
$aData['article_id'] = $iArticleId;
|
||||
$aData['journal_id'] = $aArticle['journal_id'];
|
||||
$aResult = $this->addAiReview($aData);
|
||||
if(empty($aResult['data'])){
|
||||
return json_encode($aResult);
|
||||
//获取文章内容
|
||||
$aChunkContent = [];
|
||||
if(!in_array($sQuestionFields, ['journal_scope','other_journal','hotspot'])){
|
||||
//实例化公共方法
|
||||
$oArticle = new Article;
|
||||
if($aArticle['state'] > 4 ){
|
||||
//查询文章内容
|
||||
$aWhere['type'] = 0;
|
||||
$aWhere['content'] = ['<>',''];
|
||||
$aWhere['state'] = 0;
|
||||
$aArticleMain = Db::table('t_article_main')->where($aWhere)->column('content');
|
||||
//查询参考文献
|
||||
$aWhere = ['state' => ['in',[0,2]],'article_id' => $iArticleId];
|
||||
$aProductionArticle = Db::name('production_article')->field('p_article_id')->where($aWhere)->find();
|
||||
if(!empty($aProductionArticle)){
|
||||
$aWhere = ['state' => 0,'p_article_id' => $aProductionArticle['p_article_id']];
|
||||
$aRefer = Db::name('production_article_refer')->field('refer_content')->where($aWhere)->column('refer_content');
|
||||
$aArticleMain = empty($aRefer) ? $aArticleMain : array_merge($aRefer,$aArticleMain);
|
||||
}
|
||||
}else{
|
||||
$aFile = json_decode($oArticle->getFileContent(['article_id' => $iArticleId]),true);
|
||||
$aFile = empty($aFile['data']) ? [] : $aFile['data'];
|
||||
$aArticleMain = empty($aFile['mains']) ? [] : $aFile['mains'];
|
||||
}
|
||||
$sContent = empty($aArticleMain) ? '' : implode("", array_unique($aArticleMain));
|
||||
if(empty($sContent)){
|
||||
return json_encode(array('status' => 4,'msg' => 'No article content found:'.$sQuestionFields));
|
||||
}
|
||||
|
||||
|
||||
//处理内容
|
||||
//过滤字符串
|
||||
$sContent = $oHelperFunction->filterAllTags($sContent);
|
||||
//将文章内容拆分参考文献
|
||||
$aDealContent = $this->dealContent($sContent);
|
||||
$sBefore= empty($aDealContent['before']) ? '' : $aDealContent['before'];
|
||||
$sReference = empty($aDealContent['after']) ? '' : $aDealContent['after'];
|
||||
if(in_array($sQuestionFields, ['attribute'])){//科学性和创新性
|
||||
$aChunkContent = $oHelperFunction->splitContent($sContent);
|
||||
}
|
||||
if($sQuestionFields == 'reference'){//参考文献
|
||||
if(empty($sReference)){
|
||||
return json_encode(array('status' => 5,'msg' => 'Reference not matched successfully' ));
|
||||
}
|
||||
$aChunkContent = [$sReference];
|
||||
}
|
||||
if(!in_array($sQuestionFields, ['attribute','reference'])){
|
||||
$aChunkContent = $oHelperFunction->splitContent($sBefore);
|
||||
}
|
||||
$aArticle['reference'] = $sReference;
|
||||
$aArticle['content'] = empty($aChunkContent[0]) ? '' : $aChunkContent[0];
|
||||
if(count($aChunkContent) > 1){
|
||||
$aArticle['content'] = $aChunkContent;
|
||||
}
|
||||
}
|
||||
|
||||
//请求OPENAI接口-非重要维度一次请求获取答案
|
||||
//获取提示词
|
||||
$aMessage = $oOpenAi->buildReviewPromptUnimportant($aSearch);
|
||||
//内容处理
|
||||
$aArticle['queue_fields'] = $sQuestionFields;
|
||||
$aArticle['question_level'] = $sQuestionLevel;
|
||||
if(count($aChunkContent) <= 1){
|
||||
$aMessage = $oOpenAi->buildReviewPrompt($aArticle);
|
||||
}else{
|
||||
$aMessage = $oOpenAi->buildReviewPromptChunk($aArticle);
|
||||
}
|
||||
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);
|
||||
//处理返回信息
|
||||
$aData = empty($aResult['data']) ? [] : $aResult['data'];
|
||||
if(empty($aData)){
|
||||
return json_encode(['status' => 6,'msg' => empty($aResult['msg']) ? 'OPENAI returns empty content' : $aResult['msg']]);
|
||||
//请求OPENAI接口
|
||||
$aParam = [
|
||||
'messages' => $aMessage,
|
||||
'model' => empty($aParam['api_model']) ? 'DeepSeek-V3' : $aParam['api_model'],
|
||||
'article_id' => empty($aArticle['article_id']) ? 0 : $aArticle['article_id'],
|
||||
'queue_fields' => $sQuestionFields,
|
||||
'question_level' => $sQuestionLevel,
|
||||
'journal_id' => empty($aArticle['journal_id']) ? 0 : $aArticle['journal_id']
|
||||
];
|
||||
if(count($aChunkContent) > 1){
|
||||
return $oOpenAi->articleReviewDealChunk($aParam);
|
||||
}else{
|
||||
return $oOpenAi->articleReviewDeal($aParam);
|
||||
}
|
||||
//执行数据入库
|
||||
$aData['article_id'] = $iArticleId;
|
||||
$aData['journal_id'] = $aArticle['journal_id'];
|
||||
$aResult = $this->addAiReview($aData);
|
||||
return json_encode($aResult);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @title AI审核内容入库
|
||||
* @param article_id 文章ID
|
||||
* @param content 内容
|
||||
* @title 将文章内容拆分参考文献
|
||||
* @param sContent 文章内容
|
||||
*/
|
||||
private function addAiReview($aParam = array()){
|
||||
|
||||
$iArticleId = empty($aParam['article_id']) ? 0 : $aParam['article_id'];
|
||||
if(empty($iArticleId)){
|
||||
return ['status' => 2,'msg' => 'Please select the article to be reviewed'];
|
||||
}
|
||||
$iJournalId = empty($aParam['journal_id']) ? 0 : $aParam['journal_id'];
|
||||
if(empty($iJournalId)){
|
||||
return ['status' => 2,'msg' => 'The journal to which the article belongs cannot be empty'];
|
||||
}
|
||||
//返回数组
|
||||
$aResult = ['status' => 1,'msg' => 'AI review successful'];
|
||||
//数据库参数
|
||||
$aFields = ['journal_scope','attribute','contradiction','unreasonable','ethics','academic','conclusion','fund_number','hotspot','submit_direction','references_past_three','references_past_five','references_ratio_JCR1','references_ratio_JCR2','registration_assessment','cite_rate','references_num'];
|
||||
foreach ($aParam as $key => $value) {
|
||||
if(empty($value)){
|
||||
continue;
|
||||
}
|
||||
if(is_array($value)){
|
||||
if(!empty($value['assessment'])){
|
||||
$sField = $key.'_'.'assessment';
|
||||
$aInsert[$sField] = empty($value['assessment']) ? '' : htmlspecialchars($value['assessment']);
|
||||
}
|
||||
if(!empty($value['explanation'])){
|
||||
$sField = $key.'_'.'explanation';
|
||||
$aInsert[$sField] = empty($value['explanation']) ? '' : htmlspecialchars($value['explanation']);
|
||||
}
|
||||
}else{
|
||||
$aInsert[$key] = empty($value) ? '' : htmlspecialchars($value);
|
||||
}
|
||||
}
|
||||
if(empty($aInsert)){
|
||||
return ['status' => 3,'msg' => 'Data is empty'];
|
||||
private function dealContent($sContent = ''){
|
||||
if(empty($sContent)){
|
||||
return [];
|
||||
}
|
||||
|
||||
//查询文章审核内容-判断新增或修改
|
||||
$aWhere = ['article_id' => $iArticleId,'journal_id' => $iJournalId];
|
||||
$aAiReview = Db::table('t_article_ai_review')->field('id')->where($aWhere)->find();
|
||||
$iLogId = empty($aAiReview['id']) ? 0 : $aAiReview['id'];
|
||||
//新增
|
||||
if(empty($iLogId)){
|
||||
$aInsert['create_time'] = date('Y-m-d H:i:s');
|
||||
$aInsert['content'] = $iArticleId;
|
||||
$iLogId = Db::name('article_ai_review')->insertGetId($aInsert);
|
||||
if(empty($iLogId)){
|
||||
$aResult = ['status' => 4,'msg' => 'Failed to add AI audit content'];
|
||||
}
|
||||
$aResult['data'] = ['id' => $iLogId];
|
||||
return $aResult;
|
||||
$pattern = '/<img\s+[^>]*?>/i';
|
||||
$sContent = preg_replace($pattern, '', $sContent);
|
||||
|
||||
// 关键修复:将分隔符从 / 改为 #,避免与 < > 冲突
|
||||
$pattern = '#<b>Reference</b>|<b>Reference:</b>|<b><i>References:</i></b>|<b><i>References</i></b>|<b>References</b>|<b>References:</b>#';
|
||||
|
||||
// 查找标识在文本中的位置
|
||||
preg_match($pattern, $sContent, $matches, PREG_OFFSET_CAPTURE);
|
||||
|
||||
if (empty($matches)) {
|
||||
// 未找到任何标识
|
||||
$before = $sContent;
|
||||
$after = '';
|
||||
} else {
|
||||
// 截取标识前后内容
|
||||
$marker = $matches[0][0];
|
||||
$markerStart = $matches[0][1];
|
||||
$before = substr($sContent, 0, $markerStart);
|
||||
$after = substr($sContent, $markerStart + strlen($marker));
|
||||
}
|
||||
if(!empty($iLogId)){
|
||||
$aWhere = ['id' => $iLogId];
|
||||
$aInsert['update_time'] = date('Y-m-d H:i:s');
|
||||
if(!Db::name('article_ai_review')->where($aWhere)->limit(1)->update($aInsert)){
|
||||
$aResult = ['status' => 5,'msg' => 'Failed to add AI audit content'];
|
||||
if(empty($after)){
|
||||
$lastPos = strrpos($sContent, 'Reference');
|
||||
if ($lastPos === false) {
|
||||
// 未找到 "Reference",返回原字符串和空
|
||||
return [$sContent, ''];
|
||||
}
|
||||
$aAiReview = Db::table('t_article_ai_review')->where($aWhere)->find();
|
||||
$aResult['data'] = $aAiReview;
|
||||
return $aResult;
|
||||
|
||||
// 拆分:关键词之前的内容
|
||||
$before = substr($sContent, 0, $lastPos);
|
||||
// 关键词及之后的内容(包含关键词本身)
|
||||
$after = substr($sContent, $lastPos);
|
||||
}
|
||||
return ['status' => 6,'msg' => 'illegal request'];
|
||||
return ['before' => $before,'after' => $after,'content' => $sContent];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -223,7 +243,9 @@ class Aireview extends Base
|
||||
}
|
||||
|
||||
//查询文章
|
||||
$aArticle = Db::name('article')->field('article_id,abstrart,keywords,journal_id,title,state')->where('article_id',$aParam['article_id'])->find();
|
||||
$oArticle = new Article;
|
||||
$aArticle = json_decode($oArticle->get($aParam),true);
|
||||
$aArticle = empty($aArticle['data']) ? [] : $aArticle['data'];
|
||||
if(empty($aArticle)){
|
||||
return json_encode(array('status' => 3,'msg' => 'No articles requiring review were found' ));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user