diff --git a/application/api/controller/Aireview.php b/application/api/controller/Aireview.php new file mode 100644 index 0000000..4ff963e --- /dev/null +++ b/application/api/controller/Aireview.php @@ -0,0 +1,243 @@ +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审核文章 + * @param article_id 文章ID + * @param abstrart 摘要 + * @param keywords 关键词 + * @param model 接口模型 + * @param stream 是否流式输出 true是false否 + */ + public function review(){ + + + //获取参数 + $aParam = $this->request->post(); + if(empty($aParam['article_id'])){ + exit(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(); + if(empty($aArticle)){ + exit(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(); + if(!empty($aAiReview)){ + exit(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查询期刊信息 + $aJournal = Db::table('t_journal')->field('zname')->where('journal_id',$aArticle['journal_id'])->find(); + if(empty($aJournal)){ + exit(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))); + } + + //处理返回信息 + $data = $this->sResponesData; + if(!is_object($data)){ + exit(json_encode(array('status' => 5,'msg' => 'There is a misunderstanding in the data returned by the interface'))); + } + $data = object_to_array($data); + $aChoices = $data['choices'] ?? []; + 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 = []; + $param['content'] = addslashes($aMessage['content']); + $param['article_id'] = $aParam['article_id']; + $aResult = $this->addAiReview($param); + exit(json_encode($aResult)); + + + } + + /** + * @title AI审核内容入库 + * @param article_id 文章ID + * @param content 内容 + */ + protected function addAiReview($aParam = array()){ + + //返回数组 + $aResult = ['status' => 1,'msg' => 'AI review successful','data' => $aParam]; + //必填参数验证 + $aFields = ['article_id','content']; + $bStatus = true; + foreach($aFields as $val){ + if(empty($aParam[$val])){ + $aResult = ['status' => 2,'msg' => $val.'cannot be empty']; + $bStatus = false; + break; + } + } + if($bStatus == false){ + return $aResult; + } + //执行入库 + $aParam['create_time'] = date('Y-m-d H:i:s'); + if(!Db::name('article_ai_review')->insert($aParam)){ + $aResult = ['status' => 2,'msg' => 'Failed to add AI audit content']; + } + return $aResult; + } + + /** + * @title 文章AI审核内容查询 + * @param article_id 文章ID + */ + public function get(){ + + //获取参数 + $aParam = $this->request->post(); + if(empty($aParam['article_id'])){ + exit(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(); + if(empty($aArticle)){ + exit(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(); + exit(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; + } +} diff --git a/application/api/controller/Article.php b/application/api/controller/Article.php index c121729..9b7fd2a 100644 --- a/application/api/controller/Article.php +++ b/application/api/controller/Article.php @@ -106,7 +106,6 @@ class Article extends Base ->limit($limit_start, $data['pageSize'])->select(); $count = $this->article_obj->where($where)->count(); - foreach ($res as $key => $val) { //查询建议转投详情 $transfer_info = $this->article_transfer_obj @@ -346,6 +345,15 @@ class Article extends Base ->order('t_article.article_id desc') ->limit($limit_start, $data['pageSize']) ->select(); + + //查询AI审核内容 chengxiaoling 20250328 start + $aAiReview = array(); + if(!empty($res)){ + $aArticleId = array_column($res, 'article_id'); + $aAiReview = Db::table('t_article_ai_review')->field('article_id,content')->whereIn('article_id',$aArticleId)->column('article_id,content'); + } + //查询AI审核内容 chengxiaoling 20250328 end + //增加审稿意见信息 foreach ($res as $key => $val) { $cache_review = $this->article_reviewer_obj @@ -383,6 +391,10 @@ class Article extends Base $file_frag[$v['type_name']][] = $v; } $res[$key]['file'] = $file_frag; + + //返回AI审核内容 chengxiaoling 20250328 start + $res[$key]['ai_review'] = empty($aAiReview[$val['article_id']]) ? '' : $aAiReview[$val['article_id']]; + //返回AI审核内容 chengxiaoling 20250328 end } //添加国家信息 @@ -616,6 +628,13 @@ class Article extends Base $user_res = $this->user_obj->where(['account' => $username])->find(); $article_old_info = $this->article_obj->where('article_id', $data['articleId'])->find(); + + //判断简介字符串长度是否不低于200 chengxiaoling 20250327 start + if(!$this->checkMinChars($data['abstrart'],200)){ + return jsonError("The abstract should not be less than 200 Chinese characters or English words!"); + } + //判断简介字符串长度是否不低于200 chengxiaoling 20250327 end + Db::startTrans(); //更新文章信息 @@ -2485,7 +2504,6 @@ class Article extends Base //接受参数,查询信息 $data = $this->request->post(); - $user_res = $this->user_obj->where('account', $data['username'])->find(); //确定用户是否属于黑名单 @@ -2919,6 +2937,12 @@ class Article extends Base if (!$rule->check($data)) { return jsonError($rule->getError()); } + //判断简介字符串长度是否不低于200 chengxiaoling 20250327 start + if(!$this->checkMinChars($data['abstrart'],200)){ + return jsonError("The abstract should not be less than 200 Chinese characters or English words!"); + } + //判断简介字符串长度是否不低于200 chengxiaoling 20250327 end + $user_info = $this->user_obj->where('user_id', $data['user_id'])->find(); $journal_info = $this->journal_obj->where('journal_id', $data['journal'])->find(); @@ -4257,4 +4281,19 @@ class Article extends Base $this->user_msg_obj->where("user_id", $data['editor_id'])->update(["state" => 1]); return jsonSuccess([]); } + + /** + * 验证字符长度 + * @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; + } }