参考文献相关上传
This commit is contained in:
541
application/api/controller/References.php
Normal file
541
application/api/controller/References.php
Normal file
@@ -0,0 +1,541 @@
|
||||
<?php
|
||||
|
||||
namespace app\api\controller;
|
||||
|
||||
use app\api\controller\Base;
|
||||
use think\Db;
|
||||
/**
|
||||
* @title 参考文献
|
||||
* @description 相关方法汇总
|
||||
*/
|
||||
class References extends Base
|
||||
{
|
||||
public function __construct(\think\Request $request = null) {
|
||||
parent::__construct($request);
|
||||
}
|
||||
//OPENAI token
|
||||
private $sApiKey = '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';
|
||||
//OPENAI URL
|
||||
private $sApiUrl = 'https://api.openai.com/v1/chat/completions';
|
||||
/**
|
||||
* 获取参考文献的信息
|
||||
* @param p_refer_id 主键ID
|
||||
*/
|
||||
public function get($aParam = []){
|
||||
|
||||
//获取参数
|
||||
$aParam = empty($aParam) ? $this->request->post() : $aParam;
|
||||
|
||||
//必填值验证
|
||||
$iPReferId = empty($aParam['p_refer_id']) ? '' : $aParam['p_refer_id'];
|
||||
if(empty($iPReferId)){
|
||||
return json_encode(['status' => 2,'msg' => 'Please select the reference to be queried']);
|
||||
}
|
||||
$aWhere = ['p_refer_id' => $iPReferId,'state' => 0];
|
||||
$aRefer = Db::name('production_article_refer')->where($aWhere)->find();
|
||||
if(empty($aRefer)){
|
||||
return json_encode(['status' => 4,'msg' => 'Reference is empty']);
|
||||
}
|
||||
//获取文章信息
|
||||
$aParam['p_article_id'] = $aRefer['p_article_id'];
|
||||
$aArticle = $this->getArticle($aParam);
|
||||
$iStatus = empty($aArticle['status']) ? 0 : $aArticle['status'];
|
||||
if($iStatus != 1){
|
||||
return json_encode($aArticle);
|
||||
}
|
||||
$aArticle = empty($aArticle['data']) ? [] : $aArticle['data'];
|
||||
if(empty($aArticle)){
|
||||
return json_encode(['status' => 3,'msg' => 'The article does not exist']);
|
||||
}
|
||||
|
||||
//获取参考文献信息作者名.文章题目.期刊名缩写.年卷页.Available at: //https://doi.org/xxxxx
|
||||
//作者
|
||||
$sData = $aRefer['refer_frag'];
|
||||
if($aRefer['refer_type'] == 'journal'){
|
||||
if(!empty($aRefer['doilink'])){
|
||||
$sAuthor = empty($aRefer['author']) ? '' : trim(trim($aRefer['author']),'.');
|
||||
if(!empty($sAuthor)){
|
||||
$aAuthor = explode(',', $sAuthor);
|
||||
if(count($aAuthor) > 3){
|
||||
$sAuthor = implode(',', array_slice($aAuthor, 0,3));
|
||||
$sAuthor .= ', et al';
|
||||
}
|
||||
if(count($aAuthor) <= 3 ){
|
||||
$sAuthor = implode(',', $aAuthor);
|
||||
}
|
||||
}
|
||||
//文章标题
|
||||
$sTitle = empty($aRefer['title']) ? '' : trim(trim($aRefer['title']),'.');
|
||||
//期刊名缩写
|
||||
$sJoura = empty($aRefer['joura']) ? '' : trim(trim($aRefer['joura']),'.');
|
||||
//年卷页
|
||||
$sDateno = empty($aRefer['dateno']) ? '' : trim(trim($aRefer['dateno']),'.');
|
||||
//DOI
|
||||
$sDoilink = empty($aRefer['doilink']) ? '' : trim($aRefer['doilink']);
|
||||
if(!empty($sDoilink)){
|
||||
$sDoilink = strpos($sDoilink ,"http")===false ? "https://doi.org/".$sDoilink : $sDoilink;
|
||||
$sDoilink = str_replace('http://doi.org/', 'https://doi.org/', $sDoilink);
|
||||
}
|
||||
$sReferDoi = empty($aRefer['refer_doi']) ? '' : trim($aRefer['refer_doi']);
|
||||
if(!empty($sReferDoi)){
|
||||
$sReferDoi = strpos($sReferDoi ,"http")===false ? "https://doi.org/".$sReferDoi : $sReferDoi;
|
||||
$sReferDoi = str_replace('http://doi.org/', 'https://doi.org/', $sReferDoi);
|
||||
}
|
||||
$sDoilink = empty($sDoilink) ? $sReferDoi : $sDoilink;
|
||||
|
||||
$sData = $sAuthor.'.'.$sTitle.'.'.$sJoura.'.'.$sDateno.".Available at:\n".$sDoilink;
|
||||
}
|
||||
}
|
||||
if($aRefer['refer_type'] == 'book'){
|
||||
$sAuthor = empty($aRefer['author']) ? '' : trim(trim($aRefer['author']),'.');
|
||||
if(!empty($sAuthor)){
|
||||
$aAuthor = explode(',', $sAuthor);
|
||||
if(count($aAuthor) > 3){
|
||||
$sAuthor = implode(',', array_slice($aAuthor, 0,3));
|
||||
$sAuthor .= ', et al';
|
||||
}
|
||||
if(count($aAuthor) <= 3 ){
|
||||
$sAuthor = implode(',', $aAuthor);
|
||||
}
|
||||
}
|
||||
//文章标题
|
||||
$sTitle = empty($aRefer['title']) ? '' : trim(trim($aRefer['title']),'.');
|
||||
//期刊名缩写
|
||||
$sJoura = empty($aRefer['joura']) ? '' : trim(trim($aRefer['joura']),'.');
|
||||
//年卷页
|
||||
$sDateno = empty($aRefer['dateno']) ? '' : trim(trim($aRefer['dateno']),'.');
|
||||
//DOI
|
||||
$sDoilink = empty($aRefer['isbn']) ? '' : trim($aRefer['isbn']);
|
||||
|
||||
$sData = $sAuthor.'.'.$sTitle.'.'.$sJoura.'.'.$sDateno.".Available at:\n".$sDoilink;
|
||||
}
|
||||
$aRefer['deal_content'] = $sData;
|
||||
return json_encode(['status' => 1,'msg' => 'success','data' => $aRefer]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改参考文献的信息
|
||||
* @param p_refer_id 主键ID
|
||||
*/
|
||||
public function modify($aParam = []){
|
||||
|
||||
//获取参数
|
||||
$aParam = empty($aParam) ? $this->request->post() : $aParam;
|
||||
|
||||
//必填值验证
|
||||
$iPReferId = empty($aParam['p_refer_id']) ? '' : $aParam['p_refer_id'];
|
||||
if(empty($iPReferId)){
|
||||
return json_encode(['status' => 2,'msg' => 'Please select the reference to be queried']);
|
||||
}
|
||||
$sContent = empty($aParam['content']) ? '' : $aParam['content'];
|
||||
if(empty($sContent)){
|
||||
return json_encode(['status' => 2,'msg' => 'Please enter the modification content']);
|
||||
}
|
||||
if(!is_string($sContent)){
|
||||
return json_encode(['status' => 2,'msg' => 'The content format is incorrect']);
|
||||
}
|
||||
|
||||
//获取参考文献信息
|
||||
$aWhere = ['p_refer_id' => $iPReferId,'state' => 0];
|
||||
$aRefer = Db::name('production_article_refer')->where($aWhere)->find();
|
||||
if(empty($aRefer)){
|
||||
return json_encode(['status' => 4,'msg' => 'Reference is empty']);
|
||||
}
|
||||
|
||||
//获取文章信息
|
||||
$aParam['p_article_id'] = $aRefer['p_article_id'];
|
||||
$aArticle = $this->getArticle($aParam);
|
||||
$iStatus = empty($aArticle['status']) ? 0 : $aArticle['status'];
|
||||
if($iStatus != 1){
|
||||
return json_encode($aArticle);
|
||||
}
|
||||
$aArticle = empty($aArticle['data']) ? [] : $aArticle['data'];
|
||||
if(empty($aArticle)){
|
||||
return json_encode(['status' => 3,'msg' => 'The article does not exist']);
|
||||
}
|
||||
|
||||
//数据处理
|
||||
$aContent = json_decode($this->dealContent(['content' => $sContent]),true);
|
||||
$aUpdate = empty($aContent['data']) ? [] : $aContent['data'];
|
||||
if(empty($aUpdate)){
|
||||
return json_encode(['status' => 5,'msg' => 'The content format is incorrect']);
|
||||
}
|
||||
$aUpdate['refer_content'] = $sContent;
|
||||
$aUpdate['is_change'] = 1;
|
||||
$aUpdate['update_time'] = time();
|
||||
//更新数据
|
||||
$aWhere = ['p_refer_id' => $iPReferId,'state' => 0];
|
||||
$result = Db::name('production_article_refer')->where($aWhere)->limit(1)->update($aUpdate);
|
||||
if($result === false){
|
||||
return json_encode(['status' => 6,'msg' => 'Update failed']);
|
||||
}
|
||||
return json_encode(['status' => 1,'msg' => 'success']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 处理参考文献的信息
|
||||
* @param p_refer_id 主键ID
|
||||
*/
|
||||
public function dealContent($aParam = []){
|
||||
//获取参数
|
||||
$aParam = empty($aParam) ? $this->request->post() : $aParam;
|
||||
//必填验证
|
||||
$sContent = empty($aParam['content']) ? '' : $aParam['content'];
|
||||
if(empty($sContent)){
|
||||
return json_encode(['status' => 2,'msg' => 'Please enter the modification content']);
|
||||
}
|
||||
if(!is_string($sContent)){
|
||||
return json_encode(['status' => 2,'msg' => 'The content format is incorrect']);
|
||||
}
|
||||
$aContent = explode('.', $sContent);
|
||||
$aUpdate = [];
|
||||
if(count($aContent) > 1){
|
||||
$aField = [0 => 'author',1 => 'title', 2 => 'joura',3 => 'dateno'];
|
||||
$aStart = array_slice($aContent, 0,4);
|
||||
foreach ($aStart as $key => $value) {
|
||||
if(empty($value)){
|
||||
continue;
|
||||
}
|
||||
$aUpdate[$aField[$key]] = trim(trim($value),'.');
|
||||
}
|
||||
|
||||
$sDoi = empty(array_slice($aContent, 4)) ? '' : implode('.', array_slice($aContent, 4));
|
||||
// 匹配http/https开头的URL正则
|
||||
$urlPattern = '/https?:\/\/[^\s<>"]+|http?:\/\/[^\s<>"]+/i';
|
||||
// 执行匹配(preg_match_all返回所有结果)
|
||||
preg_match_all($urlPattern, $sDoi, $matches);
|
||||
if(!empty($matches[0])){
|
||||
$sDoi = implode(',', array_unique($matches[0]));
|
||||
}
|
||||
if(empty($sDoi)){
|
||||
return json_encode(['status' => 4,'msg' => 'Reference DOI is empty']);
|
||||
}
|
||||
$sDoi = trim(trim($sDoi),':');
|
||||
$sDoi = strpos($sDoi ,"http")===false ? "https://doi.org/".$sDoi : $sDoi;
|
||||
$sDoi = str_replace('http://doi.org/', 'https://doi.org/', $sDoi);
|
||||
$aUpdate['doilink'] = $sDoi;
|
||||
$doiPattern = '/10\.\d{4,9}\/[^\s\/?#&=]+/i';
|
||||
if (preg_match($doiPattern, $sDoi, $matches)) {
|
||||
$aUpdate['doi'] = $matches[0];
|
||||
}else{
|
||||
$aUpdate['doi'] = $sDoi;
|
||||
}
|
||||
if(!empty($aUpdate['author'])){
|
||||
$aUpdate['author'] = trim(trim($aUpdate['author'])).'.';
|
||||
}
|
||||
|
||||
}
|
||||
return json_encode(['status' => 1,'msg' => 'success','data' => $aUpdate]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文章信息
|
||||
*/
|
||||
private function getArticle($aParam = []){
|
||||
|
||||
//获取参数
|
||||
$aParam = empty($aParam) ? $this->request->post() : $aParam;
|
||||
|
||||
//获取生产文章信息
|
||||
$iPArticleId = empty($aParam['p_article_id']) ? 0 : $aParam['p_article_id'];
|
||||
if(empty($iPArticleId)){
|
||||
return ['status' => 2,'msg' => 'Please select the article to query'];
|
||||
}
|
||||
$aWhere = ['p_article_id' => $iPArticleId,'state' => 0];
|
||||
$aProductionArticle = Db::name('production_article')->field('article_id')->where($aWhere)->find();
|
||||
$iArticleId = empty($aProductionArticle['article_id']) ? 0 : $aProductionArticle['article_id'];
|
||||
if(empty($iArticleId)) {
|
||||
return ['status' => 2,'msg' => 'No articles found'];
|
||||
}
|
||||
|
||||
//查询条件
|
||||
$aWhere = ['article_id' => $iArticleId,'state' => ['in',[5,6]]];
|
||||
$aArticle = Db::name('article')->field('article_id')->where($aWhere)->find();
|
||||
if(empty($aArticle)){
|
||||
return ['status' => 3,'msg' => 'The article does not exist or has not entered the editorial reference status'];
|
||||
}
|
||||
$aArticle['p_article_id'] = $iPArticleId;
|
||||
return ['status' => 1,'msg' => 'success','data' => $aArticle];
|
||||
}
|
||||
/**
|
||||
* AI检测
|
||||
*/
|
||||
public function checkByAi($aParam = []){
|
||||
//获取参数
|
||||
$aParam = empty($aParam) ? $this->request->post() : $aParam;
|
||||
|
||||
//获取文章信息
|
||||
$aArticle = $this->getArticle($aParam);
|
||||
$iStatus = empty($aArticle['status']) ? 0 : $aArticle['status'];
|
||||
if($iStatus != 1){
|
||||
return json_encode($aArticle);
|
||||
}
|
||||
$aArticle = empty($aArticle['data']) ? [] : $aArticle['data'];
|
||||
if(empty($aArticle)){
|
||||
return json_encode(['status' => 3,'msg' => 'The article does not exist']);
|
||||
}
|
||||
//查询参考文献信息
|
||||
$aWhere = ['p_article_id' => $aArticle['p_article_id'],'state' => 0,'doilink' => ''];
|
||||
$aRefer = Db::name('production_article_refer')->field('p_refer_id,p_article_id,refer_type,refer_content,doilink,refer_doi')->where($aWhere)->select();
|
||||
if(empty($aRefer)){
|
||||
return json_encode(['status' => 4,'msg' => 'No reference information found']);
|
||||
}
|
||||
//数据处理
|
||||
foreach ($aRefer as $key => $value) {
|
||||
if(empty($value['refer_doi'])){
|
||||
continue;
|
||||
}
|
||||
if($value['refer_doi'] == 'Not Available'){
|
||||
continue;
|
||||
}
|
||||
if($value['refer_type'] == 'journal' && !empty($value['doilink'])){
|
||||
continue;
|
||||
}
|
||||
if($value['refer_type'] == 'book' && !empty($value['isbn'])){
|
||||
continue;
|
||||
}
|
||||
//写入获取参考文献详情队列
|
||||
\think\Queue::push('app\api\job\AiCheckReferByDoi@fire',$value,'AiCheckReferByDoi');
|
||||
}
|
||||
return json_encode(['status' => 1,'msg' => 'Successfully joined the AI inspection DOI queue']);
|
||||
}
|
||||
/**
|
||||
* 获取结果
|
||||
*/
|
||||
public function getCheckByAiResult($aParam = []){
|
||||
//获取参数
|
||||
$aParam = empty($aParam) ? $this->request->post() : $aParam;
|
||||
|
||||
//必填值验证
|
||||
$iPReferId = empty($aParam['p_refer_id']) ? '' : $aParam['p_refer_id'];
|
||||
if(empty($iPReferId)){
|
||||
return json_encode(['status' => 2,'msg' => 'Please select the reference to be queried']);
|
||||
}
|
||||
//获取参考文献信息
|
||||
$aWhere = ['p_refer_id' => $iPReferId,'state' => 0];
|
||||
$aRefer = Db::name('production_article_refer')->field('p_refer_id,p_article_id,refer_type,refer_content,doilink,refer_doi,state,dateno')->where($aWhere)->find();
|
||||
if(empty($aRefer)){
|
||||
return json_encode(['status' => 4,'msg' => 'Reference is empty'.json_encode($aParam)]);
|
||||
}
|
||||
if(empty($aRefer['refer_doi'])){
|
||||
return json_encode(['status' => 4,'msg' => 'Reference DOI is empty'.json_encode($aParam)]);
|
||||
}
|
||||
if($aRefer['refer_type'] == 'journal' && !empty($aRefer['doilink'])){
|
||||
$aDateno = empty($aRefer['dateno']) ? [] : explode(':', $aRefer['dateno']);
|
||||
if(count($aDateno) > 1){
|
||||
return json_encode(['status' => 4,'msg' => 'No need to parse again-journal'.json_encode($aParam)]);
|
||||
}
|
||||
}
|
||||
if($aRefer['refer_type'] == 'book' && !empty($aRefer['isbn'])){
|
||||
return json_encode(['status' => 4,'msg' => 'No need to parse again-book'.json_encode($aParam)]);
|
||||
}
|
||||
//获取文章信息
|
||||
$aParam['p_article_id'] = $aRefer['p_article_id'];
|
||||
$aArticle = $this->getArticle($aParam);
|
||||
$iStatus = empty($aArticle['status']) ? 0 : $aArticle['status'];
|
||||
if($iStatus != 1){
|
||||
return json_encode($aArticle);
|
||||
}
|
||||
$aArticle = empty($aArticle['data']) ? [] : $aArticle['data'];
|
||||
if(empty($aArticle)){
|
||||
return json_encode(['status' => 3,'msg' => 'The article does not exist']);
|
||||
}
|
||||
|
||||
//请求AI获取结果
|
||||
$aResult = $this->curlOpenAIByDoi(['doi' => $aRefer['refer_doi']]);
|
||||
$iStatus = empty($aResult['status']) ? 0 : $aResult['status'];
|
||||
$sMsg = empty($aResult['msg']) ? 'The DOI number AI did not find any relevant information' : $aResult['msg'];
|
||||
if($iStatus != 1){
|
||||
return json_encode(['status' => 4,'msg' => $sMsg]);
|
||||
}
|
||||
$aData = empty($aResult['data']) ? [] : $aResult['data'];
|
||||
if(empty($aData)){
|
||||
return json_encode(['status' => 5,'msg' => 'AI obtains empty data']);
|
||||
}
|
||||
//写入日志
|
||||
$aLog = [];
|
||||
$aLog['content'] = json_encode($aResult);
|
||||
$aLog['update_time'] = time();
|
||||
$aLog['p_refer_id'] = $iPReferId;
|
||||
$iLogId = Db::name('production_article_refer_ai')->insertGetId($aLog);
|
||||
$iIsAiCheck = empty($aData['is_ai_check']) ? 2 : $aData['is_ai_check'];
|
||||
if($iIsAiCheck != 1){//AI未检测到信息
|
||||
return json_encode(['status' => 6,'msg' => 'AI did not find any information'.json_encode($aParam)]);
|
||||
}
|
||||
|
||||
//数据处理入库
|
||||
$aField = ['author','title','joura','dateno','doilink'];
|
||||
foreach ($aField as $key => $value) {
|
||||
if(empty($aData[$value])){
|
||||
continue;
|
||||
}
|
||||
if($value == 'author'){
|
||||
$aUpdate['author'] = implode(',', $aData['author']);
|
||||
// $aUpdate['author'] = str_replace('et al.', '', $aUpdate['author']);
|
||||
}else{
|
||||
$aUpdate[$value] = $aData[$value];
|
||||
}
|
||||
}
|
||||
if(empty($aUpdate)){
|
||||
return json_encode(['status' => 6,'msg' => 'Update data to empty'.json_encode($aData)]);
|
||||
}
|
||||
if($aRefer['refer_type'] == 'other'){
|
||||
$aUpdate['refer_type'] = 'journal';
|
||||
}
|
||||
if($aRefer['refer_type'] == 'book' && !empty($aUpdate['doilink'])){
|
||||
$aUpdate['refer_type'] = $aUpdate['doilink'];
|
||||
unset($aUpdate['doilink']);
|
||||
}
|
||||
$aLog = $aUpdate;
|
||||
$aUpdate['is_change'] = 1;
|
||||
$aUpdate['is_ai_check'] = 1;
|
||||
$aUpdate['update_time'] = time();
|
||||
Db::startTrans();
|
||||
//更新数据
|
||||
$aWhere = ['p_refer_id' => $iPReferId,'state' => 0];
|
||||
$result = Db::name('production_article_refer')->where($aWhere)->limit(1)->update($aUpdate);
|
||||
if($result === false){
|
||||
return json_encode(['status' => 6,'msg' => 'Update failed']);
|
||||
}
|
||||
//更新日志
|
||||
if(!empty($iLogId)){
|
||||
$aWhere = ['id' => $iLogId];
|
||||
if(isset($aLog['refer_type'])){
|
||||
unset($aLog['refer_type']);
|
||||
}
|
||||
$result = Db::name('production_article_refer_ai')->where($aWhere)->limit(1)->update($aLog);
|
||||
}
|
||||
Db::commit();
|
||||
return json_encode(['status' => 1,'msg' => 'success']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 对接OPENAI
|
||||
*/
|
||||
private function curlOpenAIByDoi($aParam = []){
|
||||
|
||||
//获取DOI
|
||||
$sDoi = empty($aParam['doi']) ? '' : $aParam['doi'];
|
||||
if(empty($sDoi)){
|
||||
return ['status' => 2,'msg' => 'Reference doi is empty'];
|
||||
}
|
||||
//系统角色
|
||||
$sSysMessagePrompt = '请完成以下任务:
|
||||
1. 根据提供的DOI号,查询该文献的AMA引用格式;
|
||||
2. 按照以下规则调整AMA引用格式:
|
||||
- 第三个作者名字后添加 et al.;
|
||||
- DOI前加上"Available at: ";
|
||||
- DOI信息格式调整为"https://doi.org/+真实DOI"(替换真实DOI为文献实际DOI).
|
||||
3. 严格按照以下JSON结构返回结果,仅返回JSON数据,不要额外文字,包含字段:doilink(url格式)、title(标题)、author(作者数组)、joura(出版社名称)、dateno(年;卷(期):起始页-终止页),is_ai_check(默认1)
|
||||
4. 若未查询到信息,字段is_ai_check为2,相关字段为null。';
|
||||
//用户角色
|
||||
$sUserPrompt = '我提供的DOI是:'.$sDoi;
|
||||
$aMessage = [
|
||||
['role' => 'system', 'content' => $sSysMessagePrompt],
|
||||
['role' => 'user', 'content' => $sUserPrompt],
|
||||
];
|
||||
//请求OPENAI接口
|
||||
$sModel = empty($aParam['model']) ? 'gpt-4.1' : $aParam['model'];//模型
|
||||
$sApiUrl = $this->sApiUrl;//'http://chat.taimed.cn/v1/chat/completions';//
|
||||
$aParam = ['model' => $sModel,'url' => $sApiUrl,'temperature' => 0,'messages' => $aMessage,'api_key' => $this->sApiKey];
|
||||
$oOpenAi = new \app\common\OpenAi;
|
||||
$aResult = json_decode($oOpenAi->curlOpenAI($aParam),true);
|
||||
return $aResult;
|
||||
}
|
||||
/**
|
||||
* 作者修改完成发邮件
|
||||
*/
|
||||
public function finishSendEmail(){
|
||||
//获取参数
|
||||
$aParam = empty($aParam) ? $this->request->post() : $aParam;
|
||||
//文章ID
|
||||
$iArticleId = empty($aParam['article_id']) ? '' : $aParam['article_id'];
|
||||
if(empty($iArticleId)){
|
||||
return json_encode(array('status' => 2,'msg' => 'Please select an article'));
|
||||
}
|
||||
//查询条件
|
||||
$aWhere = ['article_id' => $iArticleId,'state' => ['in',[5,6]]];
|
||||
$aArticle = Db::name('article')->field('article_id,journal_id,accept_sn')->where($aWhere)->find();
|
||||
if(empty($aArticle)){
|
||||
return json_encode(['status' => 3,'msg' => 'The article does not exist or has not entered the editorial reference status']);
|
||||
}
|
||||
$aWhere = ['article_id' => $iArticleId,'state' => 0];
|
||||
$aProductionArticle = Db::name('production_article')->field('p_article_id')->where($aWhere)->find();
|
||||
if(empty($aProductionArticle)) {
|
||||
return ['status' => 2,'msg' => 'The article has not entered the production stage'];
|
||||
}
|
||||
//查询是否有参考文献
|
||||
$aWhere = ['p_article_id' => $aProductionArticle['p_article_id'],'state' => 0];
|
||||
$aRefer = Db::name('production_article_refer')->field('article_id')->where($aWhere)->find();
|
||||
if(empty($aRefer)) {
|
||||
return ['status' => 2,'msg' => 'No reference information found, please be patient and wait for the editor to upload'];
|
||||
}
|
||||
//查询期刊信息
|
||||
if(empty($aArticle['journal_id'])){
|
||||
return json_encode(array('status' => 4,'msg' => 'The article is not associated with a journal' ));
|
||||
}
|
||||
$aWhere = ['state' => 0,'journal_id' => $aArticle['journal_id']];
|
||||
$aJournal = Db::name('journal')->where($aWhere)->find();
|
||||
if(empty($aJournal)){
|
||||
return json_encode(array('status' => 5,'msg' => 'No journal information found' ));
|
||||
}
|
||||
//查询编辑邮箱
|
||||
$iUserId = empty($aJournal['editor_id']) ? '' : $aJournal['editor_id'];
|
||||
if(empty($iUserId)){
|
||||
return json_encode(array('status' => 6,'msg' => 'The journal to which the article belongs has not designated a responsible editor' ));
|
||||
}
|
||||
$aWhere = ['user_id' => $iUserId,'state' => 0,'email' => ['<>','']];
|
||||
$aUser = Db::name('user')->field('user_id,email,realname,account')->where($aWhere)->find();
|
||||
if(empty($aUser)){
|
||||
return json_encode(['status' => 7,'msg' => "Edit email as empty"]);
|
||||
}
|
||||
|
||||
//处理发邮件
|
||||
//邮件模版
|
||||
$aEmailConfig = [
|
||||
'email_subject' => '{journal_title}-{accept_sn}',
|
||||
'email_content' => '
|
||||
Dear Editor,<br><br>
|
||||
The authors have revised the formats of all references, please check.<br>
|
||||
Sn:{accept_sn}<br><br>
|
||||
Sincerely,<br>Editorial Office<br>
|
||||
<a href="https://www.tmrjournals.com/draw_up.html?issn={journal_issn}">Subscribe to this journal</a><br>{journal_title}<br>
|
||||
Email: {journal_email}<br>
|
||||
Website: {website}'
|
||||
];
|
||||
//邮件内容
|
||||
$aSearch = [
|
||||
'{accept_sn}' => empty($aArticle['accept_sn']) ? '' : $aArticle['accept_sn'],//accept_sn
|
||||
'{journal_title}' => empty($aJournal['title']) ? '' : $aJournal['title'],//期刊名
|
||||
'{journal_issn}' => empty($aJournal['issn']) ? '' : $aJournal['issn'],
|
||||
'{journal_email}' => empty($aJournal['email']) ? '' : $aJournal['email'],
|
||||
'{website}' => empty($aJournal['website']) ? '' : $aJournal['website'],
|
||||
];
|
||||
|
||||
//发邮件
|
||||
//邮件标题
|
||||
$email = $aUser['email'];
|
||||
$title = str_replace(array_keys($aSearch), array_values($aSearch),$aEmailConfig['email_subject']);
|
||||
//邮件内容变量替换
|
||||
$content = str_replace(array_keys($aSearch), array_values($aSearch), $aEmailConfig['email_content']);
|
||||
$pre = \think\Env::get('emailtemplete.pre');
|
||||
$net = \think\Env::get('emailtemplete.net');
|
||||
$net1 = str_replace("{{email}}",trim($email),$net);
|
||||
$content=$pre.$content.$net1;
|
||||
//发送邮件
|
||||
$memail = empty($aJournal['email']) ? '' : $aJournal['email'];
|
||||
$mpassword = empty($aJournal['epassword']) ? '' : $aJournal['epassword'];
|
||||
//期刊标题
|
||||
$from_name = empty($aJournal['title']) ? '' : $aJournal['title'];
|
||||
//邮件队列组装参数
|
||||
$aResult = sendEmail($email,$title,$from_name,$content,$memail,$mpassword);
|
||||
$iStatus = empty($aResult['status']) ? 1 : $aResult['status'];
|
||||
$iIsSuccess = 2;
|
||||
$sMsg = empty($aResult['data']) ? '失败' : $aResult['data'];
|
||||
if($iStatus == 1){
|
||||
return json_encode(['status' => 1,'msg' => 'success']);
|
||||
}
|
||||
return json_encode(['status' => 8,'msg' => 'fail']);
|
||||
}
|
||||
}
|
||||
78
application/api/job/AiCheckRefer.php
Normal file
78
application/api/job/AiCheckRefer.php
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
namespace app\api\job;
|
||||
use think\queue\Job;
|
||||
use app\common\QueueJob;
|
||||
use app\common\QueueRedis;
|
||||
use think\Db;
|
||||
class AiCheckRefer
|
||||
{
|
||||
private $oQueueJob;
|
||||
private $QueueRedis;
|
||||
private $completedExprie = 3600;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->oQueueJob = new QueueJob;
|
||||
$this->QueueRedis = QueueRedis::getInstance();
|
||||
}
|
||||
|
||||
public function fire(Job $job, $data)
|
||||
{
|
||||
//任务开始判断
|
||||
$this->oQueueJob->init($job);
|
||||
|
||||
// 获取 Redis 任务的原始数据
|
||||
$rawBody = empty($job->getRawBody()) ? '' : $job->getRawBody();
|
||||
$jobData = empty($rawBody) ? [] : json_decode($rawBody, true);
|
||||
$jobId = empty($jobData['id']) ? 'unknown' : $jobData['id'];
|
||||
|
||||
$this->oQueueJob->log("-----------队列任务开始-----------");
|
||||
$this->oQueueJob->log("当前任务ID: {$jobId}, 尝试次数: {$job->attempts()}");
|
||||
|
||||
|
||||
// 获取生产文章ID
|
||||
$iPArticleId = empty($data['p_article_id']) ? 0 : $data['p_article_id'];
|
||||
if (empty($iPArticleId)) {
|
||||
$this->oQueueJob->log("无效的p_article_id,删除任务");
|
||||
$job->delete();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
|
||||
// 生成Redis键并尝试获取锁
|
||||
$sClassName = get_class($this);
|
||||
$sRedisKey = "queue_job:{$sClassName}:{$iPArticleId}";
|
||||
$sRedisValue = uniqid() . '_' . getmypid();
|
||||
if (!$this->oQueueJob->acquireLock($sRedisKey, $sRedisValue, $job)) {
|
||||
return; // 未获取到锁,已处理
|
||||
}
|
||||
|
||||
//生成内容
|
||||
$oProductionArticleRefer = new \app\api\controller\References;
|
||||
$response = $oProductionArticleRefer->checkByAi($data);
|
||||
// 验证API响应
|
||||
if (empty($response)) {
|
||||
throw new \RuntimeException("OpenAI API返回空结果");
|
||||
}
|
||||
// 检查JSON解析错误
|
||||
$aResult = json_decode($response, true);
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
throw new \RuntimeException("解析OpenAI响应失败: " . json_last_error_msg() . " | 原始响应: {$response}");
|
||||
}
|
||||
$sMsg = empty($aResult['msg']) ? 'success' : $aResult['msg'];
|
||||
//更新完成标识
|
||||
$this->QueueRedis->finishJob($sRedisKey, 'completed', $this->completedExprie,$sRedisValue);
|
||||
$job->delete();
|
||||
$this->oQueueJob->log("任务执行成功 | 日志ID: {$sRedisKey} | 执行日志:{$sMsg}");
|
||||
|
||||
} catch (\RuntimeException $e) {
|
||||
$this->oQueueJob->handleRetryableException($e,$sRedisKey,$sRedisValue, $job);
|
||||
} catch (\LogicException $e) {
|
||||
$this->oQueueJob->handleNonRetryableException($e,$sRedisKey,$sRedisValue, $job);
|
||||
} catch (\Exception $e) {
|
||||
$this->oQueueJob->handleRetryableException($e,$sRedisKey,$sRedisValue, $job);
|
||||
} finally {
|
||||
$this->oQueueJob->finnal();
|
||||
}
|
||||
}
|
||||
}
|
||||
85
application/api/job/AiCheckReferByDoi.php
Normal file
85
application/api/job/AiCheckReferByDoi.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
namespace app\api\job;
|
||||
use think\queue\Job;
|
||||
use app\common\QueueJob;
|
||||
use app\common\QueueRedis;
|
||||
use think\Db;
|
||||
class AiCheckReferByDoi
|
||||
{
|
||||
private $oQueueJob;
|
||||
private $QueueRedis;
|
||||
private $completedExprie = 3600;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->oQueueJob = new QueueJob;
|
||||
$this->QueueRedis = QueueRedis::getInstance();
|
||||
}
|
||||
|
||||
public function fire(Job $job, $data)
|
||||
{
|
||||
//任务开始判断
|
||||
$this->oQueueJob->init($job);
|
||||
|
||||
// 获取 Redis 任务的原始数据
|
||||
$rawBody = empty($job->getRawBody()) ? '' : $job->getRawBody();
|
||||
$jobData = empty($rawBody) ? [] : json_decode($rawBody, true);
|
||||
$jobId = empty($jobData['id']) ? 'unknown' : $jobData['id'];
|
||||
|
||||
$this->oQueueJob->log("-----------队列任务开始-----------");
|
||||
$this->oQueueJob->log("当前任务ID: {$jobId}, 尝试次数: {$job->attempts()}");
|
||||
|
||||
|
||||
// 获取生产文章ID
|
||||
$iPArticleId = empty($data['p_article_id']) ? 0 : $data['p_article_id'];
|
||||
if (empty($iPArticleId)) {
|
||||
$this->oQueueJob->log("无效的p_article_id,删除任务");
|
||||
$job->delete();
|
||||
return;
|
||||
}
|
||||
// 获取参考文献ID
|
||||
$iPReferId = empty($data['p_refer_id']) ? 0 : $data['p_refer_id'];
|
||||
if (empty($iPArticleId)) {
|
||||
$this->oQueueJob->log("无效的p_article_id,删除任务");
|
||||
$job->delete();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
|
||||
// 生成Redis键并尝试获取锁
|
||||
$sClassName = get_class($this);
|
||||
$sRedisKey = "queue_job:{$sClassName}:{$iPArticleId}:{$iPReferId}";
|
||||
$sRedisValue = uniqid() . '_' . getmypid();
|
||||
if (!$this->oQueueJob->acquireLock($sRedisKey, $sRedisValue, $job)) {
|
||||
return; // 未获取到锁,已处理
|
||||
}
|
||||
|
||||
//生成内容
|
||||
$oProductionArticleRefer = new \app\api\controller\References;
|
||||
$response = $oProductionArticleRefer->getCheckByAiResult($data);
|
||||
// 验证API响应
|
||||
if (empty($response)) {
|
||||
throw new \RuntimeException("OpenAI API返回空结果");
|
||||
}
|
||||
// 检查JSON解析错误
|
||||
$aResult = json_decode($response, true);
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
throw new \RuntimeException("解析OpenAI响应失败: " . json_last_error_msg() . " | 原始响应: {$response}");
|
||||
}
|
||||
$sMsg = empty($aResult['msg']) ? 'success' : $aResult['msg'];
|
||||
//更新完成标识
|
||||
$this->QueueRedis->finishJob($sRedisKey, 'completed', $this->completedExprie,$sRedisValue);
|
||||
$job->delete();
|
||||
$this->oQueueJob->log("任务执行成功 | 日志ID: {$sRedisKey} | 执行日志:{$sMsg}");
|
||||
|
||||
} catch (\RuntimeException $e) {
|
||||
$this->oQueueJob->handleRetryableException($e,$sRedisKey,$sRedisValue, $job);
|
||||
} catch (\LogicException $e) {
|
||||
$this->oQueueJob->handleNonRetryableException($e,$sRedisKey,$sRedisValue, $job);
|
||||
} catch (\Exception $e) {
|
||||
$this->oQueueJob->handleRetryableException($e,$sRedisKey,$sRedisValue, $job);
|
||||
} finally {
|
||||
$this->oQueueJob->finnal();
|
||||
}
|
||||
}
|
||||
}
|
||||
92
application/api/job/ArticleReferDetailQueue.php
Normal file
92
application/api/job/ArticleReferDetailQueue.php
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
namespace app\api\job;
|
||||
use think\queue\Job;
|
||||
use app\common\QueueJob;
|
||||
use app\common\QueueRedis;
|
||||
use app\common\ProductionArticleRefer;
|
||||
use think\Db;
|
||||
class ArticleReferDetailQueue
|
||||
{
|
||||
private $oQueueJob;
|
||||
private $QueueRedis;
|
||||
private $completedExprie = 3600;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->oQueueJob = new QueueJob;
|
||||
$this->QueueRedis = QueueRedis::getInstance();
|
||||
}
|
||||
|
||||
public function fire(Job $job, $data)
|
||||
{
|
||||
//任务开始判断
|
||||
$this->oQueueJob->init($job);
|
||||
|
||||
// 获取 Redis 任务的原始数据
|
||||
$rawBody = empty($job->getRawBody()) ? '' : $job->getRawBody();
|
||||
$jobData = empty($rawBody) ? [] : json_decode($rawBody, true);
|
||||
$jobId = empty($jobData['id']) ? 'unknown' : $jobData['id'];
|
||||
|
||||
$this->oQueueJob->log("-----------队列任务开始-----------");
|
||||
$this->oQueueJob->log("当前任务ID: {$jobId}, 尝试次数: {$job->attempts()}");
|
||||
|
||||
// // 获取文章ID
|
||||
// $iArticleId = empty($data['article_id']) ? 0 : $data['article_id'];
|
||||
// if (empty($iArticleId)) {
|
||||
// $this->oQueueJob->log("无效的article_id,删除任务");
|
||||
// $job->delete();
|
||||
// return;
|
||||
// }
|
||||
// 获取生产文章ID
|
||||
$iPArticleId = empty($data['p_article_id']) ? 0 : $data['p_article_id'];
|
||||
if (empty($iPArticleId)) {
|
||||
$this->oQueueJob->log("无效的p_article_id,删除任务");
|
||||
$job->delete();
|
||||
return;
|
||||
}
|
||||
// 获取生产文章ID
|
||||
$iPReferId = empty($data['p_refer_id']) ? 0 : $data['p_refer_id'];
|
||||
if (empty($iPReferId)) {
|
||||
$this->oQueueJob->log("无效的p_refer_id,删除任务");
|
||||
$job->delete();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
|
||||
// 生成Redis键并尝试获取锁
|
||||
$sClassName = get_class($this);
|
||||
$sRedisKey = "queue_job:{$sClassName}:{$iPArticleId}:{$iPReferId}";
|
||||
$sRedisValue = uniqid() . '_' . getmypid();
|
||||
if (!$this->oQueueJob->acquireLock($sRedisKey, $sRedisValue, $job)) {
|
||||
return; // 未获取到锁,已处理
|
||||
}
|
||||
|
||||
//生成内容
|
||||
$oProductionArticleRefer = new ProductionArticleRefer;
|
||||
$response = $oProductionArticleRefer->get($data);
|
||||
// 验证API响应
|
||||
if (empty($response)) {
|
||||
throw new \RuntimeException("返回空结果");
|
||||
}
|
||||
// 检查JSON解析错误
|
||||
$aResult = json_decode($response, true);
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
throw new \RuntimeException("解析响应失败: " . json_last_error_msg() . " | 原始响应: {$response}");
|
||||
}
|
||||
$sMsg = empty($aResult['msg']) ? 'success' : $aResult['msg'];
|
||||
//更新完成标识
|
||||
$this->QueueRedis->finishJob($sRedisKey, 'completed', $this->completedExprie,$sRedisValue);
|
||||
$job->delete();
|
||||
$this->oQueueJob->log("任务执行成功 | 日志ID: {$sRedisKey} | 执行日志:{$sMsg}");
|
||||
|
||||
} catch (\RuntimeException $e) {
|
||||
$this->oQueueJob->handleRetryableException($e,$sRedisKey,$sRedisValue, $job);
|
||||
} catch (\LogicException $e) {
|
||||
$this->oQueueJob->handleNonRetryableException($e,$sRedisKey,$sRedisValue, $job);
|
||||
} catch (\Exception $e) {
|
||||
$this->oQueueJob->handleRetryableException($e,$sRedisKey,$sRedisValue, $job);
|
||||
} finally {
|
||||
$this->oQueueJob->finnal();
|
||||
}
|
||||
}
|
||||
}
|
||||
85
application/api/job/ArticleReferQueue.php
Normal file
85
application/api/job/ArticleReferQueue.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
namespace app\api\job;
|
||||
use think\queue\Job;
|
||||
use app\common\QueueJob;
|
||||
use app\common\QueueRedis;
|
||||
use app\common\ProductionArticleRefer;
|
||||
use think\Db;
|
||||
class ArticleReferQueue
|
||||
{
|
||||
private $oQueueJob;
|
||||
private $QueueRedis;
|
||||
private $completedExprie = 180;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->oQueueJob = new QueueJob;
|
||||
$this->QueueRedis = QueueRedis::getInstance();
|
||||
}
|
||||
|
||||
public function fire(Job $job, $data)
|
||||
{
|
||||
//任务开始判断
|
||||
$this->oQueueJob->init($job);
|
||||
|
||||
// 获取 Redis 任务的原始数据
|
||||
$rawBody = empty($job->getRawBody()) ? '' : $job->getRawBody();
|
||||
$jobData = empty($rawBody) ? [] : json_decode($rawBody, true);
|
||||
$jobId = empty($jobData['id']) ? 'unknown' : $jobData['id'];
|
||||
|
||||
$this->oQueueJob->log("-----------队列任务开始-----------");
|
||||
$this->oQueueJob->log("当前任务ID: {$jobId}, 尝试次数: {$job->attempts()}");
|
||||
|
||||
// 获取文章ID
|
||||
$iArticleId = empty($data['article_id']) ? 0 : $data['article_id'];
|
||||
if (empty($iArticleId)) {
|
||||
$this->oQueueJob->log("无效的article_id,删除任务");
|
||||
$job->delete();
|
||||
return;
|
||||
}
|
||||
// 获取生产文章ID
|
||||
$iPArticleId = empty($data['p_article_id']) ? 0 : $data['p_article_id'];
|
||||
if (empty($iPArticleId)) {
|
||||
$this->oQueueJob->log("无效的p_article_id,删除任务");
|
||||
$job->delete();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
|
||||
// 生成Redis键并尝试获取锁
|
||||
$sClassName = get_class($this);
|
||||
$sRedisKey = "queue_job:{$sClassName}:{$iArticleId}:{$iPArticleId}";
|
||||
$sRedisValue = uniqid() . '_' . getmypid();
|
||||
if (!$this->oQueueJob->acquireLock($sRedisKey, $sRedisValue, $job)) {
|
||||
return; // 未获取到锁,已处理
|
||||
}
|
||||
|
||||
//生成内容
|
||||
$oProductionArticleRefer = new ProductionArticleRefer;
|
||||
$response = $oProductionArticleRefer->top($data);
|
||||
// 验证API响应
|
||||
if (empty($response)) {
|
||||
throw new \RuntimeException("OpenAI API返回空结果");
|
||||
}
|
||||
// 检查JSON解析错误
|
||||
$aResult = json_decode($response, true);
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
throw new \RuntimeException("解析OpenAI响应失败: " . json_last_error_msg() . " | 原始响应: {$response}");
|
||||
}
|
||||
$sMsg = empty($aResult['msg']) ? 'success' : $aResult['msg'];
|
||||
//更新完成标识
|
||||
$this->QueueRedis->finishJob($sRedisKey, 'completed', $this->completedExprie,$sRedisValue);
|
||||
$job->delete();
|
||||
$this->oQueueJob->log("任务执行成功 | 日志ID: {$sRedisKey} | 执行日志:{$sMsg}");
|
||||
|
||||
} catch (\RuntimeException $e) {
|
||||
$this->oQueueJob->handleRetryableException($e,$sRedisKey,$sRedisValue, $job);
|
||||
} catch (\LogicException $e) {
|
||||
$this->oQueueJob->handleNonRetryableException($e,$sRedisKey,$sRedisValue, $job);
|
||||
} catch (\Exception $e) {
|
||||
$this->oQueueJob->handleRetryableException($e,$sRedisKey,$sRedisValue, $job);
|
||||
} finally {
|
||||
$this->oQueueJob->finnal();
|
||||
}
|
||||
}
|
||||
}
|
||||
82
application/api/job/ProofReadQueue.php
Normal file
82
application/api/job/ProofReadQueue.php
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
namespace app\api\job;
|
||||
|
||||
use think\queue\Job;
|
||||
use app\common\QueueJob;
|
||||
use app\common\QueueRedis;
|
||||
use app\common\ProofRead;
|
||||
class ProofReadQueue
|
||||
{
|
||||
private $oQueueJob;
|
||||
private $QueueRedis;
|
||||
private $completedExprie = 3600;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->oQueueJob = new QueueJob;
|
||||
$this->QueueRedis = QueueRedis::getInstance();
|
||||
}
|
||||
|
||||
public function fire(Job $job, $data)
|
||||
{
|
||||
//任务开始判断
|
||||
$this->oQueueJob->init($job);
|
||||
|
||||
// 获取 Redis 任务的原始数据
|
||||
$rawBody = empty($job->getRawBody()) ? '' : $job->getRawBody();
|
||||
$jobData = empty($rawBody) ? [] : json_decode($rawBody, true);
|
||||
$jobId = empty($jobData['id']) ? 'unknown' : $jobData['id'];
|
||||
|
||||
$this->oQueueJob->log("-----------队列任务开始-----------");
|
||||
$this->oQueueJob->log("当前任务ID: {$jobId}, 尝试次数: {$job->attempts()}");
|
||||
|
||||
// 获取文章ID
|
||||
$iArticleId = empty($data['article_id']) ? 0 : $data['article_id'];
|
||||
$sChunkIndex = empty($data['chunkIndex']) ? 0 : $data['chunkIndex'];
|
||||
$sPrompt = empty($data['prompt']) ? '' : $data['prompt'];
|
||||
if (empty($iArticleId)) {
|
||||
$this->oQueueJob->log("无效的article_id,删除任务");
|
||||
$job->delete();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
|
||||
// 生成Redis键并尝试获取锁
|
||||
$sClassName = get_class($this);
|
||||
$sRedisKey = "queue_job:{$sClassName}:{$iArticleId}:{$sPrompt}_{$sChunkIndex}";
|
||||
$sRedisValue = uniqid() . '_' . getmypid();
|
||||
if (!$this->oQueueJob->acquireLock($sRedisKey, $sRedisValue, $job)) {
|
||||
return; // 未获取到锁,已处理
|
||||
}
|
||||
|
||||
//生成内容
|
||||
$oAireview = new ProofRead;
|
||||
$response = $oAireview->proofReadQueue($data);
|
||||
|
||||
// 验证API响应
|
||||
if (empty($response)) {
|
||||
throw new \RuntimeException("OpenAI API返回空结果");
|
||||
}
|
||||
// 检查JSON解析错误
|
||||
$aResult = json_decode($response, true);
|
||||
echo '<pre>';var_dump($aResult);
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
throw new \RuntimeException("解析OpenAI响应失败: " . json_last_error_msg() . " | 原始响应: {$response}");
|
||||
}
|
||||
$sMsg = empty($aResult['msg']) ? 'success' : $aResult['msg'];
|
||||
//更新完成标识
|
||||
$this->QueueRedis->finishJob($sRedisKey, 'completed', $this->completedExprie,$sRedisValue);
|
||||
$job->delete();
|
||||
$this->oQueueJob->log("任务执行成功 | 日志ID: {$sRedisKey} | 执行日志:{$sMsg}");
|
||||
|
||||
} catch (\RuntimeException $e) {
|
||||
$this->oQueueJob->handleRetryableException($e,$sRedisKey,$sRedisValue, $job);
|
||||
} catch (\LogicException $e) {
|
||||
$this->oQueueJob->handleNonRetryableException($e,$sRedisKey,$sRedisValue, $job);
|
||||
} catch (\Exception $e) {
|
||||
$this->oQueueJob->handleRetryableException($e,$sRedisKey,$sRedisValue, $job);
|
||||
} finally {
|
||||
$this->oQueueJob->finnal();
|
||||
}
|
||||
}
|
||||
}
|
||||
303
application/common/ProductionArticleRefer.php
Normal file
303
application/common/ProductionArticleRefer.php
Normal file
@@ -0,0 +1,303 @@
|
||||
<?php
|
||||
namespace app\common;
|
||||
use think\Db;
|
||||
use think\Env;
|
||||
class ProductionArticleRefer
|
||||
{
|
||||
|
||||
// DOI匹配核心正则(生产级优化:支持%字符、限制长度、单词边界断言)
|
||||
// private const DOI_PATTERN = '/(?:doi[:\s]?|DOI[:\s]?)?\b10\.\d+(?:\.\d+)*\/[a-zA-Z0-9._\-!()%\/:;@$&+=?#[\]<>~`|^]+/i';
|
||||
|
||||
// 错误码与错误信息映射(标准化错误处理)
|
||||
private const ERROR_CODES = [
|
||||
'EMPTY_STRING' => 'Input string is empty (preprocessed))',
|
||||
'NO_MATCH' => 'No valid DOI detected',
|
||||
'INVALID_AFTER_CLEAN' => 'No effective DOI after cleaning',
|
||||
'FORCE_EXTRACT_FAILED' => 'Forced extraction still has no valid DOI',
|
||||
'EXTRACTION_EXCEPTION' => 'Exception occurred during DOI extraction process',
|
||||
];
|
||||
|
||||
/**
|
||||
* 获取未处理的参考文献
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function top($aParam = []) {
|
||||
|
||||
//文章ID
|
||||
$iArticleId = empty($aParam['article_id']) ? '' : $aParam['article_id'];
|
||||
if(empty($iArticleId)){
|
||||
return json_encode(array('status' => 2,'msg' => 'Please select an article'.json_encode($aParam) ));
|
||||
}
|
||||
// 获取生产文章ID
|
||||
$iPArticleId = empty($aParam['p_article_id']) ? 0 : $aParam['p_article_id'];
|
||||
if(empty($iPArticleId)) {
|
||||
return json_encode(array('status' => 2,'msg' => 'Please select an production article'.json_encode($aParam) ));
|
||||
}
|
||||
|
||||
//查询未处理过的数据
|
||||
$aWhere = ['p_article_id' => $iPArticleId,'article_id' => $iArticleId,'state' => 0,'refer_doi' => ['<>',''],'is_deal' => 2];
|
||||
$aResult = Db::name('production_article_refer')->field('article_id,p_article_id,p_refer_id,refer_doi')->where($aWhere)->select();
|
||||
if(empty($aResult)){
|
||||
return json_encode(array('status' => 2,'msg' => 'The reference data to be processed is empty'.json_encode($aParam)));
|
||||
}
|
||||
|
||||
//数据处理
|
||||
foreach ($aResult as $key => $value) {
|
||||
if(empty($value['refer_doi'])){
|
||||
continue;
|
||||
}
|
||||
//调用获取参考文献详情队列
|
||||
\think\Queue::push('app\api\job\ArticleReferDetailQueue@fire', $value, 'ArticleReferDetailQueue');
|
||||
}
|
||||
return json_encode(['status' => 1,'msg' => 'Add to reference processing queue']);
|
||||
}
|
||||
/**
|
||||
* 处理参考文献
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function get($aParam = []) {
|
||||
// 获取生产文章ID
|
||||
$iPReferId = empty($aParam['p_refer_id']) ? 0 : $aParam['p_refer_id'];
|
||||
if(empty($iPReferId)) {
|
||||
return json_encode(array('status' => 2,'msg' => 'Please select a reference'.json_encode($aParam) ));
|
||||
}
|
||||
// 获取生产文章ID
|
||||
$iPArticleId = empty($aParam['p_article_id']) ? 0 : $aParam['p_article_id'];
|
||||
if(empty($iPArticleId)) {
|
||||
return json_encode(array('status' => 2,'msg' => 'Please select an production article'.json_encode($aParam) ));
|
||||
}
|
||||
//查询未处理过的数据
|
||||
$aWhere = ['p_refer_id' => $iPReferId,'p_article_id' => $iPArticleId,'state' => 0];
|
||||
$aRefer = Db::name('production_article_refer')->field('refer_doi,refer_content')->where($aWhere)->find();
|
||||
if(empty($aRefer)){
|
||||
return json_encode(array('status' => 2,'msg' => 'No reference records found'.json_encode($aParam)));
|
||||
}
|
||||
if(empty($aRefer['refer_doi'])){
|
||||
return json_encode(['status' => 4,'msg' => 'Reference DOI is empty'.json_encode($aParam)]);
|
||||
}
|
||||
|
||||
//数据处理
|
||||
$doi = str_replace('/', '%2F', $aRefer['refer_doi']);
|
||||
$url = "https://citation.doi.org/format?doi=$doi&style=cancer-translational-medicine&lang=en-US";
|
||||
$res = myGet($url);
|
||||
$frag = trim(substr($res, strpos($res, '.') + 1));
|
||||
if(empty($frag)){
|
||||
$aUpdate = ['refer_frag' => $aRefer['refer_content'],'refer_type' => 'other','is_deal' => 1,'update_time' => time()];
|
||||
$aWhere = ['p_refer_id' => $iPReferId];
|
||||
$result = Db::name('production_article_refer')->where($aWhere)->limit(1)->update($aUpdate);
|
||||
//写入通过AI获取参考文献详情队列
|
||||
\think\Queue::push('app\api\job\AiCheckReferByDoi@fire',$aParam,'AiCheckReferByDoi');
|
||||
return json_encode(array('status' => 2,'msg' => 'The data obtained from the interface is empty'.$url));
|
||||
}
|
||||
|
||||
//整理数据入库
|
||||
$update = [];
|
||||
if (mb_substr_count($frag, '.') != 3){
|
||||
$f = $frag . " Available at: " . PHP_EOL . "https://doi.org/" . $aRefer['refer_doi'];
|
||||
$update['refer_type'] = "other";
|
||||
$update['refer_frag'] = $f;
|
||||
$update['cs'] = 1;
|
||||
//写入通过AI获取参考文献详情队列
|
||||
\think\Queue::push('app\api\job\AiCheckReferByDoi@fire',$aParam,'AiCheckReferByDoi');
|
||||
}
|
||||
if (mb_substr_count($frag, '.') == 3){
|
||||
$res = explode('.', $frag);
|
||||
$update['author'] = prgeAuthor($res[0]);
|
||||
$update['title'] = trim($res[1]);
|
||||
$bj = bekjournal($res[2]);
|
||||
$joura = formateJournal(trim($bj[0]));
|
||||
$update['joura'] = $joura;
|
||||
$is_js = 0;
|
||||
if ($joura == trim($bj[0])) {
|
||||
}
|
||||
$update['refer_type'] = "journal";
|
||||
$update['is_ja'] = $joura == trim($bj[0]) ? 0 : 1;
|
||||
$update['dateno'] = str_replace(' ', '', str_replace('-', '–', trim($bj[1])));
|
||||
//新增处理 期卷页码 20251127 start
|
||||
if(!empty($update['dateno'])){
|
||||
$sStr = $update['dateno'];
|
||||
$aStr = explode(':', $sStr);
|
||||
if(!empty($aStr[1])){
|
||||
$parts = explode('–', $aStr[1]);
|
||||
if(count($parts) == 2){
|
||||
$prefix = empty($parts[0]) ? 0 : intval($parts[0]);
|
||||
$suffix = empty($parts[1]) ? 0 : intval($parts[1]);
|
||||
if($prefix > $suffix){
|
||||
$prefixLen = strlen($prefix);
|
||||
$suffixLen = strlen($suffix);
|
||||
$missingLen = $prefixLen - $suffixLen;
|
||||
if ($missingLen > 0) {
|
||||
$fillPart = substr($prefix, 0, $missingLen);
|
||||
$newSuffix = $fillPart . $suffix;
|
||||
$update['dateno'] = $aStr[0].':'.$prefix.'-'.$newSuffix;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(empty($aStr[1])){
|
||||
//写入通过AI获取参考文献详情队列
|
||||
\think\Queue::push('app\api\job\AiCheckReferByDoi@fire',$aParam,'AiCheckReferByDoi');
|
||||
}
|
||||
}
|
||||
//新增处理 期卷页码 20251127 end
|
||||
$update['doilink'] = strpos($aRefer['refer_doi'],"http")===false?"https://doi.org/" . $aRefer['refer_doi']:$aRefer['refer_doi'];
|
||||
$update['cs'] = 1;
|
||||
}
|
||||
//数据库更新
|
||||
if(empty($update)){
|
||||
return json_encode(array('status' => 3,'msg' => 'Update data to empty'.$url.'====='.$frag));
|
||||
}
|
||||
$aWhere = ['p_refer_id' => $iPReferId];
|
||||
$update += ['is_deal' => 1,'update_time' => time()];
|
||||
$result = Db::name('production_article_refer')->where($aWhere)->limit(1)->update($update);
|
||||
if($result === false){
|
||||
return json_encode(array('status' => 3,'msg' => 'Update failed'.json_encode($update)));
|
||||
}
|
||||
return json_encode(['status' => 1,'msg' => 'Update successful']);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * 实例方法:提取单个DOI(核心逻辑,生产级优化)
|
||||
// * @param string $str 待检测字符串
|
||||
// * @param bool $standardize 是否标准化DOI(转小写)
|
||||
// * @param bool $forceExtract 是否强制提取(忽略微小格式瑕疵)
|
||||
// * @return array 提取结果(含错误码、错误信息、DOI)
|
||||
// */
|
||||
// // public function extractDoiFromString(string $str, bool $standardize = true, bool $forceExtract = false): array
|
||||
// // {
|
||||
// // // 初始化标准化结果
|
||||
// // $result = [
|
||||
// // 'has_doi' => false,
|
||||
// // 'doi' => null,
|
||||
// // 'error_code' => null,
|
||||
// // 'error_msg' => null,
|
||||
// // ];
|
||||
|
||||
// // try {
|
||||
// // // 严格类型校验(防止非字符串参数传入)
|
||||
// // if (!is_string($str)) {
|
||||
// // throw new InvalidArgumentException('输入参数必须为字符串类型', 1001);
|
||||
// // }
|
||||
// // // 字符串预处理(生产级:全角转半角、URL解码、HTML标签移除等)
|
||||
// // $processedStr = $this->preprocessString($str);
|
||||
// // if (trim($processedStr) === '') {
|
||||
// // $result['error_code'] = 'EMPTY_STRING';
|
||||
// // $result['error_msg'] = self::ERROR_CODES['EMPTY_STRING'];
|
||||
// // return $result;
|
||||
// // }
|
||||
|
||||
// // // 性能优化:用preg_match仅匹配首个DOI,替代preg_match_all
|
||||
// // // 优化后的带前缀版正则
|
||||
// // $pattern = '/(?:doi[:\s]*|DOI[:\s]*)?\b10\.\d+(?:\.\d+)*\/[a-zA-Z0-9._\-!()%\/:;@$&+=?#[\]<>~`|^'"{},\\\\]+(?![\w?#])/i";
|
||||
// // if (!preg_match($pattern, $processedStr, $match)) {
|
||||
// // $result['error_code'] = 'NO_MATCH';
|
||||
// // $result['error_msg'] = self::ERROR_CODES['NO_MATCH'];
|
||||
// // return $result;
|
||||
// // }
|
||||
|
||||
// // // 清洗并验证首个DOI
|
||||
// // $cleanDoi = $this->cleanAndValidateDoi($match[0], $standardize, $forceExtract);
|
||||
// // if ($cleanDoi !== null) {
|
||||
// // $result['has_doi'] = true;
|
||||
// // $result['doi'] = $cleanDoi;
|
||||
// // } else {
|
||||
// // // 根据是否强制提取设置错误信息
|
||||
// // $errorKey = $forceExtract ? 'FORCE_EXTRACT_FAILED' : 'INVALID_AFTER_CLEAN';
|
||||
// // $result['error_code'] = $errorKey;
|
||||
// // $result['error_msg'] = self::ERROR_CODES[$errorKey];
|
||||
// // }
|
||||
|
||||
// // } catch (InvalidArgumentException $e) {
|
||||
// // // 业务异常:标准化错误码和信息
|
||||
// // $result['error_code'] = 'INVALID_PARAM';
|
||||
// // $result['error_msg'] = '参数错误:' . $e->getMessage();
|
||||
// // } catch (Exception $e) {
|
||||
// // // 系统异常:隐藏敏感信息,记录通用错误
|
||||
// // $result['error_code'] = 'EXTRACTION_EXCEPTION';
|
||||
// // $result['error_msg'] = self::ERROR_CODES['EXTRACTION_EXCEPTION'] . ':' . $e->getMessage();
|
||||
// // }
|
||||
|
||||
// // return $result;
|
||||
// // }
|
||||
|
||||
// // /**
|
||||
// // * 字符串预处理(生产级:覆盖所有编码/格式干扰场景)
|
||||
// // * @param string $str 原始字符串
|
||||
// // * @return string 预处理后的纯净字符串
|
||||
// // */
|
||||
// // private function preprocessString(string $str): string
|
||||
// // {
|
||||
// // // 1. 全角转半角(解决中文全角字符干扰,如10.1007/s11042-020-10103-4)
|
||||
// // $str = $this->fullWidthToHalfWidth($str);
|
||||
// // // 2. 移除所有HTML标签(解决网页文本中DOI被<p>/<a>/<b>等标签包裹的问题)
|
||||
// // $str = strip_tags($str);
|
||||
// // // 3. URL解码(处理%2F等URL编码的特殊字符,如10.1007%2Fs11042-020-10103-4)
|
||||
// // $str = urldecode($str);
|
||||
// // // 4. 解码HTML实体(处理&、/等HTML实体编码)
|
||||
// // $str = html_entity_decode($str, ENT_QUOTES | ENT_HTML5, 'UTF-8');
|
||||
// // // 5. 移除不可见字符(换行、制表符、零宽空格、控制字符等)
|
||||
// // $str = preg_replace('/[\x00-\x1F\x7F\x{200B}-\x{200F}]/u', ' ', $str);
|
||||
// // // 6. 合并多个空格为单个(避免连续空格干扰正则匹配)
|
||||
// // $str = preg_replace('/\s+/', ' ', $str);
|
||||
|
||||
// // return $str;
|
||||
// // }
|
||||
|
||||
// // /**
|
||||
// // * 清洗并验证DOI(生产级:优化正则规则,严格长度校验)
|
||||
// // * @param string $match 原始正则匹配结果
|
||||
// // * @param bool $standardize 是否标准化DOI(转小写)
|
||||
// // * @param bool $forceExtract 是否强制提取
|
||||
// // * @return string|null 有效DOI或null
|
||||
// // */
|
||||
// // private function cleanAndValidateDoi(string $match, bool $standardize, bool $forceExtract): ?string
|
||||
// // {
|
||||
// // // 1. 移除DOI前缀(doi:/DOI:)和首尾空白字符
|
||||
// // $cleanDoi = preg_replace('/^doi[:\s]?|^DOI[:\s]?/i', '', trim($match));
|
||||
// // // 2. 移除尾部常见标点(避免DOI被标点包裹,如10.1007/s11042-020-10103-4.)
|
||||
// // $cleanDoi = rtrim($cleanDoi, '.,;(){}[]!?"\'');
|
||||
|
||||
// // // 3. 严格的长度校验(DOI官方规范:6-200字符)
|
||||
// // $doiLength = strlen($cleanDoi);
|
||||
// // if ($doiLength < 6 || $doiLength > 200) {
|
||||
// // return null;
|
||||
// // }
|
||||
|
||||
// // // 4. 验证规则(生产级优化:添加单词边界,避免匹配不完整DOI)
|
||||
// // // 基础规则:严格遵循官方规范,10.开头+包含/+/后有内容
|
||||
// // $basicRule = '/^10\.\d+\/.+$/D';
|
||||
// // // 宽松规则:强制提取时使用,添加单词边界,避免匹配被字符包裹的DOI
|
||||
// // $looseRule = '/\b10\.\d+\/[^\s%]{1,190}\b/';
|
||||
|
||||
// // $validateRule = $forceExtract ? $looseRule : $basicRule;
|
||||
// // $isValid = preg_match($validateRule, $cleanDoi) === 1;
|
||||
|
||||
// // // 5. 验证通过则标准化(转小写),否则返回null
|
||||
// // if ($isValid) {
|
||||
// // return $standardize ? strtolower($cleanDoi) : $cleanDoi;
|
||||
// // }
|
||||
|
||||
// // return null;
|
||||
// // }
|
||||
|
||||
// // /**
|
||||
// // * 辅助方法:全角转半角
|
||||
// // * @param string $str 包含全角字符的字符串
|
||||
// // * @return string 半角字符串
|
||||
// // */
|
||||
// // private function fullWidthToHalfWidth(string $str): string
|
||||
// // {
|
||||
// // $fullWidthChars = [
|
||||
// // '0' => '0', '1' => '1', '2' => '2', '3' => '3', '4' => '4',
|
||||
// // '5' => '5', '6' => '6', '7' => '7', '8' => '8', '9' => '9',
|
||||
// // '.' => '.', '/' => '/', '-' => '-', '%' => '%', '!' => '!',
|
||||
// // '(' => '(', ')' => ')', ':' => ':', ';' => ';', ',' => ',',
|
||||
// // '"' => '"', ''' => '\''
|
||||
// // ];
|
||||
|
||||
// // return strtr($str, $fullWidthChars);
|
||||
// // }
|
||||
}
|
||||
?>
|
||||
Reference in New Issue
Block a user