基于Deepseek对WPS文档自动设置标题格式的代码优化

如何使用 DeepSeek 帮助自己的工作? 10w+人浏览 194人参与

        前文,我们实现了:在WPS中通过JavaScript宏(JSA)调用DeepSeek官方API自动识别标题级别和目录,具体可看我CSDN文章:在WPS中通过JavaScript宏(JSA)调用DeepSeek官方API自动识别标题级别和目录-CSDN博客

        还有诸多地方要改进,今天这是其中一个版本。主要是方便自己写文章之后,对文章的排版更方便一些,今天就分析出来。

        要让代码能够正确识别不同层级的标题,尤其是在存在 “一” 作为标题 1 时,把 “(二)” 识别成标题 2,将 “1” 和 “(1)” 识别成标题 3,需要对标题识别的逻辑进行优化。

1.问题分析

        当前代码在识别标题层级时,虽然有一定的规则判断,但可能因为正则匹配或者判断逻辑不够完善,导致 “(二)” 这类括号中文序号没有被正确识别为标题 2,“1” 和 “(1)” 也未能正确区分和归类。

2.改进思路

        增强正则表达式的匹配规则,确保能精准识别不同类型的标题序号。

        优化标题层级判断逻辑,保证在存在 “一” 作为标题 1 时,“(二)” 被识别为标题 2,“1” 和 “(1)” 被识别为标题 3。

3.标题序号主要修改点

(1)新增序号类型判断:添加了 hasBracketChineseNumbers 数组,用于记录是否存在括号中文序号(如 “(一)”)的标题。

(2)增强正则匹配:在遍历段落时,增加了 bracketChineseRegex 正则表达式,用于匹配括号中文序号。

(3)优化标题层级判断:在判断标题层级时,当存在 “一” 作为标题 1 时,将匹配到的括号中文序号(如 “(二)”)的标题识别为标题 2,将括号数字序号(如 “(1)”)和普通数字序号(如 “1”)的标题识别为标题 3。

4.拓展标题4

为了(1)这类格式的内容识别并设置为标题 4,需要对代码进行以下几个方面的改进:

(1)扩展标题类型的记录数组,增加对标题 4 类型的记录。

(2)完善正则表达式,使其能够匹配标题 4 的格式。

(3)增加标题 4 的处理逻辑,将匹配到的内容添加到对应的标题 4 数组中,并在设置标题样式时正确应用标题 4 的样式。

5.拓展标题4主要修改点

(1)新增标题级别:在 headings 和 apiHeadings 对象里增添了 "标题4" 数组,用来存储标题 4 的内容。

(2)新增序号类型记录:添加 hasSubBracketNumbers 数组,用于记录是否存在 (1) 格式的标题序号。

(3)完善正则匹配:在遍历段落时,添加 subBracketRegex 正则表达式,用于匹配 (1) 格式的标题。

(4)调整标题级别判断:在设置标题级别时,把匹配到的 (1) 格式内容添加到 headings["标题4"] 数组中。

(5)修改 API 请求与结果处理:向 DeepSeek API 发送请求时,要求按 4 个级别分类,并在解析 API 结果时处理标题 4 的内容。

(6)检查和设置标题 4 样式:检查样式是否存在时,增加对标题 4 样式的检查;设置标题级别时,正确应用标题 4 的样式。

(7)更新目录设置:创建目录时,将 LowerHeadingLevel 设置为 4,以此包含标题 4。

6.改完后的完整代码

