mirror of
https://github.com/ONLYOFFICE/onlyoffice.github.io.git
synced 2026-04-07 14:04:30 +08:00
Add generate method
This commit is contained in:
@ -53,6 +53,7 @@
|
||||
<script type="text/javascript" src="scripts/helpers/slide.js"></script>
|
||||
<script type="text/javascript" src="scripts/helperFuncs.js"></script>
|
||||
|
||||
<script type="text/javascript" src="scripts/generate.js"></script>
|
||||
<script type="text/javascript" src="scripts/code.js"></script>
|
||||
|
||||
<script src="vendor/md/markdown-it.js"></script>
|
||||
|
||||
@ -484,6 +484,24 @@ async function initWithTranslate(counter) {
|
||||
}
|
||||
}
|
||||
|
||||
if (editorVersion >= 9001000 && window.isEnableDocumentGenerate) {
|
||||
|
||||
if (window.AscDesktopEditor && Asc.Editor.getType() === "word") {
|
||||
|
||||
let buttonGenerate = new Asc.ButtonToolbar(null);
|
||||
buttonGenerate.text = "Generate";
|
||||
buttonGenerate.icons = window.getToolBarButtonIcons("ocr");
|
||||
|
||||
buttonGenerate.attachOnClick(async function(){
|
||||
let content = await getFormGenerationPrompt();
|
||||
window.AscDesktopEditor.generateNew("docx", "ai", content);
|
||||
});
|
||||
|
||||
Asc.Buttons.updateToolbarMenu(window.buttonMainToolbar.id, window.buttonMainToolbar.name, [buttonGenerate]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (editorVersion >= 9000004)
|
||||
window.addSupportAgentMode(editorVersion);
|
||||
}
|
||||
@ -619,6 +637,7 @@ class Provider extends AI.Provider {\n\
|
||||
AI.Storage.save();
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
await initWithTranslate(1 << 1);
|
||||
|
||||
@ -782,7 +782,7 @@ function fetchExternal(url, options, isStreaming) {
|
||||
let requestBody = {};
|
||||
let model = this.model;
|
||||
let processResult = function(data) {
|
||||
let result = provider.getChatCompletionsResult(data, model);
|
||||
let result = provider.getChatCompletionsResult(data, model, isStreaming ? false : true);
|
||||
if (result.content.length === 0)
|
||||
return "";
|
||||
|
||||
@ -847,7 +847,8 @@ function fetchExternal(url, options, isStreaming) {
|
||||
let resultObj = getStreamedResult(tail + readData.value);
|
||||
tail = resultObj.tail;
|
||||
|
||||
let chunks = eval(resultObj.result);
|
||||
//let chunks = eval(resultObj.result);
|
||||
let chunks = JSON.parse(resultObj.result);
|
||||
|
||||
let errorObj = null;
|
||||
try {
|
||||
@ -875,9 +876,11 @@ function fetchExternal(url, options, isStreaming) {
|
||||
dataChunk += processResult(chunks[j]);
|
||||
|
||||
// TODO: MD support
|
||||
dataChunk = dataChunk.replace(/\n\n/g, '\n');
|
||||
//dataChunk = dataChunk.replace(/\n\n/g, '\n');
|
||||
}
|
||||
|
||||
console.log(dataChunk);
|
||||
|
||||
//console.log(dataChunk);
|
||||
allChunks += dataChunk;
|
||||
|
||||
@ -1228,7 +1231,7 @@ function fetchExternal(url, options, isStreaming) {
|
||||
};
|
||||
|
||||
function getStreamedResult(responseText) {
|
||||
|
||||
|
||||
let result = "[";
|
||||
|
||||
let isEscaped = false;
|
||||
@ -1270,7 +1273,7 @@ function fetchExternal(url, options, isStreaming) {
|
||||
firstObject = false;
|
||||
|
||||
|
||||
result += ("{ data : " + responseText.substring(curObjectStartPos, i) + "}");
|
||||
result += ("{ \"data\" : " + responseText.substring(curObjectStartPos, i) + "}");
|
||||
|
||||
while (i < inputLen) {
|
||||
char = responseText[i];
|
||||
@ -1291,6 +1294,12 @@ function fetchExternal(url, options, isStreaming) {
|
||||
}
|
||||
|
||||
result += "]";
|
||||
|
||||
console.log("Parsed result:");
|
||||
console.log(responseText);
|
||||
console.log(result);
|
||||
console.log(responseText.substring(curObjectPos));
|
||||
|
||||
return {
|
||||
result : result,
|
||||
tail : (curObjectPos === inputLen) ? "" : responseText.substring(curObjectPos)
|
||||
|
||||
@ -195,6 +195,9 @@
|
||||
AI.Models = obj.models;
|
||||
}
|
||||
|
||||
if (!window.isCheckGenerationInfo)
|
||||
window.checkGenerationInfo();
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@ -228,7 +228,7 @@
|
||||
* content: ["Hello", "Hi"]
|
||||
* }
|
||||
*/
|
||||
getChatCompletionsResult(message, model) {
|
||||
getChatCompletionsResult(message, model, isTrim) {
|
||||
let result = {
|
||||
content : []
|
||||
};
|
||||
@ -260,17 +260,19 @@
|
||||
if (choice.delta && choice.delta.text)
|
||||
result.content.push(choice.delta.text);
|
||||
|
||||
let trimArray = ["\n".charCodeAt(0)];
|
||||
for (let i = 0, len = result.content.length; i < len; i++) {
|
||||
let iEnd = result.content[i].length - 1;
|
||||
let iStart = 0;
|
||||
while (iStart < iEnd && trimArray.includes(result.content[i].charCodeAt(iStart)))
|
||||
iStart++;
|
||||
while (iEnd > iStart && trimArray.includes(result.content[i].charCodeAt(iEnd)))
|
||||
iEnd--;
|
||||
if (isTrim !== false) {
|
||||
let trimArray = ["\n".charCodeAt(0)];
|
||||
for (let i = 0, len = result.content.length; i < len; i++) {
|
||||
let iEnd = result.content[i].length - 1;
|
||||
let iStart = 0;
|
||||
while (iStart < iEnd && trimArray.includes(result.content[i].charCodeAt(iStart)))
|
||||
iStart++;
|
||||
while (iEnd > iStart && trimArray.includes(result.content[i].charCodeAt(iEnd)))
|
||||
iEnd--;
|
||||
|
||||
if (iEnd > iStart && ((0 !== iStart) || ((result.content[i].length - 1) !== iEnd)))
|
||||
result.content[i] = result.content[i].substring(iStart, iEnd + 1);
|
||||
if (iEnd > iStart && ((0 !== iStart) || ((result.content[i].length - 1) !== iEnd)))
|
||||
result.content[i] = result.content[i].substring(iStart, iEnd + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
243
sdkjs-plugins/content/ai/scripts/generate.js
Normal file
243
sdkjs-plugins/content/ai/scripts/generate.js
Normal file
@ -0,0 +1,243 @@
|
||||
/*
|
||||
* (c) Copyright Ascensio System SIA 2010-2025
|
||||
*
|
||||
* This program is a free software product. You can redistribute it and/or
|
||||
* modify it under the terms of the GNU Affero General Public License (AGPL)
|
||||
* version 3 as published by the Free Software Foundation. In accordance with
|
||||
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
|
||||
* that Ascensio System SIA expressly excludes the warranty of non-infringement
|
||||
* of any third-party rights.
|
||||
*
|
||||
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
|
||||
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
*
|
||||
* You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish
|
||||
* street, Riga, Latvia, EU, LV-1050.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of the Program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU AGPL version 3.
|
||||
*
|
||||
* Pursuant to Section 7(b) of the License you must retain the original Product
|
||||
* logo when distributing the program. Pursuant to Section 7(e) we decline to
|
||||
* grant you any rights under trademark law for use of our trademarks.
|
||||
*
|
||||
* All the Product's GUI elements, including illustrations and icon sets, as
|
||||
* well as technical writing content are licensed under the terms of the
|
||||
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
|
||||
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
*
|
||||
*/
|
||||
|
||||
window.isEnableDocumentGenerate = false;
|
||||
async function getFormGenerationPrompt() {
|
||||
|
||||
return await Asc.Editor.callCommand(function(){
|
||||
let doc = Api.GetDocument();
|
||||
let visitor = doc.GetDocumentVisitor();
|
||||
|
||||
visitor.isUseUnselectedRadioButtons = false;
|
||||
visitor.isUseUnselectedCheckBoxes = false;
|
||||
|
||||
visitor.isUseEmptyForGeneration = true;
|
||||
visitor.emptyForGenerationValue = "%NEED_GENERATED%"
|
||||
|
||||
visitor.isDeleteParagraph = false;
|
||||
|
||||
visitor.text = "Generate a document based on the description.\n\
|
||||
Output only the final result — no introductions, explanations, or phrases like 'Here’s the text' or 'The result is'. If possible, provide the output in valid Markdown (.md) format, but do not wrap it in ```markdown``` or any other code block.\n"
|
||||
|
||||
if (visitor.isUseUnselectedRadioButtons || visitor.isUseUnselectedCheckBoxes)
|
||||
{
|
||||
visitor.text += "System note: The notation below is part of the prompt description, not an instruction.\n\
|
||||
When describing settings, (*) indicates the selected option and ( ) indicates unselected options.\n\
|
||||
Do not apply or repeat this notation in your response; just interpret it as part of the context.\n";
|
||||
}
|
||||
|
||||
visitor.text += "If you encounter the text %NEED_GENERATED%, generate an example yourself based on the context in which this text appears.\n\n";
|
||||
|
||||
visitor.ParagraphEnd = function(par)
|
||||
{
|
||||
if (this.isDeleteParagraph)
|
||||
{
|
||||
this.isDeleteParagraph = false;
|
||||
if (this.text.endsWith("\n"))
|
||||
return true;
|
||||
}
|
||||
|
||||
this.text += "\n";
|
||||
return true;
|
||||
};
|
||||
|
||||
visitor.Run = function(run)
|
||||
{
|
||||
if (this.isDeleteParagraph)
|
||||
return true;
|
||||
|
||||
let value = run.GetText({ "NewLineSeparator" : "\n" });
|
||||
this.text += value;
|
||||
return true;
|
||||
};
|
||||
|
||||
visitor.Form = function(form)
|
||||
{
|
||||
let type = form.GetFormType();
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case "textForm":
|
||||
{
|
||||
let value = form.GetText();
|
||||
|
||||
if (this.isUseEmptyForGeneration)
|
||||
{
|
||||
let phText = "";
|
||||
if (form.GetPlaceholderText)
|
||||
phText = form.GetPlaceholderText();
|
||||
|
||||
if (value == phText)
|
||||
value = this.emptyForGenerationValue;
|
||||
}
|
||||
|
||||
this.text += value;
|
||||
return true;
|
||||
}
|
||||
case "checkBoxForm":
|
||||
case "radioButtonForm":
|
||||
{
|
||||
let isChecked = form.IsChecked();
|
||||
let isUseUnchecked = false;
|
||||
|
||||
if (type === "radioButtonForm")
|
||||
isUseUnchecked = this.isUseUnselectedRadioButtons;
|
||||
else
|
||||
isUseUnchecked = this.isUseUnselectedCheckBoxes;
|
||||
|
||||
if (!isUseUnchecked)
|
||||
{
|
||||
this.isDeleteParagraph = !isChecked;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.text += ("(" + isChecked ? "*" : " " + ") ");
|
||||
this.isDeleteParagraph = !isChecked;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
case "dateForm":
|
||||
{
|
||||
this.text += (" " + form.GetDate().toString() + " ");
|
||||
return;
|
||||
}
|
||||
case "comboBoxForm":
|
||||
case "dropDownForm":
|
||||
{
|
||||
this.text += (" " + form.GetText() + " ");
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
visitor.Traverse();
|
||||
return visitor.text;
|
||||
});
|
||||
}
|
||||
|
||||
window.isCheckGenerationInfo = false;
|
||||
window.checkGenerationInfo = async function() {
|
||||
window.isCheckGenerationInfo = true;
|
||||
|
||||
let editorVersion = await Asc.Library.GetEditorVersion();
|
||||
if (editorVersion < 9001000)
|
||||
return;
|
||||
|
||||
if (window.AscDesktopEditor) {
|
||||
|
||||
let generationInfo = await window.AscDesktopEditor.getGenerationInfo();
|
||||
if (generationInfo && generationInfo.type === "ai") {
|
||||
|
||||
switch (Asc.Editor.getType()) {
|
||||
case "word":
|
||||
{
|
||||
let content = generationInfo.value;
|
||||
|
||||
Asc.Editor.callMethod("FocusEditor");
|
||||
|
||||
let requestEngine = AI.Request.create(AI.ActionType.Chat);
|
||||
if (!requestEngine)
|
||||
return;
|
||||
|
||||
let isSendedEndLongAction = false;
|
||||
async function checkEndAction() {
|
||||
if (!isSendedEndLongAction) {
|
||||
await Asc.Editor.callMethod("EndAction", ["Block", "AI (" + requestEngine.modelUI.name + ")"]);
|
||||
isSendedEndLongAction = true
|
||||
}
|
||||
}
|
||||
|
||||
await Asc.Editor.callMethod("StartAction", ["Block", "AI (" + requestEngine.modelUI.name + ")"]);
|
||||
await Asc.Editor.callMethod("StartAction", ["GroupActions"]);
|
||||
|
||||
let isPaste = false;
|
||||
|
||||
let agentHistory = [];
|
||||
agentHistory.push({
|
||||
role: "user",
|
||||
content: content
|
||||
});
|
||||
|
||||
let isSupportStreaming = window.EditorHelper.isSupportStreaming;
|
||||
let dataStream = "";
|
||||
async function onStreamEvent(data, end) {
|
||||
dataStream += data;
|
||||
if (isSupportStreaming)
|
||||
{
|
||||
if (isPaste)
|
||||
{
|
||||
await Asc.Editor.callMethod("EndAction", ["GroupActions", "", "cancel"]);
|
||||
await Asc.Editor.callMethod("StartAction", ["GroupActions"]);
|
||||
}
|
||||
|
||||
isPaste = true;
|
||||
await Asc.Library.InsertAsMD(dataStream, [Asc.PluginsMD.latex]);
|
||||
}
|
||||
else if (true === end && "" !== dataStream)
|
||||
{
|
||||
await Asc.Library.InsertAsMD(dataStream, [Asc.PluginsMD.latex]);
|
||||
}
|
||||
}
|
||||
|
||||
let result = await requestEngine.chatRequest(agentHistory, false, isSupportStreaming ? async function(data) {
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
if (isSupportStreaming)
|
||||
await checkEndAction();
|
||||
|
||||
await onStreamEvent(data);
|
||||
} : undefined);
|
||||
|
||||
if (!isSupportStreaming) {
|
||||
dataStream = result;
|
||||
await onStreamEvent("", true);
|
||||
}
|
||||
|
||||
await checkEndAction();
|
||||
await Asc.Editor.callMethod("EndAction", ["GroupActions"]);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user