// ==UserScript== // @name 通用ai插图脚本7.2 // @namespace http://tampermonkey.net/ // @version 7.2 // @license MIT // @description 免费或者使用sd的api或使用novelai3配合ai生成插图 // @author 从前跟你一样 // @grant unsafeWindow // @match *://*/* // @require https://cdn.staticfile.org/jquery/3.4.1/jquery.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/jszip/3.7.1/jszip.min.js // @connect vagrantup.com // @grant unsafeWindow // @grant GM_xmlhttpRequest // @connect sd则此处换成你的电脑域名ip、不需要带端口。 // @connect 192.168.10.2 // @connect novelai.net // @match *://*/* // @grant GM_xmlhttpRequest // @downloadURL none // ==/UserScript== //必须在connect填你的sd域名,也就是你电脑的ip地址(本地ip)或网址xxx.com (function() { 'use strict'; unsafeWindow.模式="novelai"; //sd novelai free 使用sd 或novelai 或 免费的 novelai需要获取api sd启动器需要启用api功能。例如绘世启动器中 的高级选项 启用api选择开启。 unsafeWindow.start="image:{";//检测ai输出的提示词以什么开头 会被去除;可以自定义。 unsafeWindow.end="}";///检测ai输出的提示词以什么结尾,不去除,可以自定义。提示词会采用两者之间的文字。 //以下为novelai的设置 注意更改脚本设置 需要刷新网页。 let access_token = "填你的api"//填写你的novelai的apikey,在官方网站的设置 Account 里 Get Persistent API Token let prompt = "A beautiful black-haired woman" //填写你希望固定的正面提示词 let prompt2="quality.best quality, amazing quality, very aesthetic, absurdres"//固定正面提示词 let model = "nai-diffusion-3"//使用的模型 多个选择 "safe-diffusion" "nai-diffusion" "nai-diffusion-furry" "furry-diffusion-inpainting" "nai-diffusion-2" "nai-diffusion-3-inpainting" "nai-diffusion-furry-3-inpainting" let preset_data = { "resolution": "Normal_Landscape_v3",//生成的图像大小 Normal_Square_v3 = (1024, 1024) Large_Square_v3 = (1472, 1472) Small_Square_v3 = (640, 640) Normal_Landscape_v3 = (1216, 832) 更多参考官网 "scale": 5, //提示词关联性 "sampler": "k_euler",//使用的采样器 "k_dpm_2" "k_dpmpp_2m" "ddim_v3" "steps": 28,//生成的步数 "n_samples": 1, "strength": 0.7, "noise": 0, "uc_preset": "Preset_Heavy",//预设。好像没什么用 "quality_toggle": true, "auto_smea": true, "smea": false, "smea_dyn": false, "decrisper": false, "controlnet_strength": 1, "legacy": false, "add_original_image": true, "uncond_scale": 1, "cfg_rescale": 0, "noise_schedule": "native", "legacy_v3_extend": false, "params_version": 1, "seed": 0, //生成的种子,为0则是随机。使用固定种子图像基本固定,以下为固定的负面提示词 "uc": "bad proportions, out of focus, username, text, bad anatomy, lowres, worstquality, watermark, cropped, bad body, deformed, mutated, disfigured, poorly drawn face, malformed hands, extra arms, extra limb, missing limb, too many fingers, extra legs, bad feet, missing fingers, fused fingers, acnes, floating limbs, disconnected limbs, long neck, long body, mutation, ugly, blurry, low quality, sketches, normal quality, monochrome, grayscale, signature, logo, jpeg artifacts, unfinished, displeasing, chromatic aberration, extra digits, artistic error, scan, abstract, photo, realism, screencap" } prompt=prompt+prompt2 //以下为sd的设置 unsafeWindow.url = "http://192.168.10.2:7860";//sd地址 记得要修改上面的connect 的sd域名才能访问 unsafeWindow.prompts = "highres"; //额外固定的提示词 nsfw? 也可以固定你要的 lora 。每次都会加载提示词后面。下面是反向提示词 unsafeWindow.negative_prompt = "bad proportions,out of focus,username,text,bad anatomy,lowres,worstquality,watermark,cropped,bad body,deformed,mutated,disfigured,poorly drawn face,mutated hands and fingers,malformed hands,poorly drawn hands,mutated hands,extra arms,extra limb,malformed limbs,missing limb,too many fingers,extra legs,bad feet,missing fingers,fused fingers,bad hands,acnes,floating limbs,disconnected limbs,long neck,long body,mutation,ugly,blurry,low quality,sketches,normal quality,monochrome,grayscale,signature,logo"; unsafeWindow.cfg_scale = 7;//关键词关联性 unsafeWindow.width = 512; //宽度 unsafeWindow.height = 512;//长度 unsafeWindow.restore_faces = false; //面部修复 unsafeWindow.steps = 20;//步数 unsafeWindow.sampler_name="DPM++ 2M" ; //采样方式 function unzipFile(arrayBuffer) { return new Promise((resolve, reject) => { JSZip.loadAsync(arrayBuffer) .then(function(zip) { console.log("ZIP 文件加载成功"); // 遍历 ZIP 文件中的所有文件 zip.forEach(function (relativePath, zipEntry) { console.log("文件名:", zipEntry.name); // 解压每个文件 zipEntry.async('blob').then(function(blob) { console.log("文件大小:", blob.size); // 处理解压后的文件内容 resolve(blob); }); }); }).catch(reject); }) } async function replaceWithnovelai() { var ps = document.getElementsByClassName("mes_text"); for (var i = 0; i < ps.length; i++) { var p = ps[i]; var linkText = p.textContent; var regex = new RegExp(`${unsafeWindow.start}(.*?)${unsafeWindow.end}`); var matches = linkText.match(regex); if(matches){ var targetText = matches[0]; var link = targetText.replace('image ss', ''); const button = document.createElement('button'); var uniqueId = "button_" + Math.random().toString(36).substr(2, 9); button.id = uniqueId; button.textContent = '生成图片'; button.dataset.link = link; p.innerHTML = p.innerHTML.replace(targetText, button.outerHTML); // alert(targetText); // 重新找到新创建的按钮 var newbutton = document.getElementById(uniqueId); const imgSpan = document.createElement('span'); newbutton.addEventListener('click', async function() { const payload = preset_data; const urlObj = new URL("https://api.novelai.net/ai/generate-image"); const Authorization="Bearer "+access_token; const data11 = { "input": targetText+prompt, "model": "nai-diffusion-3", "action": "generate", "parameters": preset_data } try { const response = await new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: "POST", url: urlObj, data: JSON.stringify(data11), responseType: "arraybuffer", headers: { "Content-Type": "application/json", "Authorization":Authorization }, onload: function(response) { if (response.status >= 200 && response.status < 400) { resolve(response); //alert("以成功返回"+response.status); } else { if(response.status==400){ alert("验证错误"); } if(response.status==401){ alert("api错误请检测api是否正确"); } if(response.status==402){ alert("需要有效订阅才能访问此端点。"); } if(response.status==409){ alert("发生冲突错误"); } if(response.status==500){ alert("未知错误"); } //alert("响应内容:", response.responseText); reject(new Error(`请求失败,状态码: ${response.status}`)); } }, onerror: function(error,response) { alert("请求错误,请检查代理"); reject(error); } }); }); const data123 = await response.response; let re= await unzipFile(data123); console.log('base64data'+Object.prototype.toString.call(re)); let blob = new Blob([re], { type: 'image/png' }); let imageUrl = URL.createObjectURL(blob); const img2 = document.createElement('img'); img2.src=imageUrl; img2.alt = "Generated Image2"; imgSpan.innerHTML = ''; imgSpan.appendChild(img2); } catch (error) { console.error('Error generating image:', error); } }); newbutton.parentNode.insertBefore(imgSpan, button.nextSibling); } } } async function replaceSpansWithImagesst() { var ps = document.getElementsByClassName("mes_text"); for (var i = 0; i < ps.length; i++) { var p = ps[i]; var linkText = p.textContent; var regex = new RegExp(`${unsafeWindow.start}(.*?)${unsafeWindow.end}`); var matches = linkText.match(regex); if(matches){ var targetText = matches[0]; var link = targetText.replace('image ss', ''); const button = document.createElement('button'); var uniqueId = "button_" + Math.random().toString(36).substr(2, 9); button.id = uniqueId; button.textContent = '生成图片'; button.dataset.link = link; p.innerHTML = p.innerHTML.replace(targetText, button.outerHTML); // alert(targetText); // 重新找到新创建的按钮 var newbutton = document.getElementById(uniqueId); const imgSpan = document.createElement('span'); newbutton.addEventListener('click', async function() { const url = unsafeWindow.url; const payload = { "prompt": this.dataset.link+" "+unsafeWindow.prompts, "negative_prompt": unsafeWindow.negative_prompt, "steps": unsafeWindow.steps, "sampler_name": unsafeWindow.sampler_name, "width": unsafeWindow.width, "height": unsafeWindow.height, "restore_faces": unsafeWindow.restore_faces, "cfg_scale":unsafeWindow.cfg_scale }; const urlObj = new URL(url+"/sdapi/v1/txt2img"); try { const response = await new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: "POST", url: urlObj, data: JSON.stringify(payload), headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" }, onload: function(response) { if (response.status >= 200 && response.status < 400) { resolve(response); } else { alert("请求URL:", response.finalUrl); alert("响应状态码:", response.status); alert("响应内容:", response.responseText); reject(new Error(`请求失败,状态码: ${response.status}`)); } }, onerror: function(error,response) { alert("请求错误。请检测地址是否正确.或sd已正确开启,sd启动器需要启用api功能。例如绘世启动器中 的高级选项 启用api选择开启。以及在// @connect 处填写sd所在的电脑ip。不需要带端口例如局域网为192.168.1.2,本机则是127.0.0.1"); reject(error); } }); }); const r = JSON.parse(response.responseText); for (let i of r['images']) { const png_payload = { "image": "data:image/png;base64," + i }; const response2 = await new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: "POST", url: `${url}/sdapi/v1/png-info`, data: JSON.stringify(png_payload), headers: { "Content-Type": "application/json" }, onload: resolve, onerror: reject }); }); const pngInfo = JSON.parse(response2.responseText).info; const dataURL = "data:image/png;base64," + i; const img = document.createElement('img'); img.src = dataURL; img.alt = "Generated Image"; img.dataset.parameters = pngInfo; imgSpan.innerHTML = ''; imgSpan.appendChild(img); } } catch (error) { console.error('Error generating image:', error); } }); // p.parentNode.replaceChild(button, span); newbutton.parentNode.insertBefore(imgSpan, button.nextSibling); } } } async function replaceSpansWithImagesfree() { var ps = document.getElementsByClassName("mes_text"); for (var i = 0; i < ps.length; i++) { var p = ps[i]; var linkText = p.textContent; var regex = new RegExp(`${unsafeWindow.start}(.*?)${unsafeWindow.end}`); var matches = linkText.match(regex); if(matches){ var targetText = matches[0]; var link = targetText.replace('image ss', ''); const button = document.createElement('button'); var uniqueId = "button_" + Math.random().toString(36).substr(2, 9); button.id = uniqueId; button.textContent = '生成图片'; button.dataset.link = link; p.innerHTML = p.innerHTML.replace(targetText, button.outerHTML); // alert(targetText); // 重新找到新创建的按钮 var newbutton = document.getElementById(uniqueId); const imgSpan = document.createElement('span'); newbutton.addEventListener('click', async function() { var ran = Math.floor(Math.random() * 10000).toString(); const prompt = this.dataset.link + " " +unsafeWindow.prompts+" "+ran; const url = `https://image.pollinations.ai/prompt/${encodeURIComponent(prompt)}`; const img = document.createElement('img'); img.src = url; img.alt = "Generated Image"; imgSpan.innerHTML = ''; imgSpan.appendChild(img); }); newbutton.parentNode.insertBefore(imgSpan, button.nextSibling); } } } if(unsafeWindow.模式=="sd"){ setInterval(replaceSpansWithImagesst, 5000); }else if(unsafeWindow.模式=="novelai"){ setInterval(replaceWithnovelai, 5000); }else{ setInterval(replaceSpansWithImagesfree, 5000); } ; })();