作者 202304001

AI写作工具栏功能、写作提示词修改、pdf/word文件内容上传读取

@@ -27,6 +27,7 @@ type HTMLPreviewProps = { @@ -27,6 +27,7 @@ type HTMLPreviewProps = {
27 autoHeight?: boolean; 27 autoHeight?: boolean;
28 height?: number | string; 28 height?: number | string;
29 onLoad?: (title?: string) => void; 29 onLoad?: (title?: string) => void;
  30 + width?: number | string; //20250403 新增宽度配置
30 }; 31 };
31 32
32 export type HTMLPreviewHander = { 33 export type HTMLPreviewHander = {
@@ -78,6 +79,8 @@ export const HTMLPreview = forwardRef<HTMLPreviewHander, HTMLPreviewProps>( @@ -78,6 +79,8 @@ export const HTMLPreview = forwardRef<HTMLPreviewHander, HTMLPreviewProps>(
78 : iframeHeight + 40; 79 : iframeHeight + 40;
79 }, [props.autoHeight, props.height, iframeHeight]); 80 }, [props.autoHeight, props.height, iframeHeight]);
80 81
  82 + const width = props.width || "100%"; //20250403 新增宽度配置
  83 +
81 const srcDoc = useMemo(() => { 84 const srcDoc = useMemo(() => {
82 const script = `<script>window.addEventListener("DOMContentLoaded", () => new ResizeObserver((entries) => parent.postMessage({id: '${frameId}', height: entries[0].target.clientHeight}, '*')).observe(document.body))</script>`; 85 const script = `<script>window.addEventListener("DOMContentLoaded", () => new ResizeObserver((entries) => parent.postMessage({id: '${frameId}', height: entries[0].target.clientHeight}, '*')).observe(document.body))</script>`;
83 if (props.code.includes("<!DOCTYPE html>")) { 86 if (props.code.includes("<!DOCTYPE html>")) {
@@ -98,7 +101,7 @@ export const HTMLPreview = forwardRef<HTMLPreviewHander, HTMLPreviewProps>( @@ -98,7 +101,7 @@ export const HTMLPreview = forwardRef<HTMLPreviewHander, HTMLPreviewProps>(
98 key={frameId} 101 key={frameId}
99 ref={iframeRef} 102 ref={iframeRef}
100 sandbox="allow-forms allow-modals allow-scripts" 103 sandbox="allow-forms allow-modals allow-scripts"
101 - style={{ height }} 104 + style={{ height, width }}
102 srcDoc={srcDoc} 105 srcDoc={srcDoc}
103 onLoad={handleOnLoad} 106 onLoad={handleOnLoad}
104 /> 107 />
@@ -253,7 +256,7 @@ export function Artifacts() { @@ -253,7 +256,7 @@ export function Artifacts() {
253 code={code} 256 code={code}
254 ref={previewRef} 257 ref={previewRef}
255 autoHeight={false} 258 autoHeight={false}
256 - height={"100%"} 259 + height={"100%"} //20250403 新增宽度配置
257 onLoad={(title) => { 260 onLoad={(title) => {
258 setFileName(title as string); 261 setFileName(title as string);
259 setLoading(false); 262 setLoading(false);
@@ -136,10 +136,11 @@ import clsx from "clsx"; @@ -136,10 +136,11 @@ import clsx from "clsx";
136 import { getAvailableClientsCount, isMcpEnabled } from "../mcp/actions"; 136 import { getAvailableClientsCount, isMcpEnabled } from "../mcp/actions";
137 137
138 //20250317新增 138 //20250317新增
139 -import { getExcelData, toExcel } from "../utils/excelAndWordUtils/export2Excel";  
140 -import { exportWord } from "../utils/excelAndWordUtils/word"; 139 +import { getExcelData, toExcel } from "../utils/fileExport/export2Excel";
  140 +import { exportWord, getWordData } from "../utils/fileExport/word";
141 import { getMindPrompt } from "../utils/prompt"; 141 import { getMindPrompt } from "../utils/prompt";
142 import { message } from "antd"; 142 import { message } from "antd";
  143 +import { getPdfData } from "../utils/fileExport/toPdf";
143 const localStorage = safeLocalStorage(); 144 const localStorage = safeLocalStorage();
144 145
145 const ttsPlayer = createTTSPlayer(); 146 const ttsPlayer = createTTSPlayer();
@@ -1774,33 +1775,57 @@ function _Chat() { @@ -1774,33 +1775,57 @@ function _Chat() {
1774 const [fileName, setFileName] = useState(""); 1775 const [fileName, setFileName] = useState("");
1775 1776
1776 async function uploadFile() { 1777 async function uploadFile() {
1777 - // 创建一个隐藏的文件输入框  
1778 const fileInput = document.createElement("input"); 1778 const fileInput = document.createElement("input");
1779 fileInput.type = "file"; 1779 fileInput.type = "file";
1780 - fileInput.accept = ".xlsx, .xls"; 1780 + fileInput.accept = ".xlsx, .xls, .pdf, .docx, .doc";
1781 fileInput.multiple = false; 1781 fileInput.multiple = false;
1782 - fileInput.onchange = (event: Event) => {  
1783 - const target = event.target as HTMLInputElement;  
1784 - const files = target.files;  
1785 - if (files && files.length > 0) {  
1786 - const file = files[0]; // 获取第一个文件  
1787 - getExcelData(file)  
1788 - .then((data) => {  
1789 - const value = `'''filedata  
1790 - ${file.name}  
1791 - ${JSON.stringify(data)}  
1792 - '''filedata  
1793 - `;  
1794 - setFileData(value);  
1795 - setFileName(file.name);  
1796 - console.log(value);  
1797 - })  
1798 - .catch((error) => {  
1799 - message.error("上传失败");  
1800 - }); 1782 + fileInput.style.display = "none";
  1783 + const handleFileResult = (fileName: string, data: any) => {
  1784 + if (!data) {
  1785 + message.error("未读取到内容");
  1786 + return;
  1787 + }
  1788 + setFileData(`'''filedata
  1789 + ${fileName}
  1790 + ${JSON.stringify(data)}
  1791 + '''filedata`);
  1792 + setFileName(fileName);
  1793 + };
  1794 + const handleError = (error: any, defaultMsg = "上传失败") => {
  1795 + console.error(`${defaultMsg}:`, error);
  1796 + message.error(defaultMsg);
  1797 + };
  1798 + // 文件处理器映射
  1799 + const fileHandlers: Record<string, (file: File) => Promise<any>> = {
  1800 + ".xlsx": getExcelData,
  1801 + ".xls": getExcelData,
  1802 + ".doc": getWordData,
  1803 + ".docx": getWordData,
  1804 + ".pdf": getPdfData,
  1805 + };
  1806 + fileInput.onchange = async (event: Event) => {
  1807 + try {
  1808 + const file = (event.target as HTMLInputElement).files?.[0];
  1809 + if (!file) return;
  1810 + const fileExt = file.name
  1811 + .toLowerCase()
  1812 + .slice(file.name.lastIndexOf("."));
  1813 + // 校验文件类型
  1814 + if (!Object.keys(fileHandlers).includes(fileExt)) {
  1815 + message.error("不支持的文件类型");
  1816 + return;
  1817 + }
  1818 + // 获取处理器并执行
  1819 + const handler = fileHandlers[fileExt];
  1820 + const data = await handler(file);
  1821 + handleFileResult(file.name, data);
  1822 + } catch (error) {
  1823 + handleError(error);
  1824 + } finally {
  1825 + fileInput.remove();
1801 } 1826 }
1802 - fileInput.remove();  
1803 }; 1827 };
  1828 + document.body.appendChild(fileInput);
1804 fileInput.click(); 1829 fileInput.click();
1805 } 1830 }
1806 return ( 1831 return (
@@ -21,6 +21,8 @@ export interface WriteSiderBarProps { @@ -21,6 +21,8 @@ export interface WriteSiderBarProps {
21 setHtmlCode: React.Dispatch<React.SetStateAction<string>>; 21 setHtmlCode: React.Dispatch<React.SetStateAction<string>>;
22 loading: boolean; 22 loading: boolean;
23 setLoading: React.Dispatch<React.SetStateAction<boolean>>; 23 setLoading: React.Dispatch<React.SetStateAction<boolean>>;
  24 + setWidth: React.Dispatch<React.SetStateAction<string>>;
  25 + setHtmlheader: React.Dispatch<React.SetStateAction<string>>;
24 } 26 }
25 27
26 const WritingPanel = dynamic( 28 const WritingPanel = dynamic(
@@ -31,7 +33,15 @@ const WritingPanel = dynamic( @@ -31,7 +33,15 @@ const WritingPanel = dynamic(
31 ); 33 );
32 34
33 export function WriteSiderBar(props: WriteSiderBarProps) { 35 export function WriteSiderBar(props: WriteSiderBarProps) {
34 - const { className, htmlCode, setHtmlCode, loading, setLoading } = props; 36 + const {
  37 + className,
  38 + htmlCode,
  39 + setHtmlCode,
  40 + loading,
  41 + setLoading,
  42 + setWidth,
  43 + setHtmlheader,
  44 + } = props;
35 const isMobileScreen = useMobileScreen(); 45 const isMobileScreen = useMobileScreen();
36 const { onDragStart, shouldNarrow } = useDragSideBar(); 46 const { onDragStart, shouldNarrow } = useDragSideBar();
37 const navigate = useNavigate(); 47 const navigate = useNavigate();
@@ -93,6 +103,8 @@ export function WriteSiderBar(props: WriteSiderBarProps) { @@ -93,6 +103,8 @@ export function WriteSiderBar(props: WriteSiderBarProps) {
93 setHtmlCode={setHtmlCode} 103 setHtmlCode={setHtmlCode}
94 loading={loading} 104 loading={loading}
95 setLoading={setLoading} 105 setLoading={setLoading}
  106 + setWidth={setWidth}
  107 + setHtmlheader={setHtmlheader}
96 /> 108 />
97 </SideBarBody> 109 </SideBarBody>
98 </SideBarContainer> 110 </SideBarContainer>
@@ -16,11 +16,10 @@ const mergedData = [ @@ -16,11 +16,10 @@ const mergedData = [
16 type: "select", 16 type: "select",
17 default: "公司官网", 17 default: "公司官网",
18 options: [ 18 options: [
19 - { name: "公司官网", value: "1" },  
20 - { name: "小红书", value: "2" },  
21 - { name: "微信", value: "3" },  
22 - { name: "公众号", value: "4" },  
23 - { name: "今日头条", value: "5" }, 19 + { name: "公司官网", value: "100%" },
  20 + { name: "小红书", value: "400px" },
  21 + { name: "微信公众号", value: "300px" },
  22 + { name: "今日头条", value: "500px" },
24 ], 23 ],
25 }, 24 },
26 { 25 {
@@ -62,10 +61,10 @@ const mergedData = [ @@ -62,10 +61,10 @@ const mergedData = [
62 required: false, 61 required: false,
63 default: "产品推广文案", 62 default: "产品推广文案",
64 options: [ 63 options: [
65 - { name: "产品推广文案", value: "产品推广文案" },  
66 - { name: "品牌宣传文案", value: "品牌宣传文案" },  
67 - { name: "产品说明书", value: "产品说明书" },  
68 - { name: "产品介绍", value: "产品介绍" }, 64 + { name: "产品推广文案", value: "promotion" },
  65 + { name: "品牌宣传文案", value: "propagandize" },
  66 + { name: "产品说明书", value: "instructionBook" },
  67 + { name: "产品介绍", value: "introduce" },
69 ], 68 ],
70 }, 69 },
71 { 70 {
@@ -85,9 +84,18 @@ export interface WritePanelProps { @@ -85,9 +84,18 @@ export interface WritePanelProps {
85 setHtmlCode: React.Dispatch<React.SetStateAction<string>>; 84 setHtmlCode: React.Dispatch<React.SetStateAction<string>>;
86 loading: boolean; 85 loading: boolean;
87 setLoading: React.Dispatch<React.SetStateAction<boolean>>; 86 setLoading: React.Dispatch<React.SetStateAction<boolean>>;
  87 + setWidth: React.Dispatch<React.SetStateAction<string>>;
  88 + setHtmlheader: React.Dispatch<React.SetStateAction<string>>;
88 } 89 }
89 export function WritingPanel(props: WritePanelProps) { 90 export function WritingPanel(props: WritePanelProps) {
90 - const { htmlCode, setHtmlCode, setLoading, loading } = props; 91 + const {
  92 + htmlCode,
  93 + setHtmlCode,
  94 + setLoading,
  95 + loading,
  96 + setWidth,
  97 + setHtmlheader,
  98 + } = props;
91 // 为每个选择框单独声明状态,存储name 99 // 为每个选择框单独声明状态,存储name
92 const chatStore = useChatStore(); 100 const chatStore = useChatStore();
93 const [writingPurposeName, setWritingPurposeName] = useState("公司官网"); // 写作用途 101 const [writingPurposeName, setWritingPurposeName] = useState("公司官网"); // 写作用途
@@ -104,10 +112,12 @@ export function WritingPanel(props: WritePanelProps) { @@ -104,10 +112,12 @@ export function WritingPanel(props: WritePanelProps) {
104 const handleSelectChange = (index: number, value: string) => { 112 const handleSelectChange = (index: number, value: string) => {
105 const options = mergedData[index].options; 113 const options = mergedData[index].options;
106 const selectedName = options.find((opt) => opt.value === value)?.name || ""; 114 const selectedName = options.find((opt) => opt.value === value)?.name || "";
107 - 115 + const selectedValue =
  116 + options.find((opt) => opt.value === value)?.value || "";
108 switch (index) { 117 switch (index) {
109 case 0: 118 case 0:
110 setWritingPurposeName(selectedName); 119 setWritingPurposeName(selectedName);
  120 + setWidth(selectedValue);
111 break; 121 break;
112 case 1: 122 case 1:
113 setImageModeName(selectedName); 123 setImageModeName(selectedName);
@@ -164,6 +174,19 @@ export function WritingPanel(props: WritePanelProps) { @@ -164,6 +174,19 @@ export function WritingPanel(props: WritePanelProps) {
164 if (cleanedContent.endsWith("```")) { 174 if (cleanedContent.endsWith("```")) {
165 cleanedContent = cleanedContent.substring(0, cleanedContent.length - 4); 175 cleanedContent = cleanedContent.substring(0, cleanedContent.length - 4);
166 } 176 }
  177 +
  178 + //保存html头部
  179 + const bodyTagRegex = /<body[^>]*>/i;
  180 + const bodyTagMatch = cleanedContent.match(bodyTagRegex);
  181 + if (bodyTagMatch && bodyTagMatch.index !== undefined) {
  182 + // 截取从文档开头到 <body> 标签的起始位置
  183 + const contentUpToBody = cleanedContent.slice(
  184 + 0,
  185 + bodyTagMatch.index + bodyTagMatch[0].length,
  186 + );
  187 + setHtmlheader(contentUpToBody); //保存html头部
  188 + }
  189 + localStorage.setItem("htmlCode", cleanedContent);
167 setHtmlCode(cleanedContent); 190 setHtmlCode(cleanedContent);
168 } catch (error) { 191 } catch (error) {
169 message.error("生成失败,请重试"); 192 message.error("生成失败,请重试");
  1 +.write-body{
  2 + display: flex;
  3 + flex-direction: column;
  4 + justify-content: center;
  5 + align-items: center;
  6 +}
  7 +
1 .loading-content { 8 .loading-content {
2 display: flex; 9 display: flex;
3 flex-direction: column; 10 flex-direction: column;
@@ -11,12 +11,11 @@ import Locale from "@/app/locales"; @@ -11,12 +11,11 @@ import Locale from "@/app/locales";
11 import { Path } from "@/app/constant"; 11 import { Path } from "@/app/constant";
12 import { useNavigate } from "react-router-dom"; 12 import { useNavigate } from "react-router-dom";
13 import { getClientConfig } from "@/app/config/client"; 13 import { getClientConfig } from "@/app/config/client";
14 -import React, { useMemo, useRef, useState } from "react";  
15 -import { useAppConfig } from "@/app/store"; 14 +import React, { useCallback, useMemo, useRef, useState } from "react";
  15 +import { useAppConfig, useMindMapStore } from "@/app/store";
16 import { ChatAction } from "../chat"; 16 import { ChatAction } from "../chat";
17 import { useWindowSize } from "@/app/utils"; 17 import { useWindowSize } from "@/app/utils";
18 -import { exportWord } from "@/app/utils/excelAndWordUtils/word";  
19 -import { HTMLPreview } from "../artifacts"; 18 +import { exportHtmlToWord } from "@/app/utils/fileExport/word";
20 import ReactQuill from "react-quill"; 19 import ReactQuill from "react-quill";
21 import "react-quill/dist/quill.snow.css"; 20 import "react-quill/dist/quill.snow.css";
22 21
@@ -34,7 +33,13 @@ import WordIcon from "@/app/icons/word.svg"; @@ -34,7 +33,13 @@ import WordIcon from "@/app/icons/word.svg";
34 import MindIcon from "@/app/icons/mind.svg"; 33 import MindIcon from "@/app/icons/mind.svg";
35 import PptIcon from "@/app/icons/ppt.svg"; 34 import PptIcon from "@/app/icons/ppt.svg";
36 import PdfIcon from "@/app/icons/pdf.svg"; 35 import PdfIcon from "@/app/icons/pdf.svg";
  36 +import HtmlIcon from "@/app/icons/HTML.svg";
  37 +
37 import { message } from "antd"; 38 import { message } from "antd";
  39 +import { HTMLPreview } from "../artifacts";
  40 +import { getMindPrompt } from "@/app/utils/prompt";
  41 +import { htmlToPdf2 } from "@/app/utils/fileExport/toPdf";
  42 +import { htmlToExcel } from "@/app/utils/fileExport/export2Excel";
38 43
39 export function WritingPage() { 44 export function WritingPage() {
40 const isMobileScreen = useMobileScreen(); 45 const isMobileScreen = useMobileScreen();
@@ -45,10 +50,14 @@ export function WritingPage() { @@ -45,10 +50,14 @@ export function WritingPage() {
45 const scrollRef = useRef<HTMLDivElement>(null); 50 const scrollRef = useRef<HTMLDivElement>(null);
46 const isWriting = location.pathname === Path.Writing; 51 const isWriting = location.pathname === Path.Writing;
47 const { height } = useWindowSize(); 52 const { height } = useWindowSize();
  53 + const [width, setWidth] = useState("100%");
48 const [isEdit, setIsEdit] = useState(false); 54 const [isEdit, setIsEdit] = useState(false);
49 const [loading, setLoading] = useState(false); 55 const [loading, setLoading] = useState(false);
50 const quillRef = useRef<ReactQuill | null>(null); 56 const quillRef = useRef<ReactQuill | null>(null);
51 - const [htmlCode, setHtmlCode] = useState(""); 57 + const [htmlHeader, setHtmlheader] = useState("");
  58 + const [htmlCode, setHtmlCode] = useState(
  59 + localStorage.getItem("htmlCode") || "",
  60 + );
52 61
53 //编辑器 62 //编辑器
54 const toolbarOptions = [ 63 const toolbarOptions = [
@@ -60,42 +69,66 @@ export function WritingPage() { @@ -60,42 +69,66 @@ export function WritingPage() {
60 ["link", "image"], 69 ["link", "image"],
61 ]; 70 ];
62 71
63 - const copyToClipboard = () => {  
64 - // 检查quillRef.current是否为null  
65 - if (quillRef.current) {  
66 - const editor = quillRef.current.getEditor(); // 获取编辑器实例  
67 - const range = editor.getSelection(); // 获取当前选择的范围  
68 - const text = editor.getText(); // 获取编辑器中的文本内容 72 + // 生成完整HTML内容
  73 + const generateFullHtml = useCallback(
  74 + () => `${htmlHeader}${htmlCode}</body></html>`,
  75 + [htmlHeader, htmlCode],
  76 + );
69 77
70 - if (range && range.length > 0) {  
71 - // 如果有选中的文本,复制选中的内容  
72 - const selectedText = text.substring(  
73 - range.index,  
74 - range.index + range.length,  
75 - );  
76 - navigator.clipboard  
77 - .writeText(selectedText)  
78 - .then(() => {  
79 - message.success("复制成功");  
80 - })  
81 - .catch((err) => {  
82 - message.error("复制失败:");  
83 - });  
84 - } else {  
85 - // 如果没有选择文本,就复制全部内容  
86 - navigator.clipboard  
87 - .writeText(text)  
88 - .then(() => {  
89 - message.success("复制成功");  
90 - })  
91 - .catch((err) => {  
92 - message.error("复制失败:");  
93 - });  
94 - }  
95 - } else {  
96 - console.error("Quill编辑器尚未初始化"); 78 + const handleCopy = async () => {
  79 + try {
  80 + const blob = new Blob([htmlCode], { type: "text/html" });
  81 + const clipboardItem = new ClipboardItem({ "text/html": blob });
  82 + await navigator.clipboard.write([clipboardItem]);
  83 + message.success("复制成功!");
  84 + } catch (error) {
  85 + message.error("复制失败");
97 } 86 }
98 }; 87 };
  88 + //跳转到ppt页面
  89 + function toPowerpoint(pptMessage: string) {
  90 + navigate("/powerpoint", { state: { msg: true, pptMessage: pptMessage } });
  91 + }
  92 + // 转至思维导图页面
  93 + const toMind = useCallback(
  94 + (content: string) => {
  95 + const { setMindMapData } = useMindMapStore.getState();
  96 + setMindMapData(
  97 + [
  98 + {
  99 + role: "user",
  100 + content: getMindPrompt(content, true),
  101 + },
  102 + ],
  103 + content,
  104 + );
  105 + navigate("/mind", { state: { msg: true } });
  106 + },
  107 + [navigate],
  108 + );
  109 +
  110 + //导出html文件
  111 + const exportHtml = useCallback(() => {
  112 + try {
  113 + const htmlContent = generateFullHtml();
  114 + const blob = new Blob([htmlContent], { type: "text/html" });
  115 + const url = URL.createObjectURL(blob);
  116 + const a = document.createElement("a");
  117 + a.href = url;
  118 + a.download = "output.html";
  119 + a.click();
  120 + URL.revokeObjectURL(url);
  121 + message.success("导出成功");
  122 + } catch (error) {
  123 + message.error("导出失败");
  124 + }
  125 + }, [generateFullHtml]);
  126 +
  127 + function hasTable(htmlContent: string): boolean {
  128 + const parser = new DOMParser();
  129 + const doc = parser.parseFromString(htmlContent, "text/html");
  130 + return doc.querySelector("table") !== null;
  131 + }
99 132
100 return ( 133 return (
101 <> 134 <>
@@ -105,6 +138,8 @@ export function WritingPage() { @@ -105,6 +138,8 @@ export function WritingPage() {
105 setHtmlCode={setHtmlCode} 138 setHtmlCode={setHtmlCode}
106 loading={loading} 139 loading={loading}
107 setLoading={setLoading} 140 setLoading={setLoading}
  141 + setWidth={setWidth}
  142 + setHtmlheader={setHtmlheader}
108 /> 143 />
109 <WindowContent> 144 <WindowContent>
110 <div className={chatStyles.chat} key={"1"}> 145 <div className={chatStyles.chat} key={"1"}>
@@ -130,66 +165,97 @@ export function WritingPage() { @@ -130,66 +165,97 @@ export function WritingPage() {
130 <div className={`window-header-main-title`}>AI-Writing</div> 165 <div className={`window-header-main-title`}>AI-Writing</div>
131 </div> 166 </div>
132 <div className={chatStyles["chat-message-actions"]}> 167 <div className={chatStyles["chat-message-actions"]}>
133 - <div className={chatStyles["chat-input-actions"]}>  
134 - <ChatAction  
135 - text={Locale.Chat.Actions.ReWrite}  
136 - icon={<ReloadIcon />}  
137 - onClick={() => {}}  
138 - />  
139 - <ChatAction  
140 - text={Locale.Chat.Actions.Copy}  
141 - icon={<CopyIcon />}  
142 - onClick={copyToClipboard}  
143 - />  
144 - {!isEdit ? ( 168 + {htmlCode && (
  169 + <div className={chatStyles["chat-input-actions"]}>
145 <ChatAction 170 <ChatAction
146 - text={Locale.Chat.Actions.Edit}  
147 - icon={<EditIcon />}  
148 - onClick={() => {  
149 - setIsEdit(true); 171 + text={Locale.Chat.Actions.ReWrite}
  172 + icon={<ReloadIcon />}
  173 + onClick={() => {}}
  174 + disabled={isEdit}
  175 + />
  176 + <ChatAction
  177 + text={Locale.Chat.Actions.Copy}
  178 + icon={<CopyIcon />}
  179 + onClick={handleCopy}
  180 + disabled={isEdit}
  181 + />
  182 + {!isEdit ? (
  183 + <ChatAction
  184 + text={Locale.Chat.Actions.Edit}
  185 + icon={<EditIcon />}
  186 + onClick={() => {
  187 + setIsEdit(true);
  188 + }}
  189 + />
  190 + ) : (
  191 + <ChatAction
  192 + text={Locale.Chat.Actions.CancelEdit}
  193 + icon={<EditIcon />}
  194 + onClick={() => {
  195 + setIsEdit(false);
  196 + }}
  197 + />
  198 + )}
  199 + <ChatAction
  200 + text={Locale.Export.Pdf}
  201 + icon={<PdfIcon />}
  202 + onClick={async () => {
  203 + setLoading(true);
  204 + await htmlToPdf2(htmlCode);
  205 + setLoading(false);
150 }} 206 }}
  207 + disabled={isEdit}
151 /> 208 />
152 - ) : (  
153 <ChatAction 209 <ChatAction
154 - text="取消编辑"  
155 - icon={<EditIcon />} 210 + text={Locale.Export.Word}
  211 + icon={<WordIcon />}
156 onClick={() => { 212 onClick={() => {
157 - setIsEdit(false); 213 + const html = `${htmlHeader}
  214 + ${htmlCode}
  215 + </body>
  216 + </html>
  217 + `;
  218 + exportHtmlToWord(html);
158 }} 219 }}
  220 + disabled={isEdit}
159 /> 221 />
160 - )} 222 + {hasTable(htmlCode) && (
  223 + <ChatAction
  224 + text={Locale.Export.Excel}
  225 + icon={<ExcelIcon />}
  226 + onClick={() => {
  227 + htmlToExcel(htmlCode);
  228 + }}
  229 + disabled={isEdit}
  230 + />
  231 + )}
161 232
162 - <ChatAction  
163 - text={Locale.Export.Pdf}  
164 - icon={<PdfIcon />}  
165 - onClick={() => {}}  
166 - />  
167 - {htmlCode && (  
168 <ChatAction 233 <ChatAction
169 - text={Locale.Export.Word}  
170 - icon={<WordIcon />} 234 + text={Locale.Export.Ppt}
  235 + icon={<PptIcon />}
171 onClick={() => { 236 onClick={() => {
172 - exportWord(htmlCode); 237 + toPowerpoint(htmlCode);
173 }} 238 }}
  239 + disabled={isEdit}
174 /> 240 />
175 - )}  
176 - <ChatAction  
177 - text={Locale.Export.Excel}  
178 - icon={<ExcelIcon />}  
179 - onClick={() => {}}  
180 - disabled={true}  
181 - />  
182 - <ChatAction  
183 - text={Locale.Export.Ppt}  
184 - icon={<PptIcon />}  
185 - onClick={() => {}}  
186 - />  
187 - <ChatAction  
188 - text={Locale.Export.Mind.title}  
189 - icon={<MindIcon />}  
190 - onClick={() => {}}  
191 - />  
192 - </div> 241 + <ChatAction
  242 + text={Locale.Export.Mind.title}
  243 + icon={<MindIcon />}
  244 + onClick={() => {
  245 + toMind(htmlCode);
  246 + }}
  247 + disabled={isEdit}
  248 + />
  249 + <ChatAction
  250 + text={Locale.Export.Html}
  251 + icon={<HtmlIcon />}
  252 + onClick={() => {
  253 + exportHtml();
  254 + }}
  255 + disabled={isEdit}
  256 + />
  257 + </div>
  258 + )}
193 </div> 259 </div>
194 <div className="window-actions"> 260 <div className="window-actions">
195 {showMaxIcon && ( 261 {showMaxIcon && (
@@ -209,7 +275,10 @@ export function WritingPage() { @@ -209,7 +275,10 @@ export function WritingPage() {
209 {isMobileScreen && <SDIcon width={50} height={50} />} 275 {isMobileScreen && <SDIcon width={50} height={50} />}
210 </div> 276 </div>
211 </div> 277 </div>
212 - <div className={chatStyles["chat-body"]} ref={scrollRef}> 278 + <div
  279 + className={`${chatStyles["chat-body"]} ${styles["write-body"]}`}
  280 + ref={scrollRef}
  281 + >
213 {loading ? ( 282 {loading ? (
214 <div className={clsx("no-dark", styles["loading-content"])}> 283 <div className={clsx("no-dark", styles["loading-content"])}>
215 <BotIcon /> 284 <BotIcon />
@@ -231,7 +300,8 @@ export function WritingPage() { @@ -231,7 +300,8 @@ export function WritingPage() {
231 <HTMLPreview 300 <HTMLPreview
232 code={htmlCode} 301 code={htmlCode}
233 autoHeight={!document.fullscreenElement} 302 autoHeight={!document.fullscreenElement}
234 - height={!document.fullscreenElement ? 600 : height} 303 + height={!document.fullscreenElement ? "100%" : height}
  304 + width={width}
235 /> 305 />
236 )) 306 ))
237 )} 307 )}
  1 +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1743667735062" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4363" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><path d="M354.40128 0c-87.04 0-157.44 70.55872-157.44 157.59872v275.68128H78.72c-21.6576 0-39.36256 17.69984-39.36256 39.36256v236.31872c0 21.6576 17.69984 39.35744 39.36256 39.35744h118.24128v118.08256c0 87.04 70.4 157.59872 157.44 157.59872h472.63744c87.04 0 157.59872-70.55872 157.59872-157.59872V315.0336c0-41.74848-38.9888-81.93024-107.52-149.27872l-29.11744-29.12256L818.87744 107.52C751.5392 38.9888 711.39328 0 669.59872 0H354.4064z m0 78.72h287.20128c28.35456 7.0912 27.99616 42.1376 27.99616 76.8v120.16128c0 21.6576 17.69984 39.35744 39.36256 39.35744h118.07744c39.38816 0 78.87872-0.0256 78.87872 39.36256v512c0 43.32032-35.55328 78.87872-78.87872 78.87872H354.4064c-43.32544 0-78.72-35.5584-78.72-78.87872v-118.08256h393.91744c21.66272 0 39.36256-17.69472 39.36256-39.35744V472.64256c0-21.66272-17.69984-39.36256-39.36256-39.36256H275.68128V157.59872c0-43.32032 35.39456-78.87872 78.72-78.87872zM75.03872 493.59872h22.08256v73.92256H176.7936V493.59872h23.04v175.68256h-23.04V587.6736H97.1264v81.60256h-22.08256V493.59872z m151.68 0h121.92256v20.16256h-49.92v155.52H276.6336v-155.52h-49.92v-20.16256z m148.80256 0h32.64l49.92 143.04256h0.95744l48.96256-143.04256h33.59744v175.68256h-22.07744v-106.56256c0-10.88 0.31744-26.55744 0.95744-47.03744h-0.95744l-52.80256 153.6h-19.2l-52.79744-153.6h-0.96256c1.28 22.4 1.92 38.71744 1.92 48.95744v104.64256h-20.15744V493.59872z m214.07744 0h22.08256v155.52h69.12v20.16256h-91.20256V493.59872z" p-id="4364"></path></svg>
@@ -53,6 +53,7 @@ const cn = { @@ -53,6 +53,7 @@ const cn = {
53 PinToastAction: "查看", 53 PinToastAction: "查看",
54 Delete: "删除", 54 Delete: "删除",
55 Edit: "编辑", 55 Edit: "编辑",
  56 + CancelEdit: "取消编辑",
56 FullScreen: "全屏", 57 FullScreen: "全屏",
57 RefreshTitle: "刷新标题", 58 RefreshTitle: "刷新标题",
58 RefreshToast: "已发送刷新标题请求", 59 RefreshToast: "已发送刷新标题请求",
@@ -148,6 +149,7 @@ const cn = { @@ -148,6 +149,7 @@ const cn = {
148 Excel: "下载Excel", 149 Excel: "下载Excel",
149 Pdf: "导出PDF", 150 Pdf: "导出PDF",
150 Ppt: "导出PPT", 151 Ppt: "导出PPT",
  152 + Html: "导出HTML",
151 }, 153 },
152 Select: { 154 Select: {
153 Search: "搜索消息", 155 Search: "搜索消息",
@@ -3,4 +3,4 @@ export * from "./update"; @@ -3,4 +3,4 @@ export * from "./update";
3 export * from "./access"; 3 export * from "./access";
4 export * from "./config"; 4 export * from "./config";
5 export * from "./plugin"; 5 export * from "./plugin";
6 -export * from "./message"; 6 +export * from "./mindMap";
@@ -106,7 +106,6 @@ export function getExcelData(file: File): Promise<any[][]> { @@ -106,7 +106,6 @@ export function getExcelData(file: File): Promise<any[][]> {
106 reject(new Error("Failed to read file data")); 106 reject(new Error("Failed to read file data"));
107 return; 107 return;
108 } 108 }
109 -  
110 const workbook = XLSX.read(data, { type: "array" }); 109 const workbook = XLSX.read(data, { type: "array" });
111 const firstSheetName = workbook.SheetNames[0]; 110 const firstSheetName = workbook.SheetNames[0];
112 const worksheet = workbook.Sheets[firstSheetName]; 111 const worksheet = workbook.Sheets[firstSheetName];
@@ -127,3 +126,29 @@ export function getExcelData(file: File): Promise<any[][]> { @@ -127,3 +126,29 @@ export function getExcelData(file: File): Promise<any[][]> {
127 reader.readAsArrayBuffer(file); 126 reader.readAsArrayBuffer(file);
128 }); 127 });
129 } 128 }
  129 +
  130 +export function htmlToExcel(htmlContent: string) {
  131 + const parser = new DOMParser();
  132 + const doc = parser.parseFromString(htmlContent, "text/html");
  133 + const table = doc.querySelector("table");
  134 + if (!table) {
  135 + return [];
  136 + }
  137 + const rows = table.querySelectorAll("tr");
  138 + const tableData: string[][] = [];
  139 + // 提取表格数据(包含表头)
  140 + rows.forEach((row) => {
  141 + const cells = row.querySelectorAll("td, th");
  142 + const rowData: string[] = [];
  143 + cells.forEach((cell) => {
  144 + rowData.push(cell.textContent?.trim() || "");
  145 + });
  146 + tableData.push(rowData);
  147 + });
  148 + // 使用二维数组直接创建工作表
  149 + const ws = XLSX.utils.aoa_to_sheet(tableData);
  150 + // 创建工作簿并保存
  151 + const wb = XLSX.utils.book_new();
  152 + XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
  153 + XLSX.writeFile(wb, "export.xlsx");
  154 +}
  1 +import html2canvas from "html2canvas";
  2 +import jsPDF from "jspdf";
  3 +import { pdfToText } from "pdf-ts";
  4 +
  5 +export async function htmlToPdf2(htmlCode: string) {
  6 + const container = document.createElement("div");
  7 + container.style.cssText = `
  8 + position: fixed;
  9 + left: -9999px;
  10 + top: -9999px;
  11 + width: 210mm; // 固定 A4 宽度
  12 + background: white;
  13 + `;
  14 + container.innerHTML = htmlCode;
  15 + document.body.appendChild(container);
  16 +
  17 + try {
  18 + // 关键修改 1: 确保所有图片加载完成
  19 + await waitForImages(container);
  20 +
  21 + // 关键修改 2: 强制触发布局计算
  22 + void container.offsetHeight;
  23 +
  24 + const canvas = await html2canvas(container, {
  25 + scale: 2,
  26 + useCORS: true,
  27 + logging: true,
  28 + scrollY: -window.scrollY, // 消除滚动偏移
  29 + windowWidth: container.scrollWidth,
  30 + windowHeight: container.scrollHeight,
  31 + });
  32 +
  33 + const pdf = new jsPDF("p", "mm", "a4");
  34 + const pageWidth = pdf.internal.pageSize.getWidth();
  35 + const imgRatio = canvas.width / canvas.height;
  36 +
  37 + // 关键修改 3: 动态计算高度
  38 + const imgHeight = (pageWidth * canvas.height) / canvas.width;
  39 + pdf.addImage(
  40 + canvas.toDataURL("image/png"),
  41 + "PNG",
  42 + 0,
  43 + 0,
  44 + pageWidth,
  45 + imgHeight,
  46 + );
  47 +
  48 + // 关键修改 4: 处理多页内容
  49 + if (imgHeight > pdf.internal.pageSize.getHeight()) {
  50 + pdf.addPage();
  51 + pdf.addImage(
  52 + canvas.toDataURL("image/png"),
  53 + "PNG",
  54 + 0,
  55 + -pdf.internal.pageSize.getHeight(),
  56 + pageWidth,
  57 + imgHeight,
  58 + );
  59 + }
  60 +
  61 + pdf.save("document.pdf");
  62 + } catch (error) {
  63 + console.error("生成失败:", error);
  64 + } finally {
  65 + document.body.removeChild(container);
  66 + }
  67 +}
  68 +
  69 +// 图片加载等待函数
  70 +const waitForImages = (element: HTMLElement) => {
  71 + return new Promise<void>((resolve) => {
  72 + const images = element.getElementsByTagName("img");
  73 + let loaded = 0;
  74 +
  75 + const checkDone = () => {
  76 + if (loaded >= images.length) resolve();
  77 + };
  78 +
  79 + if (images.length === 0) return resolve();
  80 +
  81 + Array.from(images).forEach((img) => {
  82 + if (img.complete) {
  83 + loaded++;
  84 + checkDone();
  85 + } else {
  86 + img.onload = () => {
  87 + loaded++;
  88 + checkDone();
  89 + };
  90 + img.onerror = checkDone;
  91 + }
  92 + });
  93 + });
  94 +};
  95 +
  96 +export function htmlToPdf(htmlCode: string) {
  97 + // 1. 动态创建一个 div 元素,并配置为隐藏(display: none)
  98 + const container = document.createElement("div");
  99 + container.innerHTML = htmlCode;
  100 + container.style.display = "none";
  101 + document.body.appendChild(container);
  102 + // 2. 为了让 html2canvas 能捕获内容,将 display 修改为 block,并移至视野之外
  103 + container.style.display = "block";
  104 + container.style.position = "absolute";
  105 + container.style.top = "-9999px";
  106 + container.style.left = "-9999px";
  107 + window.pageYOffset = 0;
  108 + document.documentElement.scrollTop = 0;
  109 + document.body.scrollTop = 0;
  110 + setTimeout(() => {
  111 + html2canvas(container, {
  112 + allowTaint: true,
  113 + useCORS: true,
  114 + scale: 2, // 提升画面质量,但是会增加文件大小
  115 + height: container.scrollHeight, // 需要注意,element的 高度 宽度一定要在这里定义一下,不然会存在只下载了当前你能看到的页面 避雷避雷!!!
  116 + windowHeight: container.scrollHeight,
  117 + }).then(function (canvas) {
  118 + var contentWidth = canvas.width;
  119 + var contentHeight = canvas.height;
  120 + // console.log('contentWidth', contentWidth)
  121 + // console.log('contentHeight', contentHeight)
  122 + // 一页pdf显示html页面生成的canvas高度;
  123 + var pageHeight = (contentWidth * 841.89) / 592.28;
  124 + // 未生成pdf的html页面高度
  125 + var leftHeight = contentHeight;
  126 + // console.log('pageHeight', pageHeight)
  127 + // console.log('leftHeight', leftHeight)
  128 + // 页面偏移
  129 + var position = 0;
  130 + // a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高 //40是左右页边距
  131 + var imgWidth = 595.28 - 40;
  132 + var imgHeight = (592.28 / contentWidth) * contentHeight;
  133 + var pageData = canvas.toDataURL("image/jpeg", 1.0);
  134 + var pdf = new jsPDF("p", "pt", "a4");
  135 + // 有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
  136 + // 当内容未超过pdf一页显示的范围,无需分页
  137 + if (leftHeight < pageHeight) {
  138 + // console.log('没超过1页')
  139 + pdf.addImage(pageData, "JPEG", 20, 20, imgWidth, imgHeight);
  140 + } else {
  141 + while (leftHeight > 0) {
  142 + // console.log('超过1页')
  143 + pdf.addImage(pageData, "JPEG", 20, position, imgWidth, imgHeight);
  144 + leftHeight -= pageHeight;
  145 + position -= 841.89;
  146 + // 避免添加空白页
  147 + if (leftHeight > 0) {
  148 + pdf.addPage();
  149 + }
  150 + }
  151 + }
  152 + pdf.save("out.pdf");
  153 + });
  154 + }, 1000);
  155 +}
  156 +
  157 +export async function getPdfData(file: File) {
  158 + try {
  159 + const arrayBuffer = await file.arrayBuffer();
  160 + const text = await pdfToText(new Uint8Array(arrayBuffer));
  161 + return text;
  162 + } catch (error) {
  163 + console.error("Error extracting PDF content:", error);
  164 + throw error;
  165 + }
  166 +}
1 -import { Document, Packer, Paragraph, TextRun } from "docx"; 1 +import { Document, Packer, Paragraph } from "docx";
2 import { saveAs } from "file-saver"; 2 import { saveAs } from "file-saver";
3 -import * as cheerio from "cheerio"; 3 +import * as mammoth from "mammoth";
4 4
5 export function exportWord(content: string) { 5 export function exportWord(content: string) {
6 - console.log(content)  
7 - // 简单类型检测示例  
8 - const isHTML = (text: string): boolean => {  
9 - return /<html[\s>]/.test(text) &&  
10 - /<\/html>/.test(text) &&  
11 - /<head>/.test(text) &&  
12 - /<body>/.test(text)  
13 - }  
14 - if (isHTML(content)) {  
15 - exportHtmlToWord(content)  
16 - } else {  
17 - exportMarkdownToWord(content)  
18 - } 6 + console.log(content);
  7 + // 简单类型检测示例
  8 + const isHTML = (text: string): boolean => {
  9 + return (
  10 + /<html[\s>]/.test(text) &&
  11 + /<\/html>/.test(text) &&
  12 + /<head>/.test(text) &&
  13 + /<body>/.test(text)
  14 + );
  15 + };
  16 + if (isHTML(content)) {
  17 + exportHtmlToWord(content);
  18 + } else {
  19 + exportMarkdownToWord(content);
  20 + }
19 } 21 }
20 22
21 -function exportHtmlToWord(content: string) {  
22 - console.log("-----------------------------------"+content)  
23 - let cleanedContent = content.startsWith('```html') ? content.substring(8) : content;  
24 - if (cleanedContent.endsWith('```')) {  
25 - cleanedContent = cleanedContent.substring(0, cleanedContent.length - 4);  
26 - }  
27 - const blob = new Blob([cleanedContent], { type: 'application/msword' });  
28 - const url = URL.createObjectURL(blob);  
29 - const a = document.createElement('a');  
30 - a.href = url;  
31 - a.download = 'htmldemo.docx';  
32 - // 触发点击事件,开始下载  
33 - document.body.appendChild(a);  
34 - a.click();  
35 - // 下载完成后移除临时链接元素  
36 - document.body.removeChild(a);  
37 - // 释放 Blob URL 对象  
38 - URL.revokeObjectURL(url); 23 +export function exportHtmlToWord(content: string) {
  24 + let cleanedContent = content.startsWith("```html")
  25 + ? content.substring(8)
  26 + : content;
  27 + if (cleanedContent.endsWith("```")) {
  28 + cleanedContent = cleanedContent.substring(0, cleanedContent.length - 4);
  29 + }
  30 + const blob = new Blob([cleanedContent], { type: "application/msword" });
  31 + const url = URL.createObjectURL(blob);
  32 + const a = document.createElement("a");
  33 + a.href = url;
  34 + a.download = "htmldemo.docx";
  35 + // 触发点击事件,开始下载
  36 + document.body.appendChild(a);
  37 + a.click();
  38 + // 下载完成后移除临时链接元素
  39 + document.body.removeChild(a);
  40 + // 释放 Blob URL 对象
  41 + URL.revokeObjectURL(url);
39 } 42 }
40 43
41 function exportMarkdownToWord(content: string) { 44 function exportMarkdownToWord(content: string) {
42 - // 按换行符拆分内容  
43 - const lines = content.split(/\r?\n/);  
44 - const paragraphs: Paragraph[] = [];  
45 - for (const line of lines) {  
46 - // 去除 Markdown 标记(#、*等)  
47 - const cleanedLine = line.replace(/^#+\s*/, "").replace(/^\*\*\s*|\*\s*/g, "").trim();  
48 - // 处理空行  
49 - if (cleanedLine === "") {  
50 - paragraphs.push(new Paragraph(""));  
51 - continue;  
52 - }  
53 - // 添加文本段落  
54 - paragraphs.push(new Paragraph(cleanedLine)); 45 + // 按换行符拆分内容
  46 + const lines = content.split(/\r?\n/);
  47 + const paragraphs: Paragraph[] = [];
  48 + for (const line of lines) {
  49 + // 去除 Markdown 标记(#、*等)
  50 + const cleanedLine = line
  51 + .replace(/^#+\s*/, "")
  52 + .replace(/^\*\*\s*|\*\s*/g, "")
  53 + .trim();
  54 + // 处理空行
  55 + if (cleanedLine === "") {
  56 + paragraphs.push(new Paragraph(""));
  57 + continue;
55 } 58 }
  59 + // 添加文本段落
  60 + paragraphs.push(new Paragraph(cleanedLine));
  61 + }
56 62
57 - // 创建 Word 文档对象  
58 - const doc = new Document({  
59 - sections: [{  
60 - children: paragraphs,  
61 - }], 63 + // 创建 Word 文档对象
  64 + const doc = new Document({
  65 + sections: [
  66 + {
  67 + children: paragraphs,
  68 + },
  69 + ],
  70 + });
  71 +
  72 + // 转换为 Blob 并下载
  73 + Packer.toBlob(doc)
  74 + .then((blob) => {
  75 + saveAs(blob, "demo.docx");
  76 + })
  77 + .catch((error) => {
  78 + console.error("导出 Word 失败:", error);
62 }); 79 });
  80 +}
63 81
64 - // 转换为 Blob 并下载  
65 - Packer.toBlob(doc)  
66 - .then((blob) => {  
67 - saveAs(blob, "demo.docx");  
68 - })  
69 - .catch((error) => {  
70 - console.error("导出 Word 失败:", error);  
71 - }); 82 +export async function getWordData(file: File) {
  83 + try {
  84 + const arrayBuffer = await file.arrayBuffer();
  85 + const { value, messages } = await mammoth.extractRawText({ arrayBuffer });
  86 + return value;
  87 + } catch (error) {
  88 + console.error("Error extracting Word content:", error);
  89 + throw error;
  90 + }
72 } 91 }
1 import type { writePromptParam } from "@/app/types/prompt"; 1 import type { writePromptParam } from "@/app/types/prompt";
2 2
3 -export function getWrtingPrompt(param: writePromptParam) {  
4 - let writingPurposeName;  
5 - switch (param.writingPurposeName) {  
6 - case "公司官网":  
7 - writingPurposeName = "公司官网的介绍";  
8 - break;  
9 - case "小红书":  
10 - writingPurposeName = "小红书的介绍";  
11 - break;  
12 - case "微信":  
13 - writingPurposeName = "微信的介绍";  
14 - break;  
15 - case "公众号":  
16 - writingPurposeName = "公众号的介绍";  
17 - break;  
18 - case "今日头条":  
19 - writingPurposeName = "今日头条的介绍";  
20 - break;  
21 - }  
22 - const isImg = `文案要配上图片,实现图文混排,要美观,要符合${writingPurposeName}的排版标准和写作风格,写作风格要${param.writingStyleName}, 3 +export function getWrtingPrompt(param: writePromptParam): string {
  4 + const {
  5 + isImgName,
  6 + writingPurposeName: rawPurpose,
  7 + writingStyleName: rawStyle,
  8 + writingTypeName: rawType,
  9 + writingLanguageName,
  10 + prompt,
  11 + writingCount,
  12 + } = param;
  13 +
  14 + const purposeMap: Record<string, string> = {
  15 + 公司官网: "公司官网的介绍",
  16 + 小红书: "小红书的介绍",
  17 + 微信: "微信的介绍",
  18 + 公众号: "公众号的介绍",
  19 + 今日头条: "今日头条的介绍",
  20 + };
  21 + const styleMap: Record<string, string> = {
  22 + 专业: "专业的风格",
  23 + 活泼: "活泼的风格",
  24 + 严谨: "严谨的风格",
  25 + };
  26 + const typeMap: Record<string, string> = {
  27 + 产品推广文案: "产品推广的文案",
  28 + 品牌宣传文案: "品牌宣传的文案",
  29 + 产品说明书: "产品的说明书",
  30 + 产品介绍: "产品的介绍",
  31 + };
  32 +
  33 + let isImg = "";
  34 + if (isImgName === "是") {
  35 + const purpose = purposeMap[rawPurpose] || "公司官网的介绍";
  36 + const style = styleMap[rawStyle] || "专业的风格";
  37 +
  38 + isImg = `文案要配上图片,实现图文混排,要美观,要符合${purpose}的排版标准和写作风格,写作风格要${style},
23 你没有图片没关系,把图文混排的效果实现,并在你认为要插入图片的地方将图片的Prompt用英文输出给:![description](https://image.pollinations.ai/prompt/description?nologo=true),记得图片地址后面的?nologo=true一定不能去掉了, 39 你没有图片没关系,把图文混排的效果实现,并在你认为要插入图片的地方将图片的Prompt用英文输出给:![description](https://image.pollinations.ai/prompt/description?nologo=true),记得图片地址后面的?nologo=true一定不能去掉了,
24 因为这个语法可以自动按照提示生成并渲染图片。你可以帮我大幅提高生成图片质量和丰富程度,比如增加相机光圈、具体场景描述等内容,注意图片一定要用<img,否则在HTML下图片可能显示不了`; 40 因为这个语法可以自动按照提示生成并渲染图片。你可以帮我大幅提高生成图片质量和丰富程度,比如增加相机光圈、具体场景描述等内容,注意图片一定要用<img,否则在HTML下图片可能显示不了`;
  41 + }
  42 + const writingTypeName = typeMap[rawType] || "产品推广文案";
25 43
26 - const input = `帮我使用${param.writingLanguageName}写一篇主题是${  
27 - param.prompt  
28 - }的${param.writingTypeName},  
29 - ${param.isImgName === "是" ? isImg : ""}  
30 - ,字数要求不少于${  
31 - param.writingCount  
32 - }字,字数不包括html代码和图片Prompt。输出成标准的html,直接给结果,不要做任何解释`; 44 + const input = `帮我使用${writingLanguageName}写一篇主题是${prompt}的${writingTypeName},${isImg},字数要求不少于${writingCount}字,
  45 + 字数不包括html代码和图片Prompt。输出成标准的html并且样式必须为内联样式,直接给结果,不要做任何解释`;
33 return input; 46 return input;
34 } 47 }
35 48
@@ -43,9 +43,12 @@ @@ -43,9 +43,12 @@
43 "fuse.js": "^7.0.0", 43 "fuse.js": "^7.0.0",
44 "heic2any": "^0.0.4", 44 "heic2any": "^0.0.4",
45 "html-to-image": "^1.11.11", 45 "html-to-image": "^1.11.11",
  46 + "html2canvas": "^1.4.1",
46 "idb-keyval": "^6.2.1", 47 "idb-keyval": "^6.2.1",
  48 + "jspdf": "^3.0.1",
47 "lodash-es": "^4.17.21", 49 "lodash-es": "^4.17.21",
48 "lucide-react": "^0.484.0", 50 "lucide-react": "^0.484.0",
  51 + "mammoth": "^1.9.0",
49 "markdown-to-txt": "^2.0.1", 52 "markdown-to-txt": "^2.0.1",
50 "mermaid": "^10.6.1", 53 "mermaid": "^10.6.1",
51 "mind-elixir": "^4.5.0", 54 "mind-elixir": "^4.5.0",
@@ -53,6 +56,7 @@ @@ -53,6 +56,7 @@
53 "next": "^14.1.1", 56 "next": "^14.1.1",
54 "node-fetch": "^3.3.1", 57 "node-fetch": "^3.3.1",
55 "openapi-client-axios": "^7.5.5", 58 "openapi-client-axios": "^7.5.5",
  59 + "pdf-ts": "^0.0.2",
56 "rc-tooltip": "^6.4.0", 60 "rc-tooltip": "^6.4.0",
57 "react": "^18.2.0", 61 "react": "^18.2.0",
58 "react-dom": "^18.2.0", 62 "react-dom": "^18.2.0",
@@ -1271,6 +1271,13 @@ @@ -1271,6 +1271,13 @@
1271 dependencies: 1271 dependencies:
1272 regenerator-runtime "^0.14.0" 1272 regenerator-runtime "^0.14.0"
1273 1273
  1274 +"@babel/runtime@^7.26.7":
  1275 + version "7.27.0"
  1276 + resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.27.0.tgz#fbee7cf97c709518ecc1f590984481d5460d4762"
  1277 + integrity sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==
  1278 + dependencies:
  1279 + regenerator-runtime "^0.14.0"
  1280 +
1274 "@babel/template@^7.18.10", "@babel/template@^7.20.7": 1281 "@babel/template@^7.18.10", "@babel/template@^7.20.7":
1275 version "7.20.7" 1282 version "7.20.7"
1276 resolved "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz" 1283 resolved "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz"
@@ -2626,6 +2633,11 @@ @@ -2626,6 +2633,11 @@
2626 dependencies: 2633 dependencies:
2627 parchment "^1.1.2" 2634 parchment "^1.1.2"
2628 2635
  2636 +"@types/raf@^3.4.0":
  2637 + version "3.4.3"
  2638 + resolved "https://registry.npmmirror.com/@types/raf/-/raf-3.4.3.tgz#85f1d1d17569b28b8db45e16e996407a56b0ab04"
  2639 + integrity sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==
  2640 +
2629 "@types/react-dom@^18.2.7": 2641 "@types/react-dom@^18.2.7":
2630 version "18.2.7" 2642 version "18.2.7"
2631 resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.7.tgz" 2643 resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.7.tgz"
@@ -2669,6 +2681,11 @@ @@ -2669,6 +2681,11 @@
2669 resolved "https://registry.npmmirror.com/@types/tough-cookie/-/tough-cookie-4.0.5.tgz" 2681 resolved "https://registry.npmmirror.com/@types/tough-cookie/-/tough-cookie-4.0.5.tgz"
2670 integrity sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA== 2682 integrity sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==
2671 2683
  2684 +"@types/trusted-types@^2.0.7":
  2685 + version "2.0.7"
  2686 + resolved "https://registry.npmmirror.com/@types/trusted-types/-/trusted-types-2.0.7.tgz#baccb07a970b91707df3a3e8ba6896c57ead2d11"
  2687 + integrity sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==
  2688 +
2672 "@types/unist@*", "@types/unist@^2.0.0": 2689 "@types/unist@*", "@types/unist@^2.0.0":
2673 version "2.0.6" 2690 version "2.0.6"
2674 resolved "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz" 2691 resolved "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz"
@@ -2898,6 +2915,11 @@ @@ -2898,6 +2915,11 @@
2898 "@webassemblyjs/wast-parser" "1.9.0" 2915 "@webassemblyjs/wast-parser" "1.9.0"
2899 "@xtuc/long" "4.2.2" 2916 "@xtuc/long" "4.2.2"
2900 2917
  2918 +"@xmldom/xmldom@^0.8.6":
  2919 + version "0.8.10"
  2920 + resolved "https://registry.npmmirror.com/@xmldom/xmldom/-/xmldom-0.8.10.tgz#a1337ca426aa61cef9fe15b5b28e340a72f6fa99"
  2921 + integrity sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==
  2922 +
2901 "@xmldom/xmldom@^0.9.7": 2923 "@xmldom/xmldom@^0.9.7":
2902 version "0.9.8" 2924 version "0.9.8"
2903 resolved "https://registry.npmmirror.com/@xmldom/xmldom/-/xmldom-0.9.8.tgz" 2925 resolved "https://registry.npmmirror.com/@xmldom/xmldom/-/xmldom-0.9.8.tgz"
@@ -2985,12 +3007,12 @@ aggregate-error@^3.0.0: @@ -2985,12 +3007,12 @@ aggregate-error@^3.0.0:
2985 clean-stack "^2.0.0" 3007 clean-stack "^2.0.0"
2986 indent-string "^4.0.0" 3008 indent-string "^4.0.0"
2987 3009
2988 -ajv-keywords@^3.5.2: 3010 +ajv-keywords@^3.1.0, ajv-keywords@^3.5.2:
2989 version "3.5.2" 3011 version "3.5.2"
2990 resolved "https://registry.npmmirror.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz" 3012 resolved "https://registry.npmmirror.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz"
2991 integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== 3013 integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==
2992 3014
2993 -ajv@^6.12.4, ajv@^6.12.5: 3015 +ajv@^6.1.0, ajv@^6.12.4, ajv@^6.12.5:
2994 version "6.12.6" 3016 version "6.12.6"
2995 resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" 3017 resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz"
2996 integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== 3018 integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
@@ -3109,7 +3131,7 @@ arg@^4.1.0: @@ -3109,7 +3131,7 @@ arg@^4.1.0:
3109 resolved "https://registry.npmmirror.com/arg/-/arg-4.1.3.tgz" 3131 resolved "https://registry.npmmirror.com/arg/-/arg-4.1.3.tgz"
3110 integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== 3132 integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
3111 3133
3112 -argparse@^1.0.7: 3134 +argparse@^1.0.7, argparse@~1.0.3:
3113 version "1.0.10" 3135 version "1.0.10"
3114 resolved "https://registry.npmmirror.com/argparse/-/argparse-1.0.10.tgz" 3136 resolved "https://registry.npmmirror.com/argparse/-/argparse-1.0.10.tgz"
3115 integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== 3137 integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
@@ -3198,6 +3220,11 @@ asynckit@^0.4.0: @@ -3198,6 +3220,11 @@ asynckit@^0.4.0:
3198 resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" 3220 resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz"
3199 integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== 3221 integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
3200 3222
  3223 +atob@^2.1.2:
  3224 + version "2.1.2"
  3225 + resolved "https://registry.npmmirror.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
  3226 + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
  3227 +
3201 available-typed-arrays@^1.0.5: 3228 available-typed-arrays@^1.0.5:
3202 version "1.0.5" 3229 version "1.0.5"
3203 resolved "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz" 3230 resolved "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz"
@@ -3318,16 +3345,36 @@ balanced-match@^1.0.0: @@ -3318,16 +3345,36 @@ balanced-match@^1.0.0:
3318 resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" 3345 resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz"
3319 integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 3346 integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
3320 3347
  3348 +base64-arraybuffer@^1.0.2:
  3349 + version "1.0.2"
  3350 + resolved "https://registry.npmmirror.com/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz#1c37589a7c4b0746e34bd1feb951da2df01c1bdc"
  3351 + integrity sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==
  3352 +
  3353 +base64-js@^1.5.1:
  3354 + version "1.5.1"
  3355 + resolved "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
  3356 + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
  3357 +
3321 bath-es5@^3.0.3: 3358 bath-es5@^3.0.3:
3322 version "3.0.3" 3359 version "3.0.3"
3323 resolved "https://registry.npmjs.org/bath-es5/-/bath-es5-3.0.3.tgz" 3360 resolved "https://registry.npmjs.org/bath-es5/-/bath-es5-3.0.3.tgz"
3324 integrity sha512-PdCioDToH3t84lP40kUFCKWCOCH389Dl1kbC8FGoqOwamxsmqxxnJSXdkTOsPoNHXjem4+sJ+bbNoQm5zeCqxg== 3361 integrity sha512-PdCioDToH3t84lP40kUFCKWCOCH389Dl1kbC8FGoqOwamxsmqxxnJSXdkTOsPoNHXjem4+sJ+bbNoQm5zeCqxg==
3325 3362
  3363 +big.js@^5.2.2:
  3364 + version "5.2.2"
  3365 + resolved "https://registry.npmmirror.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
  3366 + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==
  3367 +
3326 binary-extensions@^2.0.0: 3368 binary-extensions@^2.0.0:
3327 version "2.2.0" 3369 version "2.2.0"
3328 resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz" 3370 resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz"
3329 integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== 3371 integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
3330 3372
  3373 +bluebird@~3.4.0:
  3374 + version "3.4.7"
  3375 + resolved "https://registry.npmmirror.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3"
  3376 + integrity sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==
  3377 +
3331 boolbase@^1.0.0: 3378 boolbase@^1.0.0:
3332 version "1.0.0" 3379 version "1.0.0"
3333 resolved "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz" 3380 resolved "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz"
@@ -3365,6 +3412,11 @@ bser@2.1.1: @@ -3365,6 +3412,11 @@ bser@2.1.1:
3365 dependencies: 3412 dependencies:
3366 node-int64 "^0.4.0" 3413 node-int64 "^0.4.0"
3367 3414
  3415 +btoa@^1.2.1:
  3416 + version "1.2.1"
  3417 + resolved "https://registry.npmmirror.com/btoa/-/btoa-1.2.1.tgz#01a9909f8b2c93f6bf680ba26131eb30f7fa3d73"
  3418 + integrity sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==
  3419 +
3368 buffer-from@^1.0.0: 3420 buffer-from@^1.0.0:
3369 version "1.1.2" 3421 version "1.1.2"
3370 resolved "https://registry.npmmirror.com/buffer-from/-/buffer-from-1.1.2.tgz" 3422 resolved "https://registry.npmmirror.com/buffer-from/-/buffer-from-1.1.2.tgz"
@@ -3444,6 +3496,20 @@ caniuse-lite@^1.0.30001579, caniuse-lite@^1.0.30001688: @@ -3444,6 +3496,20 @@ caniuse-lite@^1.0.30001579, caniuse-lite@^1.0.30001688:
3444 resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001692.tgz" 3496 resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001692.tgz"
3445 integrity sha512-A95VKan0kdtrsnMubMKxEKUKImOPSuCpYgxSQBo036P5YYgVIcOYJEgt/txJWqObiRQeISNCfef9nvlQ0vbV7A== 3497 integrity sha512-A95VKan0kdtrsnMubMKxEKUKImOPSuCpYgxSQBo036P5YYgVIcOYJEgt/txJWqObiRQeISNCfef9nvlQ0vbV7A==
3446 3498
  3499 +canvg@^3.0.11:
  3500 + version "3.0.11"
  3501 + resolved "https://registry.npmmirror.com/canvg/-/canvg-3.0.11.tgz#4b4290a6c7fa36871fac2b14e432eff33b33cf2b"
  3502 + integrity sha512-5ON+q7jCTgMp9cjpu4Jo6XbvfYwSB2Ow3kzHKfIyJfaCAOHLbdKPQqGKgfED/R5B+3TFFfe8pegYA+b423SRyA==
  3503 + dependencies:
  3504 + "@babel/runtime" "^7.12.5"
  3505 + "@types/raf" "^3.4.0"
  3506 + core-js "^3.8.3"
  3507 + raf "^3.4.1"
  3508 + regenerator-runtime "^0.13.7"
  3509 + rgbcolor "^1.0.1"
  3510 + stackblur-canvas "^2.0.0"
  3511 + svg-pathdata "^6.0.3"
  3512 +
3447 ccount@^2.0.0: 3513 ccount@^2.0.0:
3448 version "2.0.1" 3514 version "2.0.1"
3449 resolved "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz" 3515 resolved "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz"
@@ -3758,6 +3824,11 @@ core-js-compat@^3.25.1: @@ -3758,6 +3824,11 @@ core-js-compat@^3.25.1:
3758 dependencies: 3824 dependencies:
3759 browserslist "^4.21.5" 3825 browserslist "^4.21.5"
3760 3826
  3827 +core-js@^3.6.0, core-js@^3.8.3:
  3828 + version "3.41.0"
  3829 + resolved "https://registry.npmmirror.com/core-js/-/core-js-3.41.0.tgz#57714dafb8c751a6095d028a7428f1fb5834a776"
  3830 + integrity sha512-SJ4/EHwS36QMJd6h/Rg+GyR4A5xE0FSI3eZ+iBVpfqf1x0eTSg1smWLHrA+2jQThZSh97fmSgFSU8B61nxosxA==
  3831 +
3761 core-util-is@~1.0.0: 3832 core-util-is@~1.0.0:
3762 version "1.0.3" 3833 version "1.0.3"
3763 resolved "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.3.tgz" 3834 resolved "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.3.tgz"
@@ -3834,6 +3905,13 @@ css-box-model@^1.2.1: @@ -3834,6 +3905,13 @@ css-box-model@^1.2.1:
3834 dependencies: 3905 dependencies:
3835 tiny-invariant "^1.0.6" 3906 tiny-invariant "^1.0.6"
3836 3907
  3908 +css-line-break@^2.1.0:
  3909 + version "2.1.0"
  3910 + resolved "https://registry.npmmirror.com/css-line-break/-/css-line-break-2.1.0.tgz#bfef660dfa6f5397ea54116bb3cb4873edbc4fa0"
  3911 + integrity sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==
  3912 + dependencies:
  3913 + utrie "^1.0.2"
  3914 +
3837 css-select@^4.1.3: 3915 css-select@^4.1.3:
3838 version "4.3.0" 3916 version "4.3.0"
3839 resolved "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz" 3917 resolved "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz"
@@ -4388,6 +4466,11 @@ diff@^5.0.0: @@ -4388,6 +4466,11 @@ diff@^5.0.0:
4388 resolved "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz" 4466 resolved "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz"
4389 integrity sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw== 4467 integrity sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==
4390 4468
  4469 +dingbat-to-unicode@^1.0.1:
  4470 + version "1.0.1"
  4471 + resolved "https://registry.npmmirror.com/dingbat-to-unicode/-/dingbat-to-unicode-1.0.1.tgz#5091dd673241453e6b5865e26e5a4452cdef5c83"
  4472 + integrity sha512-98l0sW87ZT58pU4i61wa2OHwxbiYSbuxsCBozaVnYX2iCnr3bLM3fIes1/ej7h1YdOKuKt/MLs706TVnALA65w==
  4473 +
4391 dir-glob@^3.0.1: 4474 dir-glob@^3.0.1:
4392 version "3.0.1" 4475 version "3.0.1"
4393 resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz" 4476 resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz"
@@ -4487,6 +4570,13 @@ dompurify@^3.0.5: @@ -4487,6 +4570,13 @@ dompurify@^3.0.5:
4487 resolved "https://registry.npmjs.org/dompurify/-/dompurify-3.0.5.tgz" 4570 resolved "https://registry.npmjs.org/dompurify/-/dompurify-3.0.5.tgz"
4488 integrity sha512-F9e6wPGtY+8KNMRAVfxeCOHU0/NPWMSENNq4pQctuXRqqdEPW7q3CrLbR5Nse044WwacyjHGOMlvNsBe1y6z9A== 4571 integrity sha512-F9e6wPGtY+8KNMRAVfxeCOHU0/NPWMSENNq4pQctuXRqqdEPW7q3CrLbR5Nse044WwacyjHGOMlvNsBe1y6z9A==
4489 4572
  4573 +dompurify@^3.2.4:
  4574 + version "3.2.4"
  4575 + resolved "https://registry.npmmirror.com/dompurify/-/dompurify-3.2.4.tgz#af5a5a11407524431456cf18836c55d13441cd8e"
  4576 + integrity sha512-ysFSFEDVduQpyhzAob/kkuJjf5zWkZD8/A9ywSp1byueyuCfHamrCBa14/Oc2iiB0e51B+NpxSl5gmzn+Ms/mg==
  4577 + optionalDependencies:
  4578 + "@types/trusted-types" "^2.0.7"
  4579 +
4490 domutils@^2.8.0: 4580 domutils@^2.8.0:
4491 version "2.8.0" 4581 version "2.8.0"
4492 resolved "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz" 4582 resolved "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz"
@@ -4505,6 +4595,13 @@ domutils@^3.0.1, domutils@^3.1.0: @@ -4505,6 +4595,13 @@ domutils@^3.0.1, domutils@^3.1.0:
4505 domelementtype "^2.3.0" 4595 domelementtype "^2.3.0"
4506 domhandler "^5.0.3" 4596 domhandler "^5.0.3"
4507 4597
  4598 +duck@^0.1.12:
  4599 + version "0.1.12"
  4600 + resolved "https://registry.npmmirror.com/duck/-/duck-0.1.12.tgz#de7adf758421230b6d7aee799ce42670586b9efa"
  4601 + integrity sha512-wkctla1O6VfP89gQ+J/yDesM0S7B7XLXjKGzXxMDVFg7uEn706niAtyYovKbyq1oT9YwDcly721/iUWoc8MVRg==
  4602 + dependencies:
  4603 + underscore "^1.13.1"
  4604 +
4508 dunder-proto@^1.0.1: 4605 dunder-proto@^1.0.1:
4509 version "1.0.1" 4606 version "1.0.1"
4510 resolved "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz" 4607 resolved "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz"
@@ -4559,6 +4656,11 @@ emoji-regex@^9.2.2: @@ -4559,6 +4656,11 @@ emoji-regex@^9.2.2:
4559 resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz" 4656 resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz"
4560 integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== 4657 integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
4561 4658
  4659 +emojis-list@^3.0.0:
  4660 + version "3.0.0"
  4661 + resolved "https://registry.npmmirror.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78"
  4662 + integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==
  4663 +
4562 encoding-sniffer@^0.2.0: 4664 encoding-sniffer@^0.2.0:
4563 version "0.2.0" 4665 version "0.2.0"
4564 resolved "https://registry.npmmirror.com/encoding-sniffer/-/encoding-sniffer-0.2.0.tgz" 4666 resolved "https://registry.npmmirror.com/encoding-sniffer/-/encoding-sniffer-0.2.0.tgz"
@@ -5132,6 +5234,11 @@ fetch-blob@^3.1.2, fetch-blob@^3.1.4: @@ -5132,6 +5234,11 @@ fetch-blob@^3.1.2, fetch-blob@^3.1.4:
5132 node-domexception "^1.0.0" 5234 node-domexception "^1.0.0"
5133 web-streams-polyfill "^3.0.3" 5235 web-streams-polyfill "^3.0.3"
5134 5236
  5237 +fflate@^0.8.1:
  5238 + version "0.8.2"
  5239 + resolved "https://registry.npmmirror.com/fflate/-/fflate-0.8.2.tgz#fc8631f5347812ad6028bbe4a2308b2792aa1dea"
  5240 + integrity sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==
  5241 +
5135 file-entry-cache@^6.0.1: 5242 file-entry-cache@^6.0.1:
5136 version "6.0.1" 5243 version "6.0.1"
5137 resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz" 5244 resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz"
@@ -5626,6 +5733,14 @@ html-to-image@^1.11.11: @@ -5626,6 +5733,14 @@ html-to-image@^1.11.11:
5626 resolved "https://registry.npmmirror.com/html-to-image/-/html-to-image-1.11.11.tgz" 5733 resolved "https://registry.npmmirror.com/html-to-image/-/html-to-image-1.11.11.tgz"
5627 integrity sha512-9gux8QhvjRO/erSnDPv28noDZcPZmYE7e1vFsBLKLlRlKDSqNJYebj6Qz1TGd5lsRV+X+xYyjCKjuZdABinWjA== 5734 integrity sha512-9gux8QhvjRO/erSnDPv28noDZcPZmYE7e1vFsBLKLlRlKDSqNJYebj6Qz1TGd5lsRV+X+xYyjCKjuZdABinWjA==
5628 5735
  5736 +html2canvas@^1.0.0-rc.5, html2canvas@^1.4.1:
  5737 + version "1.4.1"
  5738 + resolved "https://registry.npmmirror.com/html2canvas/-/html2canvas-1.4.1.tgz#7cef1888311b5011d507794a066041b14669a543"
  5739 + integrity sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==
  5740 + dependencies:
  5741 + css-line-break "^2.1.0"
  5742 + text-segmentation "^1.0.3"
  5743 +
5629 htmlparser2@^9.1.0: 5744 htmlparser2@^9.1.0:
5630 version "9.1.0" 5745 version "9.1.0"
5631 resolved "https://registry.npmmirror.com/htmlparser2/-/htmlparser2-9.1.0.tgz" 5746 resolved "https://registry.npmmirror.com/htmlparser2/-/htmlparser2-9.1.0.tgz"
@@ -6531,7 +6646,7 @@ json2mq@^0.2.0: @@ -6531,7 +6646,7 @@ json2mq@^0.2.0:
6531 dependencies: 6646 dependencies:
6532 string-convert "^0.2.0" 6647 string-convert "^0.2.0"
6533 6648
6534 -json5@^1.0.2: 6649 +json5@^1.0.1, json5@^1.0.2:
6535 version "1.0.2" 6650 version "1.0.2"
6536 resolved "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz" 6651 resolved "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz"
6537 integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== 6652 integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==
@@ -6543,6 +6658,21 @@ json5@^2.2.2, json5@^2.2.3: @@ -6543,6 +6658,21 @@ json5@^2.2.2, json5@^2.2.3:
6543 resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz" 6658 resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz"
6544 integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== 6659 integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
6545 6660
  6661 +jspdf@^3.0.1:
  6662 + version "3.0.1"
  6663 + resolved "https://registry.npmmirror.com/jspdf/-/jspdf-3.0.1.tgz#d81e1964f354f60412516eb2449ea2cccd4d2a3b"
  6664 + integrity sha512-qaGIxqxetdoNnFQQXxTKUD9/Z7AloLaw94fFsOiJMxbfYdBbrBuhWmbzI8TVjrw7s3jBY1PFHofBKMV/wZPapg==
  6665 + dependencies:
  6666 + "@babel/runtime" "^7.26.7"
  6667 + atob "^2.1.2"
  6668 + btoa "^1.2.1"
  6669 + fflate "^0.8.1"
  6670 + optionalDependencies:
  6671 + canvg "^3.0.11"
  6672 + core-js "^3.6.0"
  6673 + dompurify "^3.2.4"
  6674 + html2canvas "^1.0.0-rc.5"
  6675 +
6546 "jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.3: 6676 "jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.3:
6547 version "3.3.3" 6677 version "3.3.3"
6548 resolved "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz" 6678 resolved "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz"
@@ -6551,7 +6681,7 @@ json5@^2.2.2, json5@^2.2.3: @@ -6551,7 +6681,7 @@ json5@^2.2.2, json5@^2.2.3:
6551 array-includes "^3.1.5" 6681 array-includes "^3.1.5"
6552 object.assign "^4.1.3" 6682 object.assign "^4.1.3"
6553 6683
6554 -jszip@*, jszip@^3.10.1: 6684 +jszip@*, jszip@^3.10.1, jszip@^3.7.1:
6555 version "3.10.1" 6685 version "3.10.1"
6556 resolved "https://registry.npmmirror.com/jszip/-/jszip-3.10.1.tgz" 6686 resolved "https://registry.npmmirror.com/jszip/-/jszip-3.10.1.tgz"
6557 integrity sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g== 6687 integrity sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==
@@ -6680,6 +6810,15 @@ loader-runner@^4.1.0: @@ -6680,6 +6810,15 @@ loader-runner@^4.1.0:
6680 resolved "https://registry.npmmirror.com/loader-runner/-/loader-runner-4.3.0.tgz" 6810 resolved "https://registry.npmmirror.com/loader-runner/-/loader-runner-4.3.0.tgz"
6681 integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== 6811 integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==
6682 6812
  6813 +loader-utils@^1.0.0:
  6814 + version "1.4.2"
  6815 + resolved "https://registry.npmmirror.com/loader-utils/-/loader-utils-1.4.2.tgz#29a957f3a63973883eb684f10ffd3d151fec01a3"
  6816 + integrity sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==
  6817 + dependencies:
  6818 + big.js "^5.2.2"
  6819 + emojis-list "^3.0.0"
  6820 + json5 "^1.0.1"
  6821 +
6683 locate-path@^5.0.0: 6822 locate-path@^5.0.0:
6684 version "5.0.0" 6823 version "5.0.0"
6685 resolved "https://registry.npmmirror.com/locate-path/-/locate-path-5.0.0.tgz" 6824 resolved "https://registry.npmmirror.com/locate-path/-/locate-path-5.0.0.tgz"
@@ -6746,6 +6885,15 @@ loose-envify@^1.1.0, loose-envify@^1.4.0: @@ -6746,6 +6885,15 @@ loose-envify@^1.1.0, loose-envify@^1.4.0:
6746 dependencies: 6885 dependencies:
6747 js-tokens "^3.0.0 || ^4.0.0" 6886 js-tokens "^3.0.0 || ^4.0.0"
6748 6887
  6888 +lop@^0.4.2:
  6889 + version "0.4.2"
  6890 + resolved "https://registry.npmmirror.com/lop/-/lop-0.4.2.tgz#c9c2f958a39b9da1c2f36ca9ad66891a9fe84640"
  6891 + integrity sha512-RefILVDQ4DKoRZsJ4Pj22TxE3omDO47yFpkIBoDKzkqPRISs5U1cnAdg/5583YPkWPaLIYHOKRMQSvjFsO26cw==
  6892 + dependencies:
  6893 + duck "^0.1.12"
  6894 + option "~0.2.1"
  6895 + underscore "^1.13.1"
  6896 +
6749 lowlight@^2.0.0: 6897 lowlight@^2.0.0:
6750 version "2.8.1" 6898 version "2.8.1"
6751 resolved "https://registry.npmjs.org/lowlight/-/lowlight-2.8.1.tgz" 6899 resolved "https://registry.npmjs.org/lowlight/-/lowlight-2.8.1.tgz"
@@ -6805,6 +6953,22 @@ makeerror@1.0.12: @@ -6805,6 +6953,22 @@ makeerror@1.0.12:
6805 dependencies: 6953 dependencies:
6806 tmpl "1.0.5" 6954 tmpl "1.0.5"
6807 6955
  6956 +mammoth@^1.9.0:
  6957 + version "1.9.0"
  6958 + resolved "https://registry.npmmirror.com/mammoth/-/mammoth-1.9.0.tgz#71e34ca280735275788bfe95e653a058dcab4df2"
  6959 + integrity sha512-F+0NxzankQV9XSUAuVKvkdQK0GbtGGuqVnND9aVf9VSeUA82LQa29GjLqYU6Eez8LHqSJG3eGiDW3224OKdpZg==
  6960 + dependencies:
  6961 + "@xmldom/xmldom" "^0.8.6"
  6962 + argparse "~1.0.3"
  6963 + base64-js "^1.5.1"
  6964 + bluebird "~3.4.0"
  6965 + dingbat-to-unicode "^1.0.1"
  6966 + jszip "^3.7.1"
  6967 + lop "^0.4.2"
  6968 + path-is-absolute "^1.0.0"
  6969 + underscore "^1.13.1"
  6970 + xmlbuilder "^10.0.0"
  6971 +
6808 markdown-table@^3.0.0: 6972 markdown-table@^3.0.0:
6809 version "3.0.3" 6973 version "3.0.3"
6810 resolved "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz" 6974 resolved "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz"
@@ -7481,6 +7645,11 @@ node-domexception@^1.0.0: @@ -7481,6 +7645,11 @@ node-domexception@^1.0.0:
7481 resolved "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz" 7645 resolved "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz"
7482 integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== 7646 integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==
7483 7647
  7648 +node-ensure@^0.0.0:
  7649 + version "0.0.0"
  7650 + resolved "https://registry.npmmirror.com/node-ensure/-/node-ensure-0.0.0.tgz#ecae764150de99861ec5c810fd5d096b183932a7"
  7651 + integrity sha512-DRI60hzo2oKN1ma0ckc6nQWlHU69RH6xN0sjQTjMpChPfTYvKZdcQFfdYK2RWbJcKyUizSIy/l8OTGxMAM1QDw==
  7652 +
7484 node-fetch@^3.3.1: 7653 node-fetch@^3.3.1:
7485 version "3.3.1" 7654 version "3.3.1"
7486 resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.1.tgz" 7655 resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.1.tgz"
@@ -7639,6 +7808,11 @@ openapi-types@^12.1.3: @@ -7639,6 +7808,11 @@ openapi-types@^12.1.3:
7639 resolved "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz" 7808 resolved "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz"
7640 integrity sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw== 7809 integrity sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==
7641 7810
  7811 +option@~0.2.1:
  7812 + version "0.2.4"
  7813 + resolved "https://registry.npmmirror.com/option/-/option-0.2.4.tgz#fd475cdf98dcabb3cb397a3ba5284feb45edbfe4"
  7814 + integrity sha512-pkEqbDyl8ou5cpq+VsnQbe/WlEy5qS7xPzMS1U55OCG9KPvwFD46zDbxQIj3egJSFc3D+XhYOPUzz49zQAVy7A==
  7815 +
7642 optionator@^0.9.3: 7816 optionator@^0.9.3:
7643 version "0.9.3" 7817 version "0.9.3"
7644 resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz" 7818 resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz"
@@ -7770,6 +7944,26 @@ path-type@^4.0.0: @@ -7770,6 +7944,26 @@ path-type@^4.0.0:
7770 resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" 7944 resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz"
7771 integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== 7945 integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
7772 7946
  7947 +pdf-ts@^0.0.2:
  7948 + version "0.0.2"
  7949 + resolved "https://registry.npmmirror.com/pdf-ts/-/pdf-ts-0.0.2.tgz#27fc7842f998fdd679ae1aa2b95e42b8e0736758"
  7950 + integrity sha512-t9VmdLA+8dvX9t3XulCD1hIEWi0N94p2WpfTPwDcvYCW/NElaK+abHj4q5F4XhJcnxzm6dzlileyaH7qcIbnmQ==
  7951 + dependencies:
  7952 + pdfjs-dist "1.10.100"
  7953 +
  7954 +pdfjs-dist@1.10.100:
  7955 + version "1.10.100"
  7956 + resolved "https://registry.npmmirror.com/pdfjs-dist/-/pdfjs-dist-1.10.100.tgz#d5a250b42482ab6e41d763a795ce7cdebe6b1894"
  7957 + integrity sha512-aCfONGqlBeazYxik3rjd7xaoCKMRYECwZSCC3EC3weqibF2V1Bp/v9WZbF7Lyy5Q6UE4NqOYu126r7U+Le4Uhg==
  7958 + dependencies:
  7959 + node-ensure "^0.0.0"
  7960 + worker-loader "^1.0.0"
  7961 +
  7962 +performance-now@^2.1.0:
  7963 + version "2.1.0"
  7964 + resolved "https://registry.npmmirror.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
  7965 + integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==
  7966 +
7773 picocolors@^1.0.0, picocolors@^1.1.1: 7967 picocolors@^1.0.0, picocolors@^1.1.1:
7774 version "1.1.1" 7968 version "1.1.1"
7775 resolved "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz" 7969 resolved "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz"
@@ -7943,6 +8137,13 @@ raf-schd@^4.0.3: @@ -7943,6 +8137,13 @@ raf-schd@^4.0.3:
7943 resolved "https://registry.npmmirror.com/raf-schd/-/raf-schd-4.0.3.tgz" 8137 resolved "https://registry.npmmirror.com/raf-schd/-/raf-schd-4.0.3.tgz"
7944 integrity sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ== 8138 integrity sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==
7945 8139
  8140 +raf@^3.4.1:
  8141 + version "3.4.1"
  8142 + resolved "https://registry.npmmirror.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39"
  8143 + integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==
  8144 + dependencies:
  8145 + performance-now "^2.1.0"
  8146 +
7946 randombytes@^2.1.0: 8147 randombytes@^2.1.0:
7947 version "2.1.0" 8148 version "2.1.0"
7948 resolved "https://registry.npmmirror.com/randombytes/-/randombytes-2.1.0.tgz" 8149 resolved "https://registry.npmmirror.com/randombytes/-/randombytes-2.1.0.tgz"
@@ -8445,6 +8646,11 @@ regenerate@^1.4.2: @@ -8445,6 +8646,11 @@ regenerate@^1.4.2:
8445 resolved "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz" 8646 resolved "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz"
8446 integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== 8647 integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==
8447 8648
  8649 +regenerator-runtime@^0.13.7:
  8650 + version "0.13.11"
  8651 + resolved "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9"
  8652 + integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==
  8653 +
8448 regenerator-runtime@^0.14.0: 8654 regenerator-runtime@^0.14.0:
8449 version "0.14.1" 8655 version "0.14.1"
8450 resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz" 8656 resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz"
@@ -8646,6 +8852,11 @@ rfdc@^1.3.0: @@ -8646,6 +8852,11 @@ rfdc@^1.3.0:
8646 resolved "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz" 8852 resolved "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz"
8647 integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== 8853 integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==
8648 8854
  8855 +rgbcolor@^1.0.1:
  8856 + version "1.0.1"
  8857 + resolved "https://registry.npmmirror.com/rgbcolor/-/rgbcolor-1.0.1.tgz#d6505ecdb304a6595da26fa4b43307306775945d"
  8858 + integrity sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==
  8859 +
8649 rimraf@^3.0.2: 8860 rimraf@^3.0.2:
8650 version "3.0.2" 8861 version "3.0.2"
8651 resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" 8862 resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz"
@@ -8745,6 +8956,14 @@ scheduler@^0.23.0: @@ -8745,6 +8956,14 @@ scheduler@^0.23.0:
8745 dependencies: 8956 dependencies:
8746 loose-envify "^1.1.0" 8957 loose-envify "^1.1.0"
8747 8958
  8959 +schema-utils@^0.4.0:
  8960 + version "0.4.7"
  8961 + resolved "https://registry.npmmirror.com/schema-utils/-/schema-utils-0.4.7.tgz#ba74f597d2be2ea880131746ee17d0a093c68187"
  8962 + integrity sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==
  8963 + dependencies:
  8964 + ajv "^6.1.0"
  8965 + ajv-keywords "^3.1.0"
  8966 +
8748 schema-utils@^3.0.0: 8967 schema-utils@^3.0.0:
8749 version "3.3.0" 8968 version "3.3.0"
8750 resolved "https://registry.npmmirror.com/schema-utils/-/schema-utils-3.3.0.tgz" 8969 resolved "https://registry.npmmirror.com/schema-utils/-/schema-utils-3.3.0.tgz"
@@ -8976,6 +9195,11 @@ stack-utils@^2.0.3: @@ -8976,6 +9195,11 @@ stack-utils@^2.0.3:
8976 dependencies: 9195 dependencies:
8977 escape-string-regexp "^2.0.0" 9196 escape-string-regexp "^2.0.0"
8978 9197
  9198 +stackblur-canvas@^2.0.0:
  9199 + version "2.7.0"
  9200 + resolved "https://registry.npmmirror.com/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz#af931277d0b5096df55e1f91c530043e066989b6"
  9201 + integrity sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==
  9202 +
8979 statuses@2.0.1: 9203 statuses@2.0.1:
8980 version "2.0.1" 9204 version "2.0.1"
8981 resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz" 9205 resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz"
@@ -9173,6 +9397,11 @@ svg-parser@^2.0.4: @@ -9173,6 +9397,11 @@ svg-parser@^2.0.4:
9173 resolved "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz" 9397 resolved "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz"
9174 integrity sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ== 9398 integrity sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==
9175 9399
  9400 +svg-pathdata@^6.0.3:
  9401 + version "6.0.3"
  9402 + resolved "https://registry.npmmirror.com/svg-pathdata/-/svg-pathdata-6.0.3.tgz#80b0e0283b652ccbafb69ad4f8f73e8d3fbf2cac"
  9403 + integrity sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==
  9404 +
9176 svgo@^2.8.0: 9405 svgo@^2.8.0:
9177 version "2.8.0" 9406 version "2.8.0"
9178 resolved "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz" 9407 resolved "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz"
@@ -9250,6 +9479,13 @@ test-exclude@^6.0.0: @@ -9250,6 +9479,13 @@ test-exclude@^6.0.0:
9250 glob "^7.1.4" 9479 glob "^7.1.4"
9251 minimatch "^3.0.4" 9480 minimatch "^3.0.4"
9252 9481
  9482 +text-segmentation@^1.0.3:
  9483 + version "1.0.3"
  9484 + resolved "https://registry.npmmirror.com/text-segmentation/-/text-segmentation-1.0.3.tgz#52a388159efffe746b24a63ba311b6ac9f2d7943"
  9485 + integrity sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==
  9486 + dependencies:
  9487 + utrie "^1.0.2"
  9488 +
9253 text-table@^0.2.0: 9489 text-table@^0.2.0:
9254 version "0.2.0" 9490 version "0.2.0"
9255 resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" 9491 resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz"
@@ -9444,6 +9680,11 @@ unbox-primitive@^1.0.2: @@ -9444,6 +9680,11 @@ unbox-primitive@^1.0.2:
9444 has-symbols "^1.0.3" 9680 has-symbols "^1.0.3"
9445 which-boxed-primitive "^1.0.2" 9681 which-boxed-primitive "^1.0.2"
9446 9682
  9683 +underscore@^1.13.1:
  9684 + version "1.13.7"
  9685 + resolved "https://registry.npmmirror.com/underscore/-/underscore-1.13.7.tgz#970e33963af9a7dda228f17ebe8399e5fbe63a10"
  9686 + integrity sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==
  9687 +
9447 undici-types@~6.19.2: 9688 undici-types@~6.19.2:
9448 version "6.19.8" 9689 version "6.19.8"
9449 resolved "https://registry.npmmirror.com/undici-types/-/undici-types-6.19.8.tgz" 9690 resolved "https://registry.npmmirror.com/undici-types/-/undici-types-6.19.8.tgz"
@@ -9621,6 +9862,13 @@ util-deprecate@~1.0.1: @@ -9621,6 +9862,13 @@ util-deprecate@~1.0.1:
9621 resolved "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz" 9862 resolved "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz"
9622 integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== 9863 integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
9623 9864
  9865 +utrie@^1.0.2:
  9866 + version "1.0.2"
  9867 + resolved "https://registry.npmmirror.com/utrie/-/utrie-1.0.2.tgz#d42fe44de9bc0119c25de7f564a6ed1b2c87a645"
  9868 + integrity sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==
  9869 + dependencies:
  9870 + base64-arraybuffer "^1.0.2"
  9871 +
9624 uuid@^9.0.0: 9872 uuid@^9.0.0:
9625 version "9.0.0" 9873 version "9.0.0"
9626 resolved "https://registry.npmmirror.com/uuid/-/uuid-9.0.0.tgz" 9874 resolved "https://registry.npmmirror.com/uuid/-/uuid-9.0.0.tgz"
@@ -9854,6 +10102,14 @@ word@~0.3.0: @@ -9854,6 +10102,14 @@ word@~0.3.0:
9854 resolved "https://registry.npmmirror.com/word/-/word-0.3.0.tgz" 10102 resolved "https://registry.npmmirror.com/word/-/word-0.3.0.tgz"
9855 integrity sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA== 10103 integrity sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==
9856 10104
  10105 +worker-loader@^1.0.0:
  10106 + version "1.1.1"
  10107 + resolved "https://registry.npmmirror.com/worker-loader/-/worker-loader-1.1.1.tgz#920d74ddac6816fc635392653ed8b4af1929fd92"
  10108 + integrity sha512-qJZLVS/jMCBITDzPo/RuweYSIG8VJP5P67mP/71alGyTZRe1LYJFdwLjLalY3T5ifx0bMDRD3OB6P2p1escvlg==
  10109 + dependencies:
  10110 + loader-utils "^1.0.0"
  10111 + schema-utils "^0.4.0"
  10112 +
9857 wrap-ansi@^6.2.0: 10113 wrap-ansi@^6.2.0:
9858 version "6.2.0" 10114 version "6.2.0"
9859 resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz" 10115 resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz"
@@ -9920,6 +10176,11 @@ xml@^1.0.1: @@ -9920,6 +10176,11 @@ xml@^1.0.1:
9920 resolved "https://registry.npmmirror.com/xml/-/xml-1.0.1.tgz" 10176 resolved "https://registry.npmmirror.com/xml/-/xml-1.0.1.tgz"
9921 integrity sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw== 10177 integrity sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==
9922 10178
  10179 +xmlbuilder@^10.0.0:
  10180 + version "10.1.1"
  10181 + resolved "https://registry.npmmirror.com/xmlbuilder/-/xmlbuilder-10.1.1.tgz#8cae6688cc9b38d850b7c8d3c0a4161dcaf475b0"
  10182 + integrity sha512-OyzrcFLL/nb6fMGHbiRDuPup9ljBycsdCypwuyg5AAHvyWzGfChJpCXMG88AGTIMFhGZ9RccFN1e6lhg3hkwKg==
  10183 +
9923 xmlchars@^2.2.0: 10184 xmlchars@^2.2.0:
9924 version "2.2.0" 10185 version "2.2.0"
9925 resolved "https://registry.npmmirror.com/xmlchars/-/xmlchars-2.2.0.tgz" 10186 resolved "https://registry.npmmirror.com/xmlchars/-/xmlchars-2.2.0.tgz"