بناء تطبيقات الذكاء الاصطناعي باستخدام Google Gemini API و TypeScript

AI Bot
بواسطة AI Bot ·

جاري تحميل مشغل تحويل النص إلى كلام الصوتي...

وصل Google Gemini 2.5 Pro. مع نافذة سياق تتسع لمليون رمز، وقدرات متعددة الوسائط أصلية، واستدعاء دوال مدمج، يُعد Gemini واحداً من أقوى واجهات برمجة تطبيقات الذكاء الاصطناعي المتاحة اليوم. في هذا الدليل، ستتعلم كيفية تسخير إمكاناته الكاملة باستخدام TypeScript.

ما ستتعلمه

بنهاية هذا الدليل، ستكون قادراً على:

  • إعداد حزمة Google Generative AI SDK في مشروع TypeScript
  • توليد النصوص باستخدام Gemini 2.5 Pro و Gemini 2.5 Flash
  • معالجة الصور وملفات PDF والصوت عبر المدخلات متعددة الوسائط
  • تنفيذ البث المباشر للاستجابات في الوقت الحقيقي
  • استخدام استدعاء الدوال لربط Gemini بأدوات خارجية
  • استخراج بيانات منظمة باستخدام مخطط JSON
  • بناء مساعد ذكاء اصطناعي عملي مع سجل المحادثات

المتطلبات الأساسية

قبل البدء، تأكد من توفر:

  • Node.js 20+ مثبت على جهازك (node --version)
  • معرفة بـ TypeScript (الأنواع، async/await، الوحدات)
  • مفتاح API من Google AI Studio — احصل عليه مجاناً من aistudio.google.com
  • محرر أكواد — يُنصح باستخدام VS Code أو Cursor
  • فهم أساسي لواجهات REST APIs والبرمجة غير المتزامنة

الخطوة 1: إعداد المشروع

أنشئ مشروع TypeScript جديد وثبّت حزمة Google Generative AI SDK:

mkdir gemini-ai-app && cd gemini-ai-app
npm init -y
npm install @google/generative-ai
npm install -D typescript @types/node tsx

هيّئ TypeScript:

npx tsc --init --target ES2022 --module NodeNext --moduleResolution NodeNext --outDir dist --rootDir src --strict

أنشئ هيكل المشروع:

mkdir src
touch src/index.ts .env

أضف مفتاح API في ملف .env:

GEMINI_API_KEY=your_api_key_here

حدّث سكربتات package.json:

{
  "scripts": {
    "dev": "tsx watch src/index.ts",
    "build": "tsc",
    "start": "node dist/index.js"
  }
}

الخطوة 2: أول عملية توليد نص

لنبدأ بمثال بسيط لتوليد النصوص. أنشئ ملف src/index.ts:

import { GoogleGenerativeAI } from "@google/generative-ai";
 
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY!);
 
async function generateText() {
  const model = genAI.getGenerativeModel({
    model: "gemini-2.5-pro",
  });
 
  const result = await model.generateContent(
    "اشرح الحوسبة الكمومية في 3 جمل لمطور برمجيات."
  );
 
  console.log(result.response.text());
}
 
generateText();

شغّل الكود:

GEMINI_API_KEY=your_key tsx src/index.ts

ستحصل على شرح موجز للحوسبة الكمومية. دالة generateContent ترسل طلباً واحداً وتعيد الاستجابة الكاملة.

فهم كائن الاستجابة

الاستجابة تحتوي على أكثر من مجرد نص:

async function inspectResponse() {
  const model = genAI.getGenerativeModel({ model: "gemini-2.5-pro" });
 
  const result = await model.generateContent("مرحباً يا Gemini!");
  const response = result.response;
 
  console.log("النص:", response.text());
  console.log("الاستخدام:", response.usageMetadata);
  // { promptTokenCount: 4, candidatesTokenCount: 12, totalTokenCount: 16 }
}

حقل usageMetadata يساعدك في تتبع استهلاك الرموز لإدارة التكاليف.


الخطوة 3: اختيار النموذج المناسب

يوفر Gemini عدة نماذج محسّنة لحالات استخدام مختلفة:

