生成公微内容接口提取公共方法

This commit is contained in:
chengxl
2025-07-02 15:12:46 +08:00
parent 43aea4ad8d
commit f9a5f22984

View File

@@ -8,6 +8,7 @@ use app\common\Wechat;
use app\common\Material;
use think\Cache;
use think\Queue;
use app\common\OpenAi;
/**
* @title 数据库接口
* @description 数据库接口
@@ -17,20 +18,6 @@ class Aiarticle extends Base
{
protected $aLogo = ['media_id' => 'Cn8zlXvVB5DwjcA9h40z9fprHDoc3Jqv97SwrInpmyYiilkeRdKvpD63cWqTYHfz','url' => 'http://mmbiz.qpic.cn/mmbiz_jpg/QHFVW13lONaQJxK9QbHU9CtrvTS2ModZnUyeAvuVN67t8XP85DxVJwDJf2YxCTalrsr17jS080xM6xQv5yGiaEQ/0?wx_fmt=jpeg'];//默认头像
/**OPENAI相关配置----------start**/
//OPENAI接口地址
protected $sUrl = 'https://api.openai.com/v1/chat/completions';
//OPENAI接口key
protected $sApiKey = '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';
protected $proxy = '';
//接口返回对象
protected $sResponesData;
//接口返回错误信息
protected $sError;
//接口超时请求
protected $timeout = 60;
/**OPENAI相关配置----------end**/
//数据表必填字段[ai_article]
protected $aAiFileds = ['article_id','title_english','title_chinese','journal_issn','covered','digest','research_result','content','highlights','discussion','prospect','research_background','discussion_results','research_method','overview','summary'];
@@ -40,45 +27,6 @@ class Aiarticle extends Base
protected $sJournalUsx = 'https://www.tmrjournals.com';
//投稿系统
protected $sSubmissionUrl = 'https://submission.tmrjournals.com/';
protected $aOpenAiAsk = [
1 => '"将以下内容翻译为中文,仅返回翻译结果,不要解释:\n {#content#}"',
'default' => '
**核心要求**
1 内容涵盖哪些学科及方法请罗列
2 学术规范翻译并提炼摘要更强调逻辑性、科学术语准确性和表达的严谨性并且不需要分点展示字数小于200字以便更方便读者阅读
3 研究背景提炼,大于500字
4 针对文章简单总结讨论和结果, 大于450字
5 简单总结文章的研究方法, 大于300字
6 针对稿件内容进行展望撰写
7 总结归纳亮点【3点以上】
8 你是一名资深医学翻译专家,请将标题翻译成中文【内容需自然流畅、口语化、连贯性、学术性】
{#title_chinese#}
9 你是一名资深医学翻译专家,请将文章内容翻译成中文【内容需自然流畅、口语化、连贯性、学术性】
{#content#}
**稿件关键信息**
- 稿件简介:{#abstract#}
- 稿件内容:{#content#}
**输出格式**
中文格式[英文简写忽略首字母大写]
格式内容
```json{"covered": "【总字数<=100】", "digest": "【总字数<=500】", "research_background": "【总字数>200】", "discussion_results": "【总字数>450】","research_method" => "【总字数>300】", "prospect": "", "highlights": "", "title_chinese": "", "content": ""}',
'Review' => '
**核心要求**
1 内容涵盖哪些学科及方法请罗列
2 翻译好的内容将以公众号的形式推送给读者按学术规范翻译并提炼文章概述整体内容应大于1200字其中应包函文章背景不少于400字内容其他内容提炼更强调逻辑性、科学术语准确性和表达的严谨性注意内容不要有严重重复不需要分点展示,大于1000字
3 针对文章结论生成一个简单总结内容不要和文章概述重复字数150以内
4 请将标题翻译成中文【内容需自然流畅、口语化、连贯性、学术性】
{#title_chinese#}
5 请将文章内容翻译成中文【内容需自然流畅、口语化、连贯性、学术性】
{#content#}
**稿件关键信息**
- 稿件简介:{#abstract#}
- 稿件内容:{#content#}
**输出格式**
中文格式[英文简写忽略首字母大写]
格式内容
```json{"covered": "【总字数<=100】", "overview": "【总字数>=1000】", "summary": "【总字数>=300】", "title_chinese": "", "content": ""}'
];
//文章图片icon地址
protected $sArticleIcon = '/public/articleicon/';
@@ -101,71 +49,9 @@ class Aiarticle extends Base
//生成AI文章状态
protected $sGenerateStatusName = 'generate_status_article_id';
public function __construct(\think\Request $request = null) {
$this->proxy = '';
parent::__construct($request);
}
/**
* CURL 发送请求到 OpenAI
* @param $messages 内容
* @param $model 模型类型
*/
protected function curlOpenAI($messages, $model = 'gpt-4o'){
$sUrl = $this->sUrl;
$data = [
'model' => $model,
// 'messages' => $messages,
'messages' => [
// [
// 'role' => 'system',
// 'content' => '你是一名资深医学期刊编辑,需遵循医学原则回答以下问题。回答的内容会以微信公众号的形式推送给学术专家,要提高内容的连贯性,逻辑性,科学性,避免让学术专家产生质疑'
// ],
[
'role' => 'user',
'content' => $messages
]
],
'temperature' => 0.3,// 降低随机性0-10为最确定
// 'top_p' => 9, // 控制生成多样性
// 'max_tokens' => 1500, // 防止答案截断
// 'frequency_penalty' => 0.5, // 减少重复内容
// 'presence_penalty' => 0.2 // 鼓励提及新概念
];
$oCurl = curl_init();
// 通用配置
curl_setopt($oCurl, CURLOPT_URL, $sUrl);
// 设置头信息
curl_setopt($oCurl, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer ' . $this->sApiKey
]);
curl_setopt($oCurl, CURLOPT_PROXY,$this->proxy);
curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER,true);
curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST,2);
curl_setopt($oCurl, CURLOPT_POST, true); //设置为POST方式
curl_setopt($oCurl, CURLOPT_POSTFIELDS,json_encode($data));
curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, TRUE) ; // 获取数据返回
// curl_setopt($oCurl, CURLOPT_TIMEOUT, $this->timeout);
$result = curl_exec($oCurl);
//请求失败
if (curl_errno($oCurl)){
$this->sError = curl_errno($oCurl);
curl_close($oCurl);
return FALSE;
}
$this->sResponesData = json_decode($result);
curl_close($oCurl);
return TRUE;
}
/**
* @title 请求OPENAI
* @param aSearch array 模版内容
@@ -174,7 +60,7 @@ class Aiarticle extends Base
private function _createContentForOpenAI($aSearch = [],$sArticleType = 'default',$isTranslate = 2){
if(empty($aSearch) || empty($sArticleType)){
return json_encode(array('status' => 2,'msg' => 'Please select a template or enter the content you want to consult'.$this->sError));
return json_encode(array('status' => 2,'msg' => 'Please select a template or enter the content you want to consult'));
}
//组织参数
if(in_array($sArticleType, ['Mini Review','Review'])){
@@ -186,36 +72,34 @@ class Aiarticle extends Base
$sArticleType = 1;
}
$sTemplate = $this->aOpenAiAsk[$sArticleType];
$sTemplate = str_replace(array_keys($aSearch), array_values($aSearch), $sTemplate);
//请求接口
$sModel = empty($aParam['api_model']) ? 'gpt-4o' : $aParam['api_model'];
$result = $this->curlOpenAI($sTemplate,$sModel);
if($result == FALSE){
return json_encode(array('status' => 2,'msg' => 'Interface request failed'.$this->sError));
//获取问答内容
$oOpenAi = new OpenAi;
if($sArticleType == 'default'){
$aMessage = $oOpenAi->buildDefaultPrompt($aSearch);
}
if($sArticleType == 'Review'){
$aMessage = $oOpenAi->buildReviewPrompt($aSearch);
}
if($sArticleType == 1){
$aMessage = $oOpenAi->buildTranslatePrompt($aSearch);
}
if(empty($aMessage)){
return json_encode(['status' => 5,'msg' => 'AI Q&A content not obtained']);
}
//请求OPENAI接口
$aParam = ['messages' => $aMessage,'model' => empty($aParam['api_model']) ? 'gpt-4.1' : $aParam['api_model']];
$aResult = json_decode($oOpenAi->curlOpenAI($aParam),true);
$iStatus = empty($aResult['status']) ? 0 : $aResult['status'];
if($iStatus != 1){
return json_encode($aResult);
}
//处理返回信息
$data = $this->sResponesData;
if(!is_object($data)){
return json_encode(array('status' => 3,'msg' => 'There is a misunderstanding in the data returned by the interface'));
$aData = empty($aResult['data']) ? [] : $aResult['data'];
if(empty($aData)){
return json_encode(['status' => 6,'msg' => 'OPENAI returns empty content']);
}
$data = object_to_array($data);
$aChoices = $data['choices'] ?? [];
if(empty($aChoices)){
return json_encode(array('status' => 4,'msg' => 'OPENAI did not return data'));
}
$aChoicesInfo = $aChoices[0] ?? [];
$aMessage = $aChoicesInfo['message'] ?? [];
if(empty($aMessage['content'])){
return json_encode(array('status' => 5,'msg' => 'OPENAI returns empty data'));
}
$sContent = trim(trim($aMessage['content'],'```json'),'```');
$aContent = json_decode($sContent,true);
return json_encode(array('status' => 1,'msg' => 'OPENAI successfully generated content','data' => $aContent));
return json_encode(array('status' => 1,'msg' => 'OPENAI successfully generated content','data' => $aData));
}
public function create($aParam = []){
@@ -974,7 +858,7 @@ class Aiarticle extends Base
if(empty($aParsedUrl['scheme'])){
$aAuthorSerach['{###icon_path###}'] = trim($this->sSubmissionUrl,'/').$this->sUserIcon.$val;
}else{
$aAuthorSerach['{###icon_path###}'] = $val;
$aAuthorSerach['{###icon_path###}'] = $sIconInfo;
}
$aAuthorSerach['{###icon_path###}'] = trim($aAuthorSerach['{###icon_path###}'],'/');
}else{
@@ -1168,7 +1052,6 @@ class Aiarticle extends Base
$sWechatId = $aJournalInfo['issn'] ?? 'default';
}
//查询该模版是否推送到微信公众号
$aWhere['wechat_id'] = $sWechatId;
$aWhere['template_id'] = $sTemplate;
@@ -1178,7 +1061,6 @@ class Aiarticle extends Base
return json_encode(['status' => 4, 'msg' => 'Already uploaded to draft box']);
}
//数据处理-标题
$sTitle = empty($aAiArticle['title']) ? '' : $aAiArticle['title'];
$sTitle = mb_convert_encoding($sTitle, 'UTF-8', 'auto');