ابنِ أول إضافة كروم مدعومة بالذكاء الاصطناعي باستخدام Manifest V3 و OpenAI

إضافات كروم من أقوى الأدوات التي يمكنك بناؤها كمطوّر ويب. تعمل مباشرة داخل المتصفح — المكان الذي يقضي فيه المستخدمون معظم وقتهم — وعندما تُضيف إليها الذكاء الاصطناعي، تتحوّل إلى أدوات بالغة القوة.
في هذا الدرس، سنبني SummarizeAI — إضافة كروم تستطيع:
- تلخيص أي صفحة ويب بنقرة واحدة
- تحديد نص والحصول على شرح بالذكاء الاصطناعي
- حفظ الملخصات محلياً للرجوع إليها لاحقاً
- تعمل بالكامل مع Manifest V3 (المعيار الحالي)
لماذا Manifest V3؟ أوقفت Google دعم Manifest V2 نهائياً منذ 2025. جميع الإضافات الجديدة يجب أن تستخدم Manifest V3، الذي يستبدل صفحات الخلفية بـ Service Workers ويفرض سياسات أمان أكثر صرامة.
المتطلبات الأساسية
قبل البدء، تأكد من توفر التالي:
- متصفح Google Chrome (الإصدار 120 أو أحدث)
- Node.js (الإصدار 18 أو أحدث) — للتحزيم فقط، ليس مطلوباً وقت التشغيل
- مفتاح OpenAI API — احصل عليه من هنا
- معرفة أساسية بـ JavaScript و HTML و CSS
- محرر أكواد (يُنصح بـ VS Code)
هيكل المشروع
هذه البنية التي سنعمل عليها:
summarize-ai/
├── manifest.json # ملف الإعدادات الرئيسي (V3)
├── background.js # Service Worker
├── content.js # سكريبت المحتوى (يُحقن في الصفحات)
├── popup/
│ ├── popup.html # واجهة النافذة المنبثقة
│ ├── popup.css # تنسيقات النافذة
│ └── popup.js # منطق النافذة
├── options/
│ ├── options.html # صفحة الإعدادات
│ └── options.js # منطق الإعدادات
├── lib/
│ └── ai-client.js # غلاف واجهة OpenAI
├── icons/
│ ├── icon-16.png
│ ├── icon-48.png
│ └── icon-128.png
└── README.md
الخطوة 1: إنشاء ملف Manifest
ملف الـ Manifest هو قلب أي إضافة كروم. أنشئ ملف manifest.json:
{
"manifest_version": 3,
"name": "SummarizeAI",
"version": "1.0.0",
"description": "ملخّص صفحات وشارح نصوص مدعوم بالذكاء الاصطناعي",
"permissions": [
"activeTab",
"storage",
"contextMenus",
"scripting"
],
"host_permissions": [
"https://api.openai.com/*"
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_popup": "popup/popup.html",
"default_icon": {
"16": "icons/icon-16.png",
"48": "icons/icon-48.png",
"128": "icons/icon-128.png"
}
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"],
"css": []
}
],
"options_page": "options/options.html",
"icons": {
"16": "icons/icon-16.png",
"48": "icons/icon-48.png",
"128": "icons/icon-128.png"
}
}الفروقات الأساسية في Manifest V3
| الخاصية | Manifest V2 | Manifest V3 |
|---|---|---|
| الخلفية | صفحة دائمة | Service Worker |
| طلبات الشبكة | webRequest مع حظر | declarativeNetRequest |
| كود خارجي | مسموح | ممنوع |
| سياسة الأمان | مرنة | صارمة |
في Manifest V3، لا يمكنك تحميل سكريبتات من مصادر خارجية. كل الكود يجب أن يكون مُضمّناً مع الإضافة. هذا يعني لا روابط CDN — كل شيء يُشحن محلياً.
الخطوة 2: بناء عميل الذكاء الاصطناعي
أنشئ ملف lib/ai-client.js — هذا الغلاف يتعامل مع واجهة OpenAI:
// lib/ai-client.js
const DEFAULT_MODEL = "gpt-4o-mini";
class AIClient {
constructor(apiKey, model = DEFAULT_MODEL) {
this.apiKey = apiKey;
this.model = model;
this.baseUrl = "https://api.openai.com/v1/chat/completions";
}
async complete(systemPrompt, userMessage, options = {}) {
const { maxTokens = 1000, temperature = 0.3 } = options;
const response = await fetch(this.baseUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${this.apiKey}`,
},
body: JSON.stringify({
model: this.model,
messages: [
{ role: "system", content: systemPrompt },
{ role: "user", content: userMessage },
],
max_tokens: maxTokens,
temperature,
}),
});
if (!response.ok) {
const error = await response.json();
throw new Error(
`خطأ OpenAI API: ${error.error?.message || response.statusText}`
);
}
const data = await response.json();
return data.choices[0].message.content;
}
async summarize(text) {
return this.complete(
"أنت ملخّص محترف. قدّم ملخصاً واضحاً ومنظّماً للنص. استخدم نقاطاً للأفكار الرئيسية. لا تتجاوز 200 كلمة.",
`لخّص النص التالي:\n\n${text}`
);
}
async explain(text) {
return this.complete(
"أنت شارح متميّز. اشرح النص المُعطى بعبارات بسيطة وواضحة. إذا كان تقنياً، بسّطه للقارئ العام.",
`اشرح هذا:\n\n${text}`,
{ maxTokens: 500 }
);
}
}
if (typeof globalThis !== "undefined") {
globalThis.AIClient = AIClient;
}نستخدم gpt-4o-mini افتراضياً لأنه سريع، رخيص، وكافٍ لمهام التلخيص. يمكن للمستخدم التبديل إلى gpt-4o من الإعدادات للحصول على جودة أعلى.
الخطوة 3: إعداد Service Worker (سكريبت الخلفية)
الـ Service Worker يدير قوائم السياق، تمرير الرسائل، والتنسيق بين الأجزاء:
// background.js
importScripts("lib/ai-client.js");
// إنشاء قائمة السياق عند التثبيت
chrome.runtime.onInstalled.addListener(() => {
chrome.contextMenus.create({
id: "explain-selection",
title: "اشرح بالذكاء الاصطناعي",
contexts: ["selection"],
});
chrome.contextMenus.create({
id: "summarize-page",
title: "لخّص هذه الصفحة",
contexts: ["page"],
});
chrome.storage.sync.get(["apiKey", "model"], (result) => {
if (!result.model) {
chrome.storage.sync.set({ model: "gpt-4o-mini" });
}
});
});
// معالجة نقرات قائمة السياق
chrome.contextMenus.onClicked.addListener(async (info, tab) => {
const { apiKey, model } = await chrome.storage.sync.get([
"apiKey",
"model",
]);
if (!apiKey) {
chrome.notifications.create({
type: "basic",
iconUrl: "icons/icon-48.png",
title: "SummarizeAI",
message: "الرجاء إدخال مفتاح OpenAI API في إعدادات الإضافة.",
});
return;
}
const client = new AIClient(apiKey, model);
if (info.menuItemId === "explain-selection" && info.selectionText) {
try {
const explanation = await client.explain(info.selectionText);
chrome.tabs.sendMessage(tab.id, {
type: "SHOW_RESULT",
title: "شرح الذكاء الاصطناعي",
content: explanation,
});
} catch (error) {
chrome.tabs.sendMessage(tab.id, {
type: "SHOW_ERROR",
message: error.message,
});
}
}
if (info.menuItemId === "summarize-page") {
chrome.scripting.executeScript(
{
target: { tabId: tab.id },
func: () => document.body.innerText,
},
async (results) => {
if (results && results[0]) {
const pageText = results[0].result.substring(0, 10000);
try {
const summary = await client.summarize(pageText);
chrome.tabs.sendMessage(tab.id, {
type: "SHOW_RESULT",
title: "ملخص الصفحة",
content: summary,
});
} catch (error) {
chrome.tabs.sendMessage(tab.id, {
type: "SHOW_ERROR",
message: error.message,
});
}
}
}
);
}
});
// معالجة الرسائل من النافذة المنبثقة
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.type === "SUMMARIZE_TAB") {
handleSummarizeTab(message.tabId).then(sendResponse);
return true;
}
if (message.type === "GET_HISTORY") {
chrome.storage.local.get(["history"], (result) => {
sendResponse(result.history || []);
});
return true;
}
});
async function handleSummarizeTab(tabId) {
const { apiKey, model } = await chrome.storage.sync.get([
"apiKey",
"model",
]);
if (!apiKey) return { error: "مفتاح API غير مُعيّن" };
const results = await chrome.scripting.executeScript({
target: { tabId },
func: () => ({
text: document.body.innerText,
title: document.title,
url: window.location.href,
}),
});
if (!results || !results[0]) return { error: "تعذّرت قراءة الصفحة" };
const { text, title, url } = results[0].result;
const client = new AIClient(apiKey, model);
try {
const summary = await client.summarize(text.substring(0, 10000));
const { history = [] } = await chrome.storage.local.get(["history"]);
history.unshift({
title,
url,
summary,
timestamp: Date.now(),
});
await chrome.storage.local.set({
history: history.slice(0, 50),
});
return { summary, title };
} catch (error) {
return { error: error.message };
}
}الـ Service Workers في Manifest V3 ليست دائمة. قد يتم إيقافها بعد 30 ثانية من عدم النشاط. لا تخزّن حالة في متغيّرات — استخدم دائماً chrome.storage.
الخطوة 4: بناء سكريبت المحتوى
سكريبت المحتوى يحقن لوحة نتائج عائمة في صفحات الويب:
// content.js
(function () {
let resultPanel = null;
function createPanel() {
if (resultPanel) return resultPanel;
resultPanel = document.createElement("div");
resultPanel.id = "summarize-ai-panel";
resultPanel.innerHTML = `
<div class="sai-header">
<span class="sai-title">SummarizeAI</span>
<button class="sai-close">×</button>
</div>
<div class="sai-body">
<div class="sai-loading" style="display:none">
<div class="sai-spinner"></div>
<span>جارٍ التحليل...</span>
</div>
<div class="sai-content"></div>
</div>
`;
const style = document.createElement("style");
style.textContent = `
#summarize-ai-panel {
position: fixed;
bottom: 20px;
left: 20px;
width: 380px;
max-height: 500px;
background: #1a1a2e;
color: #eee;
border-radius: 12px;
box-shadow: 0 8px 32px rgba(0,0,0,0.3);
z-index: 999999;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
font-size: 14px;
overflow: hidden;
direction: rtl;
animation: sai-slide-in 0.3s ease-out;
}
@keyframes sai-slide-in {
from { transform: translateY(20px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
.sai-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 16px;
background: #16213e;
border-bottom: 1px solid #0f3460;
}
.sai-title { font-weight: 600; color: #e94560; }
.sai-close {
background: none; border: none; color: #888;
font-size: 20px; cursor: pointer; padding: 0 4px;
}
.sai-close:hover { color: #fff; }
.sai-body {
padding: 16px; max-height: 400px;
overflow-y: auto; line-height: 1.8;
}
.sai-content ul { padding-right: 20px; }
.sai-content li { margin-bottom: 6px; }
.sai-spinner {
width: 20px; height: 20px;
border: 2px solid #333; border-top: 2px solid #e94560;
border-radius: 50%;
animation: sai-spin 0.8s linear infinite;
display: inline-block; margin-left: 8px;
vertical-align: middle;
}
@keyframes sai-spin { to { transform: rotate(360deg); } }
.sai-loading { display: flex; align-items: center; color: #888; }
.sai-error {
color: #e94560; padding: 8px;
background: rgba(233,69,96,0.1); border-radius: 6px;
}
`;
document.head.appendChild(style);
document.body.appendChild(resultPanel);
resultPanel.querySelector(".sai-close").addEventListener("click", () => {
resultPanel.style.display = "none";
});
return resultPanel;
}
function showLoading() {
const panel = createPanel();
panel.style.display = "block";
panel.querySelector(".sai-loading").style.display = "flex";
panel.querySelector(".sai-content").innerHTML = "";
}
function showResult(title, content) {
const panel = createPanel();
panel.style.display = "block";
panel.querySelector(".sai-loading").style.display = "none";
panel.querySelector(".sai-title").textContent = title;
const formatted = content
.replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>")
.replace(/^- (.*)/gm, "<li>$1</li>")
.replace(/(<li>.*<\/li>)/s, "<ul>$1</ul>")
.replace(/\n/g, "<br>");
panel.querySelector(".sai-content").innerHTML = formatted;
}
function showError(message) {
const panel = createPanel();
panel.style.display = "block";
panel.querySelector(".sai-loading").style.display = "none";
panel.querySelector(".sai-content").innerHTML = `
<div class="sai-error">⚠️ ${message}</div>
`;
}
chrome.runtime.onMessage.addListener((message) => {
if (message.type === "SHOW_RESULT") {
showResult(message.title, message.content);
}
if (message.type === "SHOW_ERROR") {
showError(message.message);
}
if (message.type === "SHOW_LOADING") {
showLoading();
}
});
})();الخطوة 5: بناء واجهة النافذة المنبثقة
النافذة المنبثقة هي ما يراه المستخدم عند النقر على أيقونة الإضافة.
<!-- popup/popup.html -->
<!DOCTYPE html>
<html dir="rtl" lang="ar">
<head>
<meta charset="UTF-8" />
<link rel="stylesheet" href="popup.css" />
</head>
<body>
<div class="container">
<header>
<h1>🤖 SummarizeAI</h1>
</header>
<div id="no-key-warning" class="warning" style="display: none">
<p>⚠️ مفتاح API غير مُعيّن.</p>
<a href="#" id="open-settings">فتح الإعدادات</a>
</div>
<div id="main-content">
<button id="summarize-btn" class="primary-btn">
✨ لخّص هذه الصفحة
</button>
<div id="result" style="display: none">
<h3 id="result-title"></h3>
<div id="result-content"></div>
</div>
<div id="loading" style="display: none">
<div class="spinner"></div>
<span>جارٍ تحليل الصفحة...</span>
</div>
<hr />
<h3>📚 الملخصات الأخيرة</h3>
<div id="history-list"></div>
</div>
</div>
<script src="popup.js"></script>
</body>
</html>// popup/popup.js
document.addEventListener("DOMContentLoaded", async () => {
const summarizeBtn = document.getElementById("summarize-btn");
const resultDiv = document.getElementById("result");
const resultTitle = document.getElementById("result-title");
const resultContent = document.getElementById("result-content");
const loadingDiv = document.getElementById("loading");
const historyList = document.getElementById("history-list");
const noKeyWarning = document.getElementById("no-key-warning");
const { apiKey } = await chrome.storage.sync.get(["apiKey"]);
if (!apiKey) {
noKeyWarning.style.display = "block";
summarizeBtn.disabled = true;
}
document.getElementById("open-settings").addEventListener("click", (e) => {
e.preventDefault();
chrome.runtime.openOptionsPage();
});
summarizeBtn.addEventListener("click", async () => {
const [tab] = await chrome.tabs.query({
active: true,
currentWindow: true,
});
summarizeBtn.disabled = true;
loadingDiv.style.display = "block";
resultDiv.style.display = "none";
chrome.runtime.sendMessage(
{ type: "SUMMARIZE_TAB", tabId: tab.id },
(response) => {
loadingDiv.style.display = "none";
summarizeBtn.disabled = false;
if (response.error) {
resultTitle.textContent = "خطأ";
resultContent.textContent = response.error;
} else {
resultTitle.textContent = response.title;
resultContent.innerHTML = formatContent(response.summary);
}
resultDiv.style.display = "block";
loadHistory();
}
);
});
async function loadHistory() {
chrome.runtime.sendMessage({ type: "GET_HISTORY" }, (history) => {
historyList.innerHTML = history
.slice(0, 10)
.map(
(item) => `
<div class="history-item" data-url="${item.url}">
<div class="title">${item.title}</div>
<div class="date">${new Date(item.timestamp).toLocaleDateString("ar")}</div>
</div>
`
)
.join("");
historyList.querySelectorAll(".history-item").forEach((el) => {
el.addEventListener("click", () => {
chrome.tabs.create({ url: el.dataset.url });
});
});
});
}
loadHistory();
});
function formatContent(text) {
return text
.replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>")
.replace(/^- (.*)/gm, "<li>$1</li>")
.replace(/\n/g, "<br>");
}الخطوة 6: بناء صفحة الإعدادات
<!-- options/options.html -->
<!DOCTYPE html>
<html dir="rtl" lang="ar">
<head>
<meta charset="UTF-8" />
<title>إعدادات SummarizeAI</title>
<style>
body {
font-family: -apple-system, sans-serif;
max-width: 500px;
margin: 40px auto;
padding: 20px;
background: #0f0f23;
color: #eee;
}
h1 { color: #e94560; }
label { display: block; margin-top: 16px; font-weight: 600; }
input, select {
width: 100%;
padding: 10px;
margin-top: 6px;
background: #1a1a2e;
border: 1px solid #333;
border-radius: 6px;
color: #eee;
font-size: 14px;
}
button {
margin-top: 20px;
padding: 10px 24px;
background: #e94560;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
}
.saved {
color: #4ecca3;
margin-right: 12px;
display: none;
}
</style>
</head>
<body>
<h1>⚙️ إعدادات SummarizeAI</h1>
<label for="apiKey">مفتاح OpenAI API</label>
<input type="password" id="apiKey" placeholder="sk-..." />
<label for="model">النموذج</label>
<select id="model">
<option value="gpt-4o-mini">GPT-4o Mini (سريع واقتصادي)</option>
<option value="gpt-4o">GPT-4o (جودة أعلى)</option>
<option value="gpt-4.1-nano">GPT-4.1 Nano (فائق السرعة)</option>
</select>
<button id="save">حفظ الإعدادات</button>
<span class="saved" id="saved-msg">✓ تم الحفظ!</span>
<script src="options.js"></script>
</body>
</html>// options/options.js
document.addEventListener("DOMContentLoaded", async () => {
const apiKeyInput = document.getElementById("apiKey");
const modelSelect = document.getElementById("model");
const saveBtn = document.getElementById("save");
const savedMsg = document.getElementById("saved-msg");
const { apiKey, model } = await chrome.storage.sync.get([
"apiKey",
"model",
]);
if (apiKey) apiKeyInput.value = apiKey;
if (model) modelSelect.value = model;
saveBtn.addEventListener("click", () => {
chrome.storage.sync.set(
{
apiKey: apiKeyInput.value.trim(),
model: modelSelect.value,
},
() => {
savedMsg.style.display = "inline";
setTimeout(() => (savedMsg.style.display = "none"), 2000);
}
);
});
});الخطوة 7: تحميل واختبار الإضافة
لنُحمّل الإضافة في كروم:
- افتح كروم واذهب إلى
chrome://extensions/ - فعّل "وضع المطوّر" من الزر في أعلى اليمين
- انقر "تحميل غير مُحزّم" واختر مجلد
summarize-ai/ - ستظهر أيقونة الإضافة في شريط الأدوات
تسلسل الاختبار
- إعداد مفتاح API: انقر على الإضافة ← لاحظ التحذير ← انقر "فتح الإعدادات" ← أدخل المفتاح ← احفظ
- تلخيص صفحة: اذهب لأي مقال ← انقر الإضافة ← انقر "لخّص هذه الصفحة"
- شرح نص: حدد أي نص في صفحة ← انقر يمين ← "اشرح بالذكاء الاصطناعي"
- مراجعة السجل: افتح النافذة المنبثقة — ملخصاتك الأخيرة تظهر في الأسفل
لتصحيح الأخطاء، افتح chrome://extensions/، جد SummarizeAI، وانقر "Service Worker" لفحص سكريبت الخلفية. انقر يمين على النافذة المنبثقة واختر "فحص" لتصحيحها.
الخطوة 8: إضافة اختصارات لوحة المفاتيح
اجعل الإضافة أسرع باختصارات. أضف إلى manifest.json:
{
"commands": {
"summarize-page": {
"suggested_key": {
"default": "Alt+S",
"mac": "Alt+S"
},
"description": "تلخيص الصفحة الحالية"
},
"_execute_action": {
"suggested_key": {
"default": "Alt+A",
"mac": "Alt+A"
},
"description": "فتح نافذة SummarizeAI"
}
}
}معالجة الأمر في background.js:
chrome.commands.onCommand.addListener(async (command) => {
if (command === "summarize-page") {
const [tab] = await chrome.tabs.query({
active: true,
currentWindow: true,
});
const result = await handleSummarizeTab(tab.id);
if (result.summary) {
chrome.tabs.sendMessage(tab.id, {
type: "SHOW_RESULT",
title: "ملخص الصفحة",
content: result.summary,
});
}
}
});الخطوة 9: التعامل مع الحالات الاستثنائية
الإضافات الحقيقية تحتاج للتعامل مع الأخطاء بذكاء:
// أضف إلى background.js
// تحديد معدل الطلبات
const rateLimiter = {
lastCall: 0,
minInterval: 2000,
canProceed() {
const now = Date.now();
if (now - this.lastCall < this.minInterval) {
return false;
}
this.lastCall = now;
return true;
},
};
// تغليف استدعاءات API
async function safeApiCall(fn) {
if (!rateLimiter.canProceed()) {
return { error: "انتظر لحظة قبل المحاولة مرة أخرى." };
}
try {
return await fn();
} catch (error) {
if (error.message.includes("429")) {
return { error: "تم الوصول لحد الطلبات. انتظر دقيقة." };
}
if (error.message.includes("401")) {
return { error: "مفتاح API غير صالح. تحقق من الإعدادات." };
}
return { error: `خطأ غير متوقع: ${error.message}` };
}
}الخطوة 10: التحضير لمتجر كروم
عندما تكون جاهزاً للنشر:
1. إعداد الأيقونات
ستحتاج أيقونات بأحجام 16×16 و 48×48 و 128×128 بكسل بصيغة PNG. استخدم أداة مثل Figma أو حتى مولّد صور بالذكاء الاصطناعي.
2. إنشاء ملف ZIP
zip -r summarize-ai.zip summarize-ai/ \
-x "*.DS_Store" \
-x "*node_modules*" \
-x "*.git*"3. الإرسال لمتجر كروم
- اذهب إلى لوحة تحكم مطوري Chrome Web Store
- ادفع رسوم التسجيل لمرة واحدة (5 دولار)
- انقر "عنصر جديد" وارفع ملف ZIP
- املأ بيانات القائمة: الوصف، لقطات الشاشة، التصنيف
- أرسل للمراجعة (عادة 1-3 أيام عمل)
سياسة الخصوصية مطلوبة: إذا كانت إضافتك ترسل بيانات لواجهات خارجية (مثل OpenAI)، يجب عليك توفير رابط سياسة خصوصية. هذا مُلزَم من Chrome Web Store.
تطوير الإضافة
إليك أفكاراً لتوسيع SummarizeAI:
- دعم اللغات المتعددة: اكتشاف لغة الصفحة وتلخيصها بلغة المستخدم المفضلة
- أوامر مخصصة: السماح للمستخدمين بتعريف أوامرهم الخاصة للتلخيص المتخصص
- دعم PDF: استخدام
pdf.jsلاستخراج النص من ملفات PDF - التصدير: حفظ الملخصات كـ Markdown أو إرسالها إلى Notion
- البث المباشر: استخدام واجهة البث من OpenAI لعرض الاستجابة في الوقت الحقيقي
- ذكاء اصطناعي محلي: الدمج مع Ollama للتلخيص بدون إنترنت
الخلاصة
في هذا الدرس، بنينا إضافة كروم كاملة مدعومة بالذكاء الاصطناعي باستخدام Manifest V3. إليك ما غطيناه:
- ✅ هيكل Manifest V3 والفروقات الأساسية عن V2
- ✅ Service Workers للمعالجة في الخلفية
- ✅ سكريبتات المحتوى لحقن واجهات في صفحات الويب
- ✅ دمج واجهة OpenAI للتلخيص والشرح
- ✅ واجهة النافذة المنبثقة مع تتبع السجل
- ✅ قوائم السياق واختصارات لوحة المفاتيح
- ✅ معالجة الأخطاء وتحديد معدل الطلبات
- ✅ عملية النشر على Chrome Web Store
الكود المصدري الكامل متاح على GitHub. إضافات كروم وسيلة رائعة لتوصيل الذكاء الاصطناعي مباشرة حيث يحتاجه المستخدمون — داخل متصفحهم. ابدأ البناء الآن! 🚀
ناقش مشروعك معنا
نحن هنا للمساعدة في احتياجات تطوير الويب الخاصة بك. حدد موعدًا لمناقشة مشروعك وكيف يمكننا مساعدتك.
دعنا نجد أفضل الحلول لاحتياجاتك.
مقالات ذات صلة

بناء وكيل ذكاء اصطناعي مستقل باستخدام Agentic RAG و Next.js
تعلم كيف تبني وكيل ذكاء اصطناعي يقرر بشكل مستقل متى وكيف يسترجع المعلومات من قواعد البيانات المتجهية. دليل عملي شامل باستخدام Vercel AI SDK و Next.js مع أمثلة قابلة للتنفيذ.

بناء وكلاء الذكاء الاصطناعي من الصفر باستخدام TypeScript: إتقان نمط ReAct مع Vercel AI SDK
تعلّم كيفية بناء وكلاء الذكاء الاصطناعي من الأساس باستخدام TypeScript. يغطي هذا الدليل التعليمي نمط ReAct، واستدعاء الأدوات، والاستدلال متعدد الخطوات، وحلقات الوكلاء الجاهزة للإنتاج مع Vercel AI SDK.

بناء روبوت محادثة RAG باستخدام Supabase pgvector و Next.js
تعلم بناء روبوت محادثة ذكاء اصطناعي يجيب على الأسئلة باستخدام بياناتك الخاصة. يغطي هذا الدليل تضمينات المتجهات والبحث الدلالي و RAG مع Supabase و Next.js.