Onlyoffice集成与AI交互操作指引(Iframe版)

发布于:2025-09-06 ⋅ 阅读:(19) ⋅ 点赞:(0)

Onlyoffice集成与AI交互操作指引(Iframe版)

本文档系统介绍了软件系统集成OnlyOffice实现在线编辑与AI辅助功能的方案。主要内容包括:后端需提供文档配置信息并实现Callback接口以处理文档保存;前端通过Vue集成编辑器,利用连接器(connector)调用API实现文本操作、菜单定制及事件监听;AI交互采用基于postMessage的消息机制,实现从编辑器发送文本到AI处理并返回结果替换的完整异步流程。该方案实现了文档编辑与AI能力的深度结合。

OnlyOffice集成

后端对接

Onlyoffice只提供的是文档的在线编辑能力,文档的保存、权限、文档信息、配置信息等都需要通过后端服务进行返回。

获取config配置
  1. 描述

    • 配置文件主要包含用户信息,文档信息,编辑器配置,监听事件,及token等配置,用于文件内容的读取和编辑器的渲染。
  2. 文档参考链接

  3. 获取配置及文档信息(根据文档链接和操作模式返回配置信息)

{
    "document": {
        "fileType": "docx",
        "info": {
            "favorite": true,
            "folder": "Example Files",
            "owner": "John Smith",
            "sharingSettings": [
                {
                    "permissions": "Full Access",
                    "user": "John Smith"
                },
                {
                    "isLink": true,
                    "permissions": "Read Only",
                    "user": "External link"
                }
            ],
            "uploaded": "2010-07-07 3:46 PM"
        },
        "isForm": true,
        "key": "Khirz6zTPdfd7",
        "permissions": {
            "chat": true,
            "comment": true,
            "commentGroups": [
                {
                    "edit": [
                        "Group2",
                        ""
                    ],
                    "remove": [
                        ""
                    ],
                    "view": ""
                }
            ],
            "copy": true,
            "deleteCommentAuthorOnly": false,
            "download": true,
            "edit": true,
            "editCommentAuthorOnly": false,
            "fillForms": true,
            "modifyContentControl": true,
            "modifyFilter": true,
            "print": true,
            "protect": true,
            "review": true,
            "reviewGroups": [
                "Group1",
                "Group2",
                ""
            ],
            "userInfoGroups": [
                "Group1",
                ""
            ]
        },
        "referenceData": {
            "fileKey": "BCFA2CED",
            "instanceId": "https://example.com"
        },
        "title": "Example Document Title.docx",
        "url": "https://example.com/url-to-example-document.docx"
    },
    "documentType": "word",
    "editorConfig": {
        "actionLink": "ACTION_DATA",
        "callbackUrl": "https://example.com/url-to-callback.ashx",
        "coEditing": {
            "change": true,
            "mode": "fast"
        },
        "createUrl": "https://example.com/url-to-create-document/",
        "customization": {
            "about": true,
            "anonymous": {
                "label": "Guest",
                "request": true
            },
            "autosave": true,
            "close": {
                "text": "Close file",
                "visible": true
            },
            "comments": true,
            "compactHeader": false,
            "compactToolbar": false,
            "compatibleFeatures": false,
            "customer": {
                "address": "My City, 123a-45",
                "info": "Some additional information",
                "logo": "https://example.com/logo-big.png",
                "logoDark": "https://example.com/dark-logo-big.png",
                "mail": "john@example.com",
                "name": "John Smith and Co.",
                "phone": "123456789",
                "www": "example.com"
            },
            "features": {
                "featuresTips": true,
                "roles": true,
                "spellcheck": {
                    "change": true,
                    "mode": true
                },
                "tabBackground": {
                    "change": true,
                    "mode": "header"
                },
                "tabStyle": {
                    "change": true,
                    "mode": "fill"
                }
            },
            "feedback": {
                "url": "https://example.com",
                "visible": true
            },
            "font": {
                "name": "Arial",
                "size": "11px"
            },
            "forceWesternFontSize": false,
            "forcesave": false,
            "goback": {
                "blank": true,
                "text": "Open file location",
                "url": "https://example.com"
            },
            "help": true,
            "hideNotes": false,
            "hideRightMenu": true,
            "hideRulers": false,
            "integrationMode": "embed",
            "layout": {
                "header": {
                    "editMode": true,
                    "save": true,
                    "user": true,
                    "users": true
                },
                "leftMenu": {
                    "mode": true,
                    "navigation": true,
                    "spellcheck": true
                },
                "rightMenu": {
                    "mode": true
                },
                "statusBar": {
                    "actionStatus": true,
                    "docLang": true,
                    "textLang": true
                },
                "toolbar": {
                    "collaboration": {
                        "mailmerge": true
                    },
                    "draw": true,
                    "file": {
                        "close": true,
                        "info": true,
                        "save": true,
                        "settings": true
                    },
                    "home": {},
                    "layout": true,
                    "plugins": true,
                    "protect": true,
                    "references": true,
                    "save": true,
                    "view": {
                        "navigation": true
                    }
                }
            },
            "loaderLogo": "https://example.com/loader-logo.png",
            "loaderName": "The document is loading, please wait...",
            "logo": {
                "image": "https://example.com/logo.png",
                "imageDark": "https://example.com/dark-logo.png",
                "imageLight": "https://example.com/light-logo.png",
                "url": "https://example.com",
                "visible": true
            },
            "macros": true,
            "macrosMode": "warn",
            "mentionShare": true,
            "mobile": {
                "forceView": true,
                "info": false,
                "standardView": false
            },
            "plugins": true,
            "pointerMode": "select",
            "review": {
                "hideReviewDisplay": false,
                "hoverMode": false,
                "reviewDisplay": "original",
                "showReviewChanges": false,
                "trackChanges": true
            },
            "showHorizontalScroll": true,
            "showVerticalScroll": true,
            "slidePlayerBackground": "#000000",
            "submitForm": {
                "resultMessage": "text",
                "visible": true
            },
            "toolbarHideFileName": false,
            "uiTheme": "theme-dark",
            "unit": "cm",
            "wordHeadingsColor": "#00ff00",
            "zoom": 100
        },
        "embedded": {
            "embedUrl": "https://example.com/embedded?doc=exampledocument1.docx",
            "fullscreenUrl": "https://example.com/embedded?doc=exampledocument1.docx#fullscreen",
            "saveUrl": "https://example.com/download?doc=exampledocument1.docx",
            "shareUrl": "https://example.com/view?doc=exampledocument1.docx",
            "toolbarDocked": "top"
        },
        "lang": "en",
        "mode": "edit",
        "plugins": {
            "autostart": [
                "asc.{0616AE85-5DBE-4B6B-A0A9-455C4F1503AD}",
                "asc.{FFE1F462-1EA2-4391-990D-4CC84940B754}"
            ],
            "options": {
                "all": {
                    "keyAll": "valueAll"
                },
                "asc.{38E022EA-AD92-45FC-B22B-49DF39746DB4}": {
                    "keyYoutube": "valueYoutube"
                }
            },
            "pluginsData": [
                "https://example.com/plugin1/config.json",
                "https://example.com/plugin2/config.json"
            ]
        },
        "recent": [
            {
                "folder": "Example Files",
                "title": "exampledocument1.docx",
                "url": "https://example.com/exampledocument1.docx"
            },
            {
                "folder": "Example Files",
                "title": "exampledocument2.docx",
                "url": "https://example.com/exampledocument2.docx"
            }
        ],
        "region": "en-US",
        "templates": [
            {
                "image": "https://example.com/exampletemplate1.png",
                "title": "exampletemplate1.docx",
                "url": "https://example.com/url-to-create-template1"
            },
            {
                "image": "https://example.com/exampletemplate2.png",
                "title": "exampletemplate2.docx",
                "url": "https://example.com/url-to-create-template2"
            }
        ],
        "user": {
            "group": "Group1,Group2",
            "id": "78e1e841",
            "image": "https://example.com/url-to-user-avatar.png",
            "name": "John Smith"
        }
    },
    "events": {},
    "height": "100%",
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.LwimMJA3puF3ioGeS-tfczR3370GXBZMIL-bdpu4hOU",
    "type": "desktop",
    "width": "100%"
}
实现Callback接口
  1. 描述

    • callback的链接在获取配置时已经返回,onlyoffice会根据配置的callback地址,进行回调,通知服务有关文档编辑的状态,用户需要根据相关状态实现文档的保存。
  2. 文档参考链接

  1. 注意事项
  • 要对回调内容中token进行校验,校验合法后才允许文件的更新保存

