كيفية تزويد إضافة الذكاء الاصطناعي لـ ONLYOFFICE بميزات مخصصة
قدمت إضافة الذكاء الاصطناعي ONLYOFFICE بنية جديدة صديقة للمطورين. إذا كنتم ترغبون في توسيع قدرات الإضافة، على سبيل المثال، لإضافة وظيفة ذكاء اصطناعي محددة، فلن تحتاجوا بعد الآن إلى تحرير ملف ضخم أحادي (monolithic).
بدلاً من ذلك، تتميز الإضافة الآن بمساحة عمل مخصصة تقع في مجلد .dev. سيوضح لكم هذا الدليل بالضبط كيفية استخدام مساحة العمل هذه لإضافة وظيفة مخصصة جديدة.
سنقوم ببناء ميزة وصف الصورة (Describe image) لمحرر المستندات كمثال لنا.

سير عمل التطوير
المفهوم الأساسي بسيط: أنتم تعملون في مجلد dev. ويقوم نص برمجي ببناء كود الإنتاج.
- .dev/helpers/: هذا هو مكان العمل الخاص بكم (sandbox). هذا هو المكان الذي تنشئون فيه الملفات الجديدة.
- helpers.js: هذا هو ملف الإنتاج الذي تقرأه الإضافة فعلياً. لا تقوموا بتحريره مباشرة. يتم إنشاؤه تلقائياً.
الخطوة 1: اختاروا نطاق المحرر الخاص بكم
داخل مجلد .dev/helpers/، ستجدون ثلاثة مجلدات تتوافق مع محررات ONLYOFFICE:
- word/ (محرر المستندات)
- cell/ (محرر جداول البيانات)
- slide/ (محرر العروض التقديمية)
نظراً لأن وظيفة وصف الصورة الخاصة بنا مخصصة للمستندات النصية، فسنعمل في مجلد .dev/helpers/word/
الخطوة 2: أنشئوا وظيفتكم الخاصة
أنشئوا ملفاً جديداً باسم describe-image.js داخل مجلد .dev/helpers/word/.
تستخدم الإضافة فئة محددة تسمى RegisteredFunction لتعريف القدرات. تخبر هذه البنية الذكاء الاصطناعي ماذا تفعل الوظيفة وكيف يتم استدعاؤها.
نصيحة: تأكدوا من أن صيغة الكود نظيفة (انتبهوا لأقواس الإغلاق المفقودة).
الكود:
(function () {
let func = new RegisteredFunction({
name: "describeImage",
description:
"Allows users to select an image and generate a meaningful title, description, caption, or alt text for it using AI.",
// Define parameters so the AI knows what to ask for
parameters: {
type: "object",
properties: {
prompt: {
type: "string",
description:
"instruction for the AI (e.g., 'Add a short title for this chart.')",
},
},
required: ["prompt"],
},
// Provide examples to train the AI on usage
examples: [
{
prompt: "Add a short title for this chart.",
arguments: { prompt: "Add a short title for this chart." },
},
{
prompt: "Write me a 1–2 sentence description of this photo.",
arguments: {
prompt: "Write me a 1–2 sentence description of this photo.",
},
},
{
prompt: "Generate a descriptive caption for this organizational chart.",
arguments: {
prompt:
"Generate a descriptive caption for this organizational chart.",
},
},
{
prompt: "Provide accessibility-friendly alt text for this infographic.",
arguments: {
prompt:
"Provide accessibility-friendly alt text for this infographic.",
},
},
],
});
// The actual logic executed inside the editor
func.call = async function (params) {
let prompt = params.prompt;
async function insertMessage(message) {
Asc.scope._message = String(message || "");
// 3. Insert the result into the document
await Asc.Editor.callCommand(function () {
const msg = Asc.scope._message || "";
const doc = Api.GetDocument();
const selected =
(doc.GetSelectedDrawings && doc.GetSelectedDrawings()) || [];
if (selected.length > 0) {
for (let i = 0; i < selected.length; i++) {
const drawing = selected[i];
const para = Api.CreateParagraph();
para.AddText(msg);
drawing.InsertParagraph(para, "after", true);
}
} else {
const para = Api.CreateParagraph();
para.AddText(msg);
let range = doc.GetCurrentParagraph();
range.InsertParagraph(para, "after", true);
}
Asc.scope._message = "";
}, true);
}
try {
// 1. Get the selected image
let imageData = await new Promise((resolve) => {
window.Asc.plugin.executeMethod(
"GetImageDataFromSelection",
[],
function (result) {
resolve(result);
}
);
});
if (!imageData || !imageData.src) {
await insertMessage("Please select a valid image first.");
return;
}
const whiteRectangleBase64 =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==";
if (imageData.src === whiteRectangleBase64) {
await insertMessage("Please select a valid image first.");
return;
}
let argPrompt = prompt + " (for the selected image)";
// 2. Send image + prompt to the AI engine
let requestEngine = AI.Request.create(AI.ActionType.Chat);
if (!requestEngine) {
await insertMessage("AI request engine not available.");
return;
}
const allowVision = /(vision|gemini|gpt-4o|gpt-4v|gpt-4-vision)/i;
if (!allowVision.test(requestEngine.modelUI.name)) {
await insertMessage(
"⚠ This model may not support images. Please choose a vision-capable model (e.g. GPT-4V, Gemini, etc.)."
);
return;
}
await Asc.Editor.callMethod("StartAction", [
"Block",
"AI (" + requestEngine.modelUI.name + ")",
]);
await Asc.Editor.callMethod("StartAction", ["GroupActions"]);
let messages = [
{
role: "user",
content: [
{ type: "text", text: argPrompt },
{
type: "image_url",
image_url: { url: imageData.src, detail: "high" },
},
],
},
];
let resultText = "";
await requestEngine.chatRequest(messages, false, async function (data) {
if (data) {
resultText += data;
}
});
await Asc.Editor.callMethod("EndAction", ["GroupActions"]);
await Asc.Editor.callMethod("EndAction", [
"Block",
"AI (" + requestEngine.modelUI.name + ")",
]);
Asc.scope.text = resultText || "";
if (!Asc.scope.text.trim()) {
await insertMessage(
"⚠ AI request failed (maybe the model cannot handle images)."
);
return;
}
await insertMessage(Asc.scope.text);
} catch (e) {
try {
await Asc.Editor.callMethod("EndAction", ["GroupActions"]);
await Asc.Editor.callMethod("EndAction", [
"Block",
"AI (describeImage)",
]);
} catch (ee) {
/* ignore */
}
console.error("describeImage error:", e);
await insertMessage(
"An unexpected error occurred while describing the image."
);
}
};
return func;
})();
الخطوة 3: تجميع التغييرات الخاصة بكم
هذه هي أهم خطوة في سير العمل الجديد. لا يمكن للإضافة قراءة ملفكم الجديد مباشرة بعد. يجب عليكم تشغيل النص البرمجي المساعد لدمج ملفكم الجديد في منطق الإضافة الرئيسي.
- افتحوا طرفيتكم (terminal).
- انتقلوا إلى دليل المساعدين:
cd .dev/helpers
3. شغلوا نص بناء بايثون (Python build script):
python3 helpers.py
سيقوم النص البرمجي helpers.py بمسح مجلدات word/ وcell/ وslide/، والعثور على ملفكم الجديد describe-image.js، ودمجه في ملف helpers.js الرئيسي.
الخطوة 4: اختبار الميزة الخاصة بكم
- أعيدوا تحميل الإضافة في ONLYOFFICE.
- حددوا صورة في مستندكم.
- اسألوا الذكاء الاصطناعي: “صف هذه الصورة” أو “اكتب عنواناً لهذه الصورة.”
سيتعرف الذكاء الاصطناعي الآن على وظيفتكم المخصصة الجديدة وسيقوم بتنفيذ المنطق الذي كتبتموه للتو.
ONLYOFFICE ١. أنشئ حسابك المجاني من
،٢. قم بعرض و تحرير أو التعاون على المستندات، الجداول ، العروض التقديمية


