Merge pull request #336 from chengzhongxue/main
优化twikoo,文章ai摘要 资源文件, twikoo更新到v1.6.17
This commit is contained in:
commit
c3864b3248
|
@ -0,0 +1,374 @@
|
|||
(function () {
|
||||
|
||||
let ai = GLOBAL_CONFIG.source.postAi.ai;
|
||||
let randomNum = GLOBAL_CONFIG.source.postAi.randomNum; //按钮最大的随机次数,也就是一篇文章最大随机出来几种
|
||||
let basicWordCount = GLOBAL_CONFIG.source.postAi.basicWordCount; // 最低获取字符数, 最小1000, 最大1999
|
||||
let btnLink = GLOBAL_CONFIG.source.postAi.btnLink;
|
||||
let gptName = GLOBAL_CONFIG.source.postAi.gptName;
|
||||
let modeName = GLOBAL_CONFIG.source.postAi.modeName;
|
||||
let switchBtn = GLOBAL_CONFIG.source.postAi.switchBtn //# 可以配置是否显示切换按钮 以切换tianli/local
|
||||
let keys = GLOBAL_CONFIG.source.postAi.keys;
|
||||
let Referers = GLOBAL_CONFIG.source.postAi.Referers;
|
||||
|
||||
// 当前随机到的ai摘要到index
|
||||
let lastAiRandomIndex = -1;
|
||||
let animationRunning = true; // 标志变量,控制动画函数的运行
|
||||
// 当前gpt模式
|
||||
let mode = modeName
|
||||
// 刷新点击次数
|
||||
let refreshNum = 0
|
||||
// 记录上一次传递给aiAbstract的参数
|
||||
let prevParam;
|
||||
const aiTitleRefreshIcon = document.querySelector(".ai-title .haofont.hao-icon-arrow-rotate-right")
|
||||
const explanation = document.querySelector(".ai-explanation");
|
||||
const post_ai = document.querySelector(".post-ai");
|
||||
let ai_str = "";
|
||||
let ai_str_length = "";
|
||||
let delay_init = 600;
|
||||
let i = 0;
|
||||
let j = 0;
|
||||
let sto = [];
|
||||
let elapsed = 0;
|
||||
const animate = timestamp => {
|
||||
if (!animationRunning) {
|
||||
return; // 动画函数停止运行
|
||||
}
|
||||
if (!animate.start) animate.start = timestamp;
|
||||
elapsed = timestamp - animate.start;
|
||||
if (elapsed >= 20) {
|
||||
animate.start = timestamp;
|
||||
if (i < ai_str_length - 1) {
|
||||
let char = ai_str.charAt(i + 1);
|
||||
let delay = /[,.,。!?!?]/.test(char) ? 150 : 20;
|
||||
if (explanation.firstElementChild) {
|
||||
explanation.removeChild(explanation.firstElementChild);
|
||||
}
|
||||
explanation.innerHTML += char;
|
||||
let div = document.createElement("div");
|
||||
div.className = "ai-cursor";
|
||||
explanation.appendChild(div);
|
||||
i++;
|
||||
if (delay === 150) {
|
||||
document.querySelector(".ai-explanation .ai-cursor").style.opacity = "0";
|
||||
}
|
||||
if (i === ai_str_length - 1) {
|
||||
observer.disconnect(); // 暂停监听
|
||||
explanation.removeChild(explanation.firstElementChild);
|
||||
}
|
||||
sto[0] = setTimeout(() => {
|
||||
requestAnimationFrame(animate);
|
||||
}, delay);
|
||||
}
|
||||
} else {
|
||||
requestAnimationFrame(animate);
|
||||
}
|
||||
};
|
||||
const observer = new IntersectionObserver(
|
||||
entries => {
|
||||
let isVisible = entries[0].isIntersecting;
|
||||
animationRunning = isVisible; // 标志变量更新
|
||||
if (animationRunning) {
|
||||
delay_init = i === 0 ? 200 : 20;
|
||||
sto[1] = setTimeout(() => {
|
||||
if (j) {
|
||||
i = 0;
|
||||
j = 0;
|
||||
}
|
||||
if (i === 0) {
|
||||
explanation.innerHTML = ai_str.charAt(0);
|
||||
}
|
||||
requestAnimationFrame(animate);
|
||||
}, delay_init);
|
||||
}
|
||||
},
|
||||
{ threshold: 0 }
|
||||
);
|
||||
function clearSTO() {
|
||||
if (sto.length) {
|
||||
sto.forEach(item => {
|
||||
if (item) {
|
||||
clearTimeout(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
function startAI(str, df = true) {
|
||||
i = 0; //重置计数器
|
||||
j = 1;
|
||||
clearSTO();
|
||||
animationRunning = false;
|
||||
elapsed = 0;
|
||||
observer.disconnect(); // 暂停上一次监听
|
||||
explanation.innerHTML = df ? "生成中. . ." : "请等待. . .";
|
||||
ai_str = str;
|
||||
ai_str_length = ai_str.length;
|
||||
observer.observe(post_ai); //启动新监听
|
||||
}
|
||||
|
||||
async function aiAbstract(num = basicWordCount) {
|
||||
i = 0; //重置计数器
|
||||
j = 1;
|
||||
clearSTO();
|
||||
animationRunning = false;
|
||||
elapsed = 0;
|
||||
observer.disconnect(); // 暂停上一次监听
|
||||
if (mode === "tianli") {
|
||||
num = Math.max(10, Math.min(2000, num));
|
||||
const options = {
|
||||
key: keys,
|
||||
Referer: Referers
|
||||
};
|
||||
|
||||
const truncateDescription = getTitleAndContent(num);
|
||||
const queryParams = `key=${options.key}&content=${truncateDescription}`;
|
||||
const requestOptions = {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Referer: options.Referer
|
||||
},
|
||||
};
|
||||
try {
|
||||
let animationInterval = null
|
||||
if (animationInterval) clearInterval(animationInterval);
|
||||
animationInterval = setInterval(() => {
|
||||
const animationText = "生成中" + ".".repeat(j);
|
||||
explanation.innerHTML = animationText;
|
||||
j = (j % 3) + 1; // 在 1、2、3 之间循环
|
||||
}, 500);
|
||||
const response = await fetch(`https://summary.tianli0.top/?${queryParams}`, requestOptions);
|
||||
let result;
|
||||
if (response.status === 403) {
|
||||
result = {
|
||||
summary: "403 refer与key不匹配,本地无法显示。"
|
||||
}
|
||||
} else if (response.status === 500) {
|
||||
result = {
|
||||
summary: "500 系统内部错误"
|
||||
}
|
||||
} else {
|
||||
result = await response.json();
|
||||
}
|
||||
const summary = result.summary.trim();
|
||||
setTimeout(() => {
|
||||
aiTitleRefreshIcon.style.opacity = "1";
|
||||
}, 300)
|
||||
startAI(summary);
|
||||
clearInterval(animationInterval)
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
} else {
|
||||
const strArr = ai.split(",").map(item => item.trim()); // 将字符串转换为数组,去除每个字符串前后的空格
|
||||
if (strArr.length !== 1) {
|
||||
let randomIndex = Math.floor(Math.random() * strArr.length); // 随机生成一个索引
|
||||
while (randomIndex === lastAiRandomIndex) { // 如果随机到了上次的索引
|
||||
randomIndex = Math.floor(Math.random() * strArr.length); // 再次随机
|
||||
}
|
||||
lastAiRandomIndex = randomIndex; // 更新上次随机到的索引
|
||||
startAI(strArr[randomIndex]);
|
||||
} else {
|
||||
startAI(strArr[0])
|
||||
}
|
||||
setTimeout(() => {
|
||||
aiTitleRefreshIcon.style.opacity = "1";
|
||||
}, 600)
|
||||
}
|
||||
}
|
||||
|
||||
function aiRecommend() {
|
||||
i = 0; //重置计数器
|
||||
j = 1;
|
||||
clearSTO();
|
||||
animationRunning = false;
|
||||
elapsed = 0;
|
||||
explanation.innerHTML = "生成中. . .";
|
||||
ai_str = "";
|
||||
ai_str_length = "";
|
||||
observer.disconnect(); // 暂停上一次监听
|
||||
sto[2] = setTimeout(() => {
|
||||
explanation.innerHTML = recommendList();
|
||||
}, 600);
|
||||
}
|
||||
function aiGoHome() {
|
||||
startAI("正在前往博客主页...", false);
|
||||
sto[2] = setTimeout(() => {
|
||||
pjax.loadUrl("/");
|
||||
}, 1000);
|
||||
}
|
||||
const ai_btn_item = document.querySelectorAll(".ai-btn-item");
|
||||
function Introduce() {
|
||||
if (mode == "tianli") {
|
||||
startAI("我是文章辅助AI: TianliGPT,点击下方的按钮,让我生成本文简介、推荐相关文章等。")
|
||||
} else {
|
||||
startAI("我是文章辅助AI: " + gptName + " GPT,点击下方的按钮,让我生成本文简介、推荐相关文章等。")
|
||||
}
|
||||
}
|
||||
function aiTitleRefreshIconClick() {
|
||||
aiTitleRefreshIcon.click()
|
||||
}
|
||||
const aiFunctions = [Introduce, aiTitleRefreshIconClick, aiRecommend, aiGoHome];
|
||||
ai_btn_item.forEach((item, index) => {
|
||||
item.addEventListener("click", () => {
|
||||
aiFunctions[index]();
|
||||
});
|
||||
});
|
||||
|
||||
function recommendList() {
|
||||
let thumbnail = document.querySelectorAll('.relatedPosts-list a');
|
||||
if (!thumbnail.length) {
|
||||
const cardRecentPost = document.querySelector('.card-widget.card-recent-post');
|
||||
if (!cardRecentPost) return '';
|
||||
|
||||
thumbnail = cardRecentPost.querySelectorAll('.aside-list-item a');
|
||||
|
||||
let list = '';
|
||||
for (let i = 0; i < thumbnail.length; i++) {
|
||||
const item = thumbnail[i];
|
||||
list += `<div class="ai-recommend-item"><span class="index">${i + 1}:</span><a href="javascript:;" onclick="pjax.loadUrl('${item.href}')" title="${item.title}" data-pjax-state="">${item.title}</a></div>`;
|
||||
}
|
||||
|
||||
return `很抱歉,无法找到类似的文章,你也可以看看本站最新发布的文章:<br /><div class="ai-recommend">${list}</div>`;
|
||||
}
|
||||
|
||||
let list = '';
|
||||
for (let i = 0; i < thumbnail.length; i++) {
|
||||
const item = thumbnail[i];
|
||||
list += `<div class="ai-recommend-item"><span>推荐${i + 1}:</span><a href="javascript:;" onclick="pjax.loadUrl('${item.href}')" title="${item.title}" data-pjax-state="">${item.title}</a></div>`;
|
||||
}
|
||||
|
||||
return `推荐文章:<br /><div class="ai-recommend">${list}</div>`;
|
||||
}
|
||||
|
||||
|
||||
function changeShowMode() {
|
||||
if (mode === "tianli") {
|
||||
mode = "local";
|
||||
document.getElementById("ai-tag").innerHTML = gptName + " GPT";
|
||||
aiAbstract(basicWordCount);
|
||||
} else {
|
||||
mode = "tianli";
|
||||
document.getElementById("ai-tag").innerHTML = "Tianli GPT";
|
||||
|
||||
const truncateDescription = getTitleAndContent(basicWordCount);
|
||||
let value = Math.floor(Math.random() * randomNum) + basicWordCount;
|
||||
while (value === prevParam || truncateDescription.length - value === prevParam) {
|
||||
value = Math.floor(Math.random() * randomNum) + basicWordCount;
|
||||
}
|
||||
aiTitleRefreshIcon.style.opacity = "0.2";
|
||||
aiTitleRefreshIcon.style.transitionDuration = "0.3s";
|
||||
aiTitleRefreshIcon.style.transform = "rotate(" + 360 * refreshNum + "deg)";
|
||||
if (truncateDescription.length <= 1000) {
|
||||
let param = truncateDescription.length - Math.floor(Math.random() * randomNum);
|
||||
while (param === prevParam) {
|
||||
param = truncateDescription.length - Math.floor(Math.random() * randomNum);
|
||||
}
|
||||
aiAbstract(param);
|
||||
prevParam = param;
|
||||
} else {
|
||||
aiAbstract(value);
|
||||
prevParam = value;
|
||||
}
|
||||
refreshNum++;
|
||||
}
|
||||
}
|
||||
|
||||
//- 监听tag点击事件
|
||||
document.getElementById("ai-tag").addEventListener("click", () => {
|
||||
if (mode === "tianli") {
|
||||
document.querySelectorAll(".ai-btn-item").forEach(item => item.style.display = "none");
|
||||
document.getElementById("go-tianli-blog").style.display = "block";
|
||||
startAI("你好,我是Tianli开发的摘要生成助理TianliGPT,是一个基于GPT-4的生成式AI。我在这里只负责摘要的预生成和显示,你无法与我直接沟通,如果你也需要一个这样的AI摘要接口,可以在下方购买。(暂未开放购买,敬请期待)")
|
||||
} else {
|
||||
document.getElementById("go-tianli-blog").style.display = "none";
|
||||
startAI("你好,我是本站摘要生成助理" + gptName + " GPT,是一个基于GPT-4的生成式AI。我在这里只负责摘要的预生成和显示,你无法与我直接沟通。")
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
aiTitleRefreshIcon.addEventListener("click", () => {
|
||||
const truncateDescription = getTitleAndContent(basicWordCount);
|
||||
let value = Math.floor(Math.random() * randomNum) + basicWordCount;
|
||||
while (value === prevParam || truncateDescription.length - value === prevParam) {
|
||||
value = Math.floor(Math.random() * randomNum) + basicWordCount;
|
||||
}
|
||||
aiTitleRefreshIcon.style.opacity = "0.2";
|
||||
aiTitleRefreshIcon.style.transitionDuration = "0.3s";
|
||||
aiTitleRefreshIcon.style.transform = "rotate(" + 360 * refreshNum + "deg)";
|
||||
if (truncateDescription.length <= 1000) {
|
||||
let param = truncateDescription.length - Math.floor(Math.random() * randomNum);
|
||||
while (param === prevParam) {
|
||||
param = truncateDescription.length - Math.floor(Math.random() * randomNum);
|
||||
}
|
||||
aiAbstract(param);
|
||||
prevParam = param;
|
||||
} else {
|
||||
aiAbstract(value);
|
||||
prevParam = value;
|
||||
}
|
||||
showAiBtn();
|
||||
refreshNum++;
|
||||
});
|
||||
|
||||
document.getElementById("go-tianli-blog").addEventListener("click", () => {
|
||||
window.open(btnLink, "_blank");
|
||||
});
|
||||
|
||||
if (switchBtn) {
|
||||
document.getElementById("ai-Toggle").addEventListener("click", () => {
|
||||
changeShowMode()
|
||||
});
|
||||
}
|
||||
|
||||
function showAiBtn() {
|
||||
document.querySelectorAll(".ai-btn-item").forEach(item => {
|
||||
if (item.id !== "go-tianli-blog") {
|
||||
item.style.display = "block";
|
||||
}
|
||||
if (item.id === "go-tianli-blog") {
|
||||
item.style.display = "none";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//读取文章中的所有文本
|
||||
function getTitleAndContent(basicWordCount) {
|
||||
try {
|
||||
const title = document.title;
|
||||
const container = document.querySelector('#post #article-container');
|
||||
if (!container) {
|
||||
console.warn('TianliGPT:找不到文章容器。请尝试将引入的代码放入到文章容器之后。如果本身没有打算使用摘要功能可以忽略此提示。');
|
||||
return '';
|
||||
}
|
||||
const paragraphs = container.getElementsByTagName('p');
|
||||
|
||||
const headings = container.querySelectorAll('h1, h2, h3, h4, h5');
|
||||
let content = '';
|
||||
|
||||
for (let h of headings) {
|
||||
content += h.innerText + ' ';
|
||||
}
|
||||
|
||||
for (let p of paragraphs) {
|
||||
// 移除包含'http'的链接
|
||||
const filteredText = p.innerText.replace(/https?:\/\/[^\s]+/g, '');
|
||||
content += filteredText;
|
||||
}
|
||||
|
||||
const combinedText = title + ' ' + content;
|
||||
let wordLimit = 1000;
|
||||
if (basicWordCount !== "undefined") {
|
||||
wordLimit = basicWordCount;
|
||||
}
|
||||
const truncatedText = combinedText.slice(0, wordLimit);
|
||||
return truncatedText;
|
||||
} catch (e) {
|
||||
console.error('TianliGPT错误:可能由于一个或多个错误导致没有正常运行,原因出在获取文章容器中的内容失败,或者可能是在文章转换过程中失败。', e);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
aiAbstract();
|
||||
showAiBtn()
|
||||
})()
|
|
@ -0,0 +1,158 @@
|
|||
var commentBarrageConfig = {
|
||||
//同时最多显示弹幕数
|
||||
maxBarrage: GLOBAL_CONFIG.source.twikoo.maxBarrage,
|
||||
//弹幕显示间隔时间ms
|
||||
barrageTime: GLOBAL_CONFIG.source.twikoo.barrageTime,
|
||||
//twikoo部署地址腾讯云的为环境ID
|
||||
twikooUrl: GLOBAL_CONFIG.source.twikoo.twikooUrl,
|
||||
//token获取见上方
|
||||
accessToken: GLOBAL_CONFIG.source.twikoo.accessToken,
|
||||
mailMd5: GLOBAL_CONFIG.source.twikoo.mailMd5,
|
||||
pageUrl: window.location.pathname,
|
||||
barrageTimer: [],
|
||||
barrageList: [],
|
||||
barrageIndex: 0,
|
||||
dom: document.querySelector('.comment-barrage'),
|
||||
}
|
||||
|
||||
var commentInterval = null;
|
||||
var hoverOnCommentBarrage = false;
|
||||
|
||||
$(".comment-barrage").hover(function () {
|
||||
hoverOnCommentBarrage = true;
|
||||
//console.log("热评悬浮");
|
||||
}, function () {
|
||||
hoverOnCommentBarrage = false;
|
||||
//console.log("停止悬浮");
|
||||
});
|
||||
|
||||
function initCommentBarrage() {
|
||||
//console.log("开始创建热评")
|
||||
|
||||
var data = JSON.stringify({
|
||||
"event": "COMMENT_GET",
|
||||
"commentBarrageConfig.accessToken": commentBarrageConfig.accessToken,
|
||||
"url": commentBarrageConfig.pageUrl
|
||||
});
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.withCredentials = true;
|
||||
xhr.addEventListener("readystatechange", function () {
|
||||
if (this.readyState === 4) {
|
||||
commentBarrageConfig.barrageList = commentLinkFilter(JSON.parse(this.responseText).data);
|
||||
commentBarrageConfig.dom.innerHTML = '';
|
||||
}
|
||||
});
|
||||
xhr.open("POST", commentBarrageConfig.twikooUrl);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.send(data);
|
||||
|
||||
|
||||
clearInterval(commentInterval);
|
||||
commentInterval = null;
|
||||
|
||||
commentInterval = setInterval(() => {
|
||||
if (commentBarrageConfig.barrageList.length && !hoverOnCommentBarrage) {
|
||||
popCommentBarrage(commentBarrageConfig.barrageList[commentBarrageConfig.barrageIndex]);
|
||||
commentBarrageConfig.barrageIndex += 1;
|
||||
commentBarrageConfig.barrageIndex %= commentBarrageConfig.barrageList.length;
|
||||
}
|
||||
if ((commentBarrageConfig.barrageTimer.length > (commentBarrageConfig.barrageList.length > commentBarrageConfig.maxBarrage ? commentBarrageConfig.maxBarrage : commentBarrageConfig.barrageList.length)) && !hoverOnCommentBarrage) {
|
||||
removeCommentBarrage(commentBarrageConfig.barrageTimer.shift())
|
||||
}
|
||||
}, commentBarrageConfig.barrageTime)
|
||||
}
|
||||
|
||||
function commentLinkFilter(data) {
|
||||
data.sort((a, b) => {
|
||||
return a.created - b.created;
|
||||
})
|
||||
let newData = [];
|
||||
data.forEach(item => {
|
||||
newData.push(...getCommentReplies(item));
|
||||
});
|
||||
return newData;
|
||||
}
|
||||
|
||||
function getCommentReplies(item) {
|
||||
if (item.replies) {
|
||||
let replies = [item];
|
||||
item.replies.forEach(item => {
|
||||
replies.push(...getCommentReplies(item));
|
||||
})
|
||||
return replies;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function popCommentBarrage(data) {
|
||||
|
||||
let barrage = document.createElement('div');
|
||||
let width = commentBarrageConfig.dom.clientWidth;
|
||||
let height = commentBarrageConfig.dom.clientHeight;
|
||||
barrage.className = 'comment-barrage-item'
|
||||
barrage.innerHTML = `
|
||||
<div class="barrageHead">
|
||||
<a class="barrageTitle
|
||||
${data.mailMd5 === commentBarrageConfig.mailMd5 ? "barrageBloggerTitle" : ""}" href="#post-comment">
|
||||
${data.mailMd5 === commentBarrageConfig.mailMd5 ? "博主" : "热评"}
|
||||
</a>
|
||||
<div class="barrageNick">${data.nick}</div>
|
||||
<img class="barrageAvatar" src="https://cravatar.cn/avatar/${data.mailMd5}"/>
|
||||
<a class="comment-barrage-close" href="javascript:heo.switchCommentBarrage()"><i class="haofont hao-icon-xmark"></i></a>
|
||||
</div>
|
||||
<a class="barrageContent" href="#${data.id}">${data.comment}</a>
|
||||
`
|
||||
commentBarrageConfig.barrageTimer.push(barrage);
|
||||
commentBarrageConfig.dom.append(barrage);
|
||||
}
|
||||
|
||||
function removeCommentBarrage(barrage) {
|
||||
barrage.className = 'comment-barrage-item out';
|
||||
setTimeout(() => {
|
||||
commentBarrageConfig.dom.removeChild(barrage);
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
|
||||
// 自动隐藏
|
||||
document.addEventListener('scroll', btf.throttle(function () {
|
||||
//滚动条高度+视窗高度 = 可见区域底部高度
|
||||
var visibleBottom = window.scrollY + document.documentElement.clientHeight;
|
||||
//可见区域顶部高度
|
||||
var visibleTop = window.scrollY;
|
||||
// 获取翻页按钮容器
|
||||
var pagination = document.querySelector('.comment-barrage');
|
||||
// 获取位置监测容器,此处采用评论区
|
||||
var eventlistner = document.getElementById('post-comment');
|
||||
if (eventlistner && pagination) {
|
||||
var centerY = eventlistner.offsetTop + (eventlistner.offsetHeight / 2);
|
||||
if (document.body.clientWidth > 768) {
|
||||
if (centerY > visibleBottom) {
|
||||
pagination.style.bottom = '0';
|
||||
} else {
|
||||
pagination.style.bottom = '-200px';
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 200))
|
||||
|
||||
initCommentBarrage();
|
||||
|
||||
if (localStorage.getItem('commentBarrageSwitch') !== 'false') {
|
||||
$(".comment-barrage").show();
|
||||
$(".menu-commentBarrage-text").text("关闭热评");
|
||||
document.querySelector("#consoleCommentBarrage").classList.add("on");
|
||||
|
||||
} else {
|
||||
$(".comment-barrage").hide();
|
||||
$(".menu-commentBarrage-text").text("显示热评");
|
||||
document.querySelector("#consoleCommentBarrage").classList.remove("on");
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
document.addEventListener('pjax:send', function () {
|
||||
clearInterval(commentInterval);
|
||||
});
|
File diff suppressed because one or more lines are too long
|
@ -1,174 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org">
|
||||
|
||||
<!-- 评论弹幕 -->
|
||||
|
||||
<script data-pjax=""
|
||||
th:fragment="commentBarrage"
|
||||
th:if="${theme.config.comments.twikooEnable && #strings.equals(theme.config.comments.use, 'Twikoo') && not #strings.isEmpty(theme.config.comments.twikoos.envId)
|
||||
&& not #strings.isEmpty(theme.config.comments.twikoos.accessToken)}">
|
||||
|
||||
|
||||
var commentBarrageConfig = {
|
||||
//同时最多显示弹幕数
|
||||
maxBarrage: [[${ theme.config.comments.twikoos.maxBarrage }]],
|
||||
//弹幕显示间隔时间ms
|
||||
barrageTime: [[${ theme.config.comments.twikoos.barrageTime }]],
|
||||
//twikoo部署地址腾讯云的为环境ID
|
||||
twikooUrl: "[(${theme.config.comments.twikoos.envId})]",
|
||||
//token获取见上方
|
||||
accessToken: "[(${theme.config.comments.twikoos.accessToken})]",
|
||||
mailMd5: "[(${theme.config.comments.twikoos.mailMd5})]",
|
||||
pageUrl: window.location.pathname,
|
||||
barrageTimer: [],
|
||||
barrageList: [],
|
||||
barrageIndex: 0,
|
||||
dom: document.querySelector('.comment-barrage'),
|
||||
}
|
||||
|
||||
var commentInterval = null;
|
||||
var hoverOnCommentBarrage = false;
|
||||
|
||||
$(".comment-barrage").hover(function () {
|
||||
hoverOnCommentBarrage = true;
|
||||
//console.log("热评悬浮");
|
||||
}, function () {
|
||||
hoverOnCommentBarrage = false;
|
||||
//console.log("停止悬浮");
|
||||
});
|
||||
|
||||
function initCommentBarrage() {
|
||||
//console.log("开始创建热评")
|
||||
|
||||
var data = JSON.stringify({
|
||||
"event": "COMMENT_GET",
|
||||
"commentBarrageConfig.accessToken": commentBarrageConfig.accessToken,
|
||||
"url": commentBarrageConfig.pageUrl
|
||||
});
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.withCredentials = true;
|
||||
xhr.addEventListener("readystatechange", function () {
|
||||
if (this.readyState === 4) {
|
||||
commentBarrageConfig.barrageList = commentLinkFilter(JSON.parse(this.responseText).data);
|
||||
commentBarrageConfig.dom.innerHTML = '';
|
||||
}
|
||||
});
|
||||
xhr.open("POST", commentBarrageConfig.twikooUrl);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.send(data);
|
||||
|
||||
|
||||
clearInterval(commentInterval);
|
||||
commentInterval = null;
|
||||
|
||||
commentInterval = setInterval(() => {
|
||||
if (commentBarrageConfig.barrageList.length && !hoverOnCommentBarrage) {
|
||||
popCommentBarrage(commentBarrageConfig.barrageList[commentBarrageConfig.barrageIndex]);
|
||||
commentBarrageConfig.barrageIndex += 1;
|
||||
commentBarrageConfig.barrageIndex %= commentBarrageConfig.barrageList.length;
|
||||
}
|
||||
if ((commentBarrageConfig.barrageTimer.length > (commentBarrageConfig.barrageList.length > commentBarrageConfig.maxBarrage ? commentBarrageConfig.maxBarrage : commentBarrageConfig.barrageList.length)) && !hoverOnCommentBarrage) {
|
||||
removeCommentBarrage(commentBarrageConfig.barrageTimer.shift())
|
||||
}
|
||||
}, commentBarrageConfig.barrageTime)
|
||||
}
|
||||
|
||||
function commentLinkFilter(data) {
|
||||
data.sort((a, b) => {
|
||||
return a.created - b.created;
|
||||
})
|
||||
let newData = [];
|
||||
data.forEach(item => {
|
||||
newData.push(...getCommentReplies(item));
|
||||
});
|
||||
return newData;
|
||||
}
|
||||
|
||||
function getCommentReplies(item) {
|
||||
if (item.replies) {
|
||||
let replies = [item];
|
||||
item.replies.forEach(item => {
|
||||
replies.push(...getCommentReplies(item));
|
||||
})
|
||||
return replies;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function popCommentBarrage(data) {
|
||||
|
||||
let barrage = document.createElement('div');
|
||||
let width = commentBarrageConfig.dom.clientWidth;
|
||||
let height = commentBarrageConfig.dom.clientHeight;
|
||||
barrage.className = 'comment-barrage-item'
|
||||
barrage.innerHTML = `
|
||||
<div class="barrageHead">
|
||||
<a class="barrageTitle
|
||||
${data.mailMd5 === commentBarrageConfig.mailMd5 ? "barrageBloggerTitle" : ""}" href="#post-comment">
|
||||
${data.mailMd5 === commentBarrageConfig.mailMd5 ? "博主" : "热评"}
|
||||
</a>
|
||||
<div class="barrageNick">${data.nick}</div>
|
||||
<img class="barrageAvatar" src="https://cravatar.cn/avatar/${data.mailMd5}"/>
|
||||
<a class="comment-barrage-close" href="javascript:heo.switchCommentBarrage()"><i class="haofont hao-icon-xmark"></i></a>
|
||||
</div>
|
||||
<a class="barrageContent" href="#${data.id}">${data.comment}</a>
|
||||
`
|
||||
commentBarrageConfig.barrageTimer.push(barrage);
|
||||
commentBarrageConfig.dom.append(barrage);
|
||||
}
|
||||
|
||||
function removeCommentBarrage(barrage) {
|
||||
barrage.className = 'comment-barrage-item out';
|
||||
setTimeout(() => {
|
||||
commentBarrageConfig.dom.removeChild(barrage);
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
|
||||
// 自动隐藏
|
||||
document.addEventListener('scroll', btf.throttle(function () {
|
||||
//滚动条高度+视窗高度 = 可见区域底部高度
|
||||
var visibleBottom = window.scrollY + document.documentElement.clientHeight;
|
||||
//可见区域顶部高度
|
||||
var visibleTop = window.scrollY;
|
||||
// 获取翻页按钮容器
|
||||
var pagination = document.querySelector('.comment-barrage');
|
||||
// 获取位置监测容器,此处采用评论区
|
||||
var eventlistner = document.getElementById('post-comment');
|
||||
if (eventlistner && pagination) {
|
||||
var centerY = eventlistner.offsetTop + (eventlistner.offsetHeight / 2);
|
||||
if (document.body.clientWidth > 768) {
|
||||
if (centerY > visibleBottom) {
|
||||
pagination.style.bottom = '0';
|
||||
} else {
|
||||
pagination.style.bottom = '-200px';
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 200))
|
||||
|
||||
initCommentBarrage();
|
||||
|
||||
if (localStorage.getItem('commentBarrageSwitch') !== 'false') {
|
||||
$(".comment-barrage").show();
|
||||
$(".menu-commentBarrage-text").text("关闭热评");
|
||||
document.querySelector("#consoleCommentBarrage").classList.add("on");
|
||||
|
||||
} else {
|
||||
$(".comment-barrage").hide();
|
||||
$(".menu-commentBarrage-text").text("显示热评");
|
||||
document.querySelector("#consoleCommentBarrage").classList.remove("on");
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
document.addEventListener('pjax:send', function () {
|
||||
clearInterval(commentInterval);
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
</html>
|
|
@ -217,12 +217,28 @@
|
|||
css: 'https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/fancybox/3.5.7/jquery.fancybox.min.css'
|
||||
},
|
||||
twikoo:{
|
||||
js: '/themes/theme-hao/assets/libs/twikoo/twikoo.all.min.js'
|
||||
js: '/themes/theme-hao/assets/libs/twikoo/twikoo.all.min.js',
|
||||
maxBarrage: [[${ theme.config.comments.twikoos.maxBarrage }]],
|
||||
barrageTime: [[${ theme.config.comments.twikoos.barrageTime }]],
|
||||
twikooUrl: "[(${theme.config.comments.twikoos.envId})]",
|
||||
accessToken: "[(${theme.config.comments.twikoos.accessToken})]",
|
||||
mailMd5: "[(${theme.config.comments.twikoos.mailMd5})]",
|
||||
},
|
||||
welcome:{
|
||||
key:"[(${theme.config.sidebar.welcome.key})]",
|
||||
locationLng: [[${theme.config.sidebar.welcome.locationLng}]],
|
||||
locationLat: [[${theme.config.sidebar.welcome.locationLat}]],
|
||||
},
|
||||
postAi:{
|
||||
ai : '[(${post.status.excerpt})]',
|
||||
randomNum : [[${theme.config.post.aiDescription.randomNum}]], //按钮最大的随机次数,也就是一篇文章最大随机出来几种
|
||||
basicWordCount : [[${theme.config.post.aiDescription.basicWordCount}]], // 最低获取字符数, 最小1000, 最大1999
|
||||
btnLink : "[(${theme.config.post.aiDescription.btnLink})]",
|
||||
gptName : "[(${theme.config.post.aiDescription.gptName})]",
|
||||
modeName : [[${theme.config.post.aiDescription.mode}]],
|
||||
switchBtn : [[${theme.config.post.aiDescription.switchBtn}]], //# 可以配置是否显示切换按钮 以切换tianli/local
|
||||
keys : "[(${theme.config.post.aiDescription.key})]",
|
||||
Referers : "[(${theme.config.post.aiDescription.Referer})]",
|
||||
}
|
||||
},
|
||||
date_suffix: {
|
||||
|
|
|
@ -95,7 +95,10 @@
|
|||
<script data-pjax src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/Swiper/8.0.6/swiper-bundle.min.js"></script>
|
||||
|
||||
<!-- 评论弹幕 -->
|
||||
<script th:replace="~{modules/comment/commentBarrage :: commentBarrage}"></script>
|
||||
<script th:if="${theme.config.comments.twikooEnable && #strings.equals(theme.config.comments.use, 'Twikoo') &&
|
||||
not #strings.isEmpty(theme.config.comments.twikoos.envId) &&
|
||||
not #strings.isEmpty(theme.config.comments.twikoos.accessToken)}" data-pjax=""
|
||||
th:src="${assets_link + '/libs/twikoo/commentBarrage.js'}"></script>
|
||||
|
||||
<!-- Tocbot 目录生成 start -->
|
||||
<th:block th:replace="~{modules/common/toc-bot :: toc-bot}"></th:block>
|
||||
|
|
|
@ -1,388 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org">
|
||||
|
||||
<!-- 文章ai摘要 -->
|
||||
|
||||
<script data-pjax th:fragment="postHeadAiDescription" th:if="${theme.config.post.aiDescription.aiDescriptionEnable}">
|
||||
|
||||
|
||||
(function () {
|
||||
|
||||
let ai = "[[${post.status.excerpt}]]"
|
||||
let randomNum = [[${theme.config.post.aiDescription.randomNum}]] //按钮最大的随机次数,也就是一篇文章最大随机出来几种
|
||||
let basicWordCount = [[${theme.config.post.aiDescription.basicWordCount}]] // 最低获取字符数, 最小1000, 最大1999
|
||||
let btnLink = "[[${theme.config.post.aiDescription.btnLink}]]"
|
||||
let gptName = "[[${theme.config.post.aiDescription.gptName}]]"
|
||||
let modeName = "[[${theme.config.post.aiDescription.mode}]]"
|
||||
let switchBtn = [[${theme.config.post.aiDescription.switchBtn}]] //# 可以配置是否显示切换按钮 以切换tianli/local
|
||||
let keys = "[[${theme.config.post.aiDescription.key}]]"
|
||||
let Referers = "[[${theme.config.post.aiDescription.Referer}]]"
|
||||
|
||||
// 当前随机到的ai摘要到index
|
||||
let lastAiRandomIndex = -1;
|
||||
let animationRunning = true; // 标志变量,控制动画函数的运行
|
||||
// 当前gpt模式
|
||||
let mode = modeName
|
||||
// 刷新点击次数
|
||||
let refreshNum = 0
|
||||
// 记录上一次传递给aiAbstract的参数
|
||||
let prevParam;
|
||||
const aiTitleRefreshIcon = document.querySelector(".ai-title .haofont.hao-icon-arrow-rotate-right")
|
||||
const explanation = document.querySelector(".ai-explanation");
|
||||
const post_ai = document.querySelector(".post-ai");
|
||||
let ai_str = "";
|
||||
let ai_str_length = "";
|
||||
let delay_init = 600;
|
||||
let i = 0;
|
||||
let j = 0;
|
||||
let sto = [];
|
||||
let elapsed = 0;
|
||||
const animate = timestamp => {
|
||||
if (!animationRunning) {
|
||||
return; // 动画函数停止运行
|
||||
}
|
||||
if (!animate.start) animate.start = timestamp;
|
||||
elapsed = timestamp - animate.start;
|
||||
if (elapsed >= 20) {
|
||||
animate.start = timestamp;
|
||||
if (i < ai_str_length - 1) {
|
||||
let char = ai_str.charAt(i + 1);
|
||||
let delay = /[,.,。!?!?]/.test(char) ? 150 : 20;
|
||||
if (explanation.firstElementChild) {
|
||||
explanation.removeChild(explanation.firstElementChild);
|
||||
}
|
||||
explanation.innerHTML += char;
|
||||
let div = document.createElement("div");
|
||||
div.className = "ai-cursor";
|
||||
explanation.appendChild(div);
|
||||
i++;
|
||||
if (delay === 150) {
|
||||
document.querySelector(".ai-explanation .ai-cursor").style.opacity = "0";
|
||||
}
|
||||
if (i === ai_str_length - 1) {
|
||||
observer.disconnect(); // 暂停监听
|
||||
explanation.removeChild(explanation.firstElementChild);
|
||||
}
|
||||
sto[0] = setTimeout(() => {
|
||||
requestAnimationFrame(animate);
|
||||
}, delay);
|
||||
}
|
||||
} else {
|
||||
requestAnimationFrame(animate);
|
||||
}
|
||||
};
|
||||
const observer = new IntersectionObserver(
|
||||
entries => {
|
||||
let isVisible = entries[0].isIntersecting;
|
||||
animationRunning = isVisible; // 标志变量更新
|
||||
if (animationRunning) {
|
||||
delay_init = i === 0 ? 200 : 20;
|
||||
sto[1] = setTimeout(() => {
|
||||
if (j) {
|
||||
i = 0;
|
||||
j = 0;
|
||||
}
|
||||
if (i === 0) {
|
||||
explanation.innerHTML = ai_str.charAt(0);
|
||||
}
|
||||
requestAnimationFrame(animate);
|
||||
}, delay_init);
|
||||
}
|
||||
},
|
||||
{ threshold: 0 }
|
||||
);
|
||||
function clearSTO() {
|
||||
if (sto.length) {
|
||||
sto.forEach(item => {
|
||||
if (item) {
|
||||
clearTimeout(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
function startAI(str, df = true) {
|
||||
i = 0; //重置计数器
|
||||
j = 1;
|
||||
clearSTO();
|
||||
animationRunning = false;
|
||||
elapsed = 0;
|
||||
observer.disconnect(); // 暂停上一次监听
|
||||
explanation.innerHTML = df ? "生成中. . ." : "请等待. . .";
|
||||
ai_str = str;
|
||||
ai_str_length = ai_str.length;
|
||||
observer.observe(post_ai); //启动新监听
|
||||
}
|
||||
|
||||
async function aiAbstract(num = basicWordCount) {
|
||||
i = 0; //重置计数器
|
||||
j = 1;
|
||||
clearSTO();
|
||||
animationRunning = false;
|
||||
elapsed = 0;
|
||||
observer.disconnect(); // 暂停上一次监听
|
||||
if (mode === "tianli") {
|
||||
num = Math.max(10, Math.min(2000, num));
|
||||
const options = {
|
||||
key: keys,
|
||||
Referer: Referers
|
||||
};
|
||||
|
||||
const truncateDescription = getTitleAndContent(num);
|
||||
const queryParams = `key=${options.key}&content=${truncateDescription}`;
|
||||
const requestOptions = {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Referer: options.Referer
|
||||
},
|
||||
};
|
||||
try {
|
||||
let animationInterval = null
|
||||
if (animationInterval) clearInterval(animationInterval);
|
||||
animationInterval = setInterval(() => {
|
||||
const animationText = "生成中" + ".".repeat(j);
|
||||
explanation.innerHTML = animationText;
|
||||
j = (j % 3) + 1; // 在 1、2、3 之间循环
|
||||
}, 500);
|
||||
const response = await fetch(`https://summary.tianli0.top/?${queryParams}`, requestOptions);
|
||||
let result;
|
||||
if (response.status === 403) {
|
||||
result = {
|
||||
summary: "403 refer与key不匹配,本地无法显示。"
|
||||
}
|
||||
} else if (response.status === 500) {
|
||||
result = {
|
||||
summary: "500 系统内部错误"
|
||||
}
|
||||
} else {
|
||||
result = await response.json();
|
||||
}
|
||||
const summary = result.summary.trim();
|
||||
setTimeout(() => {
|
||||
aiTitleRefreshIcon.style.opacity = "1";
|
||||
}, 300)
|
||||
startAI(summary);
|
||||
clearInterval(animationInterval)
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
} else {
|
||||
const strArr = ai.split(",").map(item => item.trim()); // 将字符串转换为数组,去除每个字符串前后的空格
|
||||
if (strArr.length !== 1) {
|
||||
let randomIndex = Math.floor(Math.random() * strArr.length); // 随机生成一个索引
|
||||
while (randomIndex === lastAiRandomIndex) { // 如果随机到了上次的索引
|
||||
randomIndex = Math.floor(Math.random() * strArr.length); // 再次随机
|
||||
}
|
||||
lastAiRandomIndex = randomIndex; // 更新上次随机到的索引
|
||||
startAI(strArr[randomIndex]);
|
||||
} else {
|
||||
startAI(strArr[0])
|
||||
}
|
||||
setTimeout(() => {
|
||||
aiTitleRefreshIcon.style.opacity = "1";
|
||||
}, 600)
|
||||
}
|
||||
}
|
||||
|
||||
function aiRecommend() {
|
||||
i = 0; //重置计数器
|
||||
j = 1;
|
||||
clearSTO();
|
||||
animationRunning = false;
|
||||
elapsed = 0;
|
||||
explanation.innerHTML = "生成中. . .";
|
||||
ai_str = "";
|
||||
ai_str_length = "";
|
||||
observer.disconnect(); // 暂停上一次监听
|
||||
sto[2] = setTimeout(() => {
|
||||
explanation.innerHTML = recommendList();
|
||||
}, 600);
|
||||
}
|
||||
function aiGoHome() {
|
||||
startAI("正在前往博客主页...", false);
|
||||
sto[2] = setTimeout(() => {
|
||||
pjax.loadUrl("/");
|
||||
}, 1000);
|
||||
}
|
||||
const ai_btn_item = document.querySelectorAll(".ai-btn-item");
|
||||
function Introduce() {
|
||||
if (mode == "tianli") {
|
||||
startAI("我是文章辅助AI: TianliGPT,点击下方的按钮,让我生成本文简介、推荐相关文章等。")
|
||||
} else {
|
||||
startAI("我是文章辅助AI: " + gptName + " GPT,点击下方的按钮,让我生成本文简介、推荐相关文章等。")
|
||||
}
|
||||
}
|
||||
function aiTitleRefreshIconClick() {
|
||||
aiTitleRefreshIcon.click()
|
||||
}
|
||||
const aiFunctions = [Introduce, aiTitleRefreshIconClick, aiRecommend, aiGoHome];
|
||||
ai_btn_item.forEach((item, index) => {
|
||||
item.addEventListener("click", () => {
|
||||
aiFunctions[index]();
|
||||
});
|
||||
});
|
||||
|
||||
function recommendList() {
|
||||
let thumbnail = document.querySelectorAll('.relatedPosts-list a');
|
||||
if (!thumbnail.length) {
|
||||
const cardRecentPost = document.querySelector('.card-widget.card-recent-post');
|
||||
if (!cardRecentPost) return '';
|
||||
|
||||
thumbnail = cardRecentPost.querySelectorAll('.aside-list-item a');
|
||||
|
||||
let list = '';
|
||||
for (let i = 0; i < thumbnail.length; i++) {
|
||||
const item = thumbnail[i];
|
||||
list += `<div class="ai-recommend-item"><span class="index">${i + 1}:</span><a href="javascript:;" onclick="pjax.loadUrl('${item.href}')" title="${item.title}" data-pjax-state="">${item.title}</a></div>`;
|
||||
}
|
||||
|
||||
return `很抱歉,无法找到类似的文章,你也可以看看本站最新发布的文章:<br /><div class="ai-recommend">${list}</div>`;
|
||||
}
|
||||
|
||||
let list = '';
|
||||
for (let i = 0; i < thumbnail.length; i++) {
|
||||
const item = thumbnail[i];
|
||||
list += `<div class="ai-recommend-item"><span>推荐${i + 1}:</span><a href="javascript:;" onclick="pjax.loadUrl('${item.href}')" title="${item.title}" data-pjax-state="">${item.title}</a></div>`;
|
||||
}
|
||||
|
||||
return `推荐文章:<br /><div class="ai-recommend">${list}</div>`;
|
||||
}
|
||||
|
||||
|
||||
function changeShowMode() {
|
||||
if (mode === "tianli") {
|
||||
mode = "local";
|
||||
document.getElementById("ai-tag").innerHTML = gptName + " GPT";
|
||||
aiAbstract(basicWordCount);
|
||||
} else {
|
||||
mode = "tianli";
|
||||
document.getElementById("ai-tag").innerHTML = "Tianli GPT";
|
||||
|
||||
const truncateDescription = getTitleAndContent(basicWordCount);
|
||||
let value = Math.floor(Math.random() * randomNum) + basicWordCount;
|
||||
while (value === prevParam || truncateDescription.length - value === prevParam) {
|
||||
value = Math.floor(Math.random() * randomNum) + basicWordCount;
|
||||
}
|
||||
aiTitleRefreshIcon.style.opacity = "0.2";
|
||||
aiTitleRefreshIcon.style.transitionDuration = "0.3s";
|
||||
aiTitleRefreshIcon.style.transform = "rotate(" + 360 * refreshNum + "deg)";
|
||||
if (truncateDescription.length <= 1000) {
|
||||
let param = truncateDescription.length - Math.floor(Math.random() * randomNum);
|
||||
while (param === prevParam) {
|
||||
param = truncateDescription.length - Math.floor(Math.random() * randomNum);
|
||||
}
|
||||
aiAbstract(param);
|
||||
prevParam = param;
|
||||
} else {
|
||||
aiAbstract(value);
|
||||
prevParam = value;
|
||||
}
|
||||
refreshNum++;
|
||||
}
|
||||
}
|
||||
|
||||
//- 监听tag点击事件
|
||||
document.getElementById("ai-tag").addEventListener("click", () => {
|
||||
if (mode === "tianli") {
|
||||
document.querySelectorAll(".ai-btn-item").forEach(item => item.style.display = "none");
|
||||
document.getElementById("go-tianli-blog").style.display = "block";
|
||||
startAI("你好,我是Tianli开发的摘要生成助理TianliGPT,是一个基于GPT-4的生成式AI。我在这里只负责摘要的预生成和显示,你无法与我直接沟通,如果你也需要一个这样的AI摘要接口,可以在下方购买。(暂未开放购买,敬请期待)")
|
||||
} else {
|
||||
document.getElementById("go-tianli-blog").style.display = "none";
|
||||
startAI("你好,我是本站摘要生成助理" + gptName + " GPT,是一个基于GPT-4的生成式AI。我在这里只负责摘要的预生成和显示,你无法与我直接沟通。")
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
aiTitleRefreshIcon.addEventListener("click", () => {
|
||||
const truncateDescription = getTitleAndContent(basicWordCount);
|
||||
let value = Math.floor(Math.random() * randomNum) + basicWordCount;
|
||||
while (value === prevParam || truncateDescription.length - value === prevParam) {
|
||||
value = Math.floor(Math.random() * randomNum) + basicWordCount;
|
||||
}
|
||||
aiTitleRefreshIcon.style.opacity = "0.2";
|
||||
aiTitleRefreshIcon.style.transitionDuration = "0.3s";
|
||||
aiTitleRefreshIcon.style.transform = "rotate(" + 360 * refreshNum + "deg)";
|
||||
if (truncateDescription.length <= 1000) {
|
||||
let param = truncateDescription.length - Math.floor(Math.random() * randomNum);
|
||||
while (param === prevParam) {
|
||||
param = truncateDescription.length - Math.floor(Math.random() * randomNum);
|
||||
}
|
||||
aiAbstract(param);
|
||||
prevParam = param;
|
||||
} else {
|
||||
aiAbstract(value);
|
||||
prevParam = value;
|
||||
}
|
||||
showAiBtn();
|
||||
refreshNum++;
|
||||
});
|
||||
|
||||
document.getElementById("go-tianli-blog").addEventListener("click", () => {
|
||||
window.open(btnLink, "_blank");
|
||||
});
|
||||
|
||||
if (switchBtn) {
|
||||
document.getElementById("ai-Toggle").addEventListener("click", () => {
|
||||
changeShowMode()
|
||||
});
|
||||
}
|
||||
|
||||
function showAiBtn() {
|
||||
document.querySelectorAll(".ai-btn-item").forEach(item => {
|
||||
if (item.id !== "go-tianli-blog") {
|
||||
item.style.display = "block";
|
||||
}
|
||||
if (item.id === "go-tianli-blog") {
|
||||
item.style.display = "none";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//读取文章中的所有文本
|
||||
function getTitleAndContent(basicWordCount) {
|
||||
try {
|
||||
const title = document.title;
|
||||
const container = document.querySelector('#post #article-container');
|
||||
if (!container) {
|
||||
console.warn('TianliGPT:找不到文章容器。请尝试将引入的代码放入到文章容器之后。如果本身没有打算使用摘要功能可以忽略此提示。');
|
||||
return '';
|
||||
}
|
||||
const paragraphs = container.getElementsByTagName('p');
|
||||
|
||||
const headings = container.querySelectorAll('h1, h2, h3, h4, h5');
|
||||
let content = '';
|
||||
|
||||
for (let h of headings) {
|
||||
content += h.innerText + ' ';
|
||||
}
|
||||
|
||||
for (let p of paragraphs) {
|
||||
// 移除包含'http'的链接
|
||||
const filteredText = p.innerText.replace(/https?:\/\/[^\s]+/g, '');
|
||||
content += filteredText;
|
||||
}
|
||||
|
||||
const combinedText = title + ' ' + content;
|
||||
let wordLimit = 1000;
|
||||
if (basicWordCount !== "undefined") {
|
||||
wordLimit = basicWordCount;
|
||||
}
|
||||
const truncatedText = combinedText.slice(0, wordLimit);
|
||||
return truncatedText;
|
||||
} catch (e) {
|
||||
console.error('TianliGPT错误:可能由于一个或多个错误导致没有正常运行,原因出在获取文章容器中的内容失败,或者可能是在文章转换过程中失败。', e);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
aiAbstract();
|
||||
showAiBtn()
|
||||
})()
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
</html>
|
|
@ -122,9 +122,9 @@
|
|||
<article th:class="'post-content '+${ theme.config.code.enable_line || pluginFinder.available('PluginPrismJS') ? 'line-numbers' : ''}" id="article-container" th:utext="${post.content.content}">
|
||||
</article>
|
||||
|
||||
|
||||
<!-- 文章ai摘要 -->
|
||||
<script th:replace="~{modules/postHeadAiDescription :: postHeadAiDescription}"></script>
|
||||
<script data-pjax th:if="${theme.config.post.aiDescription.aiDescriptionEnable}"
|
||||
th:src="${assets_link + '/libs/gpt/post-ai.js'}"></script>
|
||||
|
||||
<!-- 版权声明 -->
|
||||
<th:block th:replace="~{modules/post/copyright :: copyright}"></th:block>
|
||||
|
|
Loading…
Reference in New Issue