@@ -0,0 +1,695 @@
< ? php
namespace app\api\controller ;
use app\api\controller\Base ;
use app\common\CitationRelevanceService ;
use app\common\CrossrefService ;
use app\common\PubmedService ;
use think\Db ;
use think\Env ;
/**
* @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 ]);
}
/**
* 参考文献鉴别:正文引用上下文 + PubMed/Crossref + 大模型向量相似度
* 参数: p_refer_id( 必填)
* 环境变量( 可选) : citation_chat_url、citation_chat_model、citation_chat_api_key、citation_chat_timeout、crossref_mailto、pubmed_email
*/
public function checkCitationRelevance ( $aParam = [])
{
$aParam = empty ( $aParam ) ? $this -> request -> post () : $aParam ;
$pReferId = intval ( isset ( $aParam [ 'p_refer_id' ]) ? $aParam [ 'p_refer_id' ] : 0 );
if ( ! $pReferId ) {
return jsonError ( 'p_refer_id is required' );
}
$refer = Db :: name ( 'production_article_refer' )
-> where ( 'p_refer_id' , $pReferId )
-> where ( 'state' , 0 )
-> find ();
if ( empty ( $refer )) {
return jsonError ( 'Reference not found' );
}
$aArticle = $this -> getArticle ([ 'p_article_id' => $refer [ 'p_article_id' ]]);
$iStatus = empty ( $aArticle [ 'status' ]) ? 0 : $aArticle [ 'status' ];
if ( $iStatus != 1 ) {
return json_encode ( $aArticle );
}
$aArticle = empty ( $aArticle [ 'data' ]) ? [] : $aArticle [ 'data' ];
if ( empty ( $aArticle [ 'article_id' ])) {
return jsonError ( 'Article not found' );
}
$articleId = intval ( $aArticle [ 'article_id' ]);
$mains = Db :: name ( 'article_main' )
-> where ( 'article_id' , $articleId )
-> whereIn ( 'state' , [ 0 , 2 ])
-> order ( 'sort asc' )
-> select ();
if ( empty ( $mains )) {
return jsonError ( 'article_main is empty' );
}
$citationMark = intval ( $refer [ 'index' ]) + 1 ;
$context = $this -> extractCitationContextFromMains ( $mains , $citationMark );
if ( $context === '' ) {
return jsonError ( 'Citation context not found in article_main for mark [' . $citationMark . ']' );
}
$apiKey = trim (( string ) Env :: get ( 'citation_chat_api_key' , '' ));
if ( $apiKey === '' ) {
return jsonError ( 'Please set env citation_chat_api_key for embedding via chat' );
}
$config = [
'chat_url' => trim (( string ) Env :: get ( 'citation_chat_url' , 'http://chat.taimed.cn/v1/chat/completions' )),
'chat_model' => trim (( string ) Env :: get ( 'citation_chat_model' , 'DeepSeek-Coder-V2-Instruct' )),
'timeout' => max ( 60 , intval ( Env :: get ( 'citation_chat_timeout' , 180 ))),
'embedding_dim' => max ( 32 , intval ( Env :: get ( 'citation_embedding_dim' , 256 ))),
'embedding_headers' => [
'Authorization: Bearer ' . $apiKey ,
],
];
$pubmed = new PubmedService ([
'email' => trim (( string ) Env :: get ( 'pubmed_email' , '' )),
'tool' => trim (( string ) Env :: get ( 'pubmed_tool' , 'tmrjournals' )),
]);
$crossref = new CrossrefService ([
'mailto' => trim (( string ) Env :: get ( 'crossref_mailto' , '' )),
]);
$svc = new CitationRelevanceService ( $pubmed , $crossref , $config );
$qc = $svc -> checkOne ( $context , $refer , []);
return jsonSuccess ([
'p_refer_id' => $pReferId ,
'citation_mark' => $citationMark ,
'refer_index' => intval ( $refer [ 'index' ]),
'context' => $context ,
'problem_flag' => $qc [ 'problem_flag' ] ? ? '' ,
'problem_reason' => $qc [ 'problem_reason' ] ? ? '' ,
'relevance_flag' => $qc [ 'relevance_flag' ] ? ? '' ,
'relevance_score' => $qc [ 'relevance_score' ] ? ? 0 ,
'reason' => $qc [ 'reason' ] ? ? '' ,
'pubmed' => $qc [ 'pubmed' ] ? ? [],
]);
}
/**
* 从 t_article_main 拼接正文,按 [n] 定位句子并取前后各 1 句作为上下文
*/
private function extractCitationContextFromMains ( array $mains , int $citationMark ) : string
{
if ( $citationMark <= 0 ) {
return '' ;
}
$chunks = [];
foreach ( $mains as $row ) {
$text = isset ( $row [ 'content' ]) ? ( string ) $row [ 'content' ] : '' ;
if ( $text === '' ) {
continue ;
}
$text = preg_replace ( '/<\s*\/?\s*blue[^>]*>/i' , '' , $text );
$text = strip_tags ( $text );
$text = html_entity_decode ( $text , ENT_QUOTES | ENT_HTML5 , 'UTF-8' );
$text = preg_replace ( '/\s+/u' , ' ' , trim ( $text ));
if ( $text !== '' ) {
$chunks [] = $text ;
}
}
$fullText = implode ( " \n " , $chunks );
if ( $fullText === '' ) {
return '' ;
}
$sentences = $this -> splitEnglishSentences ( $fullText );
$pattern = '/\[' . preg_quote (( string ) $citationMark , '/' ) . '\]/' ;
foreach ( $sentences as $si => $sent ) {
if ( ! preg_match ( $pattern , $sent )) {
continue ;
}
$start = max ( 0 , $si - 1 );
$end = min ( count ( $sentences ) - 1 , $si + 1 );
$ctx = implode ( ' ' , array_slice ( $sentences , $start , $end - $start + 1 ));
return trim ( preg_replace ( '/\s+/u' , ' ' , $ctx ));
}
return '' ;
}
private function splitEnglishSentences ( string $text ) : array
{
$text = trim ( $text );
if ( $text === '' ) {
return [];
}
$text = preg_replace ( '/\s+/u' , ' ' , $text );
$parts = preg_split ( '/(?<=[\.\?\!])\s+/' , $text );
$out = [];
foreach ( $parts as $p ) {
$p = trim (( string ) $p );
if ( $p !== '' ) {
$out [] = $p ;
}
}
return $out ;
}
/**
* 修改参考文献的信息
* @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' ]);
}
$sContent = str_replace ([ '?' , '? ' ], '.' , $sContent );
$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';
$doiPattern = '/\b10\.\d+(?:\.\d+)*\/[^\s?#&=]+/i' ;
if ( preg_match ( $doiPattern , $sDoi , $matches )) {
$aUpdate [ 'doi' ] = $matches [ 0 ];
$aUpdate [ 'doilink' ] = 'https://doi.org/' . '' . $aUpdate [ 'doi' ];
} 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' => [ 'in' ,[ 0 , 2 ]]];
$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 [ 'cs' ] = 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' ]);
}
}