النموذجالأفضل لـنافذة السياقالسرعة
gemini-2.5-proالاستدلال المعقد، البرمجة، التحليلمليون رمزمتوسطة
gemini-2.5-flashالاستجابات السريعة، الإنتاجية العاليةمليون رمزسريعة
gemini-2.5-flash-liteالكفاءة في التكلفة، المهام البسيطةمليون رمزالأسرع
// للتحليل المعقد
const pro = genAI.getGenerativeModel({ model: "gemini-2.5-pro" });
 
// للتطبيقات التي تحتاج سرعة
const flash = genAI.getGenerativeModel({ model: "gemini-2.5-flash" });
 
// للمهام البسيطة بحجم كبير
const lite = genAI.getGenerativeModel({ model: "gemini-2.5-flash-lite" });

نصيحة: ابدأ بـ gemini-2.5-flash أثناء التطوير. انتقل إلى pro فقط عندما تحتاج قدراته المعززة في الاستدلال. Flash أرخص بكثير وأسرع.


الخطوة 4: المدخلات متعددة الوسائط — الصور وملفات PDF

من أقوى ميزات Gemini هي الفهم الأصلي للوسائط المتعددة. يمكنك إرسال صور وملفات PDF وصوت وفيديو مع النص.

تحليل صورة

import { GoogleGenerativeAI } from "@google/generative-ai";
import * as fs from "fs";
import * as path from "path";
 
async function analyzeImage(imagePath: string) {
  const model = genAI.getGenerativeModel({ model: "gemini-2.5-flash" });
 
  const imageData = fs.readFileSync(imagePath);
  const base64Image = imageData.toString("base64");
  const mimeType = imagePath.endsWith(".png") ? "image/png" : "image/jpeg";
 
  const result = await model.generateContent([
    {
      inlineData: {
        mimeType,
        data: base64Image,
      },
    },
    "صف هذه الصورة بالتفصيل. ما الأشياء والألوان والمشهد الذي تراه؟",
  ]);
 
  console.log(result.response.text());
}
 
analyzeImage("./sample-image.jpg");

معالجة مستند PDF

async function analyzePDF(pdfPath: string) {
  const model = genAI.getGenerativeModel({ model: "gemini-2.5-pro" });
 
  const pdfData = fs.readFileSync(pdfPath);
  const base64PDF = pdfData.toString("base64");
 
  const result = await model.generateContent([
    {
      inlineData: {
        mimeType: "application/pdf",
        data: base64PDF,
      },
    },
    "لخّص النقاط الرئيسية في هذا المستند. اذكر المواضيع الأساسية وأي بنود عمل.",
  ]);
 
  console.log(result.response.text());
}

مقارنة صور متعددة

async function compareImages(image1Path: string, image2Path: string) {
  const model = genAI.getGenerativeModel({ model: "gemini-2.5-flash" });
 
  const image1 = fs.readFileSync(image1Path).toString("base64");
  const image2 = fs.readFileSync(image2Path).toString("base64");
 
  const result = await model.generateContent([
    { inlineData: { mimeType: "image/jpeg", data: image1 } },
    { inlineData: { mimeType: "image/jpeg", data: image2 } },
    "قارن بين هاتين الصورتين. ما هي الاختلافات والتشابهات؟",
  ]);
 
  console.log(result.response.text());
}

الخطوة 5: بث الاستجابات

لتجربة مستخدم أفضل، يمكنك بث الاستجابات رمزاً بعد رمز بدلاً من انتظار الاستجابة الكاملة:

async function streamResponse(prompt: string) {
  const model = genAI.getGenerativeModel({ model: "gemini-2.5-flash" });
 
  const result = await model.generateContentStream(prompt);
 
  process.stdout.write("Gemini: ");
 
  for await (const chunk of result.stream) {
    const text = chunk.text();
    process.stdout.write(text);
  }
 
  console.log("\n");
 
  // الوصول للاستجابة المجمعة بعد البث
  const aggregated = await result.response;
  console.log("إجمالي الرموز:", aggregated.usageMetadata?.totalTokenCount);
}
 
streamResponse("اكتب قصيدة قصيرة عن TypeScript.");

البث المباشر في خادم ويب

إليك كيفية دمج البث مع خادم HTTP بسيط:

import { createServer } from "http";
 
