// ==UserScript== // @name 一键将网页 AI 对话完美粘贴到 Word、WPS 和 Excel 的效率工具 // @description 一键复制 AI 回复到 Word / Excel,支持 ChatGPT、Claude、Gemini、DeepSeek、豆包、Kimi // @namespace xiaotianguo // @version 0.1.0 // @match https://chatgpt.com/* // @match https://chat.openai.com/* // @match https://chat.deepseek.com/* // @match https://claude.ai/* // @match https://*.claude.ai/* // @match https://gemini.google.com/* // @match https://kimi.moonshot.cn/* // @match https://kimi.com/* // @match https://www.kimi.com/* // @match https://www.doubao.com/* // @match https://doubao.com/* // @grant clipboardWrite // ==/UserScript== (function () { 'use strict'; async function writeClipboard(html, text) { var _a; if (!((_a = navigator.clipboard) == null ? void 0 : _a.write)) { throw new Error("当前浏览器不支持多格式剪贴板写入"); } const item = new ClipboardItem({ "text/html": new Blob([html], { type: "text/html" }), "text/plain": new Blob([text], { type: "text/plain" }) }); await navigator.clipboard.write([item]); } function escapeHtml(value) { return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'"); } function normalizeText(value) { return value.replace(/\u00a0/g, " ").replace(/\s+\n/g, "\n").trim(); } const BLOCK_SELECTOR = "h1,h2,h3,h4,h5,h6,p,ul,ol,pre,blockquote,table,div"; const CODE_LANGUAGE_LABELS$1 = /* @__PURE__ */ new Set([ "bash", "shell", "sh", "zsh", "fish", "console", "terminal", "python", "javascript", "typescript", "js", "ts", "jsx", "tsx", "java", "go", "rust", "c", "cpp", "c++", "c#", "cs", "php", "ruby", "swift", "kotlin", "scala", "sql", "html", "css", "json", "yaml", "yml", "xml", "toml", "ini", "dockerfile", "powershell", "pwsh", "lua", "perl", "r", "matlab" ]); function extractBlocks(root) { const blocks = []; const nodes = Array.from(root.children); for (const child of nodes) { if (isActionUi(child)) continue; const extracted = extractBlock(child); blocks.push(...extracted); } if (blocks.length === 0) { const text = normalizeText(root.innerText || root.textContent || ""); if (text) { blocks.push({ type: "paragraph", children: [{ type: "text", text }] }); } } return mergeAdjacentParagraphs(blocks); } function hasTable(blocks) { return blocks.some((block) => block.type === "table"); } function extractBlock(node) { if (shouldIgnoreElement(node) || isCodeLanguageLabel(node)) { return []; } const tag = node.tagName.toLowerCase(); if (tag === "div" && shouldFlattenDiv(node)) { return extractBlocks(node); } if (/^h[1-6]$/.test(tag)) { return [{ type: "heading", level: Number(tag[1]), children: extractInline(node) }]; } if (tag === "p") { return [{ type: "paragraph", children: extractInline(node) }]; } if (tag === "blockquote") { return [{ type: "blockquote", children: extractBlocks(node) }]; } if (tag === "pre") { return [{ type: "code_block", text: normalizeText(node.innerText || node.textContent || ""), language: node.getAttribute("data-language") || void 0 }]; } if (tag === "table") { return [{ type: "table", rows: extractTable(node) }]; } if (tag === "ul" || tag === "ol") { return [extractList(node)]; } const directBlocks = Array.from(node.querySelectorAll(":scope > " + BLOCK_SELECTOR)); if (directBlocks.length > 0) { return extractBlocks(node); } const text = normalizeText(node.innerText || node.textContent || ""); if (!text) { return []; } return [{ type: "paragraph", children: extractInline(node) }]; } function extractInline(node) { const inlines = []; for (const child of Array.from(node.childNodes)) { if (child.nodeType === Node.TEXT_NODE) { const text = child.textContent ?? ""; if (text) inlines.push({ type: "text", text }); continue; } if (child.nodeType !== Node.ELEMENT_NODE) continue; const element = child; if (isActionUi(element) || shouldIgnoreElement(element)) continue; const tag = element.tagName.toLowerCase(); if (tag === "br") { inlines.push({ type: "br" }); continue; } if (tag === "strong" || tag === "b") { inlines.push({ type: "strong", children: extractInline(element) }); continue; } if (tag === "em" || tag === "i") { inlines.push({ type: "em", children: extractInline(element) }); continue; } if (tag === "del" || tag === "s") { inlines.push({ type: "del", children: extractInline(element) }); continue; } if (tag === "code") { inlines.push({ type: "code", text: normalizeText(element.innerText || element.textContent || "") }); continue; } if (tag === "a") { inlines.push({ type: "link", href: element.getAttribute("href") || "", children: extractInline(element) }); continue; } const nested = extractInline(element); if (nested.length > 0) { inlines.push(...nested); } } return mergeTextNodes(inlines); } function extractList(node) { const items = Array.from(node.children).filter((child) => child instanceof HTMLLIElement).map((li) => { const directBlockChildren = Array.from(li.children).filter( (child) => child instanceof HTMLElement && child.matches(BLOCK_SELECTOR) ); if (directBlockChildren.length === 0) { return [{ type: "paragraph", children: extractInline(li) }]; } return directBlockChildren.flatMap((child) => extractBlock(child)); }); return { type: "list", ordered: node.tagName.toLowerCase() === "ol", items }; } function extractTable(table) { const rowElements = Array.from(table.querySelectorAll("tr")); return rowElements.map((row) => ({ cells: Array.from(row.children).filter((cell) => cell instanceof HTMLTableCellElement).map((cell) => ({ text: normalizeText(cell.innerText || cell.textContent || ""), html: cell.innerHTML.trim(), header: cell.tagName.toLowerCase() === "th" })) })).filter((row) => row.cells.length > 0); } function mergeTextNodes(nodes) { const merged = []; for (const node of nodes) { if (node.type === "text") { const text = node.text; if (!text) continue; const last = merged[merged.length - 1]; if ((last == null ? void 0 : last.type) === "text") { last.text += text; } else { merged.push({ type: "text", text }); } continue; } merged.push(node); } return merged; } function mergeAdjacentParagraphs(blocks) { return blocks.filter((block) => { if (block.type !== "paragraph") return true; return normalizeText(block.children.map((child) => child.type === "text" ? child.text : "").join("")) !== "" || block.children.length > 0; }); } function isCodeLanguageLabel(node) { const text = normalizeText(node.innerText || node.textContent || ""); if (!text) return false; if (text.length > 20) return false; if (text.includes("\n")) return false; if (!CODE_LANGUAGE_LABELS$1.has(text.toLowerCase())) return false; const next = node.nextElementSibling; const prev = node.previousElementSibling; const adjacentHasCode = [next, prev].some((element) => { if (!element) return false; const tag = element.tagName.toLowerCase(); return tag === "pre" || tag === "code" || element.querySelector("pre, code") !== null; }); return adjacentHasCode; } function shouldIgnoreElement(node) { if (isActionUi(node)) return true; const tag = node.tagName.toLowerCase(); if (["button", "input", "textarea", "select", "option", "script", "style", "svg", "path"].includes(tag)) { return true; } if (node.getAttribute("role") === "button") { return true; } const ariaLabel = node.getAttribute("aria-label") || ""; if (/(复制|下载|copy|download)/i.test(ariaLabel)) { return true; } const className = typeof node.className === "string" ? node.className : ""; if (/(toolbar|action|operate|copy|download|thinking|reasoning)/i.test(className)) { return true; } const text = normalizeText(node.innerText || node.textContent || ""); if (/^(思考中|思考过程|推理中|已深度思考|thinking|reasoning)/i.test(text)) { return true; } const hasInteractive = node.querySelector('button,[role="button"]') !== null; const hasContentBlocks = node.querySelector("pre,table,blockquote,ul,ol,p,h1,h2,h3,h4,h5,h6") !== null; if (hasInteractive && !hasContentBlocks && /^(text|plain\s*text|复制|下载|copy|download|text复制下载)+$/i.test(text.replace(/\s+/g, ""))) { return true; } return false; } function shouldFlattenDiv(node) { return !node.attributes.length || node.attributes.length === 1 && node.hasAttribute("class"); } function isActionUi(node) { return node.dataset.aiOfficeCopyUi === "1" || node.closest('[data-ai-office-copy-ui="1"]') !== null; } function serializeFirstTableForExcel(blocks) { const table = blocks.find((block) => block.type === "table"); if (!table || table.type !== "table") { return null; } return { html: wrapTable(table.rows), text: table.rows.map((row) => row.cells.map((cell) => cell.text).join(" ")).join("\n") }; } function wrapTable(rows) { const html = rows.map((row) => `${row.cells.map((cell) => { const tag = cell.header ? "th" : "td"; return `<${tag}>${cell.html || escapeHtml(cell.text)}`; }).join("")}`).join(""); return `${html}
`; } const REMOVE_SELECTORS = [ '[data-ai-office-copy-ui="1"]', "button", '[role="button"]', "svg", "script", "style", ".absolute.left-0.top-0.right-0.bottom-0", '[class*="copy"]', '[class*="download"]', '[class*="toolbar"]', '[class*="action"]' ]; const CODE_LANGUAGE_LABELS = /* @__PURE__ */ new Set([ "bash", "shell", "sh", "zsh", "fish", "console", "terminal", "python", "javascript", "typescript", "js", "ts", "jsx", "tsx", "java", "go", "rust", "c", "cpp", "c++", "c#", "cs", "php", "ruby", "swift", "kotlin", "scala", "sql", "html", "css", "json", "yaml", "yml", "xml", "toml", "ini", "dockerfile", "powershell", "pwsh", "lua", "perl", "r", "matlab", "运行" ]); function serializeDomForWord(root) { const clone = root.cloneNode(true); for (const selector of REMOVE_SELECTORS) { clone.querySelectorAll(selector).forEach((node) => node.remove()); } stripCodeLanguageLabels(clone); normalizeCodeBlocks(clone); normalizeStructuredHtml(clone); normalizeListStyles(clone); const html = `${clone.innerHTML}`; const text = renderStructuredText(clone).trim(); return { html, text }; } function stripCodeLanguageLabels(root) { root.querySelectorAll("div, span, p").forEach((node) => { const text = normalizeText(node.innerText || node.textContent || ""); if (!text || text.length > 20 || text.includes("\n")) return; if (!CODE_LANGUAGE_LABELS.has(text.toLowerCase())) return; const next = node.nextElementSibling; const prev = node.previousElementSibling; const adjacentHasCode = [next, prev].some((element) => { if (!element) return false; const cls = typeof element.className === "string" ? element.className : ""; return element.tagName.toLowerCase() === "pre" || element.querySelector("pre, code") !== null || /code|pre/i.test(cls); }); if (adjacentHasCode) { node.remove(); } }); } function normalizeCodeBlocks(root) { root.querySelectorAll('[class*="code-content"], [class*="code-area"], [class*="code-block"] pre').forEach((node) => { const text = normalizeText(node.innerText || node.textContent || ""); if (!text) return; if (node.tagName.toLowerCase() === "pre") return; const pre = document.createElement("pre"); const code = document.createElement("code"); code.textContent = text; pre.appendChild(code); node.replaceWith(pre); }); } function normalizeStructuredHtml(root) { root.querySelectorAll('.md-box-line-break, [class*="md-box-line-break"], .wrapper-GYqxgQ').forEach((node) => { node.remove(); }); root.querySelectorAll(".paragraph, .paragraph-pP9ZLC, .paragraph-element").forEach((node) => { if (node.tagName.toLowerCase() === "p") return; const p = document.createElement("p"); p.innerHTML = node.innerHTML; node.replaceWith(p); }); root.querySelectorAll("li").forEach((li) => { const children = Array.from(li.children); if (children.length === 0) return; const leadingParagraphs = children.filter((child) => child.tagName.toLowerCase() === "p"); if (leadingParagraphs.length > 1) { const first = leadingParagraphs[0]; for (let i = 1; i < leadingParagraphs.length; i += 1) { first.innerHTML += "
" + leadingParagraphs[i].innerHTML; leadingParagraphs[i].remove(); } } const firstElement = li.firstElementChild; if (firstElement && firstElement.tagName.toLowerCase() === "p" && li.childElementCount === 1) { li.innerHTML = firstElement.innerHTML; } }); } function normalizeListStyles(root) { root.querySelectorAll("ol").forEach((ol) => { ol.style.margin = "0.5em 0 0.5em 1.6em"; ol.style.paddingLeft = "1.2em"; }); root.querySelectorAll("li > p:first-child").forEach((p) => { p.style.margin = "0"; }); root.querySelectorAll("ol > li > ul, ul > li > ul").forEach((ul) => { ul.style.margin = "0.25em 0 0.25em 1.4em"; ul.style.paddingLeft = "1em"; ul.style.listStyleType = "circle"; }); root.querySelectorAll("ol > li > ol, ul > li > ol").forEach((ol) => { ol.style.margin = "0.25em 0 0.25em 1.4em"; ol.style.paddingLeft = "1em"; }); } function renderStructuredText(root) { const blocks = []; for (const node of Array.from(root.childNodes)) { const rendered = renderNodeText(node, 0); if (rendered) { blocks.push(rendered); } } return blocks.join("\n\n").replace(/\n{3,}/g, "\n\n"); } function renderNodeText(node, depth) { if (node.nodeType === Node.TEXT_NODE) { return normalizeText(node.textContent || ""); } if (node.nodeType !== Node.ELEMENT_NODE) return ""; const el = node; const tag = el.tagName.toLowerCase(); if (tag === "h1" || tag === "h2" || tag === "h3" || tag === "h4" || tag === "h5" || tag === "h6") { return normalizeText(el.innerText || el.textContent || ""); } if (tag === "p") { return normalizeInlineText(el); } if (tag === "pre") { return normalizePreserveLines(el.innerText || el.textContent || ""); } if (tag === "ul") { return Array.from(el.children).filter((child) => child instanceof HTMLElement && child.tagName.toLowerCase() === "li").map((li) => renderListItem(li, depth, "-")).join("\n"); } if (tag === "ol") { return Array.from(el.children).filter((child) => child instanceof HTMLElement && child.tagName.toLowerCase() === "li").map((li, index) => { const value = li.value || index + 1; return renderListItem(li, depth, `${value}.`); }).join("\n"); } if (tag === "li") { return renderListItem(el, depth, "-"); } const childBlocks = Array.from(el.childNodes).map((child) => renderNodeText(child, depth)).filter(Boolean); if (childBlocks.length > 0) { return childBlocks.join("\n"); } return normalizeText(el.innerText || el.textContent || ""); } function renderListItem(li, depth, marker) { const indent = " ".repeat(depth); const childIndent = " ".repeat(depth + 1); const inlineParts = []; const nestedParts = []; for (const child of Array.from(li.childNodes)) { if (child.nodeType === Node.TEXT_NODE) { const text2 = normalizeText(child.textContent || ""); if (text2) inlineParts.push(text2); continue; } if (child.nodeType !== Node.ELEMENT_NODE) continue; const el = child; const tag = el.tagName.toLowerCase(); if (tag === "ul" || tag === "ol") { const nested = renderNodeText(el, depth + 1); if (nested) nestedParts.push(nested); continue; } if (tag === "pre") { const code = normalizePreserveLines(el.innerText || el.textContent || ""); if (code) nestedParts.push(code.split("\n").map((line) => `${childIndent}${line}`).join("\n")); continue; } const text = tag === "p" ? normalizeInlineText(el) : normalizeText(el.innerText || el.textContent || ""); if (text) inlineParts.push(text); } const firstLine = `${indent}${marker} ${inlineParts.join(" ").trim()}`.trimEnd(); return [firstLine, ...nestedParts].filter(Boolean).join("\n"); } function normalizeInlineText(el) { const parts = []; for (const node of Array.from(el.childNodes)) { if (node.nodeType === Node.TEXT_NODE) { const text2 = normalizeText(node.textContent || ""); if (text2) parts.push(text2); continue; } if (node.nodeType !== Node.ELEMENT_NODE) continue; const child = node; const tag = child.tagName.toLowerCase(); if (tag === "br") { parts.push("\n"); continue; } const text = normalizeText(child.innerText || child.textContent || ""); if (text) parts.push(text); } return parts.join(" ").replace(/\s*\n\s*/g, "\n").replace(/[ \t]{2,}/g, " ").trim(); } function normalizePreserveLines(value) { return value.replace(/\r\n/g, "\n").split("\n").map((line) => line.replace(/\s+$/g, "")).join("\n").trim(); } function serializeForWord(blocks) { const html = blocks.map(renderBlockHtml).join(""); const text = blocks.map(renderBlockText).join("\n\n").trim(); return { html: wrapHtml(html), text }; } function wrapHtml(body) { return `${body}`; } function renderBlockHtml(block) { switch (block.type) { case "heading": return `${renderInlineHtml(block.children)}`; case "paragraph": return `

