From 3efcab006aa2edf5a9c67e05b4dfb121d3673d0b Mon Sep 17 00:00:00 2001 From: chengxl Date: Mon, 28 Jul 2025 15:06:21 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E9=85=8D=E7=BD=AE=E8=B0=83?= =?UTF-8?q?=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- application/common/OpenAi.php | 114 +++++++++++++++++++--------------- 1 file changed, 63 insertions(+), 51 deletions(-) diff --git a/application/common/OpenAi.php b/application/common/OpenAi.php index 7d8e2bd..e2219b6 100644 --- a/application/common/OpenAi.php +++ b/application/common/OpenAi.php @@ -24,7 +24,7 @@ class OpenAi protected $sTmrUrl = "http://journalapi.tmrjournals.com/public/index.php";//"http://zmzm.journal.dev.com/";//; protected $aArticleImportantPrompt = [ "journal_scope" => [ - 'system' => '你是一位资深的学术评审专家,负责严谨、客观地评估学术文章。 + 'system' => '你是一位资深的学术评审专家,负责严谨、客观地评估学术文章。 请针对问题提供客观、专业的评估,并给出简要的理由。请返回中文解释!返回格式必须严格遵循以下JSON结构:{ "journal_scope": { "assessment": "是/否", @@ -34,19 +34,19 @@ class OpenAi "criteria" => "根据文章的标题:{title};摘要:{abstrart}以及期刊范围:{scope}来判断文章是否符合目标期刊{journal_name}" ], "attribute" => [ - 'system' => '你是一位资深的学术评审专家,负责严谨、客观地评估学术文章。 + 'system' => '你是一位资深的学术评审专家,负责严谨、客观地评估学术文章。 请针对问题提供客观、专业的评估,并给出简要的理由。请返回中文解释!返回格式必须严格遵循以下JSON结构:{ "attribute": { "assessment": "是/否", "explanation": "请总结归纳分析" } }', - "criteria" => "请结合以下几点【研究内容的原创性:论文中的研究内容是否与已有的研究重复?是否在同样的领域提出了类似的结论,但在方法或结果上有所创新?如果有,作者是否清楚地解释了如何与之前的研究不同,或者如何在原有基础上进行扩展或改进?如果是综述文章,汇总并综合最新的研究成果,尤其是近几年内的重要发现,展示领域内最新的进展成果。作者可以识别出未被充分讨论的问题或提出新的研究问题,而不是简单文献堆砌。文章中的图表创新能否将信息的清晰呈现,方便读者理解复杂研究问题。论文方法创新性评估要点:是否采用了新的实验模型或创新的实验设计,能有效解决当前研究中的难点或空白?是否有合理的对照组和多组实验设计,确保研究结果的可靠性?是否使用了当前前沿的技术(如高通量测序、CRISPR基因编辑等),提高了实验精度或数据分析能力?是否结合了跨学科的方法(如生物信息学、人工智能等)?是否应用了多种验证手段或统计方法,确保结果的可信度?是否通过细胞实验、动物模型等多重验证,确保实验结果的可靠性?结论与数据的创新性:研究结论是否提出了新观点或新见解?是否提供了新的实验数据或观察结果,能够突破当前的研究局限?例如,发现了新的生物标志物,或对已知生物通路的作用机制提供了全新的解释】评估文章内容{content}是否有科学前沿性和创新性?" + "criteria" => "请结合以下几点【研究内容的原创性:论文中的研究内容是否与已有的研究重复?是否在同样的领域提出了类似的结论,但在方法或结果上有所创新?如果有,作者是否清楚地解释了如何与之前的研究不同,或者如何在原有基础上进行扩展或改进?如果是综述文章,汇总并综合最新的研究成果,尤其是近几年内的重要发现,展示领域内最新的进展成果。作者可以识别出未被充分讨论的问题或提出新的研究问题,而不是简单文献堆砌。文章中的图表创新能否将信息的清晰呈现,方便读者理解复杂研究问题。论文方法创新性评估要点:是否采用了新的实验模型或创新的实验设计,能有效解决当前研究中的难点或空白?是否有合理的对照组和多组实验设计,确保研究结果的可靠性?是否使用了当前前沿的技术(如高通量测序、CRISPR基因编辑等),提高了实验精度或数据分析能力?是否结合了跨学科的方法(如生物信息学、人工智能等)?是否应用了多种验证手段或统计方法,确保结果的可信度?是否通过细胞实验、动物模型等多重验证,确保实验结果的可靠性?结论与数据的创新性:研究结论是否提出了新观点或新见解?是否提供了新的实验数据或观察结果,能够突破当前的研究局限?例如,发现了新的生物标志物,或对已知生物通路的作用机制提供了全新的解释】评估文章内容{content}是否有科学前沿性和创新性?" ] //, // "contradiction" => [ - // 'system' => '你是一位资深的学术评审专家,负责严谨、客观地评估学术文章。 + // 'system' => '你是一位资深的学术评审专家,负责严谨、客观地评估学术文章。 // 请针对问题提供客观、专业的评估,并给出简要的理由。请返回中文解释!返回格式必须严格遵循以下JSON结构:{ // "contradiction": { // "assessment": "是/否", @@ -57,7 +57,7 @@ class OpenAi // ], // "unreasonable" => [ - // 'system' => '你是一位资深的学术评审专家,负责严谨、客观地评估学术文章。 + // 'system' => '你是一位资深的学术评审专家,负责严谨、客观地评估学术文章。 // 请针对问题提供客观、专业的评估,并给出简要的理由。请返回中文解释!返回格式必须严格遵循以下JSON结构:{ // "unreasonable": { // "assessment": "是/否", @@ -70,33 +70,33 @@ class OpenAi //公微问题模版 protected $aWechatQuestion = [ - 'system_message' => '您是一位医学期刊的医学科普转化专家,严格遵循用户要求的结构、语言和专业约束,不编造数据,不夸大结论,擅长将复杂的医学研究论文转化为适合微信公众号推送的专业科普内容。请根据提供的医学论文信息,按照以下严格格式生成结构化[JSON结构]输出[中文]:', + 'system_message' => '您是一位医学期刊的医学科普转化专家,严格遵循用户要求的结构、语言和专业约束,不编造数据,不夸大结论,擅长将复杂的医学研究论文转化为适合微信公众号推送的专业科普内容。请根据提供的医学论文信息,按照以下严格格式生成结构化[JSON结构]输出[中文]:', 'public_message' => [ - "covered" => "[列出文章涵盖的学科及研究方法,总字数不超过100字,学科和方法之间用逗号分隔,例如:肿瘤学,分子生物学,基因组测序,生物信息学分析]", + "covered" => "[列出文章涵盖的学科及研究方法,总字数不超过100字,学科和方法之间用逗号分隔,例如:肿瘤学,分子生物学,基因组测序,生物信息学分析]", "title_chinese" => "[将标题翻译成中文:内容需自然流畅、口语化、连贯性、学术性]" // , - // "content" => "将内容翻译成中文,需自然流畅、口语化、连贯性、学术性,保留原文的章节结构和图表编号" + // "content" => "将内容翻译成中文,需自然流畅、口语化、连贯性、学术性,保留原文的章节结构和图表编号" ], 'default' => [ - "digest" => "[学术规范翻译并提炼摘要,强调逻辑性、科学术语准确性和表达严谨性,采用段落形式,总字数不超过500字]", - "research_background" => "[提炼研究背景,采用连贯的段落形式,总字数超过200字]", - "discussion_results" => "[针对文章简单总结讨论和结果,采用连贯的段落形式,总字数超过450字]", - "research_method" => "[总结文章的研究方法,采用连贯的段落形式,总字数超过300字]", - "prospect" => "[针对稿件内容进行展望撰写,采用连贯的段落形式]", - "highlights" => "[总结归纳亮点,至少3点,每点用分号分隔]" + "digest" => "[学术规范翻译并提炼摘要,强调逻辑性、科学术语准确性和表达严谨性,采用段落形式,注意内容不要和文章内容有严重重复,总字数不超过500字]", + "research_background" => "[提炼研究背景,采用连贯的段落形式,注意内容不要和文章内容有严重重复,总字数超过200字]", + "discussion_results" => "[针对文章简单总结讨论和结果,采用连贯的段落形式,注意内容不要和文章内容有严重重复,总字数超过450字]", + "research_method" => "[总结文章的研究方法,采用连贯的段落形式,注意内容不要和文章内容有严重重复,总字数超过300字]", + "prospect" => "[针对稿件内容进行展望撰写,注意内容不要和文章内容有严重重复,采用连贯的段落形式]", + "highlights" => "[总结归纳亮点,至少3点,每点用分号分隔]" ], 'review' => [ - "overview" => "按照学术规范翻译并提炼文章概述,整体内容应大于1200字,其中应包含文章背景(不少于400字),其他内容提炼更强调逻辑性、科学术语准确性和表达的严谨性,注意内容不要有严重重复,采用连贯的段落形式", - "summary" => "针对文章结论生成一个简单总结,内容不要和文章概述重复,字数150以内", + "overview" => "按照学术规范翻译并提炼文章概述,整体内容应大于1200字,其中应包含文章背景(不少于400字),其他内容提炼更强调逻辑性、科学术语准确性和表达的严谨性,注意内容不要和文章内容有严重重复,采用连贯的段落形式", + "summary" => "针对文章结论生成一个简单总结,内容不要和文章概述重复,字数150以内", ] ]; //AI审稿提示词 protected $aReviewQuestion = [ - 'system_message' => '您是一位资深的医学期刊学术评审专家,请负责严谨、客观地评估学术文章。请根据提供的医学论文信息,按照以下严格格式生成结构化[JSON结构]输出[中文]:', + 'system_message' => '您是一位资深的医学期刊学术评审专家,请负责严谨、客观地评估学术文章。请根据提供的医学论文信息,按照以下严格格式生成结构化[JSON结构]输出[中文]:', 'default' => [ "journal_scope" => "结合标题和摘要以及期刊范围来判断文章是否符合目标期刊?", - "attribute" => "内容是否有科学前沿性和创新性?参照维度[研究内容的原创性:论文中的研究内容是否与已有的研究重复?是否在同样的领域提出了类似的结论,但在方法或结果上有所创新?如果有,作者是否清楚地解释了如何与之前的研究不同,或者如何在原有基础上进行扩展或改进?如果是综述文章,汇总并综合最新的研究成果,尤其是近几年内的重要发现,展示领域内最新的进展成果。作者可以识别出未被充分讨论的问题或提出新的研究问题,而不是简单文献堆砌。文章中的图表创新能否将信息的清晰呈现,方便读者理解复杂研究问题。论文方法创新性评估要点:是否采用了新的实验模型或创新的实验设计,能有效解决当前研究中的难点或空白?是否有合理的对照组和多组实验设计,确保研究结果的可靠性?是否使用了当前前沿的技术(如高通量测序、CRISPR基因编辑等),提高了实验精度或数据分析能力?是否结合了跨学科的方法(如生物信息学、人工智能等)?是否应用了多种验证手段或统计方法,确保结果的可信度?是否通过细胞实验、动物模型等多重验证,确保实验结果的可靠性?结论与数据的创新性:研究结论是否提出了新观点或新见解?是否提供了新的实验数据或观察结果,能够突破当前的研究局限?例如,发现了新的生物标志物,或对已知生物通路的作用机制提供了全新的解释]", + "attribute" => "内容是否有科学前沿性和创新性?参照维度[研究内容的原创性:论文中的研究内容是否与已有的研究重复?是否在同样的领域提出了类似的结论,但在方法或结果上有所创新?如果有,作者是否清楚地解释了如何与之前的研究不同,或者如何在原有基础上进行扩展或改进?如果是综述文章,汇总并综合最新的研究成果,尤其是近几年内的重要发现,展示领域内最新的进展成果。作者可以识别出未被充分讨论的问题或提出新的研究问题,而不是简单文献堆砌。文章中的图表创新能否将信息的清晰呈现,方便读者理解复杂研究问题。论文方法创新性评估要点:是否采用了新的实验模型或创新的实验设计,能有效解决当前研究中的难点或空白?是否有合理的对照组和多组实验设计,确保研究结果的可靠性?是否使用了当前前沿的技术(如高通量测序、CRISPR基因编辑等),提高了实验精度或数据分析能力?是否结合了跨学科的方法(如生物信息学、人工智能等)?是否应用了多种验证手段或统计方法,确保结果的可信度?是否通过细胞实验、动物模型等多重验证,确保实验结果的可靠性?结论与数据的创新性:研究结论是否提出了新观点或新见解?是否提供了新的实验数据或观察结果,能够突破当前的研究局限?例如,发现了新的生物标志物,或对已知生物通路的作用机制提供了全新的解释]", "contradiction" => "内容是否前后矛盾或存在逻辑不一致的问题?", "unreasonable" => "内容是否有明显的不合理之处?", "ethics" => "内容是否存在伦理号缺失或明显伦理问题?", @@ -188,8 +188,8 @@ class OpenAi if(empty($aSearch)){ return []; } - $sSysMessagePrompt = '你是一位专业的医学翻译专家,请将用户提供的内容准确、流畅地翻译成中文。翻译需自然流畅、口语化、连贯性、学术性,保留原文的专业术语和逻辑结构'; - $sUserPrompt = '"将以下内容翻译为中文,仅返回翻译结果,不要解释:\n {#content#}"'; + $sSysMessagePrompt = '你是一位专业的医学翻译专家,请将用户提供的内容准确、流畅地翻译成中文。翻译需自然流畅、口语化、连贯性、学术性,保留原文的专业术语和逻辑结构'; + $sUserPrompt = '"将以下内容翻译为中文,仅返回翻译结果,不要解释:\n {#content#}"'; $sUserPrompt = str_replace(array_keys($aSearch), array_values($aSearch), $sUserPrompt); $aMessage = [ ['role' => 'system', 'content' => $sSysMessagePrompt], @@ -199,7 +199,7 @@ class OpenAi $aMessage = [ 'model' => empty($aSearch['model']) ? 'gpt-4.1' : $aSearch['model'], 'messages' => $aMessage, - 'temperature' => 0.2,// 降低随机性(0-1,0为最确定) + 'temperature' => 0.2,// 降低随机性(0-1,0为最确定) ]; $aResult = json_decode($this->curlOpenAIStream($aMessage),true); $sJsonData = empty($aResult['data']) ? '' : $aResult['data']; @@ -283,7 +283,7 @@ class OpenAi $data = [ 'model' => $model, 'messages' => $aMessage, - 'temperature' => 0.2,// 降低随机性(0-1,0为最确定) + 'temperature' => 0.2,// 降低随机性(0-1,0为最确定) ]; $this->curl = curl_init(); @@ -357,8 +357,13 @@ class OpenAi $data = [ 'model' => $model, 'messages' => $aMessage, - 'temperature' => 0.2,// 降低随机性(0-1,0为最确定) - 'stream' => true // 关键:启用流式传输,避免超时 + // 'temperature' => 0.2,// 降低随机性(0-1,0为最确定) + 'temperature' => 0.6, // 中等随机性 + // 'max_tokens' => 1000, + 'top_p' => 0.8, + 'frequency_penalty' => 0.3, + 'presence_penalty' => 0.2, + 'stream' => true // 关键:启用流式传输,避免超时 ]; // Curl通用配置 @@ -380,10 +385,10 @@ class OpenAi // === 5. 流式响应处理(核心避免超时) === $streamContent = ''; // 累积流式返回的内容 - // 回调函数:每收到一块数据就处理并保存,避免整段等待 + // 回调函数:每收到一块数据就处理并保存,避免整段等待 curl_setopt($this->curl, CURLOPT_WRITEFUNCTION, function ($curl, $data) use (&$streamContent) { $streamContent .= $data; - return strlen($data); // 必须返回数据长度,否则CURL会中断 + return strlen($data); // 必须返回数据长度,否则CURL会中断 }); //执行请求 @@ -397,11 +402,11 @@ class OpenAi //错误处理 if (!empty($curlErrno)) { - // 超时但已有部分数据:保存进度,下次从该块重试 + // 超时但已有部分数据:保存进度,下次从该块重试 if ($curlErrno == CURLE_OPERATION_TIMEDOUT && !empty($streamContent)) { return json_encode([ 'status' => 3, - 'msg' => "处理超时,已保存进度", + 'msg' => "处理超时,已保存进度", ]); } // 其他错误(如网络问题) @@ -448,27 +453,34 @@ class OpenAi } //记录处理开始 $iNum = count($aMessage); - $sRedisKey = 'ai_create_article_'.$iId; - $this->oQueueRedis->recordQuestionProcessingStart($sRedisKey,$iNum); - //定义空数组 - $aChunkResult = $aFail = []; - $batchId = uniqid(); - $iQueueCount1 = $iQueueCount2 = 0; - foreach ($aMessage as $key => $value) { - $aParam['messages'] = $value; - $aParam['chunkIndex'] = $key; - $aParam['count_num'] = $iNum; - // if($key%2 == 0){ - $aParam['key_name'] = 'queue_1_completed'; - Queue::push('app\api\job\createFieldForQueue@fire', $aParam, 'createFieldForQueue'); - // }else{ - // $aParam['url'] = $this->sAiUrl; - // $aParam['key_name'] = 'queue_2_completed'; - // Queue::push('app\api\job\createFieldForQueue@fire', $aParam, 'createFieldForQueueBak'); - // } - + $sRedisKey = 'queue_job:ai_create_article:'.$iId; + $result = $this->oQueueRedis->recordQuestionProcessingStart($sRedisKey,$iNum); + $result = empty($result) ? 0 : $result; + if($result == 1){ + //定义空数组 + foreach ($aMessage as $key => $value) { + $aParam['messages'] = $value; + $aParam['chunkIndex'] = $key; + $aParam['count_num'] = $iNum; + // if($key%2 == 0){ + $aParam['key_name'] = 'queue_1_completed'; + Queue::push('app\api\job\createFieldForQueue@fire', $aParam, 'createFieldForQueue'); + // }else{ + // $aParam['url'] = $this->sAiUrl; + // $aParam['key_name'] = 'queue_2_completed'; + // Queue::push('app\api\job\createFieldForQueue@fire', $aParam, 'createFieldForQueueBak'); + // } + + } + return json_encode(['status' => 1, 'msg' => 'Content is being generated, please wait']); } - return json_encode(['status' => 1, 'msg' => 'Content is being generated, please wait']); + if($result == 2){ + return json_encode(['status' => 3, 'msg' => 'The data has been generated, please proceed with the next steps']); + } + if($result == 3){ + return json_encode(['status' => 4, 'msg' => 'Content is being generated, please wait']); + } + return json_encode(['status' => 5, 'msg' => 'Redis write failure']); } /** * 微信公众号-生成内容队列形式 @@ -491,11 +503,11 @@ class OpenAi $aResult = $this->curlOpenAIStream($aParam); //更新处理进度 $iIndex = empty($aParam['chunkIndex']) ? 0 : $aParam['chunkIndex']; - $sRedisKey = 'ai_create_article_'.$iId; + $sRedisKey = 'queue_job:ai_create_article:'.$iId; $sKeyName = empty($aParam['key_name']) ? 'queue_1_completed' : $aParam['key_name']; $iProgress = $this->oQueueRedis->updateQuestionProcessingProgress($sRedisKey,$sKeyName); //保存内容 - $sRedisKey = 'ai_create_article_progress_'.$iId; + $sRedisKey = 'queue_job:ai_create_article_progress:'.$iId; $this->oQueueRedis->saveChunkProgress($sRedisKey, $iIndex,$aResult); //更新入库 @@ -572,7 +584,7 @@ class OpenAi * 从文本中提取被```json```和```包裹的JSON内容并解析 * @param string $text 包含JSON代码块的文本 * @param bool $assoc 是否返回关联数组(默认true) - * @return array|object 解析后的JSON数据,失败时返回null + * @return array|object 解析后的JSON数据,失败时返回null */ public function extractAndParse($text, $assoc = true){