const server = createServer(async (req, res) => {
  if (req.method === "POST" && req.url === "/chat") {
    const body = await getBody(req);
    const { message } = JSON.parse(body);
 
    const model = genAI.getGenerativeModel({ model: "gemini-2.5-flash" });
    const result = await model.generateContentStream(message);
 
    res.writeHead(200, {
      "Content-Type": "text/event-stream",
      "Cache-Control": "no-cache",
      Connection: "keep-alive",
    });
 
    for await (const chunk of result.stream) {
      res.write(`data: ${JSON.stringify({ text: chunk.text() })}\n\n`);
    }
 
    res.write("data: [DONE]\n\n");
    res.end();
  }
});
 
server.listen(3000, () => console.log("الخادم يعمل على المنفذ 3000"));
 
function getBody(req: any): Promise<string> {
  return new Promise((resolve) => {
    let body = "";
    req.on("data", (chunk: string) => (body += chunk));
    req.on("end", () => resolve(body));
  });
}

الخطوة 6: استدعاء الدوال

استدعاء الدوال يتيح لـ Gemini تشغيل دوال TypeScript الخاصة بك لجلب بيانات فورية، أو التفاعل مع واجهات برمجة التطبيقات، أو إجراء حسابات.

تعريف الأدوات

import {
  GoogleGenerativeAI,
  FunctionDeclarationSchemaType,
} from "@google/generative-ai";
 
const tools = [
  {
    functionDeclarations: [
      {
        name: "getWeather",
        description: "الحصول على حالة الطقس الحالية لموقع محدد",
        parameters: {
          type: FunctionDeclarationSchemaType.OBJECT,
          properties: {
            location: {
              type: FunctionDeclarationSchemaType.STRING,
              description: "اسم المدينة، مثل 'تونس' أو 'الرياض'",
            },
            unit: {
              type: FunctionDeclarationSchemaType.STRING,
              enum: ["celsius", "fahrenheit"],
              description: "وحدة الحرارة",
            },
          },
          required: ["location"],
        },
      },
      {
        name: "searchProducts",
        description: "البحث عن منتجات في الكتالوج",
        parameters: {
          type: FunctionDeclarationSchemaType.OBJECT,
          properties: {
            query: {
              type: FunctionDeclarationSchemaType.STRING,
              description: "استعلام البحث",
            },
            maxPrice: {
              type: FunctionDeclarationSchemaType.NUMBER,
              description: "فلتر السعر الأقصى",
            },
          },
          required: ["query"],
        },
      },
    ],
  },
];

معالجة استدعاءات الدوال

// تطبيقات الدوال المحاكاة
function getWeather(location: string, unit = "celsius") {
  const mockData: Record<string, { temp: number; condition: string }> = {
    tunis: { temp: 24, condition: "مشمس" },
    riyadh: { temp: 35, condition: "صافي" },
    cairo: { temp: 28, condition: "غائم جزئياً" },
  };
 
  const data = mockData[location.toLowerCase()] || {
    temp: 20,
    condition: "غير معروف",
  };
 
  return {
    location,
    temperature: data.temp,
    unit,
    condition: data.condition,
  };
}
 
function searchProducts(query: string, maxPrice?: number) {
  return {
    results: [
      { name: `${query} Pro`, price: 99.99, rating: 4.5 },
      { name: `${query} Lite`, price: 49.99, rating: 4.2 },
    ].filter((p) => !maxPrice || p.price <= maxPrice),
  };
}
 
async function chatWithTools(userMessage: string) {
  const model = genAI.getGenerativeModel({
    model: "gemini-2.5-flash",
    tools,
  });
 
  const chat = model.startChat();
  const result = await chat.sendMessage(userMessage);
 
  const response = result.response;
  const functionCalls = response.functionCalls();
 
  if (functionCalls && functionCalls.length > 0) {
    const functionResponses = functionCalls.map((call) => {
      let result;
      switch (call.name) {
        case "getWeather":
          result = getWeather(
            call.args.location as string,
            call.args.unit as string
          );
          break;
        case "searchProducts":
          result = searchProducts(
            call.args.query as string,
            call.args.maxPrice as number
          );
          break;
        default:
          result = { error: "دالة غير معروفة" };
      }
 
      return {
        functionResponse: {
          name: call.name,
          response: result,
        },
      };
    });
 
    // إرسال نتائج الدوال إلى Gemini
    const finalResult = await chat.sendMessage(functionResponses);
    console.log(finalResult.response.text());
  } else {
    console.log(response.text());
  }
}
 
