From a1e8ffcfd0fb8f759c0c1754d6e1dfe40a539d1e Mon Sep 17 00:00:00 2001 From: tianya <yanghuxiao@vip.qq.com> Date: Wed, 26 Mar 2025 21:23:22 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=8C=E6=96=87=E6=9C=AC=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E5=99=A8=E6=94=AF=E6=8C=81AI=E6=93=8D=E4=BD=9C=EF=BC=8C?= =?UTF-8?q?=E9=9C=80=E8=A6=81AI=E5=8A=A9=E6=89=8B1.0.3=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/admin/ai_dialog.php | 231 ++++++++++++++++++ src/admin/api.php | 28 ++- src/admin/archives_do.php | 4 +- src/admin/inc/inc_archives_functions.php | 4 +- .../plugins/dedebizai/icons/dedebizai.png | Bin 0 -> 469 bytes .../ckeditor/plugins/dedebizai/plugin.js | 28 +++ src/system/inc/inc_fun_funAdmin.php | 2 +- 7 files changed, 290 insertions(+), 7 deletions(-) create mode 100644 src/admin/ai_dialog.php create mode 100644 src/static/ckeditor/plugins/dedebizai/icons/dedebizai.png create mode 100644 src/static/ckeditor/plugins/dedebizai/plugin.js diff --git a/src/admin/ai_dialog.php b/src/admin/ai_dialog.php new file mode 100644 index 00000000..2ebbc971 --- /dev/null +++ b/src/admin/ai_dialog.php @@ -0,0 +1,231 @@ +<?php +/** + * 富文本AI对话框 + * + * @version $id:ai_dialog.php 2025 tianya $ + * @package DedeBIZ.Dialog + * @copyright Copyright (c) 2022 DedeBIZ.COM + * @license GNU GPL v2 (https://www.dedebiz.com/license) + * @link https://www.dedebiz.com + */ +require_once(dirname(__FILE__) . "/config.php"); + +if (empty($f)) { + $f = 'form1.enclosure'; +} +if (empty($comeback)) { + $comeback = ''; +} +$addparm = ''; +if (!empty($CKEditor)) { + $addparm = '&CKEditor=' . $CKEditor; +} +if (!empty($CKEditorFuncNum)) { + $addparm .= '&CKEditorFuncNum=' . $CKEditorFuncNum; +} +if (!empty($noeditor)) { + $addparm .= '&noeditor=yes'; +} +?> +<!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"> + <title>AI提示词对话框</title> + <link rel="stylesheet" href="/static/web/css/font-awesome.min.css"> + <link rel="stylesheet" href="/static/web/css/bootstrap.min.css"> + <link rel="stylesheet" href="/static/web/css/admin.css"> + <script src="/static/web/js/jquery.min.js"></script> + <script src="/static/web/js/bootstrap.min.js"></script> + <script src="/static/web/js/admin.main.js"></script> +</head> + +<body class="p-3"> + <div class="card shadow-sm"> + <div class="card-header">小德AI助手:内容处理</div> + <div class="card-body"> + <div class="form-group"> + <div class="alert alert-warning mb-0" role="alert"> + <span>处理过程中请勿关闭当前对话框,否则富文本处理将终止</span> + </div> + </div> + <div class="form-group"> + <textarea id="prompt" class="form-control" style="height:160px" placeholder="请输入内容处理要求,例如:我需要将内容润色下,希望更专业"></textarea> + </div> + <div class="form-group"> + <label for="modelid" class="form-label">选择模型</label> + <select id="modelid" class="form-control"> + <?php + $dsql->SetQuery("SELECT AM.*,A.title as aititle FROM `#@__ai_model` AM LEFT JOIN `#@__ai` A ON A.id = AM.aiid ORDER BY AM.sortrank ASC,AM.id DESC"); + $dsql->Execute(); + while ($row = $dsql->GetObject()) { + ?> + <option value="<?php echo $row->id; ?>" <?php echo $row->isdefault == 1 ? ' selected' : ''; ?>><?php echo $row->model; ?> <?php echo $row->aititle; ?></option> + <?php + } + ?> + </select> + </div> + <div class="form-group"> + <button type="button" id="btnAIAction" class="btn btn-success btn-sm">确定</button> + </div> + </div> + </div> + <script> + $("#btnAIAction").click(async function() { + let body = window.opener.CKEDITOR.instances["<?php echo $f ?>"].getData(); + console.log(body); + let prompt = document.getElementById("prompt").value; + let modelid = document.getElementById("modelid").value; + let req = await fetch(`api.php?action=get_ai_server&pname=body_edit&modelid=${modelid}&prompt=${prompt}`); + let resp = await req.json(); + if (resp.code !== 0) { + ShowMsg("获取服务器地址失败"); + return + } + + let req2 = await fetch(`api.php?action=get_setbody_url`); + let resp2 = await req2.json(); + if (resp2.code !== 0) { + ShowMsg("获取服务器地址失败"); + return + } + let req3 = await fetch(resp2.data, { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + }, + body: new URLSearchParams({ + body: body + }) + }); + let resp3 = await req3.json(); + if (resp3.code !== 0) { + ShowMsg("提交原始内容失败"); + return + } + let eventSource = new EventSource(resp.data); + //新增状态跟踪变量 + let currentKey = null; + let tagBuffer = ""; + let isClosingTag = false; + $("#mdlAI").modal('hide'); + window.opener.CKEDITOR.instances["<?php echo $f ?>"].getCommand('openDedeBIZAi').disable(); + $("#btnAIAction").attr("disabled", "disabled"); + $("#prompt").attr("disabled", "disabled"); + $("#modelid").attr("disabled", "disabled"); + prompt = ""; + let bodyHtml = ""; + let lastChar = ""; + eventSource.onmessage = (event) => { + const chars = event.data.split(''); + chars.forEach(char => { + if (lastChar === '\\' && char === 'r') { + char = '<br>'; //替换为br标签 + lastChar = ""; //清空追踪字符 + } else { + lastChar = char; //记录当前字符 + } + if (char === '\\') { + return; //如果是反斜杠,跳过处理 + } + if (currentKey) { + if (char === '{') { + isClosingTag = true; + tagBuffer = '{'; + return; + } + if (isClosingTag) { + tagBuffer += char; + if (tagBuffer === `{/${currentKey}}`) { + if (currentKey == "content") { + window.opener.CKEDITOR.instances["<?php echo $f ?>"].setReadOnly(false); + bodyHtml = ""; + } else { + const input = document.querySelector(`[name="${currentKey}"]`); + if (input) $(input).prop("disabled", false).removeClass("disabled"); //恢复输入状态 + } + currentKey = null; + isClosingTag = false; + tagBuffer = ""; + return; + } + if (!`{/${currentKey}}`.startsWith(tagBuffer)) { + if (currentKey == "content") { + bodyHtml += tagBuffer; + console.log(bodyHtml); + window.opener.CKEDITOR.instances["<?php echo $f ?>"].setData(bodyHtml) + } else { + const input = document.querySelector(`[name="${currentKey}"]`); + if (input) input.value += tagBuffer; + } + isClosingTag = false; + tagBuffer = ""; + } + } else { + if (currentKey == "content") { + bodyHtml += char; + window.opener.CKEDITOR.instances["<?php echo $f ?>"].setData(bodyHtml) + } else { + const input = document.querySelector(`[name="${currentKey}"]`); + if (input) { + input.value += char; + input.scrollTop = input.scrollHeight; //滚动到底部 + } + } + } + } else { + if (char === '{') { + tagBuffer = '{'; + } else if (tagBuffer.startsWith('{')) { + tagBuffer += char; + if (char === '}') { + const match = tagBuffer.match(/{([^>]+)}/); + if (match) { + currentKey = match[1]; + if (currentKey == "content") { + window.opener.CKEDITOR.instances["<?php echo $f ?>"].setReadOnly(true); + } else { + const input = document.querySelector(`[name="${currentKey}"]`); + if (input) { + $(input).prop("disabled", true).addClass("disabled"); //仅禁用当前输入框 + input.value = ""; + } + } + } + tagBuffer = ""; + } + } + } + }); + }; + eventSource.onerror = (error) => { + if (error.target.readyState === EventSource.CONNECTING) { + ShowMsg("连接失败,请确保您已开启并正确配置了DedeBIZ小德AI助手。 <a class='text-success' href='https://www.dedebiz.com/ai?from=dedebiz' target='_blank'>如何配置?</a>"); + } else if (typeof error.data !== "undefined" && error.data !== "" && error.target.readyState !== EventSource.CLOSED) { + ShowMsg(error.data); + } + window.opener.CKEDITOR.instances["<?php echo $f ?>"].getCommand('openDedeBIZAi').enable(); + $("#btnAI").prop("disabled", false); + $("#btnAIAction").prop("disabled", false); + $("#prompt").prop("disabled", false); + $("#modelid").prop("disabled", false); + eventSource.close(); + }; + //监听特定事件close + eventSource.addEventListener('close', (event) => { + console.log('SSE connection closed:', event.data); + window.opener.CKEDITOR.instances["<?php echo $f ?>"].getCommand('openDedeBIZAi').enable(); + $("#btnAIAction").prop("disabled", false); + $("#prompt").prop("disabled", false); + $("#modelid").prop("disabled", false); + eventSource.close(); //关闭连接 + window.opener.CKEDITOR.instances["<?php echo $f ?>"].setReadOnly(false); + }); + }); + </script> +</body> + +</html> \ No newline at end of file diff --git a/src/admin/api.php b/src/admin/api.php index 7843cd86..66d89b33 100644 --- a/src/admin/api.php +++ b/src/admin/api.php @@ -16,7 +16,7 @@ require_once(DEDEINC.'/userlogin.class.php'); @set_time_limit(0); AjaxHead(); helper('cache'); -$action = isset($action) && in_array($action, array('is_need_check_code', 'has_new_version', 'get_changed_files', 'update_backup', 'get_update_versions', 'update', 'upload_image','get_ai_server')) ? $action : ''; +$action = isset($action) && in_array($action, array('is_need_check_code', 'has_new_version', 'get_changed_files', 'update_backup', 'get_update_versions', 'update', 'upload_image', 'get_ai_server', 'get_setbody_url')) ? $action : ''; $curDir = dirname(GetCurUrl());//当前目录 /** * 登录鉴权 @@ -74,7 +74,7 @@ if ($action === 'is_need_check_code') { $unQueryVer[] = "6.2.0"; } $row = $dsql->GetOne("SELECT COUNT(*) as dd FROM `#@__sysconfig` WHERE varname = 'cfg_bizcore_api'"); - if ($row['dd'] == 0) { + if (isset($row['dd']) && $row['dd'] == 0) { $unQueryVer[] = "6.2.3"; } if (!$dsql->IsTable("#@__sys_payment")) { @@ -83,6 +83,13 @@ if ($action === 'is_need_check_code') { if (!TableHasField("#@__arctype", "apienabled")) { $unQueryVer[] = "6.2.7"; } + if (!$dsql->IsTable("#@__ai")) { + $unQueryVer[] = "6.5.0"; + } + $row = $dsql->GetOne("SELECT COUNT(*) as dd FROM `#@__ai_prompt` WHERE pname = 'body_edit'"); + if (isset($row['dd']) && $row['dd'] == 0) { + $unQueryVer[] = "6.5.1"; + } if (count($unQueryVer) > 0) { $upsqls = GetUpdateSQL(); foreach ($unQueryVer as $vv) { @@ -459,5 +466,22 @@ if ($action === 'is_need_check_code') { "code" => 0, "data" => $url, )); +} else if($action === 'get_setbody_url') { + $params = $_GET; + unset($params['action']); + checkLogin(); + $params['timestamp'] = time(); // 加入时间戳 + $cuserLogin = new userLogin(); + $params['adminid'] = $cuserLogin->getUserID(); // 加入时间戳 + $params['ip'] = $_SERVER['REMOTE_ADDR'] ?? '127.0.0.1'; // 获取客户端IP + + ksort($params); // 按字典序排序 + $queryString = http_build_query($params); // 生成查询字符串 + $params['sign'] = md5($queryString . $cfg_ai_apikey); // 计算MD5签名 + $url = $cfg_ai_server . '/api/setbody?' . http_build_query($params); + echo json_encode(array( + "code" => 0, + "data" => $url, + )); } ?> \ No newline at end of file diff --git a/src/admin/archives_do.php b/src/admin/archives_do.php index 8fdb41f7..a2a416a1 100644 --- a/src/admin/archives_do.php +++ b/src/admin/archives_do.php @@ -658,7 +658,7 @@ else if ($dopost == "makekw") { if (strlen($keywords.$k) >= 60) { break; } else { - if (strlen($k) <= 2) continue; + if (strlen($k) <= 2 || $length == 3) continue; $keywords .= $k.','; } } @@ -666,7 +666,7 @@ else if ($dopost == "makekw") { if (strlen($keywords.$k) >= 60) { break; } else if (!in_array($k, $titleindexs)) { - if (strlen($k) <= 2) continue; + if (strlen($k) <= 2 || $length == 3) continue; $keywords .= $k.','; } } diff --git a/src/admin/inc/inc_archives_functions.php b/src/admin/inc/inc_archives_functions.php index d2c14263..5336edfa 100644 --- a/src/admin/inc/inc_archives_functions.php +++ b/src/admin/inc/inc_archives_functions.php @@ -560,7 +560,7 @@ function AnalyseHtmlBody($body, &$description, &$litpic, &$keywords, $dtype = '' if (strlen($keywords.$k) >= 60) { break; } else { - if (strlen($k) <= 2) continue; + if (strlen($k) <= 2 || $length == 3) continue; $keywords .= $k.','; } } @@ -568,7 +568,7 @@ function AnalyseHtmlBody($body, &$description, &$litpic, &$keywords, $dtype = '' if (strlen($keywords.$k) >= 60) { break; } else if (!in_array($k, $titleindexs)) { - if (strlen($k) <= 2) continue; + if (strlen($k) <= 2 || $length == 3) continue; $keywords .= $k.','; } } diff --git a/src/static/ckeditor/plugins/dedebizai/icons/dedebizai.png b/src/static/ckeditor/plugins/dedebizai/icons/dedebizai.png new file mode 100644 index 0000000000000000000000000000000000000000..a6f845c6f8087571515184d36845bbb4a4498e25 GIT binary patch literal 469 zcmV;`0V@89P)<h;3K|Lk000e1NJLTq000mG000mO0{{R3C@l|D00001b5ch_0olnc ze*gdg32;bRa{vGf6951U69E94oEQKA0LD;ER7L;)|M2ke;Nal&^z>|OYzqqu0000K z6cmbzit_UE3=9lUPfwqppP-<io}QjOJUkyCANctA_4W1q{QQ4^e*pmjg@uJ@XJ>VF zb<NGqfPjF@%gaGQK}t$W>FMcIR8+yi!J3+yR#sMge0;C3ulxJ^TU%SErlwh0S=QFp zJ3Bj}p`jNS7nYWmn3$NWtE*sOV7<M)r>CcCYHIQE@#^a8?(XhOOH0?+*K~Aretv!v z6BB)XeJw35DJdx-At3?+0;Hs*VAC`m0001}Nkl<Zc$`hoy$ga+6b0~e>SeE?K_Lht zBB`OFp@xe7`M|XyS|TVS8iX>`$RP!xCq6&UbopJl9|TAgVG2Ujfj@T0QdAYPA&dwx z=>wJmPeJ<&OYjNw$#;^&K=mFNF)3iI;97$z8FkM!n31t`{R-x>L|`3DForx}nXS}d zx{EzlYVJK>D_dcjojJMLy^F`@CU_b8benVtxjua~Y*VqTKGpdH%?dsdA>}Xg00000 LNkvXXu0mjfq*KRP literal 0 HcmV?d00001 diff --git a/src/static/ckeditor/plugins/dedebizai/plugin.js b/src/static/ckeditor/plugins/dedebizai/plugin.js new file mode 100644 index 00000000..45387826 --- /dev/null +++ b/src/static/ckeditor/plugins/dedebizai/plugin.js @@ -0,0 +1,28 @@ +CKEDITOR.plugins.add("dedebizai", { + icons: "dedebizai", + init: function (a) { + a.addCommand("openDedeBIZAi", + { + exec: function (a) { + var w = 800; + var h = 600; + var dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : window.screenX; + var dualScreenTop = window.screenTop !== undefined ? window.screenTop : window.screenY; + + var width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width; + var height = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height; + + var systemZoom = width / window.screen.availWidth; + var posLeft = (width - w) / 2 / systemZoom + dualScreenLeft; + var posTop = (height - h) / 2 / systemZoom + dualScreenTop; + window.open("./ai_dialog.php?f=" + a.name + "&noeditor=yes", "popUpImagesWin", "scrollbars=yes,resizable=yes,statebar=no,width=800,height=460,left=" + posLeft + ", top=" + posTop); + } + }); + a.ui.addButton("DedeBIZAi", + { + label: "AI助手", + command: "openDedeBIZAi", + toolbar: "insert" + }) + } +}); \ No newline at end of file diff --git a/src/system/inc/inc_fun_funAdmin.php b/src/system/inc/inc_fun_funAdmin.php index 61d07f38..2a65efcf 100755 --- a/src/system/inc/inc_fun_funAdmin.php +++ b/src/system/inc/inc_fun_funAdmin.php @@ -146,7 +146,7 @@ function SpGetEditor($fname, $fvalue, $nheight = "350", $etype = "Basic", $gtype if ($GLOBALS['cfg_db_language'] == "utf8mb4") { $emoji = ",emoji"; } - $addConfig = ",{allowedContent:true,pasteFilter:null,filebrowserImageUploadUrl:'./dialog/select_images_post.php',filebrowserUploadUrl:'./dialog/select_media_post.php?ck=1',extraPlugins:'html5video,html5audio,dedepagebreak,ddfilebrowser,mimage,textindent,tabletools,tableresize,tableselection,codesnippet{$emoji}',codeSnippet_theme: 'default'}"; + $addConfig = ",{allowedContent:true,pasteFilter:null,filebrowserImageUploadUrl:'./dialog/select_images_post.php',filebrowserUploadUrl:'./dialog/select_media_post.php?ck=1',extraPlugins:'html5video,html5audio,dedepagebreak,ddfilebrowser,mimage,dedebizai,textindent,tabletools,tableresize,tableselection,codesnippet{$emoji}',codeSnippet_theme: 'default'}"; } if (defined('DEDEUSER')) { $addConfig = ",{filebrowserImageUploadUrl:'api.php?action=upload&type=litpic&ck=1',filebrowserUploadUrl:'api.php?action=upload&type=media&ck=1',extraPlugins:'html5video,html5audio,textindent',filebrowserImageBrowseDisabled:true}";