function identifyAndSetHeadingsAndCreateTOC() {
    // 获取文档内容
    var doc = this.Application.ActiveDocument;
    // 尝试获取文档的保护类型,若抛出异常则认为文档可能存在问题
    try {
        var protectionType = doc.ProtectionType;
        if (protectionType!== -1) {
            alert("文档处于受保护状态,请先解除保护。");
            return;
        }
    } catch (error) {
        alert("获取文档保护状态时出现异常,请检查文档是否正常。");
        return;
    }

    var paragraphs = doc.Content.Paragraphs;

    // 定义标题级别映射
    var headings = {
        "标题1": [],
        "标题2": [],
        "标题3": [],
        "标题4": []
    };

    // 先判断文档中是否存在不同类型的标题序号
    var hasOne = false;
    var hasBracketOne = false;
    var hasNumberOne = false;
    var hasChineseNumbers = [];
    var hasBracketNumbers = [];
    var hasPlainNumbers = [];
    var hasBracketChineseNumbers = [];
    var hasSubBracketNumbers = [];

    for (var i = 1; i <= 10; i++) {
        hasChineseNumbers[i] = false;
        hasBracketNumbers[i] = false;
        hasPlainNumbers[i] = false;
        hasBracketChineseNumbers[i] = false;
        hasSubBracketNumbers[i] = false;
    }

    for (var i = 1; i <= paragraphs.Count; i++) {
        var para = paragraphs.Item(i);
        var text = para.Range.Text.trim();
        if (text) {
            for (var j = 1; j <= 10; j++) {
                var chineseRegex = new RegExp(`^${getChineseNumber(j)}、|^${getChineseNumber(j)}\\.|^${getChineseNumber(j)}\\s`);
                var bracketRegex = new RegExp(`^(${j})`);
                var plainRegex = new RegExp(`^${j}、|^${j}\\.|^${j}\\s`);
                var bracketChineseRegex = new RegExp(`^(${getChineseNumber(j)})`);
                var subBracketRegex = new RegExp(`^(${j})`);

                if (chineseRegex.test(text)) {
                    if (j === 1) hasOne = true;
                    hasChineseNumbers[j] = true;
                } else if (bracketRegex.test(text)) {
                    if (j === 1) hasBracketOne = true;
                    hasBracketNumbers[j] = true;
                } else if (plainRegex.test(text)) {
                    if (j === 1) hasNumberOne = true;
                    hasPlainNumbers[j] = true;
                } else if (bracketChineseRegex.test(text)) {
                    hasBracketChineseNumbers[j] = true;
                } else if (subBracketRegex.test(text)) {
                    hasSubBracketNumbers[j] = true;
                }
            }
        }
    }

    // 统计存在的标题序号类型数量
    var titleTypeCount = 0;
    for (var i = 1; i <= 10; i++) {
        if (hasChineseNumbers[i]) titleTypeCount++;
        if (hasBracketNumbers[i]) titleTypeCount++;
        if (hasPlainNumbers[i]) titleTypeCount++;
        if (hasBracketChineseNumbers[i]) titleTypeCount++;
        if (hasSubBracketNumbers[i]) titleTypeCount++;
    }

    // 根据存在情况设置标题级别
    for (var i = 1; i <= paragraphs.Count; i++) {
        var para = paragraphs.Item(i);
        var text = para.Range.Text.trim();
        if (text) {
            if (titleTypeCount > 1) {
                if (hasOne) {
                    for (var j = 1; j <= 10; j++) {
                        var chineseRegex = new RegExp(`^${getChineseNumber(j)}、|^${getChineseNumber(j)}\\.|^${getChineseNumber(j)}\\s`);
                        var bracketRegex = new RegExp(`^(${j})`);
                        var plainRegex = new RegExp(`^${j}、|^${j}\\.|^${j}\\s`);
                        var bracketChineseRegex = new RegExp(`^(${getChineseNumber(j)})`);
                        var subBracketRegex = new RegExp(`^(${j})`);

                        if (chineseRegex.test(text)) {
                            headings["标题1"].push(text);
                        } else if (bracketChineseRegex.test(text)) {
                            headings["标题2"].push(text);
                        } else if (bracketRegex.test(text) || plainRegex.test(text)) {
                            headings["标题3"].push(text);
                        } else if (subBracketRegex.test(text)) {
                            headings["标题4"].push(text);
                        }
                    }
                } else if (hasBracketOne) {
                    for (var j = 1; j <= 10; j++) {
                        var bracketRegex = new RegExp(`^(${j})`);
                        var plainRegex = new RegExp(`^${j}、|^${j}\\.|^${j}\\s`);
                        var subBracketRegex = new RegExp(`^(${j})`);

                        if (bracketRegex.test(text)) {
                            headings["标题1"].push(text);
                        } else if (plainRegex.test(text)) {
                            headings["标题2"].push(text);
                        } else if (subBracketRegex.test(text)) {
                            headings["标题3"].push(text);
                        }
                    }
                } else if (hasNumberOne) {
                    for (var j = 1; j <= 10; j++) {
                        var plainRegex = new RegExp(`^${j}、|^${j}\\.|^${j}\\s`);
                        var subBracketRegex = new RegExp(`^(${j})`);
                        var subPlainRegex = new RegExp(`^${j})`);

                        if (plainRegex.test(text)) {
                            headings["标题1"].push(text);
                        } else if (subBracketRegex.test(text)) {
                            headings["标题2"].push(text);
                        } else if (subPlainRegex.test(text)) {
                            headings["标题3"].push(text);
                        }
                    }
                }
            } else {
                // 只有一种标题序号类型,全部设为标题1
                for (var j = 1; j <= 10; j++) {
                    var chineseRegex = new RegExp(`^${getChineseNumber(j)}、|^${getChineseNumber(j)}\\.|^${getChineseNumber(j)}\\s`);
                    var bracketRegex = new RegExp(`^(${j})`);
                    var plainRegex = new RegExp(`^${j}、|^${j}\\.|^${j}\\s`);
                    var subBracketRegex = new RegExp(`^(${j})`);
                    var subPlainRegex = new RegExp(`^${j})`);
                    var bracketChineseRegex = new RegExp(`^(${getChineseNumber(j)})`);

                    if (chineseRegex.test(text) || bracketRegex.test(text) || plainRegex.test(text) || subBracketRegex.test(text) || subPlainRegex.test(text) || bracketChineseRegex.test(text)) {
                        headings["标题1"].push(text);
                    }
                }
            }
        }
    }

    // 显示正在执行的提示
    alert("正在调用 DeepSeek API 进行标题识别,请稍候...\n点击确定,将进入后台运行!");

    // 尝试调用 DeepSeek API 辅助识别标题
    var apiHeadings = {
        "标题1": [],
        "标题2": [],
        "标题3": [],
        "标题4": []
    };
    try {
        var content = "";
        for (var i = 1; i <= paragraphs.Count; i++) {
            var para = paragraphs.Item(i);
            content += para.Range.Text;
        }

        // DeepSeek API 配置
        var apiUrl = 'https://api.deepseek.com/v1/chat/completions';
        var apiKey = 'sk-e4df3c51537048af980934467b594163';
        var model = 'deepseek-chat';

        // 构建请求体,明确告知 API 识别标题序号并分类
        var requestBody = {
            "model": model,
            "messages": [
                {
                    "role": "user",
                    "content": `请识别以下文档内容中以 "一、"或"一."或"一 "、"(一)"、"1、"或"1."或"1 "、"(1)"、"1)" 等开头的标题,并按照4个级别进行分类,格式为:
标题1: [标题1内容1, 标题1内容2, ...]
标题2: [标题2内容1, 标题2内容2, ...]
标题3: [标题3内容1, 标题3内容2, ...]
标题4: [标题4内容1, 标题4内容2, ...]

${content}`
                }
            ],
            "stream": false
        };
        requestBody = JSON.stringify(requestBody);

        // 创建 XMLHttpRequest 对象
        var xhr = new XMLHttpRequest();
        xhr.open('POST', apiUrl, false);
        // 设置请求头
        xhr.setRequestHeader('Content-Type', 'application/json');
        xhr.setRequestHeader('Authorization', 'Bearer ' + apiKey);
        // 设置超时时间(单位:毫秒)
        xhr.timeout = 30000;

        // 超时处理函数
        xhr.ontimeout = function () {
            alert('请求超时,请稍后重试!');
            return;
        };

        // 发送请求
        xhr.send(requestBody);

        if (xhr.status === 200) {
            var response = JSON.parse(xhr.responseText);
            var result = response.choices[0].message.content;

            // 解析 API 结果
            var lines = result.split('\n');
            for (var i = 0; i < lines.length; i++) {
                var line = lines[i];
                if (line.startsWith('标题1:')) {
                    var titles = line.substring(4).trim().replace('[', '').replace(']', '').split(',');
                    for (var j = 0; j < titles.length; j++) {
                        apiHeadings["标题1"].push(titles[j].trim());
                    }
                } else if (line.startsWith('标题2:')) {
                    var titles = line.substring(4).trim().replace('[', '').replace(']', '').split(',');
                    for (var j = 0; j < titles.length; j++) {
                        apiHeadings["标题2"].push(titles[j].trim());
                    }
                } else if (line.startsWith('标题3:')) {
                    var titles = line.substring(4).trim().replace('[', '').replace(']', '').split(',');
                    for (var j = 0; j < titles.length; j++) {
                        apiHeadings["标题3"].push(titles[j].trim());
                    }
                } else if (line.startsWith('标题4:')) {
                    var titles = line.substring(4).trim().replace('[', '').replace(']', '').split(',');
                    for (var j = 0; j < titles.length; j++) {
                        apiHeadings["标题4"].push(titles[j].trim());
                    }
                }
            }
        } else {
            alert('请求失败,状态码:' + xhr.status);
            return;
        }
    } catch (e) {
        alert('调用 DeepSeek API 出错:' + e.message);
        return;
    }
    if (headings["标题1"].length!== 0) {
        if (apiHeadings["标题1"].length === 0) {
            alert("请继续等待30秒...");
        }
    }

    // 合并自定义规则和 API 结果
    var allHeadings = {
        "标题1": headings["标题1"].concat(apiHeadings["标题1"]),
        "标题2": headings["标题2"].concat(apiHeadings["标题2"]),
        "标题3": headings["标题3"].concat(apiHeadings["标题3"]),
        "标题4": headings["标题4"].concat(apiHeadings["标题4"])
    };

    // 隐藏正在执行的提示(这里只是逻辑上的隐藏,alert 无法真正隐藏)
    // 可以考虑使用更复杂的 UI 组件来实现显示和隐藏

    // 检查样式是否存在
    if (!doc.Styles("标题 1") ||!doc.Styles("标题 2") ||!doc.Styles("标题 3") ||!doc.Styles("标题 4")) {
        alert("样式 标题 1、标题 2、标题 3 或 标题 4 不存在,请检查!");
        return;
    }

    // 设置标题级别
    for (var i = 1; i <= paragraphs.Count; i++) {
        var para = paragraphs.Item(i);
        var text = para.Range.Text.trim();
        if (allHeadings["标题1"].includes(text)) {
            try {
                para.Style = doc.Styles("标题 1");
            } catch (e) {
                alert(`设置“标题 1”样式时出现意外错误,段落内容:${text},错误信息:${e.message}`);
            }
        } else if (allHeadings["标题2"].includes(text)) {
            try {
                para.Style = doc.Styles("标题 2");
            } catch (e) {
                alert(`设置“标题 2”样式时出现意外错误,段落内容:${text},错误信息:${e.message}`);
            }
        } else if (allHeadings["标题3"].includes(text)) {
            try {
                para.Style = doc.Styles("标题 3");
            } catch (e) {
                alert(`设置“标题 3”样式时出现意外错误,段落内容:${text},错误信息:${e.message}`);
            }
        } else if (allHeadings["标题4"].includes(text)) {
            try {
                para.Style = doc.Styles("标题 4");
            } catch (e) {
                alert(`设置“标题 4”样式时出现意外错误,段落内容:${text},错误信息:${e.message}`);
            }
        }
    }

    // 创建目录
    var tocPara = doc.Content.Paragraphs.Add();
    var tocRange = tocPara.Range;
    tocRange.InsertAfter("目录\n");
    try {
        var toc = doc.TablesOfContents.Add(tocRange, {
            "UseHeadingStyles": true,
            "UpperHeadingLevel": 1,
            "LowerHeadingLevel": 4
        });
        toc.Update();
        alert('设置标题并识别目录,完成!');
    } catch (e) {
        alert("创建目录失败,请检查标题设置!");
    }
}