chatWithTools("ما حالة الطقس في تونس وابحث لي عن خيارات لابتوب بأقل من 80 دولار؟");

سيقوم Gemini باستدعاء كلتا الدالتين بالتوازي وتجميع النتائج في استجابة بلغة طبيعية.


الخطوة 7: المخرجات المنظمة باستخدام مخطط JSON

أجبر Gemini على إرجاع البيانات بهيكل JSON محدد — مثالي لبناء خطوط بيانات موثوقة:

async function extractStructuredData(text: string) {
  const model = genAI.getGenerativeModel({
    model: "gemini-2.5-flash",
    generationConfig: {
      responseMimeType: "application/json",
      responseSchema: {
        type: FunctionDeclarationSchemaType.OBJECT,
        properties: {
          sentiment: {
            type: FunctionDeclarationSchemaType.STRING,
            enum: ["positive", "negative", "neutral"],
          },
          confidence: {
            type: FunctionDeclarationSchemaType.NUMBER,
          },
          topics: {
            type: FunctionDeclarationSchemaType.ARRAY,
            items: {
              type: FunctionDeclarationSchemaType.STRING,
            },
          },
          summary: {
            type: FunctionDeclarationSchemaType.STRING,
          },
        },
        required: ["sentiment", "confidence", "topics", "summary"],
      },
    },
  });
 
  const result = await model.generateContent(
    `حلل النص التالي:\n\n${text}`
  );
 
  const data = JSON.parse(result.response.text());
  return data;
}
 
// الاستخدام
const analysis = await extractStructuredData(
  "واجهة Gemini API الجديدة رائعة! التوثيق واضح، " +
  "وحزمة TypeScript SDK مصممة بشكل جيد، والأسعار تنافسية جداً. " +
  "لكن حدود المعدل يمكن أن تكون مصدر قلق للتطبيقات ذات الحركة العالية."
);
 
console.log(analysis);
// {
//   sentiment: "positive",
//   confidence: 0.85,
//   topics: ["API", "documentation", "SDK", "pricing", "rate limits"],
//   summary: "مراجعة إيجابية لـ Gemini API مع قلق بسيط حول حدود المعدل"
// }

الخطوة 8: بناء مساعد ذكاء اصطناعي تحادثي

لنجمع كل شيء في مساعد ذكاء اصطناعي عملي مع سجل محادثات وتعليمات نظام وإعدادات أمان:

import {
  GoogleGenerativeAI,
  HarmCategory,
  HarmBlockThreshold,
} from "@google/generative-ai";
import * as readline from "readline";
 
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY!);
 
async function startAssistant() {
  const model = genAI.getGenerativeModel({
    model: "gemini-2.5-flash",
    systemInstruction: `أنت مساعد برمجة متخصص في TypeScript و Node.js.
    تقدم إجابات موجزة وعملية مع أمثلة برمجية عند الحاجة.
    تراعي دائماً أفضل الممارسات والاعتبارات الأمنية.
    إذا لم تكن متأكداً من شيء، قل ذلك بدلاً من التخمين.`,
    safetySettings: [
      {
        category: HarmCategory.HARM_CATEGORY_HARASSMENT,
        threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE,
      },
      {
        category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
        threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE,
      },
    ],
    generationConfig: {
      temperature: 0.7,
      topP: 0.95,
      topK: 40,
      maxOutputTokens: 2048,
    },
  });
 
  const chat = model.startChat({
    history: [],
  });
 
  const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
  });
 
  console.log("المساعد الذكي جاهز! اكتب 'خروج' للإنهاء.\n");
 
  const askQuestion = () => {
    rl.question("أنت: ", async (input) => {
      const trimmed = input.trim();
      if (trimmed === "خروج" || trimmed.toLowerCase() === "exit") {
        console.log("إلى اللقاء!");
        rl.close();
        return;
      }
 
      try {
        const result = await chat.sendMessageStream(trimmed);
 
        process.stdout.write("المساعد: ");
        for await (const chunk of result.stream) {
          process.stdout.write(chunk.text());
        }
        console.log("\n");
      } catch (error: any) {
        console.error("خطأ:", error.message);
      }
 
      askQuestion();
    });
  };
 
  askQuestion();
}
 
