(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 += `