function getChineseNumber(num) {
    var chineseNumbers = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十'];
    return chineseNumbers[num - 1];
}    

效果如下:

### 使用 DeepSeek API 创建或导出 WPS 文档格式文件 为了通过 DeepSeek API 创建或导出 WPS 文档格式文件,可以按照如下方法操作: #### 准备工作 确保已经获取了用于访问 DeepSeek 的 API Key,并选择了合适的模型。对于文档生成任务,可以选择 `deepseek-chat` 或者更复杂的推理任务则选择 `deepseek-reasoner`[^3]。 #### 构建请求体 构建发送给 DeepSeek API 的 JSON 请求体时,需指定所使用的模型以及输入的内容。例如,如果要基于一段文字生成新的内容并保存到 WPS 文件中,则可以在消息部分提供相应的提示词。 ```json { "model": "deepseek-ai/DeepSeek-R1-Distill-Qwen-32B", "messages": [ { "role": "user", "content": "请根据以下信息撰写一份报告:..." } ] } ``` 此处 `"model"` 字段应替换为你实际想要调用的模型名称,而 `"content"` 中填写具体的指令或者上下文信息[^2]。 #### 发送 HTTP POST 请求 利用编程语言中的网络库向 DeepSeek 提供的服务端点发起 POST 请求,附带之前准备好的 JSON 数据作为负载。Python 示例代码如下所示: ```python import requests import json url = 'https://api.deepseek.com/v1/chat/completions' headers = {'Authorization': f'Bearer {your_api_key}', 'Content-Type': 'application/json'} data = {"model": "deepseek-ai/DeepSeek-R1-Distill-Qwen-32B", "messages":[{"role":"user","content":"..."}]} response = requests.post(url, headers=headers, data=json.dumps(data)) if response.status_code == 200: result_text = response.json()['choices'][0]['message']['content'] else: raise Exception(f'Request failed with status code {response.status_code}') ``` 请注意将 `{your_api_key}` 替换成真实的 API 密钥字符串。 #### 将返回的结果写入 WPS 文档 最后一步是把从 API 获取的文字内容转换成 `.wps` 格式的文件。这通常涉及到使用办公软件提供的 SDK 或者第三方库来处理文档对象。以下是 Python 结合 `python-docx` 库的一个简化例子(注意此库主要用于 Word .docx 文件;针对 WPS 可能需要特定的支持工具): ```python from docx import Document document = Document() paragraph = document.add_paragraph(result_text) document.save('output.wps') # 实际上这里可能不是 wps 扩展名而是 docx ``` 由于标准的 Python 库并不直接支持`.wps`扩展名的操作,因此上述示例实际上是以 DOCX 形式保存文件。对于真正的 WPS 格式支持,建议查阅相关官方文档或寻找专门为此设计的应用程序接口[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

搏博

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值