startAssistant();

شرح إعدادات التوليد

المعاملالقيمة الافتراضيةالوصف
temperature1.0يتحكم بالعشوائية. قيمة أقل = أكثر تركيزاً، قيمة أعلى = أكثر إبداعاً
topP0.95أخذ العينات النووي. يأخذ بالاعتبار الرموز ذات الاحتمال التراكمي حتى هذه القيمة
topK40يأخذ بالاعتبار فقط أعلى K رمز في كل خطوة
maxOutputTokensمتغيرالحد الأقصى لعدد الرموز المولدة

الخطوة 9: معالجة الأخطاء وتحديد المعدل

التطبيقات الإنتاجية تحتاج معالجة أخطاء قوية:

import { GoogleGenerativeAI, GoogleGenerativeAIError } from "@google/generative-ai";
 
async function safeGenerate(prompt: string, retries = 3): Promise<string> {
  const model = genAI.getGenerativeModel({ model: "gemini-2.5-flash" });
 
  for (let attempt = 1; attempt <= retries; attempt++) {
    try {
      const result = await model.generateContent(prompt);
      return result.response.text();
    } catch (error: any) {
      const status = error?.status;
 
      if (status === 429) {
        // تجاوز حد المعدل — تراجع أسي
        const delay = Math.pow(2, attempt) * 1000;
        console.warn(
          `تم تجاوز حد المعدل. إعادة المحاولة خلال ${delay / 1000} ثانية (المحاولة ${attempt}/${retries})`
        );
        await new Promise((r) => setTimeout(r, delay));
        continue;
      }
 
      if (status === 400) {
        console.error("طلب غير صالح — تحقق من الأمر أو المعاملات");
        throw error;
      }
 
      if (status === 403) {
        console.error("مفتاح API غير صالح أو تم تجاوز الحصة");
        throw error;
      }
 
      if (attempt === retries) throw error;
 
      console.warn(`خطأ (المحاولة ${attempt}/${retries}):`, error.message);
      await new Promise((r) => setTimeout(r, 1000 * attempt));
    }
  }
 
  throw new Error("تم تجاوز الحد الأقصى للمحاولات");
}

أفضل ممارسات تحديد المعدل

  1. استخدم التراجع الأسي — ضاعف وقت الانتظار بين المحاولات
  2. خزّن الاستجابات مؤقتاً — احفظ النتائج للأوامر المتطابقة
  3. استخدم Flash للحجم الكبير — لديه حدود معدل أعلى من Pro
  4. جمّع الطلبات — اجمع الأوامر المرتبطة عند الإمكان

الخطوة 10: نصائح للإنتاج

تكوين البيئة

// src/config.ts
interface GeminiConfig {
  apiKey: string;
  model: string;
  maxRetries: number;
  timeout: number;
}
 
export function getConfig(): GeminiConfig {
  const apiKey = process.env.GEMINI_API_KEY;
  if (!apiKey) {
    throw new Error("متغير البيئة GEMINI_API_KEY مطلوب");
  }
 
  return {
    apiKey,
    model: process.env.GEMINI_MODEL || "gemini-2.5-flash",
    maxRetries: parseInt(process.env.GEMINI_MAX_RETRIES || "3", 10),
    timeout: parseInt(process.env.GEMINI_TIMEOUT || "30000", 10),
  };
}

حساب الرموز

قبل إرسال أوامر كبيرة، تحقق من عدد الرموز:

async function countTokens(content: string) {
  const model = genAI.getGenerativeModel({ model: "gemini-2.5-flash" });
 
  const result = await model.countTokens(content);
  console.log(`عدد الرموز: ${result.totalTokens}`);
 
  return result.totalTokens;
}

تقدير التكلفة

