allow copy original text instead of renderend text

这个提交包含在:
binary-husky
2025-03-09 00:04:27 +08:00
父节点 07974a26d0
当前提交 e78e8b0909
共有 3 个文件被更改,包括 87 次插入12 次删除

查看文件

@@ -3,7 +3,8 @@ import re
import os import os
import math import math
import html import html
import base64
import gzip
from loguru import logger from loguru import logger
from textwrap import dedent from textwrap import dedent
from functools import lru_cache from functools import lru_cache
@@ -325,6 +326,14 @@ def markdown_convertion_for_file(txt):
# cat them together # cat them together
return pre + convert_stage_5 + suf return pre + convert_stage_5 + suf
def compress_string(s):
compress_string = gzip.compress(s.encode('utf-8'))
return base64.b64encode(compress_string).decode()
def decompress_string(s):
decoded_string = base64.b64decode(s)
return gzip.decompress(decoded_string).decode('utf-8')
@lru_cache(maxsize=128) # 使用 lru缓存 加快转换速度 @lru_cache(maxsize=128) # 使用 lru缓存 加快转换速度
def markdown_convertion(txt): def markdown_convertion(txt):
""" """
@@ -336,6 +345,12 @@ def markdown_convertion(txt):
# print('警告,输入了已经经过转化的字符串,二次转化可能出问题') # print('警告,输入了已经经过转化的字符串,二次转化可能出问题')
return txt # 已经被转化过,不需要再次转化 return txt # 已经被转化过,不需要再次转化
# 在文本中插入一个base64编码的原始文本,以便在复制时能够获得原始文本
raw_text_encoded = compress_string(txt)
raw_text_node = f'<div class="raw_text">{raw_text_encoded}</div>'
suf = raw_text_node + "</div>"
# 用于查找数学公式的正则表达式
find_equation_pattern = r'<script type="math/tex(?:.*?)>(.*?)</script>' find_equation_pattern = r'<script type="math/tex(?:.*?)>(.*?)</script>'
txt = fix_markdown_indent(txt) txt = fix_markdown_indent(txt)
@@ -493,6 +508,7 @@ def simple_markdown_convertion(text):
suf = "</div>" suf = "</div>"
if text.startswith(pre) and text.endswith(suf): if text.startswith(pre) and text.endswith(suf):
return text # 已经被转化过,不需要再次转化 return text # 已经被转化过,不需要再次转化
text = compat_non_markdown_input(text) # 兼容非markdown输入 text = compat_non_markdown_input(text) # 兼容非markdown输入
text = markdown.markdown( text = markdown.markdown(
text, text,

查看文件

@@ -332,3 +332,7 @@
text-wrap: wrap; text-wrap: wrap;
opacity: 0.8; opacity: 0.8;
} }
.raw_text {
display: none;
}

查看文件

@@ -259,7 +259,24 @@ function cancel_loading_status() {
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// 第 2 部分: 复制按钮 // 第 2 部分: 复制按钮
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// 解压缩函数
function decompressString(compressedString) {
// 第1步Base64解码
const binaryString = atob(compressedString);
// 第2步将二进制字符串转换为Uint8Array
const bytes = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
// 第3步使用DecompressionStream (基于Web Streams API)进行gzip解压缩
const ds = new DecompressionStream('gzip');
const decompressedStream = new Response(new Blob([bytes])).body.pipeThrough(ds);
// 第4步获取解压后的数据并转换为字符串
return new Response(decompressedStream).text();
}
var allow_auto_read_continously = true; var allow_auto_read_continously = true;
var allow_auto_read_tts_flag = false; var allow_auto_read_tts_flag = false;
@@ -283,19 +300,56 @@ function addCopyButton(botElement, index, is_last_in_arr) {
return; return;
} }
var copyButton = document.createElement('button'); // var copyButton = document.createElement('button');
copyButton.classList.add('copy-bot-btn'); // copyButton.classList.add('copy-bot-btn');
copyButton.setAttribute('aria-label', 'Copy'); // copyButton.setAttribute('aria-label', 'Copy');
copyButton.innerHTML = copyIcon; // copyButton.innerHTML = copyIcon;
copyButton.addEventListener('click', async () => { // copyButton.addEventListener('click', async () => {
const textToCopy = botElement.innerText; // const textToCopy = botElement.innerText;
// try {
// // push_text_to_audio(textToCopy).catch(console.error);
// if ("clipboard" in navigator) {
// await navigator.clipboard.writeText(textToCopy);
// copyButton.innerHTML = copiedIcon;
// setTimeout(() => {
// copyButton.innerHTML = copyIcon;
// }, 1500);
// } else {
// const textArea = document.createElement("textarea");
// textArea.value = textToCopy;
// document.body.appendChild(textArea);
// textArea.select();
// try {
// document.execCommand('copy');
// copyButton.innerHTML = copiedIcon;
// setTimeout(() => {
// copyButton.innerHTML = copyIcon;
// }, 1500);
// } catch (error) {
// console.error("Copy failed: ", error);
// }
// document.body.removeChild(textArea);
// }
// } catch (error) {
// console.error("Copy failed: ", error);
// }
// });
// 原始文本拷贝
var copyButtonOrig = document.createElement('button');
copyButtonOrig.classList.add('copy-bot-btn');
copyButtonOrig.setAttribute('aria-label', 'Copy');
copyButtonOrig.innerHTML = copyIcon;
copyButtonOrig.addEventListener('click', async () => {
try { try {
const base64gzipcode = botElement.getElementsByClassName('raw_text')[0].innerText;
const textToCopy = await decompressString(base64gzipcode);
// push_text_to_audio(textToCopy).catch(console.error); // push_text_to_audio(textToCopy).catch(console.error);
if ("clipboard" in navigator) { if ("clipboard" in navigator) {
await navigator.clipboard.writeText(textToCopy); await navigator.clipboard.writeText(textToCopy);
copyButton.innerHTML = copiedIcon; copyButtonOrig.innerHTML = copiedIcon;
setTimeout(() => { setTimeout(() => {
copyButton.innerHTML = copyIcon; copyButtonOrig.innerHTML = copyIcon;
}, 1500); }, 1500);
} else { } else {
const textArea = document.createElement("textarea"); const textArea = document.createElement("textarea");
@@ -304,9 +358,9 @@ function addCopyButton(botElement, index, is_last_in_arr) {
textArea.select(); textArea.select();
try { try {
document.execCommand('copy'); document.execCommand('copy');
copyButton.innerHTML = copiedIcon; copyButtonOrig.innerHTML = copiedIcon;
setTimeout(() => { setTimeout(() => {
copyButton.innerHTML = copyIcon; copyButtonOrig.innerHTML = copyIcon;
}, 1500); }, 1500);
} catch (error) { } catch (error) {
console.error("Copy failed: ", error); console.error("Copy failed: ", error);
@@ -345,7 +399,8 @@ function addCopyButton(botElement, index, is_last_in_arr) {
var messageBtnColumn = document.createElement('div'); var messageBtnColumn = document.createElement('div');
messageBtnColumn.classList.add('message-btn-row'); messageBtnColumn.classList.add('message-btn-row');
messageBtnColumn.appendChild(copyButton); // messageBtnColumn.appendChild(copyButton);
messageBtnColumn.appendChild(copyButtonOrig);
if (enable_tts) { if (enable_tts) {
messageBtnColumn.appendChild(audioButton); messageBtnColumn.appendChild(audioButton);
} }