${renderInlineHtml(block.children)}

`; case "blockquote": return `
${block.children.map(renderBlockHtml).join("")}
`; case "list": { const tag = block.ordered ? "ol" : "ul"; return `<${tag}>${block.items.map((item) => `
  • ${renderListItemHtml(item)}
  • `).join("")}`; } case "code_block": return `
    ${escapeHtml(block.text)}
    `; case "table": return renderTableHtml(block.rows); case "html_block": return block.html; } } function renderInlineHtml(nodes) { return nodes.map((node) => { switch (node.type) { case "text": return escapeHtml(node.text); case "strong": return `${renderInlineHtml(node.children)}`; case "em": return `${renderInlineHtml(node.children)}`; case "del": return `${renderInlineHtml(node.children)}`; case "code": return `${escapeHtml(node.text)}`; case "link": return `${renderInlineHtml(node.children)}`; case "br": return "
    "; } }).join(""); } function renderListItemHtml(blocks) { if (blocks.length === 0) { return ""; } if (blocks.length === 1 && blocks[0].type === "paragraph") { return renderInlineHtml(blocks[0].children); } return blocks.map(renderBlockHtml).join("") || "

    "; } function renderBlockText(block) { switch (block.type) { case "heading": case "paragraph": return normalizeText(renderInlineText(block.children)); case "blockquote": return block.children.map(renderBlockText).filter(Boolean).map((line) => `> ${line}`).join("\n"); case "list": return block.items.map((item, index) => `${block.ordered ? `${index + 1}.` : "-"} ${item.map(renderBlockText).join(" ").trim()}`).join("\n"); case "code_block": return block.text; case "table": return block.rows.map((row) => row.cells.map((cell) => cell.text).join(" ")).join("\n"); case "html_block": return block.text; } } function renderInlineText(nodes) { return nodes.map((node) => { switch (node.type) { case "text": return node.text; case "strong": case "em": case "del": case "link": return renderInlineText(node.children); case "code": return node.text; case "br": return "\n"; } }).join(""); } function renderTableHtml(rows) { const body = rows.map((row) => `${row.cells.map((cell) => { const tag = cell.header ? "th" : "td"; return `<${tag}>${cell.html || escapeHtml(cell.text)}`; }).join("")}`).join(""); return `${body}
    `; } function createActionButton(label, onClick) { const button = document.createElement("button"); button.type = "button"; button.textContent = label; button.dataset.aiOfficeCopyUi = "1"; button.style.cssText = [ "border:1px solid rgba(0,0,0,.12)", "border-radius:8px", "padding:4px 10px", "font-size:12px", "line-height:1.4", "cursor:pointer", "background:#fff", "color:#111", "box-shadow:0 1px 2px rgba(0,0,0,.06)", "transition:opacity .15s ease, transform .15s ease, background-color .15s ease, color .15s ease, border-color .15s ease" ].join(";"); button.addEventListener("click", async (event) => { event.preventDefault(); event.stopPropagation(); if (button.disabled) return; const originalText = label; const originalBackground = button.style.background; const originalColor = button.style.color; const originalBorderColor = button.style.borderColor; const setState = (text, styles) => { button.textContent = text; if (styles == null ? void 0 : styles.background) button.style.background = styles.background; if (styles == null ? void 0 : styles.color) button.style.color = styles.color; if (styles == null ? void 0 : styles.borderColor) button.style.borderColor = styles.borderColor; if (styles == null ? void 0 : styles.transform) button.style.transform = styles.transform; }; try { button.disabled = true; button.style.opacity = "0.78"; button.style.cursor = "progress"; button.style.transform = "scale(0.98)"; setState("复制中..."); await onClick(); button.style.opacity = "1"; button.style.cursor = "default"; setState("已复制", { background: "#ecfdf3", color: "#027a48", borderColor: "#12b76a", transform: "scale(1)" }); await delay(900); } catch (error) { button.style.opacity = "1"; button.style.cursor = "default"; setState("复制失败", { background: "#fef3f2", color: "#b42318", borderColor: "#f04438", transform: "scale(1)" }); await delay(1200); throw error; } finally { button.disabled = false; button.style.opacity = "1"; button.style.cursor = "pointer"; button.style.transform = "scale(1)"; button.textContent = originalText; button.style.background = originalBackground; button.style.color = originalColor; button.style.borderColor = originalBorderColor; } }); return button; } function createActionBar() { const wrapper = document.createElement("div"); wrapper.dataset.aiOfficeCopyUi = "1"; wrapper.style.cssText = [ "display:flex", "gap:8px", "margin-top:10px", "flex-wrap:wrap", "align-items:center" ].join(";"); return wrapper; } function delay(ms) { return new Promise((resolve) => window.setTimeout(resolve, ms)); } function enhanceResponse(target, contentRoot, options) { if (target.dataset.aiOfficeCopyEnhanced === "1") return; const source = contentRoot ?? target; target.dataset.aiOfficeCopyEnhanced = "1"; const actions = createActionBar(); const wordButton = createActionButton("复制为 Word", async () => { const payload = (options == null ? void 0 : options.preferRawHtml) ? serializeDomForWord(source) : serializeForWord(extractBlocks(source)); if (!payload.text) { throw new Error("未识别到可复制内容"); } await writeClipboard(payload.html, payload.text); }); actions.appendChild(wordButton); const blocks = extractBlocks(source); if (hasTable(blocks)) { const excelButton = createActionButton("复制表格为 Excel", async () => { const payload = serializeFirstTableForExcel(extractBlocks(source)); if (!payload) { throw new Error("当前回复未检测到表格"); } await writeClipboard(payload.html, payload.text); }); actions.appendChild(excelButton); } target.appendChild(actions); } function watchWithObserver(run) { run(); const observer = new MutationObserver(() => run()); observer.observe(document.body, { childList: true, subtree: true }); } function collectRoots(root, roots = []) { roots.push(root); const elements = root instanceof Document || root instanceof ShadowRoot || root instanceof Element ? Array.from(root.querySelectorAll("*")) : []; for (const element of elements) { const shadowRoot = element.shadowRoot; if (shadowRoot) { collectRoots(shadowRoot, roots); } } return roots; } function queryAllDeep(selector) { const results = []; const seen = /* @__PURE__ */ new Set(); for (const root of collectRoots(document)) { root.querySelectorAll(selector).forEach((node) => { const element = node; if (seen.has(element)) return; seen.add(element); results.push(element); }); } return results; } function findContentRoot(response, selectors) { for (const selector of selectors) { const found = response.matches(selector) ? response : response.querySelector(selector); if (found) return found; for (const root of collectRoots(response)) { const nested = root.querySelector(selector); if (nested) return nested; } } return response; } function enhanceMatches(responseSelectors, contentSelectors, enhance) { const candidates = []; const seen = /* @__PURE__ */ new Set(); for (const selector of responseSelectors) { queryAllDeep(selector).forEach((response) => { if (seen.has(response)) return; seen.add(response); candidates.push(response); }); } const topLevelCandidates = candidates.filter((candidate) => { return !candidates.some((other) => other !== candidate && other.contains(candidate)); }); for (const response of topLevelCandidates) { if (response.dataset.aiOfficeCopyEnhanced === "1") continue; if (response.closest('[data-ai-office-copy-enhanced="1"]')) continue; const content = findContentRoot(response, contentSelectors); if (content) { enhance(response, content); } } } const RESPONSE_SELECTORS$3 = [ 'article [data-message-author-role="assistant"]', "article", '[data-message-author-role="assistant"]' ]; const CONTENT_SELECTORS$4 = [ '[data-message-author-role="assistant"] .markdown', '[data-message-author-role="assistant"] .prose', ".markdown", ".prose" ]; const chatgptAdapter = { name: "chatgpt", match(url) { return url.hostname === "chatgpt.com" || url.hostname === "chat.openai.com"; }, start() { watchWithObserver(() => { enhanceMatches(RESPONSE_SELECTORS$3, CONTENT_SELECTORS$4, enhanceResponse); }); } }; const RESPONSE_SELECTORS$2 = [ ".font-claude-response", '[data-testid="conversation-turn-assistant"]', "[data-is-streaming] .font-claude-message", ".font-claude-message" ]; const CONTENT_SELECTORS$3 = [ ".standard-markdown", ".font-claude-response", ".font-claude-message", '[data-testid="artifact-panel"] .font-claude-message', ".prose", ".markdown" ]; const claudeAdapter = { name: "claude", match(url) { return url.hostname === "claude.ai" || url.hostname.endsWith(".claude.ai"); }, start() { watchWithObserver(() => { enhanceMatches(RESPONSE_SELECTORS$2, CONTENT_SELECTORS$3, enhanceResponse); }); } }; const RESPONSE_SELECTORS$1 = [ '[data-role="assistant"]', ".ds-markdown", ".markdown-body" ]; const CONTENT_SELECTORS$2 = [ ".ds-markdown", ".markdown-body", ".markdown" ]; const deepseekAdapter = { name: "deepseek", match(url) { return url.hostname === "chat.deepseek.com"; }, start() { watchWithObserver(() => { enhanceMatches(RESPONSE_SELECTORS$1, CONTENT_SELECTORS$2, enhanceResponse); }); } }; const CONTENT_SELECTORS$1 = [ ".container-P2rR72.flow-markdown-body", ".flow-markdown-body", ".content-y8qlFa.code-content", ".code-area-yxsM36", ".code-block-element-R6c8c0" ]; function enhanceDoubaoContent() { const seen = /* @__PURE__ */ new Set(); for (const selector of CONTENT_SELECTORS$1) { for (const element of queryAllDeep(selector)) { if (seen.has(element)) continue; seen.add(element); if (element.dataset.aiOfficeCopyEnhanced === "1") continue; if (element.closest('[data-ai-office-copy-enhanced="1"]')) continue; enhanceResponse(element, element, { preferRawHtml: true }); } } } const doubaoAdapter = { name: "doubao", match(url) { return url.hostname === "www.doubao.com" || url.hostname === "doubao.com"; }, start() { watchWithObserver(() => { enhanceDoubaoContent(); }); } }; const RESPONSE_SELECTORS = [ "message-content[model-response] .model-response-text", ".model-response-text", ".response-content" ]; const CONTENT_SELECTORS = [ ".model-response-text", ".markdown", ".response-content", ".prose" ]; const geminiAdapter = { name: "gemini", match(url) { return url.hostname === "gemini.google.com"; }, start() { watchWithObserver(() => { enhanceMatches(RESPONSE_SELECTORS, CONTENT_SELECTORS, enhanceResponse); }); } }; const FINAL_MARKDOWN_SELECTORS = [ ".chat-content-item.chat-content-item-assistant .markdown-container:not(.toolcall-content-text) > .markdown", ".segment.segment-assistant .markdown-container:not(.toolcall-content-text) > .markdown" ]; function getMarkdownTarget(source) { return source.closest(".markdown-container:not(.toolcall-content-text)") ?? source; } function enhanceKimiContent() { const seenSources = /* @__PURE__ */ new Set(); const seenTargets = /* @__PURE__ */ new Set(); for (const selector of FINAL_MARKDOWN_SELECTORS) { for (const source of queryAllDeep(selector)) { if (seenSources.has(source)) continue; seenSources.add(source); const target = getMarkdownTarget(source); if (seenTargets.has(target)) continue; seenTargets.add(target); if (target.dataset.aiOfficeCopyEnhanced === "1") continue; enhanceResponse(target, source, { preferRawHtml: true }); } } } const kimiAdapter = { name: "kimi", match(url) { return url.hostname === "kimi.moonshot.cn" || url.hostname === "kimi.com" || url.hostname === "www.kimi.com"; }, start() { watchWithObserver(() => { enhanceKimiContent(); }); } }; const adapters = [ chatgptAdapter, deepseekAdapter, claudeAdapter, geminiAdapter, kimiAdapter, doubaoAdapter ]; const current = adapters.find((adapter) => adapter.match(new URL(location.href))); if (current) { current.start(); console.log(`[ai-office-copy] started: ${current.name}`); } else { console.log("[ai-office-copy] no adapter matched"); } })();