function estimateCost(
  inputTokens: number,
  outputTokens: number,
  model: "pro" | "flash" | "flash-lite"
) {
  // أسعار تقريبية لكل مليون رمز (تحقق من الأسعار الحالية)
  const pricing = {
    pro: { input: 1.25, output: 10.0 },
    flash: { input: 0.15, output: 0.6 },
    "flash-lite": { input: 0.075, output: 0.3 },
  };
 
  const p = pricing[model];
  const inputCost = (inputTokens / 1_000_000) * p.input;
  const outputCost = (outputTokens / 1_000_000) * p.output;
 
  return {
    inputCost: `$${inputCost.toFixed(4)}`,
    outputCost: `$${outputCost.toFixed(4)}`,
    totalCost: `$${(inputCost + outputCost).toFixed(4)}`,
  };
}

استكشاف الأخطاء وإصلاحها

المشاكل الشائعة

"API key not valid" — مفتاح API غير صالح

  • تحقق من مفتاحك على aistudio.google.com
  • تأكد من تفعيل Generative AI API في مشروع Google Cloud
  • تحقق من عدم تقييد مفتاحك لواجهات برمجة معينة

"Resource exhausted" — أخطاء 429

  • لقد تجاوزت حد المعدل. طبّق التراجع الأسي
  • فكّر في الترقية إلى الطبقة المدفوعة لحدود أعلى
  • استخدم gemini-2.5-flash الذي لديه حدود معدل أكثر سخاءً

"Content blocked by safety filters" — تم حظر المحتوى بواسطة مرشحات الأمان

  • عدّل عتبات safetySettings (لكن كن مسؤولاً)
  • أعد صياغة الأمر لتجنب تفعيل المرشحات
  • راجع سياسات الاستخدام من Google

استجابات فارغة

  • قد يكون النموذج محظوراً بواسطة مرشحات الأمان دون إرجاع نص
  • تحقق من response.promptFeedback لمعرفة أسباب الحظر

الخطوات التالية

الآن بعد أن أتقنت أساسيات Gemini API، استكشف هذه المواضيع المتقدمة:

  • Gemini مع LangChain.js — بناء سلاسل ووكلاء ذكاء اصطناعي معقدة
  • Vertex AI — نشر على مستوى المؤسسات مع Google Cloud
  • الضبط الدقيق — تخصيص نماذج Gemini لمجالك
  • تخزين السياق مؤقتاً — تقليل التكاليف لنوافذ السياق المتكررة
  • التأريض ببحث Google — تعزيز الاستجابات ببيانات الويب الفورية

الخلاصة

لقد بنيت مجموعة أدوات كاملة لتطبيقات الذكاء الاصطناعي باستخدام Google Gemini API و TypeScript. من توليد النصوص البسيط إلى التحليل متعدد الوسائط، والبث المباشر، واستدعاء الدوال، والمخرجات المنظمة — أصبح لديك الآن كل اللبنات الأساسية لإنشاء تطبيقات ذكاء اصطناعي متطورة.

مزيج نافذة السياق الضخمة في Gemini API، والأسعار التنافسية، ودعم الوسائط المتعددة الأصلي يجعله خياراً ممتازاً لتطبيقات الذكاء الاصطناعي الإنتاجية. ابدأ بـ Flash لسرعة التطوير، وانتقل إلى Pro عندما تحتاج قدرات استدلال معززة.


هل تريد قراءة المزيد من الدروس التعليمية؟ تحقق من أحدث درس تعليمي لدينا على htmx و Alpine.js: بناء تطبيقات ويب تفاعلية بدون أطر عمل JavaScript ثقيلة.

ناقش مشروعك معنا

نحن هنا للمساعدة في احتياجات تطوير الويب الخاصة بك. حدد موعدًا لمناقشة مشروعك وكيف يمكننا مساعدتك.

دعنا نجد أفضل الحلول لاحتياجاتك.

مقالات ذات صلة

بناء وكلاء الذكاء الاصطناعي من الصفر باستخدام TypeScript: إتقان نمط ReAct مع Vercel AI SDK

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

35 د قراءة·

بناء روبوت دردشة ذكاء اصطناعي محلي باستخدام Ollama و Next.js: الدليل الشامل

ابنِ روبوت دردشة ذكاء اصطناعي خاص يعمل بالكامل على جهازك المحلي باستخدام Ollama و Next.js. يغطي هذا الدليل العملي التثبيت والبث المباشر واختيار النماذج وبناء واجهة دردشة جاهزة للإنتاج — كل ذلك دون إرسال بياناتك إلى السحابة.

25 د قراءة·