diff --git a/sdkjs-plugins/content/ai/scripts/custom-annotations/assistant-hint.js b/sdkjs-plugins/content/ai/scripts/custom-annotations/assistant-hint.js
index 1391e2d7..48b8f48c 100644
--- a/sdkjs-plugins/content/ai/scripts/custom-annotations/assistant-hint.js
+++ b/sdkjs-plugins/content/ai/scripts/custom-annotations/assistant-hint.js
@@ -34,9 +34,9 @@
///
/** @param {localStorageCustomAssistantItem} assistantData */
-function AssistantHint(assistantData)
+function AssistantHint(annotationPopup, assistantData)
{
- CustomAnnotator.call(this, assistantData);
+ CustomAnnotator.call(this, annotationPopup, assistantData);
}
AssistantHint.prototype = Object.create(CustomAnnotator.prototype);
AssistantHint.prototype.constructor = AssistantHint;
@@ -58,7 +58,7 @@ AssistantHint.prototype.annotateParagraph = async function(paraId, recalcId, tex
let response = await this.chatRequest(argPrompt);
if (!response)
return false;
-
+
let rangeId = 1;
let ranges = [];
@@ -216,36 +216,3 @@ AssistantHint.prototype.onAccept = async function(paraId, rangeId)
await Asc.Editor.callMethod("EndAction", ["GroupActions"]);
await Asc.Editor.callMethod("FocusEditor");
};
-
-/**
- * @param {string} paraId
- * @param {string} rangeId
- */
-AssistantHint.prototype.getAnnotationRangeObj = function(paraId, rangeId)
-{
- return {
- "paragraphId" : paraId,
- "rangeId" : rangeId,
- "name" : "customAssistant_" + this.assistantData.id
- };
-};
-AssistantHint.prototype._handleNewRangePositions = async function(range, paraId, text)
-{
- if (!range || range["name"] !== "customAssistant_" + this.assistantData.id || !this.paragraphs[paraId])
- return;
-
- let rangeId = range["id"];
- let annot = this.getAnnotation(paraId, rangeId);
-
- if (!annot)
- return;
-
- let start = range["start"];
- let len = range["length"];
-
- if (annot["original"] !== text.substring(start, start + len))
- {
- let annotRange = this.getAnnotationRangeObj(paraId, rangeId);
- Asc.Editor.callMethod("RemoveAnnotationRange", [annotRange]);
- }
-};
diff --git a/sdkjs-plugins/content/ai/scripts/custom-annotations/assistant-replace-hint.js b/sdkjs-plugins/content/ai/scripts/custom-annotations/assistant-replace-hint.js
index 9f4aa1c2..2bb62250 100644
--- a/sdkjs-plugins/content/ai/scripts/custom-annotations/assistant-replace-hint.js
+++ b/sdkjs-plugins/content/ai/scripts/custom-annotations/assistant-replace-hint.js
@@ -34,9 +34,9 @@
///
/** @param {localStorageCustomAssistantItem} assistantData */
-function AssistantReplaceHint(assistantData)
+function AssistantReplaceHint(annotationPopup, assistantData)
{
- CustomAnnotator.call(this, assistantData);
+ CustomAnnotator.call(this, annotationPopup, assistantData);
}
AssistantReplaceHint.prototype = Object.create(CustomAnnotator.prototype);
AssistantReplaceHint.prototype.constructor = AssistantReplaceHint;
@@ -52,11 +52,12 @@ AssistantReplaceHint.prototype.annotateParagraph = async function(paraId, recalc
if (text.length === 0)
return false;
-
+
const argPrompt = this._createPrompt(text);
+
let response = await this.chatRequest(argPrompt);
if (!response)
- return false;
+ return false;
let rangeId = 1;
let ranges = [];
@@ -65,11 +66,11 @@ AssistantReplaceHint.prototype.annotateParagraph = async function(paraId, recalc
/**
* @param {string} text
- * @param {ReplaceHintAiResponse[]} corrections
+ * @param {ReplaceHintAiResponse[]} matches
*/
- function convertToRanges(text, corrections)
+ function convertToRanges(text, matches)
{
- for (const { origin, suggestion, difference, reason, paragraph, occurrence, confidence } of corrections)
+ for (const { origin, suggestion, difference, reason, paragraph, occurrence, confidence } of matches)
{
if (origin === suggestion || confidence <= 0.7)
continue;
@@ -229,36 +230,3 @@ AssistantReplaceHint.prototype.onAccept = async function(paraId, rangeId)
await Asc.Editor.callMethod("EndAction", ["GroupActions"]);
await Asc.Editor.callMethod("FocusEditor");
};
-
-/**
- * @param {string} paraId
- * @param {string} rangeId
- */
-AssistantReplaceHint.prototype.getAnnotationRangeObj = function(paraId, rangeId)
-{
- return {
- "paragraphId" : paraId,
- "rangeId" : rangeId,
- "name" : "customAssistant_" + this.assistantData.id
- };
-};
-AssistantReplaceHint.prototype._handleNewRangePositions = async function(range, paraId, text)
-{
- if (!range || range["name"] !== "customAssistant_" + this.assistantData.id || !this.paragraphs[paraId])
- return;
-
- let rangeId = range["id"];
- let annot = this.getAnnotation(paraId, rangeId);
-
- if (!annot)
- return;
-
- let start = range["start"];
- let len = range["length"];
-
- if (annot["original"] !== text.substring(start, start + len))
- {
- let annotRange = this.getAnnotationRangeObj(paraId, rangeId);
- Asc.Editor.callMethod("RemoveAnnotationRange", [annotRange]);
- }
-};
diff --git a/sdkjs-plugins/content/ai/scripts/custom-annotations/assistant-replace.js b/sdkjs-plugins/content/ai/scripts/custom-annotations/assistant-replace.js
index d47da0aa..7718d8ac 100644
--- a/sdkjs-plugins/content/ai/scripts/custom-annotations/assistant-replace.js
+++ b/sdkjs-plugins/content/ai/scripts/custom-annotations/assistant-replace.js
@@ -34,9 +34,9 @@
///
/** @param {localStorageCustomAssistantItem} assistantData */
-function AssistantReplace(assistantData)
+function AssistantReplace(annotationPopup, assistantData)
{
- CustomAnnotator.call(this, assistantData);
+ CustomAnnotator.call(this, annotationPopup, assistantData);
}
AssistantReplace.prototype = Object.create(CustomAnnotator.prototype);
AssistantReplace.prototype.constructor = AssistantReplace;
@@ -52,12 +52,13 @@ AssistantReplace.prototype.annotateParagraph = async function(paraId, recalcId,
if (text.length === 0)
return false;
-
+
const argPrompt = this._createPrompt(text);
+
let response = await this.chatRequest(argPrompt);
if (!response)
return false;
-
+
let rangeId = 1;
let ranges = [];
@@ -65,11 +66,11 @@ AssistantReplace.prototype.annotateParagraph = async function(paraId, recalcId,
/**
* @param {string} text
- * @param {ReplaceAiResponse[]} corrections
+ * @param {ReplaceAiResponse[]} matches
*/
- function convertToRanges(text, corrections)
+ function convertToRanges(text, matches)
{
- for (const { origin, suggestion, paragraph, occurrence, confidence } of corrections)
+ for (const { origin, suggestion, paragraph, occurrence, confidence } of matches)
{
if (origin === suggestion || confidence <= 0.7)
continue;
@@ -216,36 +217,3 @@ AssistantReplace.prototype.onAccept = async function(paraId, rangeId)
await Asc.Editor.callMethod("EndAction", ["GroupActions"]);
await Asc.Editor.callMethod("FocusEditor");
};
-
-/**
- * @param {string} paraId
- * @param {string} rangeId
- */
-AssistantReplace.prototype.getAnnotationRangeObj = function(paraId, rangeId)
-{
- return {
- "paragraphId" : paraId,
- "rangeId" : rangeId,
- "name" : "customAssistant_" + this.assistantData.id
- };
-};
-AssistantReplace.prototype._handleNewRangePositions = async function(range, paraId, text)
-{
- if (!range || range["name"] !== "customAssistant_" + this.assistantData.id || !this.paragraphs[paraId])
- return;
-
- let rangeId = range["id"];
- let annot = this.getAnnotation(paraId, rangeId);
-
- if (!annot)
- return;
-
- let start = range["start"];
- let len = range["length"];
-
- if (annot["original"] !== text.substring(start, start + len))
- {
- let annotRange = this.getAnnotationRangeObj(paraId, rangeId);
- Asc.Editor.callMethod("RemoveAnnotationRange", [annotRange]);
- }
-};
diff --git a/sdkjs-plugins/content/ai/scripts/custom-annotations/custom-annotator.js b/sdkjs-plugins/content/ai/scripts/custom-annotations/custom-annotator.js
index f8509aae..8bbf0d97 100644
--- a/sdkjs-plugins/content/ai/scripts/custom-annotations/custom-annotator.js
+++ b/sdkjs-plugins/content/ai/scripts/custom-annotations/custom-annotator.js
@@ -32,210 +32,44 @@
///
-/** @param {localStorageCustomAssistantItem} assistantData */
-function CustomAnnotator(assistantData)
+function CustomAnnotator(annotationPopup, assistantData)
{
- this.paragraphs = {};
- /** @type {Object.} */
- this.waitParagraphs = {};
- this.paraToCheck = new Set();
- this.checked = new Set(); // was checked on the previous request
-
- this.type = assistantData.type; // 2
- this.assistantData = assistantData;
+ TextAnnotator.call(this, annotationPopup);
+ this.assistantData = assistantData;
+ this.type = assistantData.type;
}
+CustomAnnotator.prototype = Object.create(TextAnnotator.prototype);
+CustomAnnotator.prototype.constructor = CustomAnnotator;
+
/**
* @param {string} paraId
- * @param {number} recalcId
- * @param {string} text
- * @param {string[]} ranges
+ * @param {string} rangeId
*/
-CustomAnnotator.prototype.onChangeParagraph = async function(paraId, recalcId, text, ranges)
-{
- this._handleNewRanges(ranges, paraId, text);
- this.waitParagraphs[paraId] = {
- recalcId : recalcId,
- text : text
- };
-
- this._checkParagraph(paraId);
-};
-/**
- * @param {string} paraId
- * @param {string[]} ranges
- */
-CustomAnnotator.prototype.onClick = function(paraId, ranges)
-{
- if (!ranges || !ranges.length)
- this._closePopup();
- else
- this._openPopup(paraId, ranges[0]);
-};
-CustomAnnotator.prototype.onBlur = function()
-{
- this._closePopup();
-};
-/**
- * @param {string[]} paraIds
- */
-CustomAnnotator.prototype.checkParagraphs = async function(paraIds)
-{
- this.paraToCheck.clear()
- paraIds.forEach(function(paraId) {
- if (!this.checked.has(paraId) || this.waitParagraphs[paraId]) {
- this.paraToCheck.add(paraId);
- this._checkParagraph(paraId);
- }
- }, this);
-};
-CustomAnnotator.prototype._checkParagraph = async function(paraId)
-{
- if (!this.paraToCheck.has(paraId) || !this.waitParagraphs[paraId]) {
- return;
- }
-
- let recalcId = this.waitParagraphs[paraId].recalcId;
- let text = this.waitParagraphs[paraId].text;
-
- // TODO: Temporarily for simplicity
- let range = this.getAnnotationRangeObj(paraId);
- range["rangeId"] = undefined;
- range["all"] = true;
- await Asc.Editor.callMethod("RemoveAnnotationRange", [range]);
- await this.annotateParagraph(paraId, recalcId, text);
-
- delete this.waitParagraphs[paraId];
- this.paraToCheck.delete(paraId);
-
- this.checked.add(paraId);
-};
-CustomAnnotator.prototype.annotateParagraph = async function(paraId, recalcId, text)
-{
-};
-CustomAnnotator.prototype._openPopup = async function(paraId, rangeId)
-{
- if (!customAnnotationPopup)
- return;
-
- /** @type {InfoForPopup} */
- const popupInfo = this.getInfoForPopup(paraId, rangeId);
-
- let popup = customAnnotationPopup.open(this.type, paraId, rangeId, popupInfo);
- if (!popup)
- return;
-
- let _t = this;
- popup.onAccept = async function() {
- await _t.onAccept(paraId, rangeId);
- _t._closePopup();
- };
- popup.onReject = async function() {
- await _t.onReject(paraId, rangeId);
- _t._closePopup();
- };
-};
-CustomAnnotator.prototype._closePopup = function()
-{
- if (!customAnnotationPopup)
- return;
-
- customAnnotationPopup.close(this.type);
-};
-CustomAnnotator.prototype.getInfoForPopup = function(paraId, rangeId)
-{
- return {};
-};
-CustomAnnotator.prototype.onAccept = async function(paraId, rangeId)
-{
-};
-CustomAnnotator.prototype.onReject = async function(paraId, rangeId)
-{
- let range = this.getAnnotationRangeObj(paraId, rangeId);
- await Asc.Editor.callMethod("RemoveAnnotationRange", [range]);
-};
-CustomAnnotator.prototype.getAnnotation = function(paraId, rangeId)
-{
- if (!paraId || !rangeId || !this.paragraphs[paraId] || !this.paragraphs[paraId][rangeId])
- return {};
-
- return this.paragraphs[paraId][rangeId];
-};
CustomAnnotator.prototype.getAnnotationRangeObj = function(paraId, rangeId)
{
return {
"paragraphId" : paraId,
- "rangeId" : rangeId
+ "rangeId" : rangeId,
+ "name" : "customAssistant_" + this.assistantData.id
};
};
-CustomAnnotator.prototype._handleNewRanges = function(ranges, paraId, text)
+CustomAnnotator.prototype._handleNewRangePositions = async function(range, paraId, text)
{
- if (!ranges || !Array.isArray(ranges))
+ if (!range || range["name"] !== "customAssistant_" + this.assistantData.id || !this.paragraphs[paraId])
return;
- for (let i = 0; i < ranges.length; ++i)
- {
- this._handleNewRangePositions(ranges[i], paraId, text);
- }
-};
-CustomAnnotator.prototype._handleNewRangePositions = function(range, paraId, text)
-{
-};
-CustomAnnotator.prototype.chatRequest = async function(prompt)
-{
- let requestEngine = AI.Request.create(AI.ActionType.Chat);
- if (!requestEngine)
- return null;
+ let rangeId = range["id"];
+ let annot = this.getAnnotation(paraId, rangeId);
- let response = await requestEngine.chatRequest(prompt, false);
- return this.normalizeResponse(response);
-};
-/**
- * Normalizes AI response by removing markdown code block wrappers
- * @param {string} response - The raw AI response that might be wrapped in ```json``` blocks
- * @returns {string} - The normalized response with markdown code blocks removed
- */
-CustomAnnotator.prototype.normalizeResponse = function(response) {
- if (typeof response !== 'string') {
- return response;
- }
+ if (!annot)
+ return;
+
+ let start = range["start"];
+ let len = range["length"];
- // Trim whitespace
- let normalized = response.trim();
-
- // Check if response is wrapped in markdown code blocks
- // Patterns: ```json\n{...}\n``` or ```\n{...}\n```
- const codeBlockPattern = /^```(?:json)?\s*\n?([\s\S]*?)\n?```$/;
- const match = normalized.match(codeBlockPattern);
-
- if (match) {
- // Extract content between code block markers
- normalized = match[1].trim();
+ if (annot["original"] !== text.substring(start, start + len))
+ {
+ let annotRange = this.getAnnotationRangeObj(paraId, rangeId);
+ Asc.Editor.callMethod("RemoveAnnotationRange", [annotRange]);
}
-
- return normalized;
-};
-/**
- * @param {string} str
- * @param {string} searchStr
- * @param {string} [fromIndex]
- * @returns {number}
- */
-CustomAnnotator.prototype.simpleGraphemeIndexOf = function(str, searchStr, fromIndex = 0) {
- const codeUnitIndex = str.indexOf(searchStr, fromIndex);
- if (codeUnitIndex < 2) {
- return codeUnitIndex;
- }
- const adjustedIndex = adjustIndexForSurrogates(str, codeUnitIndex);
-
- function adjustIndexForSurrogates(str, codeUnitIndex) {
- let surrogateCount = 0;
- for (let i = 0; i < codeUnitIndex; i++) {
- const code = str.charCodeAt(i);
- if (code >= 0xD800 && code <= 0xDBFF) {
- surrogateCount++;
- }
- }
- return codeUnitIndex - surrogateCount;
- }
- return adjustedIndex;
-}
+};
\ No newline at end of file
diff --git a/sdkjs-plugins/content/ai/scripts/custom-annotations/manager.js b/sdkjs-plugins/content/ai/scripts/custom-annotations/manager.js
index 2711ee1f..15cd9711 100644
--- a/sdkjs-plugins/content/ai/scripts/custom-annotations/manager.js
+++ b/sdkjs-plugins/content/ai/scripts/custom-annotations/manager.js
@@ -36,11 +36,13 @@
///
///
///
+///
+///
class CustomAssistantManager {
constructor() {
/**
- * @type {Map}
+ * @type {Map}
*/
this._customAssistants = new Map();
this._isCustomAssistantInit = new Map();
@@ -62,13 +64,13 @@ class CustomAssistantManager {
}
switch (assistantData.type) {
case 0:
- assistant = new AssistantHint(assistantData);
+ assistant = new AssistantHint(customAnnotationPopup, assistantData);
break;
case 1:
- assistant = new AssistantReplaceHint(assistantData);
+ assistant = new AssistantReplaceHint(customAnnotationPopup, assistantData);
break;
case 2:
- assistant = new AssistantReplace(assistantData);
+ assistant = new AssistantReplace(customAnnotationPopup, assistantData);
break;
default:
throw new Error(