Files
tougao/application/api/controller/Aiarticle.php
2025-05-08 14:06:50 +08:00

1054 lines
43 KiB
PHP
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace app\api\controller;
use app\api\controller\Base;
use think\Controller;
use think\Db;
use app\common\QrCodeImage;
/**
* @title 数据库接口
* @description 数据库接口
* @group 数据库接口
*/
class Aiarticle extends Base
{
protected $sApiKey;
protected $proxy;
protected $sUrl;
protected $curl;
protected $sResponesData;
protected $sError;
protected $timeout = 60;
protected $aAiFileds = ['article_id','title_english','title_chinese','journal_id','cite','covered','digest','research_result','content','highlights','discussion_prospect','journal_content','research_background'];
protected $sJournalUrl = 'http://journalapi.tmrjournals.com/public/index.php';//'http://zmzm.journal.dev.com'; //
protected $sJournalUsx = 'https://www.tmrjournals.com';
protected $sSubmissionUrl = 'https://submission.tmrjournals.com/';
protected $aOpenAiAsk = [
1 => '
**核心要求**
1 请将姓名翻译成中文
{#author_name#}
2 请将单位翻译成中文
{#company#}
3 请将简介翻译成中文
{#introduction#}
4 请将职称翻译成中文
{#technical#}
**输出格式**
格式内容
```json
{
"author_name": "",
"company": "",
"introduction": "",
"technical": ""
}
',
2 => '
**核心要求**
1 ​内容涵盖哪些学科及方法请罗列
2 结构化摘要生成【四要素模版】
3 研究背景提炼【三段式结构】
发病率+当前治疗缺口如5年OS<20%
引用2-3篇高被引论文的矛盾结论如Nature vs Cell观点分歧
基于团队前期工作如预实验发现X调控Y
4 结论与展望撰写
结论部分与TOP3高被引文献的对比
展望部分:
现有方法的可扩展性(如空间组学升级计划)
5 按点总结归纳研究结果并做简要阐述【3点以上】
6 总结归纳亮点【3点以上】
7 禁用清单
直接复制讨论部分的原文
未达到统计学显著性的趋势描述
稿件内未提及的内容一定不要总结归纳出来
"可能""或许"等不确定性词汇
单纯古籍原文翻译(需结合现代数据解读)
未经验证的因果断言(如"证明XX药治愈癌症"
8 请将标题翻译成中文
{#title_chinese#}
9 请将稿件内容翻译成中文
{#content#}
10 请将稿件所属期刊简介翻译
{#journal_content#}
**稿件关键信息**
- 稿件简介:{#abstract#}
- 稿件内容:{#content#}
**输出格式**
中文格式[英文简写忽略首字母大写]
格式内容
```json
{
"title_chinese": "",
"content": "",
"journal_content": "",
"covered": "【总字数<=100】",
"digest": "【总字数<=500】",
"research_background": "",
"discussion_prospect": "",
"research_result": "",
"highlights": "",
}'
];
//"highlights": {
// "theory_innovation": "【中西医理论结合点】",
// "methodology": "【关键技术+量化指标】",
// "data_strength": "【数据规模/古籍分析深度】"
// }
public function __construct(\think\Request $request = null) {
// 从配置读取敏感信息(非硬编码)
$this->sApiKey = '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';
$this->proxy = '';
$this->sUrl = 'https://api.openai.com/v1/chat/completions';
parent::__construct($request);
}
/**
* CURL 发送请求到 OpenAI
* @param $messages 内容
* @param $model 模型类型
*/
protected function curlOpenAI($messages, $model = 'gpt-4o'){
$sUrl = $this->sUrl;
$data = [
'model' => $model,
'messages' => $messages,
'temperature' => 0.7
];
$this->curl = curl_init();
// 通用配置
curl_setopt($this->curl, CURLOPT_URL, $sUrl);
// 设置头信息
curl_setopt($this->curl, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer ' . $this->sApiKey
]);
curl_setopt($this->curl, CURLOPT_PROXY,$this->proxy);
curl_setopt($this->curl, CURLOPT_SSL_VERIFYPEER,true);
curl_setopt($this->curl, CURLOPT_SSL_VERIFYHOST,2);
curl_setopt($this->curl, CURLOPT_POST, true); //设置为POST方式
curl_setopt($this->curl, CURLOPT_POSTFIELDS,json_encode($data));
curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, TRUE) ; // 获取数据返回
// curl_setopt($this->curl, CURLOPT_TIMEOUT, $this->timeout);
$result = curl_exec($this->curl);
//请求失败
if (curl_errno($this->curl)){
$this->sError = curl_errno($this->curl);
curl_close($this->curl);
return FALSE;
}
$this->sResponesData = json_decode($result);
curl_close($this->curl);
return TRUE;
}
/**
* @title 请求OPENAI
* @param aSearch array 模版内容
* @param iTemplateId 模版ID
*/
private function _createContentForOpenAI($aSearch = [],$iTemplateId = 0){
if(empty($aSearch) || empty($iTemplateId)){
return json_encode(array('status' => 2,'msg' => 'Please select a template or enter the content you want to consult'.$this->sError));
}
//组织参数
$sTemplate = $this->aOpenAiAsk[$iTemplateId];
$sTemplate = str_replace(array_keys($aSearch), array_values($aSearch), $sTemplate);
$messages = [
[
'role' => 'user', //角色platform平台;developer:开发者user:用户;guideline:模型规范“指南”部分:连接https://model-spec.openai.com/2025-02-12.html#chain_of_command
'content' => $sTemplate
]
];
//请求接口
$sModel = $aParam['api_model'] ?? 'gpt-4o';
$result = $this->curlOpenAI($messages,$sModel);
if($result == FALSE){
return json_encode(array('status' => 2,'msg' => 'Interface request failed'.$this->sError));
}
//处理返回信息
$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'));
}
$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));
}
/**
* @title AI生成稿件文章
* @param article_id 文章ID
* @param model 接口模型
* @param stream 是否流式输出 true是false否
*/
public function create(){
//获取参数
$aParam = $this->request->post();
$iArticleId = empty($aParam['article_id']) ? '' : $aParam['article_id'];
if(empty($iArticleId)){
return json_encode(array('status' => 2,'msg' => 'Please select an article' ));
}
//获取文章是否生成AI内容
$aResult = json_decode($this->getArticle($iArticleId),true);
if($aResult['status'] != 1){
return json_encode($aResult);
}
//获取数据
$aArticleContent = empty($aResult['data']) ? [] : $aResult['data'];
//文章数据
$aArticle = empty($aArticleContent['article']) ? [] : $aArticleContent['article'];
//期刊数据
$aJournal = empty($aArticleContent['journal']) ? [] : $aArticleContent['journal'];
//子期刊数据
$aJournalStage = empty($aArticleContent['journal_stage']) ? [] : $aArticleContent['journal_stage'];
//通讯作者
$aAuthor = empty($aArticleContent['author']) ? [] : $aArticleContent['author'];
//生成期刊图片二维码
$aJournalQrCode = $this->createJournalQrCode($aJournal);
if(empty($aJournalQrCode['qrcode_url'])){
return json_encode(['status' => 3,'msg' => 'Journal QR code not generated']);
}
//生成文章图片二维码
$aArticleQrCode = $this->createArticleQrCode($aArticle);
if(empty($aArticleQrCode['qrcode_url'])){
return json_encode(['status' => 4,'msg' => 'Article QR code not generated']);
}
//查询文章内容
$aMain = empty($aArticleContent['main']) ? [] : $aArticleContent['main'];;
$sContent = empty($aMain) ? '' : implode(',', $aMain);
//请求OPENAI生成微信公众号文章内容
$aSearch = [];
$aSearch['{#content#}'] = $this->basic_html_filter($sContent);
$aSearch['{#abstract#}'] = $this->basic_html_filter($aArticle['abstract']);
$aSearch['{#title_chinese#}'] = $this->basic_html_filter($aArticle['title']);
$aSearch['{#journal_content#}'] = $this->basic_html_filter($aJournal['journal_content'] ?? '');
$aResult = $this->_createContentForOpenAI($aSearch,2);
$aResult = json_decode($aResult,true);
if($aResult['status'] != 1){
return json_encode($aResult);
}
$aContent = empty($aResult['data']) ? [] : $aResult['data'];
if(empty($aContent)){
return json_encode(['status' => 4,'msg' => 'Data is empty']);
}
//组装数据
$aContent['article_id'] = $iArticleId;
$aContent['title_english'] = $aArticle['title'];
$aContent['journal_id'] = $aArticle['journal_id'];
//文章引用
$aContent['cite'] = $this->_cite($aArticle,$aJournal,$aJournalStage);
if(!empty($aJournal['journal_topic'])){
$aContent['journal_topic'] = $aJournal['journal_topic'];
}
//获取AI生成表里的数据判断是新增或更新
$aAiContent = json_decode($this->getAiArticle($iArticleId),true);
$aAiContent = empty($aAiContent['data']) ? [] : $aAiContent['data'];
$aAiArticle = empty($aAiContent['ai_article']) ? [] : $aAiContent['ai_article'];
$aAiAuthor = empty($aAiContent['ai_article_autho']) ? [] : $aAiContent['ai_article_autho'];
if(empty($aAiArticle)){//新增
//执行数据入库
$aResult = $this->addAiArticle($aContent,$aAuthor);
}
if(!empty($aAiArticle)){//更新
if(empty($aAiArticle['ai_article_id'])){
return json_encode(array('status' => 8,'msg' => 'No AI article found to update'));
}
//执行数据入库
$aContent['ai_article_id'] = $aAiArticle['ai_article_id'];
$aContent['author_list'] = $aAuthor;
$aResult = $this->updateAiArticle($aContent);
}
return $aResult;
}
/**
* 处理文章引用
* @param string $html
* @return string
*/
private function _cite($aArticle = [],$aJournal = [],$aJournalStage = []){
$no = empty($aJournalStage['stage_no']) ? ':' : '(' . $aJournalStage['stage_no'] . '):';
$jabbr = empty($aJournal['jabbr']) ? '' : $aJournal['jabbr'];
$stage_year = empty($aJournalStage['stage_year']) ? '' : $aJournalStage['stage_year'];
$stage_vol = empty($aJournalStage['stage_vol']) ? '' : $aJournalStage['stage_vol'];
$sCite = '';
if ($aArticle['journal_id'] == 22) {
$sCite = $aArticle['abbr'] . '. ' . $aArticle['title'] . '[J]. ' . choiseJabbr($aArticle['article_id'],$jabbr) . ',' . $stage_year . ',' . $stage_vol . $no . $aArticle['npp'] . '. doi:' . $aArticle['doi'];
} else {
$sCite = $aArticle['abbr'] . '. ' . $aArticle['title'] . '. <i>' . choiseJabbr($aArticle['article_id'], $jabbr) . '</i>. ' . $stage_year . ';' . $stage_vol . $no . $aArticle['npp'] . '. doi:' . $aArticle['doi'];
}
return $sCite;
}
/**
* @title 处理作者数据
* @param article_id 文章ID
* @param content 内容
*/
protected function _dealAuthor($aAuthor = array()){
//返回数组
if(empty($aAuthor)){
return [];
}
//根据邮箱查询作者信息
$aArticleId = array_unique(array_column($aAuthor, 'article_id'));
$iArticleId = $aArticleId[0];
$aEmail = array_unique(array_column($aAuthor, 'email'));
$aWhere = ['email' => ['in',$aEmail]];
$aUser = Db::name('user')->field('user_id,realname,email,localname')->where($aWhere)->select();
if(empty($aUser)){
return [];
}
//查询作者详情
$aUserId = array_column($aUser, 'user_id');
$aWhere = ['reviewer_id' => ['in',$aUserId]];
$aUserInfo = DB::name('user_reviewer_info')->field('reviewer_id,technical,introduction,company')->where($aWhere)->select();
if(empty($aUserInfo)){
return [];
}
//数据处理
$aUserInfo = array_column($aUserInfo, null,'reviewer_id');
$aAuthor = array_column($aAuthor, null,'email');
$aInfo = [];
foreach ($aUser as $key => $value) {
//姓名
$sName = empty($aAuthor[$value['email']]['author_name']) ? '' : $aAuthor[$value['email']]['author_name'];
$sName = empty($sName) ? $value['realname'] : $sName;
$sName = empty($sName) ? $value['localname'] : $sName;
//单位
$sCompany = empty($aAuthor[$value['email']]['company']) ? '' : $aAuthor[$value['email']]['company'];
$sCompany1 = empty($aUserInfo[$value['user_id']]['company']) ? '' : $aUserInfo[$value['user_id']]['company'];
$sCompany = empty($sCompany) ? $sCompany1 : $sCompany;
//职称
$sTechnical = empty($aUserInfo[$value['user_id']]['technical']) ? '' : $aUserInfo[$value['user_id']]['technical'];
//简介
$sIntroduction = empty($aUserInfo[$value['user_id']]['introduction']) ? '' : $aUserInfo[$value['user_id']]['introduction'];
//请求AI翻译
// $aSearch['{#author_name#}'] = $sName;
// $aSearch['{#company#}'] = $sCompany;
// $aSearch['{#technical#}'] = $sTechnical;
// $aSearch['{#introduction#}'] = $sIntroduction;
// $aResult = $this->_createContentForOpenAI($aSearch,1);
// $aResult = json_decode($aResult,true);
// if($aResult['status'] == 1){
// $aContent = empty($aResult['data']) ? [] : $aResult['data'];
// $sCompany = empty($aContent['company']) ? $sCompany : $aContent['company'];
// $sTechnical = empty($aContent['technical']) ? $sTechnical : $aContent['technical'];
// $sIntroduction = empty($aContent['introduction']) ? $sIntroduction : $aContent['introduction'];
// }
$aInfo[] = ['email' => $value['email'],'author_name' => $sName,'technical' => $sTechnical,'introduction' => $sIntroduction,'company' => $sCompany,'article_id' => $iArticleId,'create_time' => time()];
}
return $aInfo;
}
/**
* 接口请求获取Journal数据库文章信息
* @param article_id 文章ID
*/
public function getArticle($iArticleId = ''){
$aParam = $this->request->post();
$iArticleId = empty($iArticleId) ? $aParam['article_id'] : $iArticleId;
//接口请求地址
$sUrl = $this->sJournalUrl.'/wechat/Article/getArticle';
//请求接口
$aParam['article_id'] = $iArticleId;
$aResult = object_to_array(json_decode(myPost($sUrl, $aParam)));
$iStatus = empty($aResult['status']) ? 0 : $aResult['status'];
if($iStatus != 1){
return json_encode(['status' => 0,'msg' => $aResult['msg'] ?? '操作异常']);
}
$aContent = empty($aResult['data']) ? [] : $aResult['data'];
if(!empty($aContent['journal'])){
$aJournal = $aContent['journal'];
//查询期刊主题
$aWhere['issn'] = $aJournal['issn'];
$aJournalInfo = Db::name('journal')->field('journal_topic')->where($aWhere)->find();
$aContent['journal']+=$aJournalInfo;
}
return json_encode(['status' => 1,'msg' => 'success','data' => $aContent]);
}
/**
* 获取Ai生成文章信息
* @param article_id 文章ID
*/
public function getAiArticle($iArticleId = 0){
$aParam = $this->request->post();
$iArticleId = empty($iArticleId) ? $aParam['article_id'] : $iArticleId;
//查询AI生成的文章内容
$aParam['article_id'] = $iArticleId;
$aParam['is_delete'] = 2;
$aAiArticle = Db::name('ai_article')->where($aParam)->find();
if(empty($aAiArticle)){
return json_encode(['status' => 1,'msg' => 'data is null','data' => ['ai_article' => []]]);
}
//查询文章通讯作者
if($aAuthorInfo = Db::name('ai_article_author')->where(['article_id' => $iArticleId])->select()){
//查询头像
$aEmail = array_column($aAuthorInfo, 'email');
$aUser = Db::name('user')->where(['email' => ['in',$aEmail]])->column('email,icon');
foreach ($aAuthorInfo as $key => $value) {
$aAuthorInfo[$key]['icon'] = empty($aUser[$value['email']]) ? '/static/img/userImg.f3d9bc3b.jpg' : '/public/usericon/'.$aUser[$value['email']];
}
}
return json_encode(['status' => 1,'msg' => 'success','data' => ['ai_article' => $aAiArticle,'ai_article_author' => $aAuthorInfo]]);
}
/**
* 基础HTML过滤
* @param string $html
* @return string
*/
private function basic_html_filter($html) {
// 移除所有HTML标签及PHP标签
$text = strip_tags($html);
// 转换HTML实体
$text = html_entity_decode($text, ENT_QUOTES | ENT_HTML5, 'UTF-8');
// 合并连续空白字符
$text = preg_replace('/\s+/u', ' ', $text);
return trim($text);
}
/**
* @title AI生成稿件内容入库
* @param article_id 文章ID
* @param content 内容
*/
protected function addAiArticle($aParam = array(),$aAuthor = []){
//返回数组
$aResult = ['status' => 1,'msg' => 'AI article added successfully','data' => []];
//必填参数验证
$aFields = $this->aAiFileds;
$bStatus = true;
$sFiled = '';
$aInsertParam = [];
foreach($aFields as $val){
if(empty($aParam[$val])){
$bStatus = false;
$sFiled = $val;
break;
}
if($val == 'article_id'){
$aInsertParam[$val] = $aParam[$val];
continue;
}
$aInsertParam[$val] = addslashes(strip_tags($aParam[$val]));
}
if($bStatus == false){
return json_encode(['status' => 2,'msg' => $sFiled.'cannot be empty']);
}
//执行入库
$aInsertParam['create_time'] = time();
//作者判断空值
$aInsertParam['author'] = empty($aInsertParam['author']) ? 'TMR编辑部' : $aInsertParam['author'];
Db::startTrans();
if(!$iId = Db::name('ai_article')->insertGetId($aInsertParam)){
return ['status' => 3,'msg' => 'Adding AI article failed'];
}
$aResult['data'] = array_merge($aInsertParam,['ai_article_id' => $iId]);
if(!empty($aAuthor)){
$aInfo = $this->_dealAuthor($aAuthor);
if(!empty($aInfo)){
foreach ($aInfo as $key => $value) {
//请求AI翻译
$aSearch['{#author_name#}'] = $value['author_name'];
$aSearch['{#company#}'] = $value['company'];
$aSearch['{#technical#}'] = $value['technical'];
$aSearch['{#introduction#}'] = $value['introduction'];
$aResultInfo = $this->_createContentForOpenAI($aSearch,1);
$aResultInfo = json_decode($aResultInfo,true);
if($aResultInfo['status'] == 1){
$aContent = empty($aResultInfo['data']) ? [] : $aResultInfo['data'];
$aInfo[$key]['company'] = empty($aContent['company']) ? $value['company'] : $aContent['company'];
$aInfo[$key]['technical'] = empty($aContent['technical']) ? $value['technical'] : $aContent['technical'];
$aInfo[$key]['introduction'] = empty($aContent['introduction']) ? $value['introduction'] : $aContent['introduction'];
}
}
Db::name('ai_article_author')->insertAll($aInfo);
}
}
Db::commit();
return json_encode($aResult);
}
/**
* @title AI生成稿件内容入库
* @param article_id 文章ID
* @param content 内容
*/
public function updateAiArticle($aParam = array()){
//返回数组
$aResult = ['status' => 1,'msg' => 'AI article updated successfully','data' => []];
//必填参数验证
$aFields = array_merge(['ai_article_id'],$this->aAiFileds);
$bStatus = true;
$sFiled = '';
$aUpdateParam = [];
$iAiArticleId = '';
foreach($aFields as $val){
if(empty($aParam[$val])){
$bStatus = false;
$sFiled = $val;
break;
}
if($val == 'article_id'){
continue;
}
if($val == 'ai_article_id'){
$iAiArticleId = $aParam[$val];
continue;
}
$aUpdateParam[$val] = addslashes(strip_tags($aParam[$val]));
}
if($bStatus == false){
return json_encode(['status' => 2,'msg' => $sFiled.'cannot be empty']);
}
if(empty($iAiArticleId) || empty($aUpdateParam)){
return json_encode(['status' => 1,'msg' => 'No data currently being processed']);
}
Db::startTrans();
//执行入库
$aUpdateParam['update_time'] = time();
$result = Db::name('ai_article')->where('ai_article_id',$iAiArticleId)->limit(1)->update($aUpdateParam);
if($result === false){
$aResult = json_encode(['status' => 3,'msg' => 'UPDATEING AI article failed']);
}
$aResult['data'] = $aUpdateParam;
//更新作者信息
if(!empty($aParam['author_list'])){
foreach ($aParam['author_list'] as $key => $value) {
$aWhere = ['article_id' => $value['article_id'],'email' => $value['email']];
unset($value['article_id']);
unset($value['email']);
$value['update_time'] = time();
Db::name('ai_article_author')->where($aWhere)->limit(1)->update($value);
}
}
Db::commit();
return json_encode($aResult);
}
/**
* 文章内容选择模版生成数据
* @param article_id 文章ID
* @param template_id 模版ID
*/
public function getTemplateContent($iArticleId = '',$iTemplateId = ''){
//获取参数
$aParam = $this->request->post();
//文章ID
$iArticleId = empty($iArticleId) ? $aParam['article_id'] ?? '' : $iArticleId;
//模版ID
$iTemplateId = empty($iTemplateId) ? $aParam['template_id'] ?? '' : $iTemplateId;
//必填参数验证
if(empty($iArticleId)){
return json_encode(['status' => 2, 'msg' => 'Please select an article']);
}
if(empty($iTemplateId)){
return json_encode(['status' => 2, 'msg' => 'Please select a template']);
}
//获取文章是否生成AI内容
$aResult = json_decode($this->getArticle($iArticleId),true);
if($aResult['status'] != 1){
return json_encode($aResult);
}
//获取数据
$aArticleContent = empty($aResult['data']) ? [] : $aResult['data'];
//文章数据
$aArticle = empty($aArticleContent['article']) ? [] : $aArticleContent['article'];
//期刊数据
$aJournal = empty($aArticleContent['journal']) ? [] : $aArticleContent['journal'];
//子期刊数据
$aJournalStage = empty($aArticleContent['journal_stage']) ? [] : $aArticleContent['journal_stage'];
//获取AI生成文章内容
$aAiContent = json_decode($this->getAiArticle($iArticleId),true);
$aAiContent = empty($aAiContent['data']) ? [] : $aAiContent['data'];
$aAiArticle = empty($aAiContent['ai_article']) ? [] : $aAiContent['ai_article'];
//AI通讯作者
$aAiAuthor = empty($aAiContent['ai_article_author']) ? [] : $aAiContent['ai_article_author'];
//判断是否生成AI内容
if(empty($aAiArticle)){
return json_encode(['status' => 3, 'msg' => 'The article content of WeChat official account has not been generated']);
}
//期刊访问地址
$journal_usx = $this->sJournalUsx;
if(!empty($aJournal['journal_usx'])){
//地址
$journal_usx .= $aJournal['journal_usx']??''.'/';
}
$aAiArticle['journal_usx_url'] = trim($journal_usx);
$aAiArticle += $aJournal;
//获取期刊图片二维码
$aJournalQrCode = $this->createJournalQrCode($aJournal);
$aAiArticle['journal_qrcode'] = empty($aJournalQrCode['qrcode_url']) ? '' : $this->sSubmissionUrl.'public/qrcode/'.$aJournalQrCode['qrcode_url'];
//获取期刊图片二维码
$aArticleQrCode = $this->createArticleQrCode($aArticle);
$aAiArticle['article_qrcode'] = empty($aArticleQrCode['qrcode_url']) ? '' : $this->sSubmissionUrl.'public/qrcode/'.$aArticleQrCode['qrcode_url'];
//获取模版信息
$sTemplatePath = ROOT_PATH."public/wechatTemplate/".$iTemplateId.'.html';
// 验证文件有效性
if (!file_exists($sTemplatePath)) {
return json_encode(['status' => 4, 'msg' => 'Article template does not exist']);
}
if (!is_readable($sTemplatePath)) {
return json_encode(['status' => 5, 'msg' => 'The article template is unreadable']);
}
//获取模版内容
$sTemplate = file_get_contents($sTemplatePath);
//数据处理
$aSearch = [];
foreach ($aAiArticle as $key => $value) {
$aSearch['{###'.$key.'###}'] = htmlspecialchars(trim(trim(trim($value),'【'),'】'));
}
//处理通讯作者信息数据
$aAuthorInfo = json_decode($this->dealTemplateAuthor($aAiAuthor,$iTemplateId),true);
$aSearch['{###author_info###}'] = empty($aAuthorInfo['data']['author_info']) ? ' ' : implode("\n", $aAuthorInfo['data']['author_info']);
$aSearch['{###author###}'] = empty($aAuthorInfo['data']['author']) ? ' ' : $aAuthorInfo['data']['author'];
// //处理公众号推荐
// $aRecommend = json_decode($this->dealTemplateWechatRecommend($aArticle['journal_id'],$iTemplateId),true);
// $aSearch['{###wechat_recommend###}'] = empty($aRecommend['data']) ? ' ' : implode("\n", $aRecommend['data']);
//处理往期推荐数据
$aPreviousRecommend = json_decode($this->dealTemplatePreviousRecommend($aArticle,$iTemplateId),true);
if(empty($aPreviousRecommend['data'])){
$aSearch['{###previous_recommend_summary###}'] = '';
}else{
$sSummaryTemplatePath = ROOT_PATH."public/wechatTemplate/".$iTemplateId.'_previous_recommend_summary.html';
$sSummaryTemplate = file_get_contents($sSummaryTemplatePath);
$aSearchInfo['{###previous_recommend###}'] = empty($aPreviousRecommend['data']) ? ' ' : implode("\n", $aPreviousRecommend['data']);
$sSummaryTemplate = str_replace(array_keys($aSearchInfo), array_values($aSearchInfo), $sSummaryTemplate);
$aSearch['{###previous_recommend_summary###}'] = $sSummaryTemplate;
}
//处理期刊主题数据
$aTopic = json_decode($this->dealTemplateTopic($aAiArticle['journal_topic'],$iTemplateId),true);
if(empty($aTopic['data'])){
$aSearch['{###topic_name_summary###}'] = '';
}else{
$sSummaryTemplatePath = ROOT_PATH."public/wechatTemplate/".$iTemplateId.'_topic_summary.html';
$sSummaryTemplate = file_get_contents($sSummaryTemplatePath);
$aSearchInfo['{###topic_name###}'] = empty($aTopic['data']) ? ' ' : implode("\n", $aTopic['data']);
$sSummaryTemplate = str_replace(array_keys($aSearchInfo), array_values($aSearchInfo), $sSummaryTemplate);
$aSearch['{###topic_name_summary###}'] = $sSummaryTemplate;
}
//处理文章图片地址数据
$aSearch['{###article_icon###}'] = $this->sJournalUsx.'/public/articleicon/'.$aArticle['article_icon']??'';
//处理文章期刊图片地址数据
$aSearch['{###journal_icon###}'] = $this->sJournalUsx.'/public/journalicon/'.$aJournal['journal_icon']??'';
//模版替换变量
if(empty($aSearch)){
return json_encode(['status' => 6, 'msg' => '模版内容不能为空']);
}
$sTemplate = str_replace(array_keys($aSearch), array_values($aSearch), $sTemplate);
file_put_contents(ROOT_PATH.'public/template_info.html', $sTemplate);
return json_encode(['status' => 1, 'msg' => '模版生成成功','data' => ['template' => $sTemplate]]);
}
/**
* 处理模版通讯作者
* @param article_id 文章ID
*/
private function dealTemplateAuthor($aAuthor = [],$iTemplateId = 0){
//必填字段判断
if(empty($aAuthor) || empty($iTemplateId)){
return json_encode(['status' => 2,'msg' => 'Corresponding author or template does not exist']);
}
//获取通讯作者模版
$sAuthorTemplatePath = ROOT_PATH."public/wechatTemplate/".$iTemplateId.'_author.html';
if (!file_exists($sAuthorTemplatePath)) {
return json_encode(['status' => 3, 'msg' => 'Corresponding author template does not exist','data' => '']);
}
if (!is_readable($sAuthorTemplatePath)) {
return json_encode(['status' => 4, 'msg' => 'The corresponding author template is unreadable','data' => '']);
}
$sAuthorTemplate = file_get_contents($sAuthorTemplatePath);
//处理模版变量
$aAuthorSerachInfo = [];
$sAuthorInfo = '';
foreach ($aAuthor as $key => $value) {
$aAuthorSerach = [];
foreach ($value as $k => $val) {
if($k == 'icon'){
$aAuthorSerach['{###'.$k.'###}'] = $this->sSubmissionUrl.trim($val);
}else{
$aAuthorSerach['{###'.$k.'###}'] = trim($val);
}
}
$aAuthorSerachInfo[] = str_replace(array_keys($aAuthorSerach), array_values($aAuthorSerach), $sAuthorTemplate);
$sAuthorInfo = $value['company'].' '.$value['author_name'].';';
}
return json_encode(['status' => 1,'msg' => 'success','data' => ['author_info' => $aAuthorSerachInfo,'author' => trim($sAuthorInfo,';')]]);
}
// /**
// * 处理公众号推荐
// * @param article_id 文章ID
// */
// private function dealTemplateWechatRecommend($iJournalId = 0,$iTemplateId = 0){
// if(empty($iTemplateId)){
// return json_encode(['status' => 2,'msg' => 'template does not exist']);
// }
// //获取通讯作者
// $sTemplatePath = ROOT_PATH."public/wechatTemplate/".$iTemplateId.'_wechat_recommend.html';
// if (!file_exists($sTemplatePath)) {
// return json_encode(['status' => 4, 'msg' => 'Corresponding author template does not exist','data' => '']);
// }
// if (!is_readable($sTemplatePath)) {
// return json_encode(['status' => 5, 'msg' => 'The corresponding author template is unreadable','data' => '']);
// }
// $sTemplate = file_get_contents($sTemplatePath);
// //查询公众号推荐
// $aRecommend = Db::name('ai_article')->field('article_id,title_chinese,covered,digest')->where('journal_id',$iJournalId)->select();
// $aSearchInfo = [];
// if(!empty($aRecommend)){
// foreach ($aRecommend as $key => $value) {
// $aSerach = [];
// foreach ($value as $k => $val) {
// $aSerach['{###'.$k.'###}'] = trim(trim(trim($val),'【'),'】');
// }
// $aSearchInfo[] = str_replace(array_keys($aSerach), array_values($aSerach), $sTemplate);
// }
// }
// return json_encode(['status' => 1,'msg' => 'success','data' => $aSearchInfo]);
// }
/**
* 处理模版主题
* @param article_id 文章ID
*/
private function dealTemplateTopic($sTopic = '',$iTemplateId = 0){
if(empty($iTemplateId)){
return json_encode(['status' => 2,'template does not exist']);
}
if(empty($sTopic)){
return json_encode(['status' => 2,'topic does not exist']);
}
//获取主题模版
$sTemplatePath = ROOT_PATH."public/wechatTemplate/".$iTemplateId.'_topic.html';
if (!file_exists($sTemplatePath)) {
return json_encode(['status' => 4, 'msg' => 'Corresponding author template does not exist']);
}
if (!is_readable($sTemplatePath)) {
return json_encode(['status' => 5, 'msg' => 'The corresponding author template is unreadable']);
}
$sTemplate = file_get_contents($sTemplatePath);
//数据处理
$sTopic = trim($sTopic);
$aTopic = empty($sTopic) ? [] : explode(',', $sTopic);
$aSearchInfo = [];
if(!empty($aTopic)){
foreach ($aTopic as $key => $value) {
$aSerach['{###topic_name###}'] = trim(trim(trim($value),'【'),'】');
$aSearchInfo[] = str_replace(array_keys($aSerach), array_values($aSerach), $sTemplate);
}
}
return json_encode(['status' => 1,'msg' => 'success','data' => $aSearchInfo]);
}
/**
* 处理往期推荐
* @param article_id 文章ID
*/
private function dealTemplatePreviousRecommend($aArticle=[],$iTemplateId = 0){
if(empty($iTemplateId)){
return json_encode(['status' => 2,'template does not exist']);
}
//获取往期推荐模版
$sTemplatePath = ROOT_PATH."public/wechatTemplate/".$iTemplateId.'_previous_recommend.html';
if (!file_exists($sTemplatePath)) {
return json_encode(['status' => 3, 'msg' => 'Corresponding author template does not exist']);
}
if (!is_readable($sTemplatePath)) {
return json_encode(['status' => 4, 'msg' => 'The corresponding author template is unreadable']);
}
$sTemplate = file_get_contents($sTemplatePath);
//判断是否关联文章
if(empty($aArticle['related'])){
return json_encode(['status' => 6, 'msg' => 'Unrelated articles']);
}
//获取关联文章信息
$aWhere = ['article_id' => ['in',json_decode($aArticle['related'],true)],'is_publish' => 1,'is_delete' => 2];
$aRecommend = Db::name('ai_article')->field('article_id,media_id,wechat_url')->where($aWhere)->select();
$aSearchInfo = [];
if(!empty($aRecommend)){
//查询文章图片
$aId = array_column($aRecommend, 'article_id');
$aWhere = ['w_article_id' => ['in',$aId]];
$aProductionArticle = Db::name('production_article')->where($aWhere)->column('w_article_id,icon');
foreach ($aRecommend as $key => $value) {
$aSerach['{###wechat_url###}'] = $value['wechat_url'];
$sIcon = empty($aProductionArticle[$value['article_id']]) ? '' : $this->sJournalUsx.'/public/articleicon/'.$aProductionArticle[$value['article_id']];
$aSerach['{###wechat_media_url###}'] = empty($value['wechat_media_url']) ? $sIcon : $value['wechat_media_url'];
$aSearchInfo[] = str_replace(array_keys($aSerach), array_values($aSerach), $sTemplate);
}
}
return json_encode(['status' => 1,'msg' => 'success','data' => $aSearchInfo]);
}
/**
* @title 文章AI生成稿件内容查询
* @param aJournal 期刊信息
*/
private function createJournalQrCode($aJournal = []){
$iJournalId = empty($aJournal['journal_id']) ? 0 : $aJournal['journal_id'];
//判断期刊二维码是否生成
$aWhere = ['journal_id' => $iJournalId];
$aQrCode = Db::name('journal_qrcode')->where($aWhere)->find();
if(!empty($aQrCode)){
return $aQrCode;
}
//创建二维码
//生成图片地址
$sImagePath = 'journal/'.$iJournalId.'.jpg';
$sQrCodeUrl = ROOT_PATH.'public/qrcode/'.$sImagePath;
// 验证图片是否存在
if (file_exists($sQrCodeUrl)) {
return ['qrcode_url' => $sImagePath];
}
//地址
$journal_usx = empty($aJournal['journal_usx']) ? '' : $aJournal['journal_usx'];
$sUrl = $this->sJournalUsx.'/'.$journal_usx.'/';
//二维码中间图片
$sLogo = empty($aJournal['journal_icon']) ? '' : $aJournal['journal_icon'];
if(empty($sLogo)){
$sImg = QrCodeImage::generate($sUrl,500,$sQrCodeUrl);
}else{
$sLogo = $this->sJournalUsx.'/public/journalicon/'.$sLogo;
$aImageInfo = json_decode($this->getImage($sLogo,$iJournalId,'journal'),true);
if(empty($aImageInfo['data'])){
$sImg = QrCodeImage::generate($sUrl,500,$sQrCodeUrl);
}
$sImg = QrCodeImage::withLogo($sUrl,$aImageInfo['data'],500,100, $sQrCodeUrl);
}
//插入期刊二维码表
$aParam = ['journal_id' => $iJournalId,'qrcode_url' => $sImagePath,'create_time' => time()];
$result = Db::name('journal_qrcode')->insertGetId($aParam);
return $aParam;
}
/**
* @title 文章AI生成稿件内容查询
* @param aArticle 文章信息
*/
private function createArticleQrCode($aArticle = []){
$iArticleId = empty($aArticle['article_id']) ? 0 : $aArticle['article_id'];
//判断期刊二维码是否生成
$aWhere = ['article_id' => $iArticleId];
$aQrCode = Db::name('article_qrcode')->where($aWhere)->find();
if(!empty($aQrCode)){
return $aQrCode;
}
//创建二维码
//生成图片地址
$sImagePath = 'article/'.$iArticleId.'.jpg';
$sQrCodeUrl = ROOT_PATH.'public/qrcode/'.$sImagePath;
// 验证图片是否存在
if (file_exists($sQrCodeUrl)) {
return ['qrcode_url' => $sImagePath];
}
//地址
$sUrl = $this->sJournalUsx.'/'.'article.html?J_num='.$aArticle['journal_id'].'&a_id='.$iArticleId;
//二维码中间图片
$sLogo = $aArticle['article_icon'];
if(empty($sLogo)){
$sImg = QrCodeImage::generate($sUrl,500,$sQrCodeUrl);
}else{
$sLogo = $this->sJournalUsx.'/public/articleicon/'.$sLogo;
$aImageInfo = json_decode($this->getImage($sLogo,$iArticleId,'article'),true);
if(empty($aImageInfo['data'])){
$sImg = QrCodeImage::generate($sUrl,500,$sQrCodeUrl);
}
$sImg = QrCodeImage::withLogo($sUrl,$aImageInfo['data'],500,100, $sQrCodeUrl);
}
//插入期刊二维码表
$aParam = ['article_id' => $iArticleId,'qrcode_url' => $sImagePath,'create_time' => time()];
$result = Db::name('article_qrcode')->insertGetId($aParam);
return $aParam;
}
/**
* @title 请求OPENAI翻译内容
* @param article_id 文章ID
*/
public function translate($param = [],$url=''){
if (!is_array($param)) {
throw new Exception("参数必须为array");
}
$httph = curl_init($url);
// curl_setopt($httph, CURLOPT_SSL_VERIFYPEER, 0);
// curl_setopt($httph, CURLOPT_SSL_VERIFYHOST, 1);
curl_setopt($httph, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($httph, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)");
curl_setopt($httph, CURLOPT_POST, 1); //设置为POST方式
curl_setopt($httph, CURLOPT_POSTFIELDS, $param);
curl_setopt($httph, CURLOPT_SSL_VERIFYPEER, false);
// curl_setopt($httph, CURLOPT_RETURNTRANSFER,0);
// curl_setopt($httph, CURLOPT_HEADER,1);
$rst = curl_exec($httph);
curl_close($httph);
return json_decode($rst,true);
}
/**
* @title curl 请求获取图片保存到本地
* @param sPath 图片链接地址
*/
public function getImage($sPath = '',$iId = 0,$sType = 'journal'){
//判断参数
if(empty($sPath)){
return json_encode(['status' => 2,'msg' => 'url is empty','data' => '']);
}
//获取图片名称
$aImageInfo = pathinfo($sPath);
//图片后缀名
$sExtension = empty($aImageInfo['extension']) ? 'jpg' : $aImageInfo['extension'];
//图片地址
$sImagePath = $sType.'/imgae_'.$iId.'.'.$sExtension;
$sImagePath = ROOT_PATH.'public/qrcode/'.$sImagePath;
if (file_exists($sImagePath)) {
return json_encode(['status' => 1,'msg' => 'success','data' => $sImagePath]);
}
//curl 请求
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$sPath); // 设置请求URL
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 设置返回数据而不是直接输出
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 禁用SSL验证
$response = curl_exec($ch);
if (curl_errno($ch)) {
return json_encode(['status' => 3,'msg' => 'Error:' . curl_error($ch),'data' => $sImagePath]);
}
//保存图片
file_put_contents($sImagePath, $response);
curl_close($ch);
return json_encode(['status' => 1,'msg' => 'success','data' => $sImagePath]);
}
}