diff --git a/application/api/controller/Proofread.php b/application/api/controller/Proofread.php index 541aedc..c6430b1 100644 --- a/application/api/controller/Proofread.php +++ b/application/api/controller/Proofread.php @@ -24,8 +24,6 @@ class Proofread extends Base if(empty($iArticleId)){ return json_encode(array('status' => 2,'msg' => 'Please select an article' )); } - //行号 - $iAmId = empty($aParam['am_id']) ? 0 : $aParam['am_id']; //查询文章 $aWhere = ['article_id' => $iArticleId]; $oArticle = new Article; @@ -39,7 +37,7 @@ class Proofread extends Base } //查询是否进行过校对 - $aProofReadWhere = ['article_id' => $iArticleId,'state' => 2]; + $aProofReadWhere = ['article_id' => $iArticleId,'state' => 2,'is_delete' => 2]; if(!empty($iAmId)){ $aProofReadWhere['am_id'] = $iAmId; } @@ -47,14 +45,10 @@ class Proofread extends Base if(!empty($iCount)){ return json_encode(array('status' => 5,'msg' => 'The article or paragraph has been proofread')); } - //查询文章内容 $aWhere['type'] = 0; $aWhere['content'] = ['<>','']; $aWhere['state'] = 0; - if(!empty($iAmId)){ - $aWhere['am_id'] = $iAmId; - } $aArticleMain = Db::table('t_article_main')->field('am_id,content,type,is_h1,is_h2,is_h3,ami_id,amt_id')->where($aWhere)->select(); if(empty($aArticleMain)){ return json_encode(array('status' => 5,'msg' => 'The content of the article is empty')); @@ -89,6 +83,7 @@ class Proofread extends Base $val['article_id'] = $iArticleId; $val['proof_before'] = empty($value['proof_before']) ? '' : $value['proof_before']; $val['proof_after'] = empty($value['proof_after']) ? '' : $value['proof_after']; + $val['create_time'] = time(); $aData[] = $val; } } @@ -100,10 +95,7 @@ class Proofread extends Base if(!$result){ return json_encode(array('status' => 6,'msg' => 'No errors found')); } - - //查询参考文献 - $aWhere = ['state' => ['in',[0,2]],'article_id' => $iArticleId]; - return json_encode(['status' => 1,'msg' => 'success']); + return json_encode(['status' => 1,'msg' => 'Proofreading successful']); } /** * @title 获取每行校对记录 @@ -147,8 +139,8 @@ class Proofread extends Base //查询校对内容 $aAmId = array_column($aArticleMain, 'am_id'); - $aWhere = ['am_id' => ['in',$aAmId]]; - $iState = empty($aParam['state']) ? 0 : $aParam['state']; + $aWhere = ['am_id' => ['in',$aAmId],'is_delete' => 2]; + $iState = empty($aParam['state']) ? 0 : explode(',', $aParam['state']); if(!empty($iState)){ $aWhere['state'] = ['in',$iState]; } @@ -260,7 +252,7 @@ class Proofread extends Base } //判断校对记录 - $aWhere = ['am_id' => $iAmId,'article_id' => $iArticleId,'id' => $iId]; + $aWhere = ['am_id' => $iAmId,'article_id' => $iArticleId,'id' => $iId,'is_delete' => 2]; $aProofRead = Db::name('article_proofread')->where($aWhere)->find(); if(empty($aProofRead)){ @@ -478,7 +470,7 @@ class Proofread extends Base $iIsUpdateAll = empty($aParam['is_update_all']) ? 2 : $aParam['is_update_all']; //查询内容是否存在 - $aWhere = ['am_id' => $iAmId,'article_id' => $iArticleId,'id' => $iId]; + $aWhere = ['am_id' => $iAmId,'article_id' => $iArticleId,'id' => $iId,'is_delete' => 2]; $aProofRead = Db::name('article_proofread')->field('verbatim_texts,revised_content,explanation,state')->where($aWhere)->find(); if(empty($aProofRead)){ return json_encode(['status' => 3,'msg' => 'Proofreading record is empty']); @@ -543,6 +535,7 @@ class Proofread extends Base if(!empty($iState)){ $aWhere['state'] = ['in',$iState]; } + $aWhere['is_delete'] = 2; $aCount = Db::name('article_proofread')->field('am_id,count(id) as num')->where($aWhere)->group('am_id')->select(); $aCount = empty($aCount) ? [] : array_column($aCount, 'num','am_id'); //总数量 @@ -550,4 +543,129 @@ class Proofread extends Base $am_id_count = empty($aCount[$iAmId]) ? 0 : $aCount[$iAmId]; return json_encode(['status' => 1,'msg' => 'success','data' => ['sum_count' => $iCount,'am_id_count' => $am_id_count]]); } + + /** + * @title AI文章校对-行 + * @param article_id 文章ID + */ + public function proofReadByLine(){ + + //获取参数 + $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' )); + } + //行号 + $iAmId = empty($aParam['am_id']) ? 0 : $aParam['am_id']; + if(empty($iAmId)){ + return json_encode(array('status' => 2,'msg' => 'Please select the rows that need to be proofread' )); + } + + //查询文章 + $aWhere = ['article_id' => $iArticleId]; + $oArticle = new Article; + $aArticle = json_decode($oArticle->get($aWhere),true); + $aArticle = empty($aArticle['data']) ? [] : $aArticle['data']; + if(empty($aArticle)){ + return json_encode(array('status' => 3,'msg' => 'No articles requiring review were found' )); + } + if($aArticle['state'] != 6){ + return json_encode(array('status' => 4,'msg' => 'The article has not entered the proofreading stage')); + } + + //查询文章内容 + $aWhere['type'] = 0; + $aWhere['content'] = ['<>','']; + $aWhere['state'] = 0; + $aWhere['am_id'] = $iAmId; + $aArticleMain = Db::table('t_article_main')->field('am_id,content,type,is_h1,is_h2,is_h3,ami_id,amt_id')->where($aWhere)->find(); + if(empty($aArticleMain)){ + return json_encode(array('status' => 5,'msg' => 'The content of the article is empty')); + } + //写入校对行队列 + $sQueue = \think\Queue::push('app\api\job\ArticleProofReadLine@fire',$aParam,'ArticleProofReadLine'); + return json_encode(array('status' => 1,'msg' => 'Proofreading in progress, check the results in one minute')); + } + /** + * @title AI文章校对-行队列 + * @param article_id 文章ID + */ + public function proofReadLineQueue($aParam = []){ + //获取参数 + $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' )); + } + //行号 + $iAmId = empty($aParam['am_id']) ? 0 : $aParam['am_id']; + if(empty($iAmId)){ + return json_encode(array('status' => 2,'msg' => 'Please select the rows that need to be proofread' )); + } + + //查询文章 + $aWhere = ['article_id' => $iArticleId]; + $oArticle = new Article; + $aArticle = json_decode($oArticle->get($aWhere),true); + $aArticle = empty($aArticle['data']) ? [] : $aArticle['data']; + if(empty($aArticle)){ + return json_encode(array('status' => 3,'msg' => 'No articles requiring review were found' )); + } + if($aArticle['state'] != 6){ + return json_encode(array('status' => 4,'msg' => 'The article has not entered the proofreading stage')); + } + + //查询文章内容 + $aWhere['type'] = 0; + $aWhere['content'] = ['<>','']; + $aWhere['state'] = 0; + $aWhere['am_id'] = $iAmId; + $aArticleMain = Db::table('t_article_main')->field('am_id,content,type,is_h1,is_h2,is_h3,ami_id,amt_id')->where($aWhere)->find(); + if(empty($aArticleMain)){ + return json_encode(array('status' => 5,'msg' => 'The content of the article is empty')); + } + + //实例化公共方法 + $oHelperFunction = new \app\common\HelperFunction; + $oProofReadService = new \app\common\ProofReadService; + //数据处理 + + if(empty($oHelperFunction->filterAllTags($aArticleMain['content']))){ + return json_encode(array('status' => 6,'msg' => 'The proofreading content is empty')); + } + $aResult = $oProofReadService->proofread($aArticleMain['content']); + if(empty($aResult)){ + return json_encode(array('status' => 7,'msg' => 'Not returned to school regarding the content')); + } + //数据处理 + $aError = empty($aResult['errors']) ? [] : $aResult['errors']; + if(empty($aError)){ + return json_encode(array('status' => 1,'msg' => 'No errors found')); + } + $aData = []; + foreach ($aError as $key => $value) { + $value['am_id'] = $iAmId; + $value['article_id'] = $iArticleId; + $value['proof_before'] = empty($aResult['proof_before']) ? '' : $aResult['proof_before']; + $value['proof_after'] = empty($aResult['proof_after']) ? '' : $aResult['proof_after']; + $value['create_time'] = time(); + $aData[] = $value; + } + if(empty($aData)){ + return json_encode(array('status' => 1,'msg' => 'Data processing failed')); + } + + Db::startTrans(); + //更新之前未执行的数据 + $aWhere = ['am_id' => $iAmId,'article_id' => $iArticleId,'is_delete' => 2,'state' => 2]; + $result_update = Db::name('article_proofread')->where($aWhere)->update(['is_delete' => 1,'update_time' => time()]); + //插入 + $result = Db::name('article_proofread')->insertAll($aData); + if(!$result || $result_update === false){ + return json_encode(array('status' => 6,'msg' => 'No errors found')); + } + Db::commit(); + return json_encode(['status' => 1,'msg' => 'Proofreading successful']); + } } diff --git a/application/api/job/ArticleProofReadLine.php b/application/api/job/ArticleProofReadLine.php new file mode 100644 index 0000000..5ddb216 --- /dev/null +++ b/application/api/job/ArticleProofReadLine.php @@ -0,0 +1,85 @@ +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 + $iAmId = empty($data['am_id']) ? 0 : $data['am_id']; + if (empty($iAmId)) { + $this->oQueueJob->log("无效的am_id,删除任务"); + $job->delete(); + return; + } + try { + + // 生成Redis键并尝试获取锁 + $sClassName = get_class($this); + $sRedisKey = "queue_job:{$sClassName}:{$iArticleId}_{$iAmId}"; + $sRedisValue = uniqid() . '_' . getmypid(); + if (!$this->oQueueJob->acquireLock($sRedisKey, $sRedisValue, $job)) { + return; // 未获取到锁,已处理 + } + + //生成内容 + $oProofRead = new Proofread; + $response = $oProofRead->proofReadLineQueue($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(); + } + } +} \ No newline at end of file