生成公微内容接口提取公共方法
This commit is contained in:
@@ -8,6 +8,7 @@ use app\common\Wechat;
|
|||||||
use app\common\Material;
|
use app\common\Material;
|
||||||
use think\Cache;
|
use think\Cache;
|
||||||
use think\Queue;
|
use think\Queue;
|
||||||
|
use app\common\OpenAi;
|
||||||
/**
|
/**
|
||||||
* @title 数据库接口
|
* @title 数据库接口
|
||||||
* @description 数据库接口
|
* @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'];//默认头像
|
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]
|
//数据表必填字段[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'];
|
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 $sJournalUsx = 'https://www.tmrjournals.com';
|
||||||
//投稿系统
|
//投稿系统
|
||||||
protected $sSubmissionUrl = 'https://submission.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地址
|
//文章图片icon地址
|
||||||
protected $sArticleIcon = '/public/articleicon/';
|
protected $sArticleIcon = '/public/articleicon/';
|
||||||
@@ -101,71 +49,9 @@ class Aiarticle extends Base
|
|||||||
//生成AI文章状态
|
//生成AI文章状态
|
||||||
protected $sGenerateStatusName = 'generate_status_article_id';
|
protected $sGenerateStatusName = 'generate_status_article_id';
|
||||||
public function __construct(\think\Request $request = null) {
|
public function __construct(\think\Request $request = null) {
|
||||||
|
|
||||||
$this->proxy = '';
|
|
||||||
|
|
||||||
parent::__construct($request);
|
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
|
* @title 请求OPENAI
|
||||||
* @param aSearch array 模版内容
|
* @param aSearch array 模版内容
|
||||||
@@ -174,7 +60,7 @@ class Aiarticle extends Base
|
|||||||
private function _createContentForOpenAI($aSearch = [],$sArticleType = 'default',$isTranslate = 2){
|
private function _createContentForOpenAI($aSearch = [],$sArticleType = 'default',$isTranslate = 2){
|
||||||
|
|
||||||
if(empty($aSearch) || empty($sArticleType)){
|
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'])){
|
if(in_array($sArticleType, ['Mini Review','Review'])){
|
||||||
@@ -186,36 +72,34 @@ class Aiarticle extends Base
|
|||||||
$sArticleType = 1;
|
$sArticleType = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
$sTemplate = $this->aOpenAiAsk[$sArticleType];
|
//获取问答内容
|
||||||
$sTemplate = str_replace(array_keys($aSearch), array_values($aSearch), $sTemplate);
|
$oOpenAi = new OpenAi;
|
||||||
//请求接口
|
if($sArticleType == 'default'){
|
||||||
$sModel = empty($aParam['api_model']) ? 'gpt-4o' : $aParam['api_model'];
|
$aMessage = $oOpenAi->buildDefaultPrompt($aSearch);
|
||||||
$result = $this->curlOpenAI($sTemplate,$sModel);
|
}
|
||||||
if($result == FALSE){
|
if($sArticleType == 'Review'){
|
||||||
return json_encode(array('status' => 2,'msg' => 'Interface request failed'.$this->sError));
|
$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;
|
$aData = empty($aResult['data']) ? [] : $aResult['data'];
|
||||||
if(!is_object($data)){
|
if(empty($aData)){
|
||||||
return json_encode(array('status' => 3,'msg' => 'There is a misunderstanding in the data returned by the interface'));
|
return json_encode(['status' => 6,'msg' => 'OPENAI returns empty content']);
|
||||||
}
|
}
|
||||||
$data = object_to_array($data);
|
return json_encode(array('status' => 1,'msg' => 'OPENAI successfully generated content','data' => $aData));
|
||||||
$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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function create($aParam = []){
|
public function create($aParam = []){
|
||||||
@@ -974,7 +858,7 @@ class Aiarticle extends Base
|
|||||||
if(empty($aParsedUrl['scheme'])){
|
if(empty($aParsedUrl['scheme'])){
|
||||||
$aAuthorSerach['{###icon_path###}'] = trim($this->sSubmissionUrl,'/').$this->sUserIcon.$val;
|
$aAuthorSerach['{###icon_path###}'] = trim($this->sSubmissionUrl,'/').$this->sUserIcon.$val;
|
||||||
}else{
|
}else{
|
||||||
$aAuthorSerach['{###icon_path###}'] = $val;
|
$aAuthorSerach['{###icon_path###}'] = $sIconInfo;
|
||||||
}
|
}
|
||||||
$aAuthorSerach['{###icon_path###}'] = trim($aAuthorSerach['{###icon_path###}'],'/');
|
$aAuthorSerach['{###icon_path###}'] = trim($aAuthorSerach['{###icon_path###}'],'/');
|
||||||
}else{
|
}else{
|
||||||
@@ -1168,7 +1052,6 @@ class Aiarticle extends Base
|
|||||||
$sWechatId = $aJournalInfo['issn'] ?? 'default';
|
$sWechatId = $aJournalInfo['issn'] ?? 'default';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//查询该模版是否推送到微信公众号
|
//查询该模版是否推送到微信公众号
|
||||||
$aWhere['wechat_id'] = $sWechatId;
|
$aWhere['wechat_id'] = $sWechatId;
|
||||||
$aWhere['template_id'] = $sTemplate;
|
$aWhere['template_id'] = $sTemplate;
|
||||||
@@ -1178,7 +1061,6 @@ class Aiarticle extends Base
|
|||||||
return json_encode(['status' => 4, 'msg' => 'Already uploaded to draft box']);
|
return json_encode(['status' => 4, 'msg' => 'Already uploaded to draft box']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//数据处理-标题
|
//数据处理-标题
|
||||||
$sTitle = empty($aAiArticle['title']) ? '' : $aAiArticle['title'];
|
$sTitle = empty($aAiArticle['title']) ? '' : $aAiArticle['title'];
|
||||||
$sTitle = mb_convert_encoding($sTitle, 'UTF-8', 'auto');
|
$sTitle = mb_convert_encoding($sTitle, 'UTF-8', 'auto');
|
||||||
|
|||||||
Reference in New Issue
Block a user