用了此脚本,你会发现你的linux.do多了一个对话窗口,流式输出
起因是 :看到了这两个佬的话题
就无聊的糊了一个脚本,因为会跨域,所以又要找代理
这个代理好像还要点击认证一下
其实最简单的方法,就是让@0x24a 佬允许linux.do跨域
https://cors-anywhere.herokuapp.com/
下面就是脚本的代码了
// ==UserScript==
// @name Dynamic Chat Button with SSE Response and Clear History
// @namespace http://tampermonkey.net/
// @version 1.1
// @description Create a floating chat button that opens a dialog for streaming responses like WeChat, with a clear history button.
// @author 逆向达人
// @match https://linux.do/*
// @grant none
// ==/UserScript==
(function () {
'use strict';
// Create a floating button
const button = document.createElement('div');
button.style.position = 'fixed';
button.style.bottom = '30px';
button.style.right = '30px';
button.style.width = '60px';
button.style.height = '60px';
button.style.borderRadius = '50%';
button.style.backgroundColor = '#1E90FF';
button.style.boxShadow = '0px 0px 10px rgba(0, 0, 0, 0.2)';
button.style.cursor = 'pointer';
button.style.zIndex = '1000';
button.style.transition = 'transform 0.3s ease';
button.style.backgroundImage = 'url(https://img.icons8.com/ios-filled/50/ffffff/chat.png)';
button.style.backgroundSize = '50%';
button.style.backgroundPosition = 'center';
button.style.backgroundRepeat = 'no-repeat';
// Hover effect
button.onmouseover = function () {
button.style.transform = 'scale(1.1)';
};
button.onmouseout = function () {
button.style.transform = 'scale(1)';
};
// Append the button to the body
document.body.appendChild(button);
const style = document.createElement('style');
style.textContent = `
.element {
overflow: auto; /* 保留滚动功能 */
-ms-overflow-style: none; /* 适用于 Internet Explorer 和 Edge */
scrollbar-width: none; /* 适用于 Firefox */
}
.element::-webkit-scrollbar {
display: none; /* 隐藏 Webkit 浏览器中的滚动条 */
}
/* 针对 dialog 元素 */
#custom-dialog {
overflow-y: auto; /* 保留滚动功能 */
-ms-overflow-style: none; /* 适用于 Internet Explorer 和 Edge */
scrollbar-width: none; /* 适用于 Firefox */
}
#custom-dialog::-webkit-scrollbar {
display: none; /* 隐藏 Webkit 浏览器中的滚动条 */
}
`;
document.head.appendChild(style);
// Create a dialog box
const dialog = document.createElement('div');
dialog.id = 'custom-dialog';
dialog.style.position = 'fixed';
dialog.style.bottom = '100px';
dialog.style.right = '30px';
dialog.style.minWidth = '350px';
dialog.style.height = '450px';
dialog.style.backgroundColor = '#ffffff';
dialog.style.borderRadius = '10px';
dialog.style.boxShadow = '0px 0px 15px rgba(0, 0, 0, 0.3)';
dialog.style.padding = '10px';
dialog.style.display = 'none';
dialog.style.zIndex = '1001';
dialog.style.overflowY = 'auto';
document.body.appendChild(dialog);
// Remove scrollbar and enable implicit scrolling
dialog.style.overflowY = 'hidden';
dialog.onmouseenter = function () {
dialog.style.overflowY = 'auto';
};
dialog.onmouseleave = function () {
dialog.style.overflowY = 'hidden';
};
// 创建并设置 chatContainer
const chatContainer = document.createElement('div');
chatContainer.className = 'element'; // 添加类名
chatContainer.style.height = 'calc(100% - 40px)';
chatContainer.style.overflowY = 'auto';
dialog.appendChild(chatContainer);
// Create input box
const input = document.createElement('input');
input.type = 'text';
input.style.width = '100%';
input.style.padding = '10px';
input.style.boxSizing = 'border-box';
input.style.borderRadius = '5px';
input.style.border = '1px solid #ccc';
input.placeholder = 'Type your message...';
dialog.appendChild(input);
// Create clear history button
const clearButton = document.createElement('button');
clearButton.textContent = 'Clear';
clearButton.style.position = 'absolute';
clearButton.style.top = '10px';
clearButton.style.right = '10px';
//clearButton.style.right = '10px';
clearButton.style.width = '50px';
clearButton.style.height = '30px';
clearButton.style.backgroundColor = '#FF4500';
clearButton.style.color = '#ffffff';
clearButton.style.border = 'none';
clearButton.style.borderRadius = '5px';
clearButton.style.cursor = 'pointer';
clearButton.style.boxShadow = '0px 0px 10px rgba(0, 0, 0, 0.2)';
clearButton.style.zIndex = '1002';
dialog.appendChild(clearButton);
// Clear history on button click
clearButton.addEventListener('click', () => {
setCookie('chat_history', '', -1);
chatContainer.innerHTML = '';
});
// Toggle dialog visibility
button.addEventListener('click', () => {
dialog.style.display = dialog.style.display === 'none' ? 'block' : 'none';
input.focus();
});
// Adjust dialog width based on input length
input.addEventListener('input', () => {
dialog.style.width = Math.max(300, input.value.length * 8 + 40) + 'px';
});
// Handle user input
input.addEventListener('keydown', function (event) {
if (event.key === 'Enter') {
event.preventDefault();
const userMessage = input.value.trim();
if (userMessage) {
addUserMessage(userMessage);
sendMessage(userMessage);
input.value = '';
}
}
});
function addUserMessage(message) {
const messageElem = document.createElement('div');
messageElem.style.margin = '10px 0';
// messageElem.style.marginTop = '35px';
messageElem.style.padding = '10px';
messageElem.style.borderRadius = '5px';
messageElem.style.backgroundColor = '#1E90FF';
messageElem.style.color = '#ffffff';
messageElem.style.textAlign = 'right';
messageElem.textContent = message;
chatContainer.appendChild(messageElem);
chatContainer.scrollTop = chatContainer.scrollHeight;
}
function addBotMessage(message) {
const messageElem = document.createElement('div');
messageElem.style.margin = '10px 0';
messageElem.style.padding = '10px';
messageElem.style.borderRadius = '5px';
messageElem.style.backgroundColor = '#f0f0f0';
messageElem.style.color = '#000000';
messageElem.style.textAlign = 'left';
chatContainer.appendChild(messageElem);
let index = 0;
function typeNextCharacter() {
if (index < message.length) {
messageElem.textContent += message[index];
index++;
setTimeout(typeNextCharacter, 1);
}
}
typeNextCharacter();
chatContainer.scrollTop = chatContainer.scrollHeight;
}
function getCookie(name) {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) return parts.pop().split(';').shift();
}
function setCookie(name, value, days) {
let expires = "";
if (days) {
const date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
expires = "; expires=" + date.toUTCString();
}
document.cookie = name + "=" + (value || "") + expires + "; path=/";
}
function getHistoryMessages() {
const history = getCookie('chat_history');
return history ? JSON.parse(history) : [];
}
function updateHistoryMessages(messages) {
const history = getHistoryMessages();
const newHistory = history.concat(messages).slice(-5);
setCookie('chat_history', JSON.stringify(newHistory), 7);
}
async function sendMessage(message) {
const apiUrl = 'https://fast.snova.ai/api/completion';
const proxyUrl = 'https://cors-anywhere.herokuapp.com/';
const historyMessages = getHistoryMessages();
const userMessage = {
"role": "user",
"content": message,
"id": generateUUID(),
"ref": generateUUID(),
"revision": 0,
"draft": false,
"status": "done",
"enableRealTimeChat": false,
"meta": null
};
const requestBody = {
"body": {
"messages": historyMessages.concat([userMessage]),
"max_tokens": 4000,
"stop": ["<|eot_id|>"],
"stream": true,
"stream_options": { "include_usage": true },
"model": "llama3-405b"
},
"env_type": "tp16405b"
};
try {
const response = await fetch(proxyUrl + apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(requestBody)
});
if (!response.ok) {
throw new Error('Network response was not ok');
}
const reader = response.body.getReader();
const decoder = new TextDecoder('utf-8');
let receivedMessage = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value, { stream: true });
const lines = chunk.split(/\r?\n/);
lines.forEach(line => {
if (line.startsWith("data:")) {
const jsonData = line.slice(5).trim();
if (jsonData !== "[DONE]") {
try {
const json = JSON.parse(jsonData);
// 检查 choices 是否存在并且不为空,以及 delta.content 是否存在且不为空
if (json.choices && json.choices.length > 0 && json.choices[0].delta && json.choices[0].delta.content) {
receivedMessage += json.choices[0].delta.content;
}
} catch (e) {
console.error('Error parsing SSE chunk', e);
}
}
}
});
}
const assistantMessage = {
"role": "assistant",
"content": receivedMessage,
"id": generateUUID(),
"ref": generateUUID(),
"revision": 0,
"draft": false,
"status": "done",
"enableRealTimeChat": false,
"meta": null
};
updateHistoryMessages([userMessage, assistantMessage]);
addBotMessage(receivedMessage);
} catch (error) {
console.error('Error:', error);
addBotMessage("Error: Unable to send message.");
}
}
function generateUUID() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
const r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
})();
如有侵犯,着实抱歉,联系即删贴