页面集成

VUE集成
  1. 文档参考链接

  2. 参考实现(测试验证时的实现)

该集成页面实现了编辑器集成,自定义菜单注册,API执行,AI交互,消息发送与监听

<template>
    <div style="height: 100%;">
        <div>OnlyOffice + AI交互示例</div>
        <!-- 控制按钮 -->
        <button @click="getFullText">获取全文</button>
        <button @click="replaceWithAIResult">替换文本</button>
        <button @click="getFullHtml">获取全文(HTML)</button>
        <button @click="showMessage">消息展示</button>
        <button @click="addComment">添加注释</button>
        <button @click="getSelection">获取选中文本</button>
        <button @click="getSelectionType">获取选择类型</button>
        <button @click="inputText">输入文本</button>
        <button @click="pasteHtml">粘贴HTML</button>
        <button @click="searchAndReplace">搜索替换</button>
        <div id="container">
            <div id="onlyoffice"></div>
            <!-- <iframe id="aiIframe"
                src="AIURL"></iframe> -->
        </div>
    </div>
</template>

<script>
export default {
    data() {
        return {
            docEditor: null,
            connector: null,
            aiBox: {
                width: 226,
                height: 284,
                bottom: 5,
                isDragging: false
            },
            aiResult: ""
        };
    },
    mounted() {
        this.initOnlyOffice();
        // ---------------- AI iframe 返回结果 ----------------
        window.addEventListener('message', (event) => {
            if (!event.data || event.data.type !== 'replaceText') return;
            const { content } = event.data.data;

            // 这里执行文档替换操作,比如调用 OnlyOffice connector 方法
            if (this.connector) {
                this.connector.executeMethod("PasteText", [content]);
                console.log("已替换选中文本", content);

            }
        });
    },
    methods: {
        // 初始化 OnlyOffice 编辑器
        async initOnlyOffice() {
            try {
                const res = await fetch("http://{yourbacekservice}/onlyoffice/config?id=123");
                const config = await res.json();
                config.editorConfig.events = {
                    onAppReady: () => {
                        console.log("OnlyOffice加载完成");
                    },
                    onDocumentReady: this.onDocumentReady
                };
                const script = document.createElement("script");
                script.src = "http://{youronlrofficehost}/web-apps/apps/api/documents/api.js";

                script.onload = () => {
                    this.docEditor = new DocsAPI.DocEditor("onlyoffice", config.editorConfig);
                };
                document.head.appendChild(script);
            } catch (e) {
                console.error("OnlyOffice初始化失败", e);
            }
        },

        onDocumentReady() {
            this.connector = this.docEditor.createConnector();
            console.log("文档准备就绪", this.connector);
            this.connector.attachEvent("onContextMenuShow", () => {
                this.connector.executeMethod("GetSelectedText", [], selectedText => {
                    const hasSelection = selectedText && selectedText.trim().length > 0;
                    const childItems = [
                        { id: "analyzeText", text: "分析文本内容", onClick: () => this.sendToAI(selectedText, "analyzeText") }
                    ];
                    if (hasSelection) {
                        childItems.push(
                            {
                                id: "optimizeText",
                                text: "文案优化",
                                onClick: () => this.sendToAI(selectedText, "optimizeText")
                            },
                            { id: "correctText", text: "文本纠错", onClick: () => this.sendToAI(selectedText, "correctText") },
                            {
                                id: "translateText",
                                text: "文本翻译",
                                onClick: () => this.sendToAI(selectedText, "translateText")
                            }
                        );
                    }
                    this.connector.addContextMenuItem([{ id: "hopeSeekAI", text: "HopeSeek(AI)", items: childItems }]);
                });
            });
            const iframe = document.getElementById('aiIframe');
            if (!iframe) return;
            iframe.contentWindow.postMessage({
                type: 'openChange',
                data: { isShow: true }
            }, '*');



        },


        sendToAI(content, action) {
            const iframe = document.getElementById("aiIframe");
            if (!iframe) return;
            iframe.contentWindow.postMessage({
                type: "aiRequest",
                data: { content, action, source: "onlyoffice" }
            }, "*");
        },
        getSelectionType() {
            this.connector.executeMethod("GetSelectionType", [], selectedType => {
                console.log("获取选择类型", selectedType);
            });
        },
        inputText() {
            this.connector.executeMethod("InputText", ["ONLYOFFICE Plugins", ""])
        },

        getSelection() {
            // this.connector.executeMethod("GetSelectedText", [], selectedText => {
            //     console.log("已获取选中文本", selectedText);
            // });
            this.connector.executeMethod("GetSelectedText", [{ "Numbering": false, "Math": false, "TableCellSeparator": '\n', "ParaSeparator": '\n', "TabSymbol": String.fromCharCode(9) }], function (data) {
                const sText = data;
                // ExecTypograf (sText);
                console.log(sText);
            });
        },
        replaceWithAIResult() {
            this.connector.executeMethod("PasteText", ["要粘贴的内容"]);
        },
        pasteHtml() {
            this.connector.executeMethod("PasteHtml", ["&lt;p&gt;&lt;b&gt;Plugin methods for OLE objects&lt;/b&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;AddOleObject&lt;/li&gt;&lt;li&gt;EditOleObject&lt;/li&gt;&lt;/ul&gt;"]);
        },
        searchAndReplace() {
            this.connector.executeMethod("SearchAndReplace", [
                {
                    "searchString": "目标",
                    "replaceString": "R目标R",
                    "matchCase": true
                }
            ]);
        },
        getFullText() {
            this.connector.callCommand(() => Api.GetDocument().GetText(), data => console.log(data));
        },

        getFullHtml() {
            this.connector.executeMethod("GetFileHTML", null, res => console.log(res));
        },
        showMessage() {
            this.docEditor.showMessage("12324")

        },

        // AI 浮窗拖拽操作
        startDrag(e) {
            e.preventDefault();
            this.aiBox.isDragging = true;
            this.aiBox.startY = e.clientY - this.aiBox.bottom;
            document.addEventListener('mousemove', this.onDrag);
            document.addEventListener('mouseup', this.stopDrag);
        },

        onDrag(e) {
            if (!this.aiBox.isDragging) return;
            let newY = window.innerHeight - e.clientY;
            if (newY > 5 && (window.innerHeight - newY) > 150) this.aiBox.bottom = newY;
            document.getElementById('aiBox').style.bottom = this.aiBox.bottom + 'px';
        },

        stopDrag() {
            this.aiBox.isDragging = false;
            document.removeEventListener('mousemove', this.onDrag);
            document.removeEventListener('mouseup', this.stopDrag);
        },
        addComment() {
            this.connector.executeMethod("AddComment", [
                {
                    "UserName": "John Smith",
                    "QuoteText": "text",
                    "Text": "要填写的注释内容",
                    "Time": "1662737941471",
                    "Solved": false,
                }
            ], function (comment) {
                console.log(comment)
            });
        }
    }


};
</script>

