您需要先安装一个扩展,例如 篡改猴、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);