Spaces:
Sleeping
Sleeping
Keldos
commited on
Commit
•
5314ca6
1
Parent(s):
3fc8c4b
feat: 一键复制语言模型输出到剪贴板
Browse files- assets/Kelpy-Codos.js +3 -3
- assets/custom.css +26 -1
- assets/custom.js +57 -16
- modules/utils.py +2 -0
assets/Kelpy-Codos.js
CHANGED
@@ -3,9 +3,9 @@
|
|
3 |
// @namespace https://github.com/Keldos-Li/Kelpy-Codos
|
4 |
// @version 1.0.5
|
5 |
// @author Keldos; https://keldos.me/
|
6 |
-
// @description Add copy button to PRE tags before CODE tag, for Chuanhu
|
7 |
-
// Based on Chuanhu
|
8 |
-
// @license
|
9 |
// @grant none
|
10 |
// ==/UserScript==
|
11 |
|
|
|
3 |
// @namespace https://github.com/Keldos-Li/Kelpy-Codos
|
4 |
// @version 1.0.5
|
5 |
// @author Keldos; https://keldos.me/
|
6 |
+
// @description Add copy button to PRE tags before CODE tag, for Chuanhu Chat especially.
|
7 |
+
// Based on Chuanhu Chat version: ac04408 (2023-3-22)
|
8 |
+
// @license Apache-2.0
|
9 |
// @grant none
|
10 |
// ==/UserScript==
|
11 |
|
assets/custom.css
CHANGED
@@ -4,7 +4,7 @@
|
|
4 |
}
|
5 |
|
6 |
.message p { margin-bottom: 0.6rem !important;}
|
7 |
-
.message p:last-
|
8 |
|
9 |
#app_title {
|
10 |
font-weight: var(--prose-header-text-weight);
|
@@ -247,6 +247,31 @@ ol:not(.options), ul:not(.options) {
|
|
247 |
width: auto !important;
|
248 |
border-bottom-right-radius: 0 !important;
|
249 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
250 |
|
251 |
.message-wrap>div img{
|
252 |
border-radius: 10px !important;
|
|
|
4 |
}
|
5 |
|
6 |
.message p { margin-bottom: 0.6rem !important;}
|
7 |
+
.message p:last-of-type { margin-bottom: 0 !important; }
|
8 |
|
9 |
#app_title {
|
10 |
font-weight: var(--prose-header-text-weight);
|
|
|
247 |
width: auto !important;
|
248 |
border-bottom-right-radius: 0 !important;
|
249 |
}
|
250 |
+
.raw-message {
|
251 |
+
display: none;
|
252 |
+
}
|
253 |
+
|
254 |
+
.copy-bot-btn {
|
255 |
+
border-radius: 5px;
|
256 |
+
/* background-color: #E6E6E6 !important; */
|
257 |
+
color: rgba(120, 120, 120, 0.64) !important;
|
258 |
+
padding: 4px !important;
|
259 |
+
position: absolute;
|
260 |
+
right: -22px;
|
261 |
+
bottom: 0;
|
262 |
+
cursor: pointer !important;
|
263 |
+
transition: color .2s ease, background-color .2s ease;
|
264 |
+
}
|
265 |
+
.copy-bot-btn:hover {
|
266 |
+
background-color: rgba(167, 167, 167, 0.25) !important;
|
267 |
+
color: unset !important;
|
268 |
+
}
|
269 |
+
.copy-bot-btn:active {
|
270 |
+
background-color: rgba(167, 167, 167, 0.5) !important;
|
271 |
+
}
|
272 |
+
.copy-bot-btn:focus {
|
273 |
+
outline: none;
|
274 |
+
}
|
275 |
|
276 |
.message-wrap>div img{
|
277 |
border-radius: 10px !important;
|
assets/custom.js
CHANGED
@@ -272,6 +272,36 @@ function setChatbotHeight() {
|
|
272 |
}
|
273 |
}
|
274 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
275 |
var rendertime = 0; // for debugging
|
276 |
var mathjaxUpdated = false;
|
277 |
|
@@ -326,12 +356,13 @@ function updateMathJax() {
|
|
326 |
|
327 |
let timeoutId;
|
328 |
let isThrottled = false;
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
|
|
335 |
if (shouldRenderLatex) {
|
336 |
renderMathJax();
|
337 |
mathjaxUpdated = false;
|
@@ -339,8 +370,8 @@ var mObserver = new MutationObserver(function (mutationsList, observer) {
|
|
339 |
saveHistoryHtml();
|
340 |
}
|
341 |
}
|
342 |
-
for (var node of
|
343 |
-
if (node.nodeType === 1 && node.classList.contains('message') && node.
|
344 |
if (shouldRenderLatex) {
|
345 |
renderMathJax();
|
346 |
mathjaxUpdated = false;
|
@@ -348,25 +379,25 @@ var mObserver = new MutationObserver(function (mutationsList, observer) {
|
|
348 |
saveHistoryHtml();
|
349 |
}
|
350 |
}
|
351 |
-
} else if (
|
352 |
-
if (
|
353 |
if (isThrottled) break; // 为了防止重复不断疯狂渲染,加上等待_(:з」∠)_
|
354 |
isThrottled = true;
|
355 |
clearTimeout(timeoutId);
|
356 |
timeoutId = setTimeout(() => {
|
357 |
isThrottled = false;
|
358 |
if (shouldRenderLatex) {
|
359 |
-
// console.log("changed");
|
360 |
renderMathJax();
|
361 |
mathjaxUpdated = false;
|
362 |
}
|
|
|
363 |
saveHistoryHtml();
|
364 |
}, 500);
|
365 |
}
|
366 |
}
|
367 |
}
|
368 |
});
|
369 |
-
mObserver.observe(
|
370 |
|
371 |
var loadhistorytime = 0; // for debugging
|
372 |
function saveHistoryHtml() {
|
@@ -387,10 +418,20 @@ function loadHistoryHtml() {
|
|
387 |
return; // logged in, do nothing
|
388 |
}
|
389 |
if (!historyLoaded) {
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
394 |
historyLoaded = true;
|
395 |
console.log("History Loaded");
|
396 |
loadhistorytime += 1; // for debugging
|
|
|
272 |
}
|
273 |
}
|
274 |
|
275 |
+
const copyIcon = '<span><svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" height=".8em" width=".8em" xmlns="http://www.w3.org/2000/svg"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></span>';
|
276 |
+
const copiedIcon = '<span><svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" height=".8em" width=".8em" xmlns="http://www.w3.org/2000/svg"><polyline points="20 6 9 17 4 12"></polyline></svg></span>';
|
277 |
+
function addCopyBotButton(botElement) {
|
278 |
+
var copyButton = null;
|
279 |
+
var rawMessage = null;
|
280 |
+
rawMessage = botElement.querySelector('.raw-message');
|
281 |
+
copyButton = botElement.querySelector('button.copy-bot-btn');
|
282 |
+
if (!rawMessage) return;
|
283 |
+
if (copyButton) {
|
284 |
+
copyButton.remove();
|
285 |
+
}
|
286 |
+
var button = document.createElement('button');
|
287 |
+
button.classList.add('copy-bot-btn');
|
288 |
+
button.setAttribute('aria-label', 'Copy');
|
289 |
+
button.innerHTML = copyIcon;
|
290 |
+
button.addEventListener('click', () => {
|
291 |
+
const textToCopy = rawMessage.innerText;
|
292 |
+
navigator.clipboard
|
293 |
+
.writeText(textToCopy)
|
294 |
+
.catch(() => {
|
295 |
+
console.error("copy failed");
|
296 |
+
});
|
297 |
+
button.innerHTML = copiedIcon;
|
298 |
+
setTimeout(() => {
|
299 |
+
button.innerHTML = copyIcon;
|
300 |
+
}, 1500);
|
301 |
+
});
|
302 |
+
botElement.appendChild(button);
|
303 |
+
};
|
304 |
+
|
305 |
var rendertime = 0; // for debugging
|
306 |
var mathjaxUpdated = false;
|
307 |
|
|
|
356 |
|
357 |
let timeoutId;
|
358 |
let isThrottled = false;
|
359 |
+
var mmutation
|
360 |
+
// 监听所有元素中 bot message 的变化,用来查找需要渲染的mathjax, 并为 bot 消息添加复制按钮。
|
361 |
+
var mObserver = new MutationObserver(function (mutationsList) {
|
362 |
+
for (mmutation of mutationsList) {
|
363 |
+
if (mmutation.type === 'childList') {
|
364 |
+
for (var node of mmutation.addedNodes) {
|
365 |
+
if (node.nodeType === 1 && node.classList.contains('message') && node.getAttribute('data-testid') === 'bot') {
|
366 |
if (shouldRenderLatex) {
|
367 |
renderMathJax();
|
368 |
mathjaxUpdated = false;
|
|
|
370 |
saveHistoryHtml();
|
371 |
}
|
372 |
}
|
373 |
+
for (var node of mmutation.removedNodes) {
|
374 |
+
if (node.nodeType === 1 && node.classList.contains('message') && node.getAttribute('data-testid') === 'bot') {
|
375 |
if (shouldRenderLatex) {
|
376 |
renderMathJax();
|
377 |
mathjaxUpdated = false;
|
|
|
379 |
saveHistoryHtml();
|
380 |
}
|
381 |
}
|
382 |
+
} else if (mmutation.type === 'attributes') {
|
383 |
+
if (mmutation.target.nodeType === 1 && mmutation.target.classList.contains('message') && mmutation.target.getAttribute('data-testid') === 'bot') {
|
384 |
if (isThrottled) break; // 为了防止重复不断疯狂渲染,加上等待_(:з」∠)_
|
385 |
isThrottled = true;
|
386 |
clearTimeout(timeoutId);
|
387 |
timeoutId = setTimeout(() => {
|
388 |
isThrottled = false;
|
389 |
if (shouldRenderLatex) {
|
|
|
390 |
renderMathJax();
|
391 |
mathjaxUpdated = false;
|
392 |
}
|
393 |
+
document.querySelectorAll('#chuanhu_chatbot>.wrap>.message-wrap .message.bot').forEach(addCopyBotButton);
|
394 |
saveHistoryHtml();
|
395 |
}, 500);
|
396 |
}
|
397 |
}
|
398 |
}
|
399 |
});
|
400 |
+
mObserver.observe(document.documentElement, { attributes: true, childList: true, subtree: true });
|
401 |
|
402 |
var loadhistorytime = 0; // for debugging
|
403 |
function saveHistoryHtml() {
|
|
|
418 |
return; // logged in, do nothing
|
419 |
}
|
420 |
if (!historyLoaded) {
|
421 |
+
var tempDiv = document.createElement('div');
|
422 |
+
tempDiv.innerHTML = historyHtml;
|
423 |
+
var buttons = tempDiv.querySelectorAll('button.copy-bot-btn');
|
424 |
+
for (var i = 0; i < buttons.length; i++) {
|
425 |
+
buttons[i].parentNode.removeChild(buttons[i]);
|
426 |
+
}
|
427 |
+
var fakeHistory = document.createElement('div');
|
428 |
+
fakeHistory.classList.add('history-message');
|
429 |
+
fakeHistory.innerHTML = tempDiv.innerHTML;
|
430 |
+
chatbotWrap.insertBefore(fakeHistory, chatbotWrap.firstChild);
|
431 |
+
// var fakeHistory = document.createElement('div');
|
432 |
+
// fakeHistory.classList.add('history-message');
|
433 |
+
// fakeHistory.innerHTML = historyHtml;
|
434 |
+
// chatbotWrap.insertBefore(fakeHistory, chatbotWrap.firstChild);
|
435 |
historyLoaded = true;
|
436 |
console.log("History Loaded");
|
437 |
loadhistorytime += 1; // for debugging
|
modules/utils.py
CHANGED
@@ -183,6 +183,7 @@ def convert_mdtext(md_text):
|
|
183 |
non_code_parts = code_block_pattern.split(md_text)[::2]
|
184 |
|
185 |
result = []
|
|
|
186 |
for non_code, code in zip(non_code_parts, code_blocks + [""]):
|
187 |
if non_code.strip():
|
188 |
non_code = normalize_markdown(non_code)
|
@@ -194,6 +195,7 @@ def convert_mdtext(md_text):
|
|
194 |
code = markdown_to_html_with_syntax_highlight(code)
|
195 |
result.append(code)
|
196 |
result = "".join(result)
|
|
|
197 |
result += ALREADY_CONVERTED_MARK
|
198 |
return result
|
199 |
|
|
|
183 |
non_code_parts = code_block_pattern.split(md_text)[::2]
|
184 |
|
185 |
result = []
|
186 |
+
raw = f'<span class="raw-message">{html.escape(md_text)}</span>'
|
187 |
for non_code, code in zip(non_code_parts, code_blocks + [""]):
|
188 |
if non_code.strip():
|
189 |
non_code = normalize_markdown(non_code)
|
|
|
195 |
code = markdown_to_html_with_syntax_highlight(code)
|
196 |
result.append(code)
|
197 |
result = "".join(result)
|
198 |
+
result += raw
|
199 |
result += ALREADY_CONVERTED_MARK
|
200 |
return result
|
201 |
|