<style scoped>
body,
html {
    margin: 0;
    height: 100%;
    overflow: hidden;
}

#container {
    display: flex;
    height: 100%;
}

#onlyoffice {
    flex: 2;
}

#sidebar {
    width: 350px;
    border-left: 1px solid #ddd;
}

#aiBox {
    position: fixed;
    right: 0;
    bottom: 5px;
    width: 600px;
    height: 100%;
    z-index: 2000;
    border: 1px solid #ccc;
    background: #fff;
    box-shadow: 0 0 8px rgba(0, 0, 0, 0.3);
}

#aiIframe {
    width: 70%;
    height: 100%;
    border: none;
}
</style>

连接器(connector)介绍

简介

对于我们而言,很多情况下都是简单的操作一下文档,做一些和业务系统相关操作的功能,使用到:callCommandexecuteMethodattachEventdetachEvent这四个核心块api模块。

初始化
this.connector = this.docEditor.createConnector();
核心块说明
  1. callCommand()
-   基础api调用模块,用于组合并执行复杂api或者自定义代码。
    
-  文档链接:[https://api.onlyoffice.com/docs/plugin-and-macros/interacting-with-editors/overview/how-to-call-commands/](https://api.onlyoffice.com/docs/plugin-and-macros/interacting-with-editors/overview/how-to-call-commands/)
  • 示例
this.connector.callCommand(() => Api.GetDocument().GetText(), data => console.log(data));

  1. executeMethod()。

  • 示例
this.connector.executeMethod("PasteText", ["要粘贴的内容"]);
  1. attachEvent、detachEvent
  • 绑定、解绑事件。
-  文档在这:[https://api.onlyoffice.com/docs/plugin-and-macros/interacting-with-editors/overview/how-to-attach-events/](https://api.onlyoffice.com/docs/plugin-and-macros/interacting-with-editors/overview/how-to-attach-events/)
    
-   示例
/**
* 绑定事件
*/
connector.attachEvent("onAddComment", function(){
    console.log("event: onAddComment");
});
 
/**
* 解绑事件
*/
connector.detachEvent("onAddComment");

常用API

添加上下文菜单-addContextMenuItem
  1. 文档链接

  • 代码示例
connector.attachEvent("onContextMenuShow", (options) => {
  connector.addContextMenuItem([{
    text: "mainItem",
    onClick: () => {
      console.log("[CONTEXTMENUCLICK] menuSubItem1");
    },
  }]);
});
添加工具栏菜单-addToolbarMenuItem
  1. 文档链接

  2. 代码示例

connector.addToolbarMenuItem({
  tabs: [
    {
      text: "Connector",
      items: [
        {
          id: "toolConnector1",
          type: "button",
          text: "Meaning",
          hint: "Meaning",
          lockInViewMode: true,
          icons: "./icon.svg",
          items: [
            {
              id: "toolC1",
              text: "Text",
              data: "Hello",
              onClick: (data) => {
                console.log(`[TOOLBARMENUCLICK]: ${data}`);
              },
            },
          ],
        },
      ],
    },
  ],
});
事件监听-attachEvent
  1. 文档链接

  2. 代码示例

connector.attachEvent("onChangeContentControl", (obj) => {
  console.log(`[EVENT] onChangeContentControl: ${JSON.stringify(obj)}`)
})
添加注释-AddComment
  1. 文档链接

  2. 代码示例

addComment() {
            this.connector.executeMethod("AddComment", [
                {
                    "UserName": "John Smith",
                    "QuoteText": "text",
                    "Text": "要填写的注释内容",
                    "Time": "1662737941471",
                    "Solved": false,
                }
            ], function (comment) {
                console.log(comment)
            });
        }
获取选中内容-GetSelectedContent
  1. 文档链接

  2. 代码示例


getSelection() {
  方法一:
            this.connector.executeMethod("GetSelectedText", [], selectedText => {
                console.log("已获取选中文本", selectedText);
            });

方法二:
 this.connector.executeMethod("GetSelectedText", [{"Numbering": false, "Math": false, "TableCellSeparator": '\n', "ParaSeparator": '\n', "TabSymbol": String.fromCharCode(9)}], function (data) {
                 const sText = data;
                // ExecTypograf (sText);
                console.log(sText);
            });
},
        
获取选择类型-GetSelectionType
  1. 文档链接

  2. 代码示例

getSelectionType() {
            this.connector.executeMethod("GetSelectionType", [], selectedType => {
                console.log("获取选择类型", selectedType);
            });
},
输入文本-InputText
  1. 文档链接

  2. 代码示例

  inputText() {
            this.connector.executeMethod("InputText", ["ONLYOFFICE Plugins", ""])
        },
粘贴文本-PasteText(如果当期有选中内容的话,实际是删除并粘贴)
  1. 文档链接

  2. 代码示例

this.connector.executeMethod("PasteText", ["要粘贴的内容"]);
查找并替换文本-SearchAndReplace
  1. 文档链接
  1. 代码示例
searchAndReplace() {
            this.connector.executeMethod("SearchAndReplace", [
                {
                    "searchString": "目标",
                    "replaceString": "R目标R",
                    "matchCase": true
                }
            ]);
        },

AI交互

整体说明

ONLYOFFICE与AI助手的交互本质上是一个基于 “消息驱动” 的异步通信模型,其核心是 postMessage API。整个过程可以清晰地划分为两个主要阶段:请求阶段响应阶段

整个交互流程可以概括为以下两个核心阶段:

第一阶段:从编辑器到AI助手(发送请求)

此阶段完成从用户操作到AI接收处理任务的闭环。

  1. 用户操作触发

    • 用户在ONLYOFFICE在线编辑器中选择一段文本内容。

    • 用户点击编辑器菜单中集成的AI功能按钮(例如:“内容优化”、“续写”、“翻译”、“添加注释”等)。

  2. 集成页面捕获事件并组装消息

    • 集成页面(即嵌入编辑器的父页面)监听到来自编辑器的这个特定菜单点击事件。

    • 集成页面通过编辑器提供的API(如getSelectedText)获取用户当前选中的内容。

    • 集成页面将操作事件类型(如:"analyzeText")和选中的内容组装成一个结构化的消息对象。例如:

{
  "type": "ai-request", // 固定消息类型,表明这是一条AI请求
  "source":"onlyoffice", 
  "data": {
    "action": "analyzeText",     // 具体的事件类型
    "selectedText": "这里是用户选中的文本内容...",
    "otherParams": {}     // 其他可能需要的参数
  }
}
  1. 发送消息至AI助手

    • 集成页面通过 postMessage 方法,将该消息对象发送到AI助手(通常是一个独立的、隐藏的或浮层的<iframe>窗口)。

    • 发送时指定AI助手窗口的源(origin),以确保安全。

 const iframe = document.getElementById("aiIframe");
            if (!iframe) return;
            iframe.contentWindow.postMessage({
              "type": "ai-request", // 固定消息类型,表明这是一条AI请求
              "source":"onlyoffice", 
              "data": {
                "action": "analyzeText",     // 具体的事件类型
                "selectedText": "这里是用户选中的文本内容...",
                "otherParams": {}     // 其他可能需要的参数
              }
            }, "");

第二阶段:从AI助手回编辑器(执行操作)

此阶段完成从AI生成结果到编辑器内容更新的闭环。

  1. AI助手监听并处理消息

    • AI助手窗口通过window.addEventListener('message', ...)持续监听消息。

    • 接收到消息后,首先验证消息来源的合法性,确保其来自集成的父页面。

    • 解析消息内容,根据action字段判断需要执行的具体AI任务(例如:调用“内容优化”的API)。

    • AI助手调用相应的后端AI服务接口,获取生成的结果。

  2. 用户确认与指令发送

    • AI助手将生成的结果展示给用户(在它的UI界面中)。

    • 用户查看结果后,点击“替换”、“插入”或“取消”等按钮。

    • 当用户点击“替换”时,AI助手会组装一条响应消息。例如:


{
  "type": "ai-response", // 固定消息类型,表明这是一条AI请求
  "source":"ai-plugin", 
  "data": {
    "action": "analyzeText",     // 具体的事件类型
    "content": "content",
    "otherParams": {
      "sourceMessage":{源消息内容}
    }     // 其他可能需要的参数
  }
}
  1. 集成页面接收并执行操作

    • 集成页面监听来自AI助手窗口的message事件。

    • 接收到响应消息后,同样进行来源验证和解析。

    • 根据解析出的

      • 替换(Replace):用 响应的content 替换当前选中的文本。

      • 插入(Insert):在光标处或选定位置插入响应的 content

      • 添加注释(Comment):为选定文本或指定位置添加以响应的content为内容的注释。

 window.addEventListener('message', (event) => {
           //进行事件,消息源,源数据的校验
});

整体交互流程

整个交互过程可以概括为下图所示的闭环流程:

User Editor(ONLYOFFICE) Parent Page(集成页面) AI Helper(AI助手 iframe) AI Service AI Helper 1. 选择文本并点击AI菜单 2. 触发事件 3. 获取选中文本,组装消息 4. postMessage(请求) 5. 调用API生成内容 6. 返回结果 7. 展示生成结果 8. 点击“替换” 9. 组装响应消息 10. postMessage(响应) 11. 调用编辑器API执行操作 12. 更新文档内容 User Editor(ONLYOFFICE) Parent Page(集成页面) AI Helper(AI助手 iframe) AI Service AI Helper

核心特点:

  • 解耦设计:编辑器与AI功能模块分离,通过标准API通信,易于开发和维护。

  • 安全通信:使用postMessage并严格验证 origin,保障跨域通信安全。

  • 异步交互:所有操作均为非阻塞,保证用户体验流畅。

  • 可扩展性:只需定义新的type和对应的处理逻辑,即可轻松添加更多AI功能。


网站公告

今日签到

点亮在社区的每一天
去签到