您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Advanced AI Write, powered by Gemini. Write your discourse posts with ease. Quickly ask questions.
// ==UserScript== // @name Discourse AI Write // @namespace http://tampermonkey.net/ // @version 0.3 // @description Advanced AI Write, powered by Gemini. Write your discourse posts with ease. Quickly ask questions. // @author ethandacat // @match https://x-camp.discourse.group/* // @icon https://avatars.githubusercontent.com/u/78333227?s=200&v=4 // @grant none // @license MIT // ==/UserScript== let now = new Date(); let sessionId = `${now.getFullYear().toString() + (now.getMonth() + 1).toString().padStart(2, '0') + now.getDate().toString().padStart(2, '0') + now.getHours().toString().padStart(2, '0') + now.getMinutes().toString().padStart(2, '0') + now.getSeconds().toString().padStart(2, '0') + now.getMilliseconds().toString().padStart(3, '0')}${Math.floor(Math.random() * 1000) + 1}`; console.log(sessionId); async function askGemini(prompt) { try { const res = await fetch('https://ai-write-nine.vercel.app/proxy/', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ prompt, session_id: sessionId // or make this dynamic if you want per-editor-session chats }) }); if (!res.ok) return `(Gemini error ${res.status})`; const data = await res.json(); const text = data?.candidates?.[0]?.content?.parts?.[0]?.text; return text ?? "(no response)"; } catch (err) { return `(Fetch error: ${err.message})`; } } function addButton() { const bar = document.querySelector(".d-editor-button-bar"); if (!bar || document.querySelector(".ai-write-button")) return; const button = document.createElement("button"); button.className = "btn no-text btn-icon quote ai-write-button"; button.tabIndex = 0; button.title = "AI Write"; button.innerHTML = ` <svg class="fa d-icon d-icon-microchip-ai svg-icon svg-string" xmlns="http://www.w3.org/2000/svg"> <use href="#robot"></use> </svg> `; button.addEventListener("click", () => { const pophtml = ` <div class="modal-container"> <div class="modal d-modal poll-ui-builder" data-keyboard="false" aria-modal="true" role="dialog" aria-labelledby="discourse-modal-title"> <div class="d-modal__container"> <div class="d-modal__header"> <div class="d-modal__title"> <h1 id="discourse-modal-title" class="d-modal__title-text">Discourse AI Write</h1> </div> <button class="btn no-text btn-icon btn-transparent modal-close d-ai-close" title="close" type="button"> <svg class="fa d-icon d-icon-xmark svg-icon svg-string" xmlns="http://www.w3.org/2000/svg"><use href="#xmark"></use></svg> <span aria-hidden="true"></span> </button> </div> <div class="d-modal__body" tabindex="-1"> <div class="poll-options"> <p>What should Gemini revise or generate?</p> <div class="input-group poll-option-value"> <input type="text" autofocus class="d-ai-inp"> </div> <p>Thank you for using Discourse AI Write by Ethan!</p> </div> </div> <div class="d-modal__footer"> <button class="btn btn-icon-text btn-primary d-ai-gen" type="button"> <span class="d-button-label">Generate!</span> </button> <button class="btn btn-text btn-flat d-ai-close2" type="button"> <span class="d-button-label">cancel</span> </button> </div> </div> </div> <div class="d-modal__backdrop"></div> </div> `; const pop = document.createElement("div"); pop.innerHTML = pophtml; document.querySelector(".discourse-root").appendChild(pop); document.querySelector(".d-ai-close").onclick = () => document.querySelector(".modal-container")?.remove(); document.querySelector(".d-ai-close2").onclick = () => document.querySelector(".modal-container")?.remove(); const input = document.querySelector(".d-ai-inp"); const genBtn = document.querySelector(".d-ai-gen"); genBtn.onclick = async () => { const inptxt = input.value; const modal = document.querySelector(".modal-container"); genBtn.disabled = true; genBtn.innerHTML = "<span class='d-button-label'>Loading...</span>"; const textarea = document.querySelector("textarea.d-editor-input"); if (textarea) { const result = await askGemini(inptxt); textarea.value = result; textarea.dispatchEvent(new Event("input", { bubbles: true })); } document.querySelector(".modal-container").remove(); document.querySelector(".modal-container").remove(); document.querySelector(".modal-container").remove(); }; input.addEventListener("keydown", e => { if (e.key === "Enter") genBtn.click(); else if (e.key === "Escape") document.querySelector(".modal-container")?.remove(); }); }); bar.appendChild(button); console.log("AI Write button added"); } function reliableWaitForEditor(callback) { let lastEditor = null; const check = () => { const editor = document.querySelector(".d-editor-button-bar"); if (editor && editor !== lastEditor) { lastEditor = editor; callback(); } }; setInterval(check, 300); document.addEventListener("visibilitychange", check); window.addEventListener("hashchange", check); window.addEventListener("focus", check); } reliableWaitForEditor(addButton);