生成公微内容接口提取公共方法
This commit is contained in:
@@ -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-1,0为最确定)
|
||||
// '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');
|
||||
|
||||
Reference in New Issue
Block a user