اذهب إلى المحتوى

البحث في الموقع

المحتوى عن 'chatgpt'.

  • ابحث بالكلمات المفتاحية

    أضف وسومًا وافصل بينها بفواصل ","
  • ابحث باسم الكاتب

نوع المحتوى


التصنيفات

  • الإدارة والقيادة
  • التخطيط وسير العمل
  • التمويل
  • فريق العمل
  • دراسة حالات
  • التعامل مع العملاء
  • التعهيد الخارجي
  • السلوك التنظيمي في المؤسسات
  • عالم الأعمال
  • التجارة والتجارة الإلكترونية
  • نصائح وإرشادات
  • مقالات ريادة أعمال عامة

التصنيفات

  • مقالات برمجة عامة
  • مقالات برمجة متقدمة
  • PHP
    • Laravel
    • ووردبريس
  • جافاسكربت
    • لغة TypeScript
    • Node.js
    • React
    • Vue.js
    • Angular
    • jQuery
    • Cordova
  • HTML
  • CSS
    • Sass
    • إطار عمل Bootstrap
  • SQL
  • لغة C#‎
    • ‎.NET
    • منصة Xamarin
  • لغة C++‎
  • لغة C
  • بايثون
    • Flask
    • Django
  • لغة روبي
    • إطار العمل Ruby on Rails
  • لغة Go
  • لغة جافا
  • لغة Kotlin
  • لغة Rust
  • برمجة أندرويد
  • لغة R
  • الذكاء الاصطناعي
  • صناعة الألعاب
  • سير العمل
    • Git
  • الأنظمة والأنظمة المدمجة

التصنيفات

  • تصميم تجربة المستخدم UX
  • تصميم واجهة المستخدم UI
  • الرسوميات
    • إنكسكيب
    • أدوبي إليستريتور
  • التصميم الجرافيكي
    • أدوبي فوتوشوب
    • أدوبي إن ديزاين
    • جيمب GIMP
    • كريتا Krita
  • التصميم ثلاثي الأبعاد
    • 3Ds Max
    • Blender
  • نصائح وإرشادات
  • مقالات تصميم عامة

التصنيفات

  • مقالات DevOps عامة
  • خوادم
    • الويب HTTP
    • البريد الإلكتروني
    • قواعد البيانات
    • DNS
    • Samba
  • الحوسبة السحابية
    • Docker
  • إدارة الإعدادات والنشر
    • Chef
    • Puppet
    • Ansible
  • لينكس
    • ريدهات (Red Hat)
  • خواديم ويندوز
  • FreeBSD
  • حماية
    • الجدران النارية
    • VPN
    • SSH
  • شبكات
    • سيسكو (Cisco)

التصنيفات

  • التسويق بالأداء
    • أدوات تحليل الزوار
  • تهيئة محركات البحث SEO
  • الشبكات الاجتماعية
  • التسويق بالبريد الالكتروني
  • التسويق الضمني
  • استسراع النمو
  • المبيعات
  • تجارب ونصائح
  • مبادئ علم التسويق

التصنيفات

  • مقالات عمل حر عامة
  • إدارة مالية
  • الإنتاجية
  • تجارب
  • مشاريع جانبية
  • التعامل مع العملاء
  • الحفاظ على الصحة
  • التسويق الذاتي
  • العمل الحر المهني
    • العمل بالترجمة
    • العمل كمساعد افتراضي
    • العمل بكتابة المحتوى

التصنيفات

  • الإنتاجية وسير العمل
    • مايكروسوفت أوفيس
    • ليبر أوفيس
    • جوجل درايف
    • شيربوينت
    • Evernote
    • Trello
  • تطبيقات الويب
    • ووردبريس
    • ماجنتو
    • بريستاشوب
    • أوبن كارت
    • دروبال
  • الترجمة بمساعدة الحاسوب
    • omegaT
    • memoQ
    • Trados
    • Memsource
  • برامج تخطيط موارد المؤسسات ERP
    • تطبيقات أودو odoo
  • أنظمة تشغيل الحواسيب والهواتف
    • ويندوز
    • لينكس
  • مقالات عامة

التصنيفات

  • آخر التحديثات

أسئلة وأجوبة

  • الأقسام
    • أسئلة البرمجة
    • أسئلة ريادة الأعمال
    • أسئلة العمل الحر
    • أسئلة التسويق والمبيعات
    • أسئلة التصميم
    • أسئلة DevOps
    • أسئلة البرامج والتطبيقات

التصنيفات

  • كتب ريادة الأعمال
  • كتب العمل الحر
  • كتب تسويق ومبيعات
  • كتب برمجة
  • كتب تصميم
  • كتب DevOps

ابحث في

ابحث عن


تاريخ الإنشاء

  • بداية

    نهاية


آخر تحديث

  • بداية

    نهاية


رشح النتائج حسب

تاريخ الانضمام

  • بداية

    نهاية


المجموعة


النبذة الشخصية

تم العثور على 5 نتائج

  1. عند التعرف على موضوع جديد والقراءة عنه نبدأ عادة بالبحث عن تعريف يشرح ويوضح الصورة العامة له، ثم نكتشف مجموعة من المواضيع الأخرى الفرعية المتعلقة بالموضوع الأساسي، وعادة ما نبدأ البحث عبر الإنترنت عبر ويكيبيديا مثلًا، ونقرأ ونستكشف المواضيع بين صفحة وأخرى. لكن ماذا لو كان هناك أداة تساعدنا في ذلك فتولد مواضيع فرعية من الموضوع الرئيسي أو المواضيع الفرعية عنه وتشرح كل منها، هذا ما سنطوره في هذا المقال ومصدر تلك المعلومات سيكون أحد نماذج الذكاء الاصطناعي وهو ChatGPT. هل يملك ChatGPT المعرفة تٌحاكي نماذج اللغة الكبيرة (أو Large Language Models) ومنها ChatGPT البيانات التي دُّربت عليها، فإذا دُربت على نصوص متنوعة ستتمكن من محاكاة وتوليد نصوص مشابهة لها قد لا يُلاحظ الفرق بينها وبين الأصلية، ولكن لا يمكن الاعتماد على دقتها فتلك النماذج خصوصًا المُدربة على طيف واسع من البيانات تُحاكي فقط ما دُربت عليه ولا تملك فهم حقيقي كما نحن البشر عن تلك النصوص. فكثيرًا من الأحيان سيخطئ النموذج بثقة، لذا لا يمكننا الاعتماد دومًا على معلوماته، إنما في هذا المقال سنطور تطبيق لتوليد معلومات عامة وبسيطة ليست دقيقة أو معقدة، فمثل تلك المعلومات قد وردت ضمن البيانات التي دُرب عليها ChatGPT كثيرًا ومن أكثر من رأي وزاوية، لذا يمكننا الاعتماد عليه في حال كانت المعلومات بسيطة وغير معقدة مع الحذر دومًا والتحقق من صحة المعلومات الحساسة. أفكار لمشاريع باستخدام ChatGPT بسبب سهولة التعامل مع نموذج ChatGPT والطيف الواسع من الإمكانيات يمكن الاستفادة من مثل تلك النماذج في بناء العديد من التطبيقات بأفكار متنوعة، فمثلًا تلخيص مقال طويل يستفيد منه المستخدم في الاطلاع على محتوى المقال بسرعة قبل قراءته كما فعلنا في تطبيق لخصلي في مقال سابق، أو يمكن طلب اقتراح وصفة طعام معينة وشرح طريقة تحضيرها والاستفادة من المعلومات الكامنة ضمن النموذج والذي اكتسبها أثناء مرحلة التدريب كما فعلنا في تطبيق وصفة في مقال آخر سابق، أو يمكن طلب تصحيح نص ما أدخله المستخدم والاستفادة منه كمصحح نصوص آلي، أو يمكن طلب استخراج الكلمات المفتاحية من نص معين والذي يفيد في العديد من المجالات من تخزين البيانات إلى مساعدة كُتّاب المقالات وغيرها. أما في هذا المقال سنتعرف على طريقة الاستعانة بنموذج ChatGPT لتوليد مواضيع في مجالات مختلفة والغوص في مواضيع فرعية عنها، وسوف نستفيد من المعرفة التي يملكها ChatGPT وتدرب عليها مسبقًا، وذلك بتطوير تطبيق بسيط يعرض للمستخدم بعض الأفكار العشوائية ليختار أحدها ثم نتفرع إلى مواضيع فرعية مع شرح بسيط عنها، ثم سنجعل ChatGPT يختار موضوع فرعي لنولد منه مواضيع فرعية أيضًا وهكذا يستفيد المستخدم من التطبيق في استكشاف الأفكار وتفاصيلها. دورة تطوير التطبيقات باستخدام لغة JavaScript تعلم البرمجة بلغة جافا سكريبت انطلاقًا من أبسط المفاهيم وحتى بناء تطبيقات حقيقية. اشترك الآن تحضير صفحات التطبيق نبدأ بإنشاء مجلد جديد لملفات المشروع ونُنشئ ملف HTML بالاسم index.html ونستورد ضمنه ملف مكتبة jQuery والتي سنستخدمها لتعديل محتويات الصفحة، وملف جافا سكريبت باسم script.js والذي سيحوي شيفرة التطبيق، وملف CSS يتضمن التنسيقات style.css كالتالي: <html lang="ar"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <script src="https://code.jquery.com/jquery-3.7.0.min.js"></script> <script src="script.js" defer></script> <link rel="stylesheet" href="style.css" /> <title>علمني</title> </head> <body> <div> <h1></h1> <p><span>?</span> اختر أحد المواضيع لمعرفة المزيد</p> </div> <div id="container"> </div> </body> </html> كما تلاحظ في الكود أعلاه تحتوي الصفحة على عنصر <div> بالمٌعرّف container وضمنه سنضيف محتوى المواضيع الأساسية والمواضيع الفرعية. بعد ذلك سوف ننشئ ملف التنسيقات style.css ضمن مجلد المشروع وسنكتب ضمنه التنسيقات التالية: body { direction: rtl; display: flex; flex-direction: column; max-width: 60ch; justify-items: center; align-items: center; font-size: x-large; margin: 0 auto; padding: 20vh 10vw; background-color: #f9f9f9; color: #121212; font-family: system-ui; align-items: stretch; gap: 1rem; } p { line-height: 2; color: darkslategray; } a { padding: 1rem; font-size: inherit; margin: 0 .5rem; color: darkblue; } footer { margin-top: 2rem; } form { display: flex; flex-direction: column; gap: 2rem; text-align: center; } button { background-color: #121212; color: #f9f9f9; border: none; padding: 1rem 2rem; font-size: inherit; cursor: pointer; font-family: inherit; } input { padding: 1rem 2rem; font-size: inherit; font-family: inherit; text-align: center; border: .2rem solid; } .subject { padding: 2rem 2rem; cursor: pointer; border: .15rem solid lightgray; border-radius: .5rem; } #container { gap: 2rem; display: flex; flex-direction: column; } لمعاينة شكل الموقع نضيف بعض المواضيع الوهمية يدويًا ضمن العنصر بالمعرّف container بالشكل التالي: <div class="subject"> <h2>الموضوع</h2> <p>شرح عن الموضوع</p> </div> نفتح الصفحة index.html ضمن المتصفح ونلاحظ شكل الموقع بعد التنسيق: توليد وعرض مواضيع عشوائية للمستخدم ننشئ ملف جافا سكريبت script.js ونبدأ بكتابة شيفرة التطبيق، وللتعامل مع الواجهة البرمجية لنموذج ChatGPT يجب توليد مفتاح الاستيثاق لها بعد إنشاء حساب مدفوع على موقع شركة OpenAI، ولكي نتجنب استخدام المفتاح الخاص بنا من قبل المستخدمين يمكننا الطلب من كل مستخدم إدخال مفتاحه الخاص عند أول استخدام للتطبيق وحفظه لاستخدامه لاحقًا عند الاتصال بالواجهة البرمجية للنموذج ChatGPT، حيث يسمح لنا ذلك بحرية أكبر في تطوير التطبيقات التي تعتمد على الذكاء الاصطناعي بلا أي كلفة. ولاستخدام ذلك المفتاح يجب حفظه في مكان آمن، وبما أننا لن نستخدم أي شيفرات جافاسكربت خارجية فسنخزن المفتاح ضمن التخزين المحلي لمتصفح الويب الخاص بالمستخدم باستخدام الكائن localStorage، أما في حال استخدامك لأي شيفرات من مكتبات خارجية ضمن المشروع فيمكن لتلك الشيفرات قراءة المفتاح وسرقته من المستخدم، عندها يجب البحث عن حلول أخرى كتخزين المفتاح بأمان ضمن خادم المشروع والتعريف عن المستخدم بطريقة ما مثل استخدام ملفات تعريف الارتباط Cookies وإرسال الطلبات من قبل الخادم بدلًا من قبل متصفح المستخدم نفسه، والآن نعرف التابع openAIKey والذي يتحقق وجود مفتاح مُخزن سابقًا ويعيده، وإلا يطلب من المستخدم إدخال مفتاحه باستخدام الدالة prompt وحفظ ذلك المفتاح للاستخدام لاحقًا: function openAIKey() { const localStorageKey = 'OPENAI_API_KEY'; // استخراج المفتاح المُخزن سابقًا let apiKey = localStorage.getItem(localStorageKey) if (!apiKey) { // طلب إدخال المفتاح من المستخدم apiKey = prompt('أدخل مفتاح OpenAI الخاص بك') // تخزين المفتاح localStorage.setItem(localStorageKey, apiKey) } return apiKey } وللتعامل مع نموذج ChatGPT نُعرف التابع chatGPT والذي يقبل التعليمة التي سترسل له كمعامل أول، ويُرسل طلب من نوع POST إلى المسار https://api.openai.com/v1/chat/completions بحسب توثيق تلك الواجهة البرمجية وكما شرحناها في مقال سابق، ثم نستخرج رد النموذج منه كالتالي: function chatGPT(prompt) { // إرسال الطلب return fetch('https://api.openai.com/v1/chat/completions', { method: 'POST', headers: { 'Content-Type': 'application/json', // ترويسة الاستيثاق 'Authorization': 'Bearer ' + openAIKey(), }, body: JSON.stringify({ // اسم النموذج "model": "gpt-3.5-turbo", // تعليمة المستخدم "messages": [{ "role": "user", "content": prompt }] }), }) // تفسير الطلب .then(response => response.json()) // استخراج رد النموذج .then(json => json.choices[0].message.content) } باستخدام التابع chatGPT يمكننا الآن توليد محتوى الأفكار العشوائية الأولية التي ستظهر للمستخدم بإرسال التعليمة التالية إلى ChatGPT: اقترح بعض المواضيع لأتعلم عنها، المواضيع كل موضوع بسطر: لاحظ أننا نحدد في نهاية التعليمة شكل الخرج الذي نريده وهو في هذه الحالة أن يكتب لنا كل موضوع بسطر، لنتمكن من استخراج تلك المواضيع بتقسيم الرد إلى الأسطر المكونة له، ثم تحويل كل سطر إلى كائن جافاسكربت يحتوي على الحقل title وهو عنوان الموضوع، نٌعرّف تلك العملية ضمن التابع getInitialSubjects كالتالي: function getInitialSubjects() { return chatGPT('اقترح بعض المواضيع لأتعلم عنها، المواضيع كل موضوع بسطر:') .then(subjects => subjects.split('\n').map(title => ({ title }))) } ولعرض تلك المواضيع نستخدم مكتبة jQuery لتحديد العنصر الذي سيحتوي المحتوى باستخدام التابع $ وهو صاحب المٌعرّف container، ونفرغ محتواه باستخدام empty ونمر على كل كائن منها ونولد له عناصر تحوي على عنوان الموضوع من الحقل title، ونستخدم التابع append لإضافة تلك العناصر داخل بعضها، ونعرّف عملية عرض كائنات المواضيع ضمن التابع renderSubjects ليكون كالتالي: function renderSubjects(subjects) { // العنصر الحاوي const $container = $('#container') // مسح المحتوى السابق $container.empty() for (const subject of subjects) { // إنشاء عنصر الموضوع const $subject = $(`<div class="subject"></div>`) // إضافة العنوان $subject.append(`<h2>${subject.title}</h2>`) // إضافة الموضوع إلى الحاوية $container.append($subject) } } وبذلك أصبحت كل التوابع جاهزة من توليد الأفكار العشوائية إلى عملية عرضها، لذا في نهاية الملف نستدعي التابع getInitialSubjects ونمرر تابع عرض المواضيع renderSubjects إلى التابع then من ذلك التابع لعرض تلك المواضيع بعد جلبها، ونفتح الملف index.html ضمن المتصفح سنلاحظ طلب التطبيق منا لأول مرة إدخال مفتاح الواجهة البرمجية: [prompt.png] وبعد إدخال المفتاح الخاص بنا سيُرسل طلب توليد المواضيع إلى ChatGPT وتعرض النتائج كالتالي: نلاحظ تنوع المواضيع التي ولدها وكيف أمكننا استخراجها من الرد وعرض كل منها على حدى، وفي الفقرة التالية سنضيف ميزة الدخول إلى مواضيع فرعية من أي موضوع مقترح نريد معرفة المزيد عنه. عرض مواضيع فرعية عن موضوع يمكننا أن نطلب من ChatGPT توليد مواضيع فرعية من موضوع محدد اختاره المستخدم، مع طلب إرفاق شرح بسيط عن كل موضوع فرعي، لذا يجب إرسال تعليمة مختلفة عن السابقة نطلب بها توليد المواضيع الفرعية ونحدد شكل الخرج الذي نريده ليسهل علينا استخراجه من الطلب، والصيغة التي سنرسلها ستكون كالتالي: حيث نستبدل <اسم الموضوع> بعنوان الموضوع الذي اختاره المستخدم، ونلاحظ كيف أرفقنا أمثلة عن شكل الخرج المطلوب وفي نهاية التعليمة نرشد النموذج أن يبدأ مباشرة بتوليد تلك الأفكار بالصيغة المُحددة، ولإرسال تلك التعليمة وتحويل الرد المولّد عنها إلى كائنات بعنوان ضمن الحقل title وشرح عنها ضمن الحقل desc نُعرّف التابع getSubSubjects والذي يقبل كمعامل أول عنوان الموضوع ويستدعي داخله التابع chatGPT ويمرر التعليمة مدرجًا ضمنها الموضوع المٌمرر، ثم يحول الرد إلى كائنات مواضيع بالصيغة المطلوبة كالتالي: function getSubSubjects(subject) { // توليد التعليمة const prompt = `اقترح بعض الأفكار الفرعية عن "${subject}" لأتعلم عنها مع شرح قصير عن كل منها بالصيغة التالية: الفكرة شرح قصير الفكرة شرح قصير الأفكار الفرعية بالصيغة السابقة:` return chatGPT(prompt) // تحويل الرد إلى كائنات .then(subjects => subjects.split('\n\n').map(subject => { const [title, desc] = subject.split('\n') return { title, desc } })) } نريد توليد مواضيع فرعية عند ضغط المستخدم على موضوع ما، لذا نُعدل التابع renderSubjects لإضافة تابع معالجة لحدث الضغط click والذي سيستدعي تابع توليد المواضيع الفرعية getSubSubjects مع تمرير عنوان الموضوع الذي اختاره المستخدم، ثم يمرر النتيجة للتابع نفسه renderSubjects كي تُعرض المواضيع الفرعية بدل الحالية، ونضيف لكل موضوع الشرح من الحقل desc في حال وجوده كالتالي: function renderSubjects(subjects) { ... for (const subject of subjects) { const $subject = $(`<div class="subject"></div>`) // توليد المواضيع الفرعية عند الضغط $subject.on('click', () => getSubSubjects(subject.title).then(renderSubjects)) $subject.append(`<h2>${subject.title}</h2>`) // استخراج الشرح وعرضه if (subject.desc){ $subject.append(`<p>${subject.desc}</p>`) } $container.append($subject) } } تجربة التطبيق أصبح التطبيق جاهزًا بالكامل ويمكن للمستخدم الغوص إلى ما لا نهاية في المواضيع الفرعية عن الفرعية وهكذا، لنختبر ذلك باختيار موضوع العلوم الطبيعية والفيزيائية من القائمة السابقة ونرى النتيجة: ولد مواضيع فرعية مع شرح بسيط عن كل منها عن ذلك الموضوع لندخل مثلًا إلى موضوع الذكاء الاصطناعي: أيضًا أصبحت المواضيع أكثر تخصصًا لنختر تعلم الآلة: دورة الذكاء الاصطناعي احترف برمجة الذكاء الاصطناعي AI وتحليل البيانات وتعلم كافة المعلومات التي تحتاجها لبناء نماذج ذكاء اصطناعي متخصصة. اشترك الآن الختام يمكن بتوكيل المستخدم بتوليد واستخدام مفاتيحه الخاصة بالسماح للمطور تطوير التطبيقات المعتمدة على الذكاء الاصطناعي وإتاحتها للاستخدام للجميع دون أي كلفة، والتطبيق الذي طورناه في هذا المقال يعتمد على المعرفة الكامنة ضمن نموذج ChatGPT لتوجيه توليد المحتوى الذي نرغب به، ويمكن التطوير على التطبيق بكثير من الأفكار فمثلًا إضافة رابط عودة للبداية، أو عرض المواضيع الفرعية تحت الموضوع التابعة له ليصبح التطبيق عبارة عن شجرة يمكن فردها إلى ما لا نهاية، أو إضافة زر لتوليد شرح أطول عن موضوع معين أو طلب سؤال محدد عن ذلك الموضوع، ونرى أن الأفكار لا حصر لها بسبب سهولة التعامل مع هذه النماذج باستخدام اللغة الطبيعية سواء ضمن التطبيق أو من دخل المستخدم. اقرأ أيضًا تطوير تطبيق 'وصفة' لاقتراح الوجبات باستخدام ChatGPT و DALL-E في PHP تطوير تطبيق 'اختبرني' باستخدام ChatGPT ولغة جافاسكربت مع Node.js الذكاء البشري مقابل الذكاء الاصطناعي
  2. نماذج اللغة الكبيرة (أو Large Language Models) هي نوع من نماذج الذكاء الاصطناعي التي تُدرّب على كمية كبيرة من النصوص لتستطيع بذلك توليد نصوص مشابهة لها، وهنا يأتي ChatGPT وهو نموذج لغة كبير دُرّب على محتوى كبير جدًا من الانترنت، بحيث أصبح لديه اطلاع على الكثير من المعلومات واللغات وأساليب الكتابة، وطوّر باستخدام بعض التقنيات أهمها تقنية التعلم الموجه من قبل البشر RLHF (أو Reinforcement learning from human feedback) ليتّبع في توليده للنصوص اسلوب الحوار بين المستخدم والنموذج، مما يبسط طريقة التعامل معه وتوجيهه لتوليد النصوص التي نحتاحها، وفي هذا المقال سنتعامل مع ذلك النموذج لتوليد نصائح وحكم مفيدة للمستخدم بحسب ما يطلب أو يشعر، وذلك عبر واجهة سطر الأوامر نطورها ضمن بيئة نود (Node.js) حيث يُدخل المستخدم موضوع النصيحة أو الهدف منها ويولد ChatGPT ذلك، وستحتاج لاتباع المقال معرفة بلغة جافاسكربت وبيئة نود ومدير الحزم npm. إنشاء برنامج سطر أوامر باستخدام npm كي نتمكن من تنفيذ التطبيق بسهولة من سطر الأوامر كأي برنامج آخر مثبت على الجهاز وبدلًا من تشغيله كل مرة باستخدام نود Node.js والإشارة إلى مسار ملف جافاسكربت الرئيسي للبرنامج يمكننا الاستفادة من ميزة في npm تمكننا من تحديد ملف جافاسكربت من حزمة ما كالمشروع الذي سنطوره ونشره ضمن الجهاز كبرنامج ضمن سطر الأوامر، حيث يُستخدم مدير الحزم npm عادة لتعريف البرامج في نود كحزم يمكن استخدامها ضمن المشاريع الأخرى، ولنبدأ أولًا بإنشاء مجلد جديد لملفات المشروع وليكن بالاسم inspire-cli ونعرفه كحزمة نود بتنفيذ الأمر التالي ضمن المجلد: npm init -y سينشئ عن تنفيذ ذلك الأمر ملف تعريف الحزمة package.json ضمن المجلد، وباستخدام الخيار y- ستُملئ القيم الافتراضية ضمنه دون الحاجة لإدخالها يدويًا، والآن نُنشئ ملف البرنامج الرئيسي index.js والذي سيحتوي شيفرة البرنامج، ولتعريفه كبرنامج سطر أوامر يمكن بداخل ملف تعريف الحزمة package.json وضمن المفتاح bin تعريف كائن مفاتيحه هي أسماء برامج سطر الأوامر التي توفرها هذه الحزمة، وقيمها هي مسار الملفات التي ستُنفذ باستخدام نود عند تنفيذ البرنامج، لتطبيقنا سنعرف برنامج بالاسم ألهمني ومسار ملف البرنامج له هو الملف الرئيسي index.js كالتالي: "bin": { "ألهمني": "index.js" } وضمن ملف جافاسكربت الرئيسي لذلك البرنامج index.js نضيف السطر التالي لاختبار نجاح التنفيذ، ونلاحظ سطر البداية وهو سطر يدل مدير الحزم npm على الطريقة الصحيحة لإنشاء الملف التنفيذي لبرنامج سطر الأوامر المقابل لهذا الملف لتحديد بيئة تشغيله وهي نود: #!/usr/bin/env node console.log('مرحبًا') وبذلك يمكن لأي مستخدم بعد تثبيت هذا المشروع كحزمة على جهازه تنفيذ الأمر باستخدام اسم البرنامج المُعرف ضمن الكائن bin ليُنفذ البرنامج index.js في بيئة نود ويظهر له النتيجة، ولاختباره أثناء التطوير يمكن الاستفادة من أمر الربط link من مدير الحزم npm والذي يربط الحزمة ضمن البيئة العامة للجهاز لنتمكن من استخدامها من أي مكان، لذا ننفذ الأمر التالي ضمن مجلد المشروع: npm link . تدل النقطة على المشروع الذي نرغب بربطه وتعني المشروع في المسار الحالي، وبعد تنفيذ هذا الأمر أصبح الوصول لبرنامج سطر الأوامر ممكنًا من أي مكان لنختبر ذلك بتنفيذ الأمر التالي ضمن أي طرفية terminal لنلاحظ خرج البرنامج كالتالي: أصبح برنامج سطر الأوامر جاهزًا وسنبدأ في الفقرة التالية بتطويره ليستقبل الدخل من المستخدم عبر معاملات سطر الأوامر المُمررة له. دورة تطوير التطبيقات باستخدام لغة JavaScript تعلم البرمجة بلغة جافا سكريبت انطلاقًا من أبسط المفاهيم وحتى بناء تطبيقات حقيقية. اشترك الآن استقبال الدخل من المستخدم نحتاج أن يدخل المستخدم موضوع النصيحة أو الحكمة التي يرغب بها، ويمكن استقبال ذلك عبر معاملات سطر الأوامر التي يمررها المستخدم عند تنفيذ البرنامج، ويمكن الوصول إليها في نود عبر المتغير العام process.argv وهو مصفوفة من القيم أول قيمة منه هي مسار البرنامج التنفيذي لبيئة نود التي ستُنفذ البرنامج، والقيمة الثانية هي مسار ملف البرنامج الحالي الذي سيُنفذ، والقيم الباقية هي ما تُهمنا وهي جميع المعاملات المُمررة للبرنامج من قبل المستخدم عند تنفيذه، حيث سنجمعها معًا لنكون منها الجملة التي أدخلها المستخدم لتحضيرها قبل إرسالها، لذا نعدل ملف البرنامج index.js ليصبح كالتالي: #!/usr/bin/env node const args = process.argv.slice(2) const input = args.join(' ') حيث باستخدام التابع slice على مصفوفة المعاملات المُمررة للبرنامج يمكننا تجاهل أول عنصرين منها واستخراج المعاملات المُمررة فقط، وباستخدام التابع join نجمع تلك الكلمات ونفصل بينها بفراغات لتكون قيمة الثابت input هي جملة الدخل من المستخدم، وفي الفقرة التالية سنُرسل تلك الجملة إلى نموذج ChatGPT لتوليد النصيحة المطلوبة. إرسال الدخل إلى ChatGPT وتوليد النصيحة لنتمكن من التعامل مع نموذج ChatGPT عبر الواجهة البرمجية API له يجب إنشاء حساب جديد ضمن المنصة المالكة له OpenAI وإعداد الحساب كحساب مدفوع وإدخال وسيلة الدفع، بعد ذلك يمكن توليد مفتاح للتعامل مع الواجهة البرمجية نتأكد من نسخه والاحتفاظ به، وننفذ الأمر التالي مع تبديل قيمة المفتاح لتخزينه ضمن متغيرات البيئة لجلبه ضمن البرنامج لاحقًا: set OPENAI_API_KEY=<قيمة المفتاح> وضمن نظام ماك أو لينكس يمكن تنفيذ الأمر التالي: export OPENAI_API_KEY=<قيمة المفتاح> وبذلك عند تنفيذ البرنامج من نفس هذه الطرفية سيتمكن البرنامج من الوصول لقيمة ذلك المفتاح دون الحاجة لكتابته ضمن الشيفرة المصدرية، والآن لنرسل دخل المستخدم ونطلب من نموذج ChatGPT الرد المناسب ويمكن ذلك بحسب التوثيق الرسمي لواجهة النموذج البرمجية بإرسال طلب HTTP من نوع POST إلى مسار الواجهة البرمجية https://api.openai.com/v1/chat/completions ونضع مفتاح الواجهة ضمن الترويسة Authorization وقيمتها الكلمة Bearer ثم مسافة ثم قيمة المفتاح، وضمن جسم الطلب نحدد كقيمة للمفتاح model اسم النموذج الذي نرغب بالتعامل معه وهو gpt-3.5-turbo وهو الاسم التقني لنموذج ChatGPT بالإصدار الثالث، ونضيف كقيمة للمفتاح messages مصفوفة من الكائنات المُعبرة عن الرسائل المُرسلة للنموذج نرسل ضمنها رسالة المستخدم وهو الدخل المُمرر للبرنامج، ويمكننا توجيه النموذج لشكل الخرج الذي نريده عبر تشكيل رسالة المستخدم لتصبح بالشكل التالي: const message = `ألهمني بعبارة مختصرة عن الموضوع التالي: ${input}` وبذلك نرشد النموذج داخل البرنامج لطبيعة الرد الذي نريده منه دون أن يحتاج المستخدم سوى لإدخال الموضوع الذي يريده للبرنامج، وباستخدام fetch يمكننا إرسال طلب HTTP للواجهة البرمجية للنموذج كالتالي: fetch('https://api.openai.com/v1/chat/completions', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${proccess.env.OPENAI_API_KEY}`, }, body: JSON.stringify({ "model": "gpt-3.5-turbo", "messages": [{ "role": "user", "content": message }] }), }) حيث يعيد التابع fetch وعدًا (أو Promise) يمكننا استخدام التابع then للحصول على الرد، ونحول الرد القادم إلى صيغة json ثم نستخرج منها محتوى جواب النموذج على الرسالة المرسلة من قبل المستخدم وهي ضمن القيمة json.choices[0].message.content من رد json المرسل ونعرضها له على الشاشة كالتالي: fetch(...) .then(r => r.json()) .then(json => json.choices[0].message.content) .then(gpt_response => console.log(gpt_response)) وبذلك يصبح البرنامج جاهزًا لنختبره في الفقرة التالية لتوليد بعض النصائح المفيدة. اختبار البرنامج ضمن سطر الأوامر وبما أننا عرفنا اسم البرنامج بالاسم ألهمني يصبح تنفيذ البرنامج أشبه بكتابة جملة معبرة باللغة العربية، وفي كل مرة سيُولد النموذج نصيحة مختلفة بحسب الموضوع المحدد، فمثلًا لنرى ما لديه من نصائح حول النجاح بتنفيذ الأمر ألهمني عن النجاح: النجاح هو النتيجة الإيجابية للجهود المستمرة والتفاني في العمل لتحقيق الأهداف. لنرى ما سينصح به شخص يشعر بالتعب بتنفيذ الأمر ألهمني أشعر بالتعب: استرح قليلاً، واشرب ماء بكميات كافية، ومارس التمارين الرياضية بانتظام. نصيحة تقليدية لكن يجب الاهتمام بها، وعند تنفيذ نفس الأمر مرة أخرى حصلنا على نصيحة مختلفة: لا تستسلم للتعب، النجاح يتطلب الجهد والإصرار. لاحظ سهولة التعامل مع هذه النماذج باستخدام اللغة الطبيعية، مما يفتح الاحتمالات الواسعة لتطوير العديد من التطبيقات المفيدة والأفكار الرائعة التي تضيف للمستخدم قيمة مفيدة أو توفر الوقت والجهد في بعض الأحيان، حيث يمكن التطوير على التطبيق الذي طورناه في هذا المقال بالتعديل على التعليمة المرسلة للنموذج لتغيير النتيجة التي يولدها أو اللهجة التي يتكلم بها أو حتى أن يرد بلغة مختلفة أو أي أفكار أخرى تخطر في ذهنك يمكنك مشاركتها في التعليقات ومشاركة النتائج التي حصلت عليها بعد تجربتك تطبيقها. دورة الذكاء الاصطناعي احترف برمجة الذكاء الاصطناعي AI وتحليل البيانات وتعلم كافة المعلومات التي تحتاجها لبناء نماذج ذكاء اصطناعي متخصصة. اشترك الآن اقرأ أيضًا برمجة تطبيق 'لخصلي' لتلخيص المقالات باستخدام ChatGPT ولارافل تطوير تطبيق 'وصفة' لاقتراح الوجبات باستخدام ChatGPT و DALL-E في PHP تطوير تطبيق 'اختبرني' باستخدام ChatGPT ولغة جافاسكربت مع Node.js
  3. تتميز نماذج اللغة الكبيرة أو Large Language Models بقدرتها على فهم اللغة الطبيعية وتوليد النصوص الصحيحة إملائيًا والصحيحة بمعناها أيضًا، مما يسمح بالتعامل مع نماذج الذكاء الاصناعي تلك بسهولة وبساطة من خلال اللغة الطبيعية، ومن تلك النماذج نموذج ChatGPT الشهير من شركة OpenAI والذي سنستفيد من مزاياه تلك والمعلومات الكامنة ضمنه والتي اكتسبها أثناء مرحلة تدريبه على البيانات النصية المتوفرة على الإنترنت في هذا المقال لتوليد أسئلة للمستخدم عن موضوع معين يطلبه المستخدم، ثم عرض الأجوبة التي يُدخلها المستخدم على النموذج لتحديد مستوى فهمه لذلك الموضوع وحتى تصحيح أجوبته إن كانت خاطئة، سنلاحظ أيضًا الطيف الواسع من الاحتمالات الممكنة عند التعامل مع ذلك النموذج، من توليد المحتوى إلى طلب البيانات بشكل وتنسيق محدد يسهل تكامله مع التطبيق. تجهيز المشروع وإعداد الصفحات نبدأ بإنشاء مجلد جديد للمشروع وننفذ الأمر التالي بداخله والذي سيُعرّف المشروع كحزمة وتوليد ملف توصيف المشروع package.json والذي يمكن تعريف بعض الأوامر الخاصة بالمشروع ضمنه وتحديد الاعتماديات التي يريدها: npm init -y نثبت الاعتماديات التي نحتاجها لبناء المشروع وهي مكتبة express لإنشاء خادم الويب للتطبيق والمكتبة ejs لبناء قوالب HTML لصفحات المشروع، ومكتبة openai للتعامل مع الواجهة البرمجية API لنموذج ChatGPT ومكتبة dotenv والتي سنحتاجها لتحميل متغيرات البيئة من ملف env. للمشروع، وذلك بتنفيذ الأمر التالي: npm install express ejs openai dotenv لنبدأ ببناء خادم الويب وتجهيز الصفحات الأساسية للتطبيق وهي ثلاثة صفحات صفحة يدخل فيها المستخدم موضوع الاختبار، وصفحة لعرض الاختبار وإدخال الأجوبة، وصفحة عرض النتيجة، ونولد أولًا تطبيق جديد باستدعاء تابع مكتبة Express ونضبط إعداداته لاستخدام محرك القوالب ejs كمحرك توليد ملفات العرض وتخديم الملفات الثابتة العامة من المجلد public ضمن المشروع، واستقبال الدخل المرسل من نموذج HTML والتعامل معه، وذلك ضمن الملف bin/www ونضيف له ترويسة تحديد بيئة التشغيل لذلك الملف كالتالي: #!/usr/bin/env node const path = require("path"); const express = require("express"); // إنشاء تطبيق جديد const app = express(); // ضبط محرك توليد ملفات العرض app.set('view engine', 'ejs'); //إعداد تخديم الملفات العامة app.use(express.static(path.join(__dirname, '../public'))); // ضبط استقبال المدخلات app.use(express.urlencoded({ extended: true })) نُعرّف ضمن متغير التطبيق app ثلاث مسارات وهي المسار الرئيسي / بالطريقة GET لعرض الصفحة الرئيسية، والمسار test/ لعرض الاختبار، والمسار result/ لعرض نتيجة الاختبار، وضمن كل منها نٌصيّر ونعيد صفحة القالب المقابلة لذلك المسار باستخدام التابع render من كائن الطلب req المُمرر لتابع معالجة الطلب لكل مسار، ليكون تعريف المسارات كالتالي مع تمرير بعض البيانات الوهمية لاختبار الصفحات والتي سنستبدلها لاحقًا: // الصفحة الرئيسية app.get('/', (req, res) => { res.render('index'); }) // صفحة الاختبار app.post('/test', async (req, res) => { res.render('test', { questions: [ 'السؤال الأول', 'السؤال الثاني', ] }); }) // صفحة عرض النتيجة app.post('/result', async (req, res) => { res.render('result', { results: [ { question: 'السؤال الأول', answer: 'جواب السؤال الأول', correct: true, note: null, }, { question: 'السؤال الثاني', answer: 'جواب السؤال الثاني', correct: false, note: 'ملاحظة حول الإجابة الخاطئة', } ], }) }) ملفات قوالب صفحات العرض مكانها الافتراضي ضمن المجلد views، وبما أننا نستخدم محرك ejs يجب أن تنتهي جميع تلك الملفات باللاحقة ejs.، ونربط ضمنها ملف التنسيقات style.css والذي يمكننا إنشاءه في المسار public\style.css، والصفحات هي الصفحة الرئيسية views\index.ejs وتحوي حقل لإدخال موضوع الاختبار: <html lang="ar"> <head> <link rel="stylesheet" href="style.css" /> <title>اختبرني</title> </head> <body> <h1>?</h1> <form action="test" method="post"> <input type="text" name="subject" placeholder="أدخل موضوع الاختبار"/> <button type="submit">اختبرني</button> </form> </body> </html> والصفحة الثانية لعرض الأسئلة المقترحة، حيث نمرر لقالب العرض القيمة questions والتي تحوي الأسئلة كمصفوفة سلاسل نصية، نمر عليها ضمن القالب ونعرض لكل منها نص السؤال ثم حقل مخفي يحوي نص السؤال لإرساله مع حقل الجواب المُدخل من المستخدم، والبيانات ضمن النموذج المُرسل ستحوي على القيمة answers وهي مصفوفة من الكائنات الذي يُمثل كل منها السؤال question مع الجواب answer المُدخل من قبل المستخدم لتكون من الشكل التالي: { "answers": [ { "question": "...", "answer": ""}, … ] } نستعمل صيغة الأقواس المربعة ‎[question][index]answers و ‎[answer][index]answers كأسماء لتلك الحقول ليتولى express ترجمتها إلى الكائن answers وقيمته مصفوفة من كائنات يحوي كل منها الحقل question لنص السؤال والحقل answer للجواب المقابل لذلك السؤال، ليكون ملف قالب صفحة الأسئلة كالتالي: <html lang="ar"> <head> <link rel="stylesheet" href="style.css" /> <title>اختبرني | الاختبار</title> </head> <body> <form action="result" method="post"> <% questions.forEach((question, index) => { %> <p dir="auto"><%- question %></p> <input type="hidden" name="answers[<%= index %>][question]" value="<%- question %>" /> <input type="text" name="answers[<%= index %>][answer]" /> <% }) %> <button type="submit">عرض النتيجة</button> </form> </body> </html> والصفحة الأخيرة لعرض النتيجة، حيث سنمرر لقالب العرض القيمة results وهي مصفوفة من كائنات نتائج الأسئلة، يحوي كل منها على الحقل question لنص السؤال والحقل answer للجواب المدخل من قبل المستخدم سنضعه كقيمة لحقل input مع الخاصية readonly لمنع تعديله، والحقل المنطقي correct يعبر عما إذا كان الجواب صحيحًا أم لا، وأخيرًا الحقل note والذي سنعرضه في حال كان الجواب خاطئًا ويحوي على ملاحظة من قبل ChatGPT عن الإجابة الصحيحة، وأخيرًا رابط للصفحة الرئيسية لطلب اختبار جديد كالتالي: <html lang="ar"> <head> <link rel="stylesheet" href="style.css" /> <title>اختبرني | النتيجة</title> </head> <body> <% results.forEach((result, index) => { %> <div class="result"> <p dir="auto"><%- result.question %></p> <input type="text" value="<%= result.answer %>" readonly class="<% if(result.correct){ %> correct <% } else { %> wrong <% } %>"/> <% if(!result.correct) { %> <div class="wrong"><%= result.note %></div> <% } %> </div> <% }) %> <a href="/">اختبار جديد</a> </body> </html> وقبل أن نعاين الصفحات يجب أن نضيف تعليمة تشغيل خادم الويب بنهاية الملف bin/www على منفذ محدد نستخرجه من متغيرات البيئة كالتالي: // رقم المنفذ من متغيرات البيئة const port = process.env.PORT; // تشغيل خادم الويب app.listen(port, () => console.log(`Listening on http://localhost:${port}`)) ولتحميل متغيرات البيئة من ملف env. نضعه ضمن مجلد المشروع مباشرةً نستخدم المكتبة dotenv بإضافة التعليمة التالية في بداية نفس الملف لتحميل القيم من env. وتعيينها كمتغيرات بيئة مباشرةً كالتالي: #!/usr/bin/env node // تحميل متغيرات البيئة require('dotenv').config() ... وننشئ الملف env. ونعرف ضمنه القيمة PORT بأي رقم منفذ نريده وليكن 3000: PORT=3000 ونُعرّف ضمن ملف تعريف الحزمة package.json النص البرمجي start لتشغيل الخادم ضمن القيمة scripts كالتالي: "scripts": { "start": "node bin/www" }, لتنسيق جميع الصفحات يمكن التعديل على الملف public/style.css ولن نعرض محتواه اختصارًا، وبعد التعديل عليه لتنسيق الصفحات يمكن معاينتها بتشغيل الخادم بتنفيذ التعليمة التالية بطرفية ضمن مجلد المشروع: npm start نزور الصفحة الرئيسية على الرابط المعروض بعد تشغيل الخادم: ندخل أي قيمة ضمن الصفحة السابقة لنعاين صفحة عرض الأسئلة لنشاهد التالي: ونضغط عرض النتيجة لنعاين صفحة عرض النتيجة النهائية كالتالي: بعد أن جهزنا ملفات المشروع بالكامل والصفحات المطلوبة أصبح جاهزًا الآن لربطه مع ChatGPT لتوليد المحتوى المطلوب وعرضه وهو ما سنبدأ به في الفقرات التالية. تحضير الربط مع ChatGPT قبل أن نتمكن من التعامل مع الواجهة البرمجية لنموذج ChatGPT علينا التحضير بعدة خطوات، أولًا عبر تسجيل حساب مدفوع ضمن موقع شركة OpenAI، ومنه توليد مفتاح واجهة برمجية جديد ثم نسخه إلى ملف env. ضمن المشروع وتحديده كقيمة للمفتاح OPENAI_API_KEY كالتالي: ... OPENAI_API_KEY=<قيمة المفتاح> وضمن الملف نستخدم المكتبة openai التي ثبتناها في بداية المقال ونُنشئ كائن جديد من الصنف الذي توفره OpenAIApi ونمرر له الإعدادات المناسبة مع قيمة المفتاح السابق من متغيرات البيئة في بداية الملف كالتالي: ... const { OpenAIApi, Configuration } = require("openai"); const openai = new OpenAIApi( new Configuration({ apiKey: process.env.OPENAI_API_KEY }) ) يمكننا الآن استخدام الثابت openai للتعامل مع الواجهات البرمجية التي توفرها OpenAI وتحديدًا نموذج ChatGPT وهو ما سنبدأ بالتعامل معه في الفقرة التالية. توليد أسئلة الاختبار كل ما علينا الآن هو تعديل توابع معالجة الطلبات المرسلة والطلب من نموذج ChatGPT توليد بعض الأسئلة عن الموضوع الذي أرسله المستخدم من الصفحة الرئيسية إلى المسار test/ باستخراج قيمة موضوع الاختبار ضمن تابع معالجة الطلب كالتالي: app.post('/test', async (req, res) => { // استخراج موضوع الاختبار const { subject } = req.body ... }) نحدد التعليمة التي سنرسلها إلى النموذج، وهي أهم خطوة في تلك العملية، فالتعليمة الواضحة والجيدة ينتج عنها النتيجة التي نريدها وفي حالتنا سنخبر النموذج بتوليد بعض الأسئلة عن الموضوع السابق وشكل التعليمة سيكون كالتالي: نلاحظ كيف حددنا شكل الخرج الذي نريده وهو أن يكتب كل سؤال ضمن سطر لنتمكن من استخراجه، ويمكننا تحديد شكل الخرج بطريقة متقدمة سنتعرف عليها لاحقًا أما حاليًا يمكننا فصل الجواب الناتج من النموذج إلى الأسطر المكونة له واعتبار كل سطر هو سؤال، ونبني التعليمة السابقة وندرج ضمنها قيمة الموضوع المرسل ونستخدم الثابت openai لإرسال رسالة إلى النموذج gpt-3.5-turbo وهو النسخة المتاحة دون اشتراك شهري وقت كتابة هذا المقال، حيث تحوي الرسالة على التعليمة السابقة، ثم نستخرج من الجواب قيمة الرسالة المُرسلة من النموذج ليصبح تابع معالجة طلب توليد أسئلة عن موضوع معين كالتالي: app.post('/test', async (req, res) => { // استخراج موضوع الاختبار const { subject } = req.body // بناء التعليمة const prompt = `أكتب أربعة أسئلة يمكن الاجابة عليها بجواب قصير لاختبار مستوايي في ${subject}، الأسئلة كل سؤال بسطر:`; // إرسال طلب إلى النموذج const response = await openai.createChatCompletion({ model: 'gpt-3.5-turbo', messages: [ { role: 'user', content: prompt } ] }) // استخراج الجواب const message = response.data.choices[0].message.content // استخراج الأسئلة المولدة من الجواب const questions = message.split('\n') // تمرير الأسئلة المقترحة لصفحة الاختبار res.render('test', { questions }); }) وفي الفقرة التالية سنستقبل الأجوبة من المستخدم ونُقيمها باستخدام ChatGPT مجددًا ونعرض النتيجة للمستخدم. إرسال الإجابات للتقييم بعد إدخال الإجابات في صفحة الاختبار وإرسالها إلى مسار عرض النتيجة result/ يمكننا ضمن ذلك المسار استقبال الإجابات من الكائن answers من جسم الطلب: app.post('/result', async (req, res) => { // استخراج الإجابات const { answers } = req.body ... }) قيمة ذلك المتغير ستكون مصفوفة من كائنات يحوي كل منها على نص السؤال ضمن الحقل question والجواب المُدخل من المستخدم answer، والتي سنضمنها ضمن التعليمة المُرسلة إلى ChatGPT لتقييمها، وبما أن التقييمات لكل سؤال نريدها أن تحوي معلومات عن صحة الجواب وملاحظة في حال كان خاطئًا، فيمكننا الطلب من ChatGPT إعادة الجواب بصيغة JSON ليسهل علينا استخراج المعلومات منه وعرضها للمستخدم ضمن التطبيق، وذلك بإعطاء مثال عن شكل الخرج في نهاية التعليمة ليكون شكل التعليمة النهائي كالتالي: قيم الإجابات السابقة مع الشرح بصيغة JSON التالية: [{correct: false, note:"تعليل أو ملاحظة حول الإجابة...."}، ...] نبني تلك التعليمة من الأجوبة المرسلة كالتالي: const { answers } = req.body // الأسئلة مع الأجوبة const questionsAndAnswers = answers .map(({ question, answer }) => `السؤال: ${question}\nالجواب: ${answer}`) .join('\n\n') // بناء التعليمة const prompt = `${questionsAndAnswers}\n\nقيم الإجابات السابقة مع الشرح بصيغة JSON التالية: [{correct: false, note:"تعليل أو ملاحظة حول الإجابة...."}، ...]`; ثم نرسلها إلى ChatGPT كما فعلنا سابقًا والفرق هذه المرة في معالجة الجواب حيث سنترجمه من صيغة JSON إلى مصفوفة في جافاسكريبت باستخدام التابع JSON.parse // إرسال التعليمة const response = await openai.createChatCompletion({ model: 'gpt-3.5-turbo', messages: [ { role: 'user', content: prompt } ] }) // استخراج الجواب const message = response.data.choices[0].message?.content // معالجة الجواب const results = JSON.parse(message) والآن نعرضها ضمن قالب العرض result.ejs باستخدام التابع renderمع تمرير نص السؤال والجواب المدخل من المستخدم وتقييم الجواب والملاحظة حوله كالتالي: // عرض النتيجة res.render('result', { results: results.map((result, index) => ({ question: answers[index].question, answer: answers[index].answer, note: result.note, correct: result.correct, })), }) وبذلك يصبح التطبيق جاهزًا للاختبار سنستعرضه ضمن الفقرة التالية. اختبار التطبيق لنحاول الإجابة على بعض الأسئلة المتعلقة بالبرمجة في نود لاختبار المستوى: نلاحظ اقتراح أسئلة متنوعة عن ذلك الموضوع، لنحاول الإجابة عليها باللغة العربية وترك الجواب الأخير خاطئًا: عاين ChatGPT تلك الأجوبة وحدد الصحيح والخاطئ منها بفهم النص المكتوب وربطه بسؤاله بدقة وحدد الجواب الأخير بأنه خاطئ وأعطى ملاحظة عن سبب الخطأ: خاتمة كما رأينا سهولة التعامل مع ChatGPT والاحتمالات الواسعة الممكنة ضمنه، من توليد محتوى محدد إلى قراء وفهم مدخلات المستخدم إلى إمكانية تحديد شكل الخرج المطلوب لتسهيل التعامل معه برمجيًا، ويمكن التطوير على التطبيق الذي طورناه في هذا المقال بعدة أفكار، فمثلًا يمكن تحديد عدد الأسئلة من قبل المستخدم والطلب من ChatGPT ذلك العدد من الأسئلة، أو يمكن حفظ سجل الأسئلة المجاب عنها من قبل المستخدم وإرسالها مع طلب توليد الأسئلة الجديدة والطلب منه أن تكون الأسئلة مختلفة في مواضيعها عن السابقة ما يغني تجربة المستخدم، أو إذا كان موضوع الأسئلة محددًا يمكن توليد العديد من أسئلة اختيار من متعدد عن ذلك الموضوع دفعة واحدة مع تحديد الإجابة الصحيحة لكل سؤال ثم تخزينها ضمن قاعدة بيانات أسئلة كبيرة وتُعرض للمستخدم عشوائيًا كي يتمرن عليها ونحدد مستواه وبذلك لا داعي للاتصال مع النموذج خلال مرحلة الإنتاج ونستفيد منه لتوليد محتوى الأسئلة فقط. اقرأ أيضًا برمجة تطبيق 'لخصلي' لتلخيص المقالات باستخدام ChatGPT ولارافل تطوير تطبيق 'وصفة' لاقتراح الوجبات باستخدام ChatGPT و DALL-E في PHP
  4. يسعى مجال الذكاء الاصطناعي إلى محاكاة ذكاء البشر في قدرتهم على تحليل المعطيات الحسية كالصورة والأصوات واستنتاج المعلومات المفيدة منها، وبينما يُمثل البشر تلك المعطيات بيولوجيًا طور علماء الرياضيات والحاسوب طرقًا لتمثيل ومعالجة تلك المعطيات رقميًا لنتمكن من معالجتها بخوارزميات رياضية ضمن الحاسوب، حيث يمكن تدريب نماذج الذكاء الاصطناعي على البيانات لتتمكن محاكاة ذكاء البشر في مجال محدد، أحد أنواع تلك النماذج هي نماذج اللغة الكبيرة LLM's (أو Large Language Models) وهي نماذج دُربت على كميات كبيرة من النصوص فامتلكت القدرة على توليد نصوص مشابهة لها وبل حتى فهم نصوص جديدة لم تشاهدها ضمن بيانات التدريب من قبل. من نماذج اللغة الكبيرة النموذج ChatGPT من شركة OpenAI والذي دُرّب على كمية كبيرة من النصوص الموجودة على شبكة الانترنت وطوّر ليستجيب إلى الأوامر المرسلة له من قبل المستخدم، مما يجعل هذا النموذج قادرًا على محاكاة تلك النصوص وتحديد النقاط الرئيسية فيها والرد عليها بردود كما لو أنها مكتوبة من قبل إنسان، لذا يمكن الاستفادة من مرونة التعامل معه وفهمه للأوامر باللغة الطبيعية في العديد من التطبيقات العملية، كتوليد المحتوى أو التعديل على نص معين أو التلخيص واستخراج النقاط الرئيسية من نص ما والكثير من الأفكار الأخرى، أي يمكن اعتبار تلك النماذج كمساعد ذكي يمكن طلب أي مهمة منه كما لو كنا نطلبها من شخص حقيقي، وأهم ما في تلك النماذج هو سهولة برمجتها نسبيًا، فلم نعد بحاجة لتعلم لغة برمجة مخصصة بل يمكننا التعامل معها باللغة الطبيعية وبعدة لغات أيضًا منها اللغة العربية كما سنرى لاحقًا. وفي هذا المقال سنستفيد من قدرة ذلك النموذج على فهم النصوص وإعادة صياغتها وتلخيصها في تلخيص مقالات من الإنترنت، حيث سنبني تطبيق ويب باستخدام لارافل Laravel لجلب محتوى المقال الذي يرغب المستخدم في تلخيصه، ثم الطلب من نموذج ChatGPT تلخيص ذلك المقال للمستخدم، ولمتابعة هذا المقال يجب أن تملك خبرة أساسية في لغة PHP عمومًا وإطار لارافل خصوصًا. دورة تطوير تطبيقات الويب باستخدام لغة PHP احترف تطوير النظم الخلفية وتطبيقات الويب من الألف إلى الياء دون الحاجة لخبرة برمجية مسبقة اشترك الآن إنشاء مشروع لارافل جديد وبناء الواجهات الأمامية يتألف مشروعنا بشكل عام من صفحتين رئيسيتين الأولى يدخل فيها المستخدم رابط المقال الذي يريد تلخيصه، والثانية يظهر له فيها الملخص لذلك المقال بعد أن يجلب التطبيق صفحة المقال من على الأنترنت ويستخرج محتوى المقال ويرسلها إلى نموذج ChatGPT لتلخيصها كما سنرى بالتفصيل لاحقًا، ولنبدأ أولًا بإنشاء مشروع وليكن بالاسم summarizer عبر تنفيذ الأمر التالي ضمن الطرفية والذي سيُنشئ مجلد جديد باسم المشروع يحوي هيكلية الملفات الأساسية لمشروع لارافل جديد: composer create-project laravel/laravel summarizer نحتاج لهذا المشروع صفحتين، الصفحة الأولى لإدخال رابط المقال المُراد تلخيصه وتحوي على نموذج form بسيط يرسل القيم بداخله بالطريقة POST إلى المسار summary/ والذي سنُعرفه لاحقًا، ويحوي النموذج على حقل لإدخال الرابط بالاسم url وزر الإرسال ولا ننسى تضمين قيمة الحقل csrf ضمن النموذج، وننشئ للصفحة ملف جديد بصيغة قالب blade جديدة ضمن المسار التالي resources\views\index.blade.php يحوي التالي: <head> <title>لخصلي</title> <link rel="stylesheet" href="style.css"> </head> <body> <h1>✍?</h1> <form action="/summary" method="POST"> @csrf <input type="url" name="url" placeholder="أدخل رابط المقال"> <button type="submit">لخصلي</button> </form> </body> والصفحة الثانية هي لعرض نتيجة التلخيص، تحوي على الملخص ورابط للمقال الأصل في حال أراد المستخدم قراءته ورابط للرجوع للصفحة الرئيسية لطلب تلخيص جديد، ونُنشئ ملف قالب تلك الصفحة ضمن المسار resources\views\summary.blade.php ويحوي التالي: <head> <title>لخصلي</title> <link rel="stylesheet" href="style.css"> </head> <body> <h2>ملخص المقال</h2> <p>{{ $summary }}</p> <footer> <a href="{{$url}}" target="_blank">قراءة المقال</a> <a href="/">تلخيص مقال جديد</a> </footer> </body> نلاحظ ربط ملف تنسيقات CSS بالاسم style.css في كلا الصفحتين لتنسيق محتواهما، ونُنشئ ذلك الملف ضمن المسار public\style.css ويحوي التنسيق التالي: body { direction: rtl; display: flex; flex-direction: column; max-width: 60ch; justify-items: center; align-items: center; font-size: x-large; margin: 0 auto; padding: 20vh 10vw; background-color: #f9f9f9; color: #121212; font-family: system-ui; } p { line-height: 2; text-align: center; border: .25rem solid; padding: 3rem; white-space: pre-line; } a { padding: 1rem; font-size: inherit; margin: 0 .5rem; color: darkblue; } footer { margin-top: 2rem; } form { display: flex; flex-direction: column; gap: 2rem; text-align: center; } button { background-color: #121212; color: #f9f9f9; border: none; padding: 1rem 2rem; font-size: inherit; cursor: pointer; font-family: inherit; } input { padding: 1rem 2rem; font-size: inherit; font-family: inherit; text-align: center; border: .2rem solid; } نعرف ضمن ملف التوجيه routes\web.php مسارين الأول لعرض صفحة الإدخال نعيد فيها قالب الصفحة الأولى، والمسار الثاني summary/ لاستقبال طلبات HTTP من نوع POST نستخرج ضمنه قيمة الرابط url المُدخل من قبل المستخدم ويلخص ذلك المقال ثم يعرض النتيجة ضمن قالب الصفحة الثانية ليكون محتوى الملف كالتالي: <?php use Illuminate\Http\Request; use Illuminate\Support\Facades\Route; // صفحة الإدخال Route::view('/', 'index'); // صفحة عرض التلخيص Route::post('/summary', function (Request $request) { $url = $request->input('url'); return view('summary', [ 'url' => $url, 'summary' => 'ملخص المقال هنا' ]); }); والآن يمكننا استعراض الصفحتين بتشغيل خادم التطوير أولًا باستخدام الأمر التالي: php artisan serve واستعراض الصفحة الرئيسية: وإدخال أي رابط ضمن تلك الصفحة وطلب تلخيصه لنستعرض صفحة النتيجة: بعد أن جهزنا المشروع الجديد والصفحات وعملية إرسال طلب تلخيص جديد سنبدأ في الفقرات التالية تضمين عملية جلب محتوى المقال المطلوب ثم تلخيصه باستخدام ChatGPT. جلب محتوى المقال نبدأ بإنشاء صنف جديد بالاسم Article ضمن المسار app\Article.php والذي سيكون مسؤولًا عن جلب محتوى المقال عن طريق الرابط له، ويحوي على التابع fromURL والذي يقبل رابط المقال كمعامل أول ويعيد نص المقال كسلسلة نصية، ويُنفذ ذلك باستخدام الصنف المساعد HTTP الذي يتيحه لارافل لإرسال طلب من نوع GET لجلب محتوى صفحة المقال كاملةً، ثم الاستعانة بالصنف DOMDocument لتحليل محتوى HTML من تلك الصفحة واستخراج المحتوى النصي لعناصر الفقرات ذات الوسم p والتي تحوي عادةً المحتوى النصي للمقال، ونجمع محتوى تلك الفقرات معًا في سلسلة نصية لتكون المحتوى النصي للمقال كاملًا ضمن الصفحة كالتالي: <?php namespace App; use DOMDocument; use Illuminate\Support\Facades\Http; class Article { public function fromURL($url): string { // جلب محتوى الصفحة $html = Http::withHeaders(['User-Agent' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36']) ->get($url) ->body(); // استخراج الفقرات $document = new DOMDocument(); @$document->loadHTML($html); $paragraphs = $document->getElementsByTagName('p'); // جمع محتوى الفقرات معًا $article = ''; foreach ($paragraphs as $paragraph) { $article = trim($article . "\n\n" . $paragraph->textContent); } return $article; } } أضفنا للطلب المُرسل الترويسة User-Agent والتي تتطلبها بعض المواقع لإرسال محتوى الصفحة، ونلاحظ أيضًا إضافة العلامة @ قبل تحميل محتوى الصفحة باستخدام التابع loadHTML لتجنب بعض الأخطاء التي قد تحدث عند محاولة تفسير محتوى الصفحة، ولاستخدام ذلك الصنف يمكننا تمريره كمعامل لتابع معالجة مسار صفحة النتيجة ليُنشئ لارافل تلقائيًا كائنًا جديدًا من ذلك الصنف ويمرره لتابع المسار لنتمكن من استخدامه لجلب محتوى المقال من الرابط المُرسل كالتالي: use App\Article; ... // صفحة عرض التلخيص Route::post('/summary', function (Request $request, Article $article) { $url = $request->input('url'); // جلب محتوى المقال $content = $article->fromURL($url); return view('summary', [ 'url' => $url, 'summary' => 'ملخص المقال هنا' ]); }); وفي الفقرة التالية سنرسل ذلك المحتوى إلى ChatGPT لتلخيصه ثم عرضه للمستخدم. تلخيص محتوى المقال باستخدام ChatGPT بعد أن استخرجنا محتوى المقال كاملًا يمكننا إرساله إلى ChatGPT محاطًا بتعليمة نخبر بها النموذج بأننا نريد ملخص قصير عن ذلك النص، ولكن نماذج اللغة الكبيرة مثل ChatGPT تملك حد أقصى من طول المحتوى المُرسل إليها وهو 4097 رمز (أو token) بحسب التوثيق الرسمي للنموذج، والرمز هو قطعة من النص يحدد طولها بكلمة أو عدة أحرف أو عدة كلمات أحيانًا، أي في حال كان المقال طويل وعدد الرموز المكونة له أكبر من الحد الأقصى لن نتمكن من إرساله دفعة واحدة، ويمكن الاطلاع من خلال أداة توفرها الشركة على حساب تلك الرموز من أي نص. ويمكن حل المشكلة الحد الأقصى للرموز بعدة طرق والطريقة التي سنستخدمها هي تقسيم نص المقال إلى عدة مقاطع أقصر، ثم تلخيص كل مقطع منها على حدى وجمعها معًا للحصول على ملخص المقال كاملًا، وفي حال كان ذلك الملخص أطول مما نرغب بعرضه للمستخدم نعيد تلخيص الملخص نفسه مجددًا للحصول على ملخص أقصر، ونكرر ذلك حتى الحصول على ملخص بطول مناسب للمقال كاملًا، وانتبه إلى أن هذه الطريقة اعتمدناها فقط لأغراض تعليمية وقد لا تعطي نتائج جيدة لذا ابحث عن طريقة أفضل لحل هذه المشكلة. نكمل العمل بإنشاء صنف جديد بالاسم Summary ضمن المسار app\Summary.php سيحوي على عدة لتقسيم وتلخيص النصوص سنشرحها تباعًا: <?php namespace App; class Summary { ... } التابع الرئيسي لتلخيص المقال اسمه toWords وهو يستقبل النص المراد تلخيصه وعدد يعبر عن عدد الكلمات الأقصى للملخص النهائي لذلك النص، بحيث يكون ذلك التابع مسؤولًا عن تلخيص النص باستخدام التابع summarize الذي سنعرفه لاحقًا، ثم التحقق من عدد كلمات الملخص وتكرار عملية التلخيص إن لزم الأمر إلى أن نحصل على ملخص نهائي بالطول المناسب: class Summary { public function toWords(int $at_most, string $text) { // تلخيص أولي للنص $summary = $this->summarize($text); // تكرار عملية التلخيص حسب الطول المطلوب while (count(explode(" ", $summary)) > $at_most) $summary = $this->summarize($summary); return $summary; } public function summarize(string $text): string { ... } } ونستدعي ذلك التابع ضمن تابع معالجة بعد تعريفه ضمن المعاملات في ملف التوجيه routes/web.php لتلخيص محتوى المقال بعد استخراجه إلى عدد كلمات مناسب وليكن 150 كلمة وتمرير الملخص إلى قالب الصفحة لعرضه للمستخدم كالتالي: // صفحة عرض التلخيص Route::post('/summary', function (Request $request, Article $article, Summary $summarizer) { $url = $request->input('url'); // جلب محتوى المقال $content = $article->fromURL($url); // تلخيص المقال $summary = $summarizer->toWords(100, $content); return view('summary', [ 'url' => $url, 'summary' => $summary ]); }); التابع summarize ضمن الصنف Summary مهمته تجزئة النص إلى فقرات بطول مناسب لإرسالها إلى ChatGPT للتلخيص، حيث نبدأ بتجزئة النص إلى فقراته التي يفصل بينها سطر فارغ، ثم تجميعها إلى مجموعات ولتكن مؤلفة من 8 فقرات معًا، بعدها نطلب تلخيص كل مجموعة على حدى، وبما طلب تلخيص كل مجموعة لا يتعلق بالأخرى فيمكننا إرسال طلبات التلخيص لتلك المجموعات معًا على التوازي لاختصار وقت التلخيص الكلي، فلا داعي في طريقتنا لانتظار تلخيص أول فقرة حتى نلخص التي تليها، وننفذ ذلك باستخدام التابع pool من الصنف المساعد في لارافل HTTP والذي نمرر له تابعًا يقبل معامل من النوع Pool والذي يعبر عن مجموعة من طلبات HTTP ستُرسل معًا على التوازي، توليد الطلب الواحد سنوكله لتابع منفصل بالاسم summaryRequest، وبعد انتهاء كل الطلبات نستخرج منها الملخصات من مفتاح JSON في المسار choices.0.message.content باستخدام التابع json من كل طلب منها، ثم نضمها معًا مجددًا لتشكل الملخص لكل الفقرات المرسلة: class Summary { ... public function summarize(string $text) { // الفاصل بين الفقرات $seperator = "\n\n"; // فصل النص إلى فقرات بطول مناسب $paragraphs = collect(explode($seperator, $text)) ->chunk(8) ->map(fn ($chunks) => $chunks->join($seperator)); // إرسال طلبات التلخيص على التوازي $responses = Http::pool(fn (Pool $pool) => $paragraphs->map( fn (string $paragraph) => $this->summaryRequest($pool, $paragraph) )); // استخراج تجميع الملخصات معًا return collect($responses) ->map(fn ($response) => $response->json('choices.0.message.content')) ->join($seperator); } protected function summaryRequest(Pool $pool, string $text) { ... } } ضمن التابع summaryRequest سنرسل الطلب باستخدام pool$ إلى ChatGPT لتلخيص محتوى الفقرة text$ المٌمررة له، وإرسال أي طلب للواجهة البرمجية الخاصة به تحتاج منا أولًا الحصول على مفتاح استيثاق يمكن توليده بعد إنشاء حساب جديد ضمن موقع الشركة المالكة للنموذج OpenAI وإكمال إعدادات الحساب وتعيين وسيلة الدفع ضمنه، وبعد توليد المفتاح نضعه ضمن ملف متغيرات البيئة env. ضمن مفتاح بالاسم OPENAI_API_KEY ضمن ملفات المشروع لنتمكن من اختبار إرسال الطلبات محليًا كالتالي: ... OPENAI_API_KEY=<مفتاح الاستيثاق> وبحسب صفحة التوثيق الخاصة بتلك الواجهة البرمجية فيجب أن نضع ذلك المفتاح ضمن قيمة الترويسة Authorization يسبقها الكلمة Bearer ويفصل بينهما مسافة، ويمكننا استخراج قيمة المفتاح السابق باستخدام التابع env من لارافل، ويُرسل طلب HTTP بالنوع POST إلى نموذج المحادثة ChatGPT إلى مسار الواجهة البرمجية https://api.openai.com/v1/chat/completions، وضمن جسم الطلب نحدد قيمتين، الأولى هي اسم النموذج ضمن المفتاح model في حالتنا هو gpt-3.5-turbo، والقيمة الثانية هي messages تحوي تاريخ الرسائل الواقعة بين المستخدم والنموذج سابقًا، وفي حالتنا نحتاج رسالة مستخدم واحدة تحوي تعليمات للنموذج بتلخيص الفقرة ضمن تلك الرسالة وصيغتها كالتالي: سيفهم النموذج التعليمة السابقة ويرد برسالة تحوي تلخيص للفقرة المذكورة، ليكون بذلك تابع تلخيص الفقرة summaryRequest كالتالي: protected function summaryRequest(Pool $pool, string $text) { return $pool ->withHeaders(['Authorization' => "Bearer " . env('OPENAI_API_KEY')]) ->post('https://api.openai.com/v1/chat/completions', [ 'model' => 'gpt-3.5-turbo', 'messages' => [ ['role' => 'user', 'content' => implode("\n", [ "لخص الفقرة التالية من المقال تلخيص دقيق:", $text, "التلخيص:" ])] ], ]); } بذلك يكون تضمين صنف التلخيص Summary جاهزًا سنختبره في الفقرة التالية ونرى نتيجة تلخيصه. اختبار التطبيق لنختبر التطبيق بتلخيص مقال من موقع أكاديمية حسوب عن الذكاء الاصطناعي بإدخال رابطه ضمن صفحة الإدخال وطلب التلخيص: نلاحظ أن الملخص يحوي ذكر لمعظم الأفكار التي يغطيها المقال ما يعطي صورة عامة عنه، ولنختبره مجددًا بتلخيص جديد من أكاديمية حسوب عن تعلم البرمجة: يمكن التطوير على التطبيق من عدة نواحي، فمثلًا يمكن أن نوفر للمستخدم خيارات لإدخال محتوى المقال عن طريق رابط مثلًا أو نسخ المحتوى مباشرةً، أو أن نسمح للمستخدم بتحديد طول الملخص الذي يرغب به، أو الطلب من النموذج كتابة الملخص على شكل نقاط رئيسية، أو تحديد لغة النتيجة قبل عرضها للمستخدم، وهناك العديد من الأفكار المفيدة التي يمكن تطبيقها بالاستفادة من نماذج اللغة كنموذج ChatGPT وميزاته بفهم اللغة الطبيعية بلغات متعددة. دورة الذكاء الاصطناعي احترف برمجة الذكاء الاصطناعي AI وتحليل البيانات وتعلم كافة المعلومات التي تحتاجها لبناء نماذج ذكاء اصطناعي متخصصة. اشترك الآن اقرأ أيضًا تطوير تطبيق 'وصفة' لاقتراح الوجبات باستخدام ChatGPT و DALL-E في PHP تصنيف الصور والتعرف على الوجه في مجال الذكاء الاصطناعي دليلك الشامل إلى: برمجة التطبيقات دليلك الشامل إلى: لغة PHP
  5. كثيرًا ما نحتار في اختيار وجبة طعام اليوم لتحضيرها، أو قد تتوفر لدينا بعض المكونات التي نريد تحضير وصفة ما منها ونحتار في اختيار الوصفة المناسبة، فيمكننا البحث عبر الإنترنت عن وصفات معينة واختيار الأنسب منها، لكن ماذا لو استطاع الذكاء الاصطناعي اختيار الوجبة لنا ووصف طريقة تحضيرها بل وحتى تخيل شكل الطبق النهائي، ففي هذا المقال سنستفيد من قدرات الذكاء الاصطناعي في فهم اللغة الطبيعية وقدرته على توليد المحتوى النصي والبصري لبناء تطبيق نُخبره بالمكونات الموجودة لدينا ومن أي مطبخ نُفضل أن تكون الوصفة وسيقترح لنا وصفة مناسبة مع شرح طريقة تحضيرها، حيث سنستخدم لتطويره لغة PHP وبعض نماذج الذكاء الاصطناعي التي توفرها شركة OpenAI. نماذج الذكاء الاصطناعي واستخداماتها تتميز نماذج الذكاء الاصطناعي بسرعة معالجة وتحليل المعلومات والطيف الواسع من القدرات الكامنة ضمنها، حيث يمكن للنموذج بعد تدريبه تكوين فهمًا جيدًا عن البيانات وبالتالي يستطيع توليد أو التعامل مع بيانات جديدة لم يراها سابقًا، فمثلًا نموذج GPT (اختصارًا لعبارة المحول التوليدي مسبق التدريب Generative Pre-Trained Transformer) المطور من قبل شركة OpenAI دُرّب على كمية كبيرة من البيانات النصية فكون فهم جيد عن اللغات البشرية بدءًا من صياغتها إلى تراكيب الجمل وصولًا إلى المعنى وراء النص، فأصبح بإمكانه إكمال كتابة النصوص كما لو كان من كتبها إنسان وهي وظيفته الأساسية، ونموذج DALL-E المطور من قبل نفس الشركة تم تدريبه على كمية كبيرة من الصور وتوصيفاتها فتكون ضمنه فهم وربط بين النصوص ومحتوى الصور، وبذلك أصبح قادرًا على توليد صور أقرب ما تكون إلى الطبيعية بناءً على توصيف نصي لها. في هذا المقال سنحاول حل مشكلة الحيرة في اختيار وجبة الطعام عبر تطوير تطبيق لاقتراح الوصفات باستخدام لغة البرمجة PHP، وسنستفيد من النموذج ChatGPT في اقتراح الوصفة على المستخدم بحسب ما يريد وشرح طريقة تحضيرها، ومن النموذج DALL-E لتوليد صورة تخيلية لطبق من تلك الوصفة، أي سيكون محتوى التطبيق مولّد بالكامل من قبل نماذج الذكاء الاصطناعي. دورة تطوير تطبيقات الويب باستخدام لغة PHP احترف تطوير النظم الخلفية وتطبيقات الويب من الألف إلى الياء دون الحاجة لخبرة برمجية مسبقة اشترك الآن تحضير ملفات المشروع وتطوير واجهة المستخدم سنحتاج بدايةً لبيئة PHP مثبتة وتعمل على نظام التشغيل، ويمكن تنزيل النسخة المناسبة من الموقع الرسمي لها ثم تثبيته على الجهاز، وللتأكد من صحة التثبيت يمكن تنفيذ الأمر التالي ضمن سطر الأوامر للتحقق من رقم النسخة المثبتة: php -v سيظهر معلومات عن رقم النسخة، ويفضل استخدام النسخة 7.4 أو أعلى، ونبدأ بإنشاء ملف جديد سيحتوي على ملفات المشروع وليكن بالاسم recipe-php، وننشئ ضمنه الملفات التالية: index.php ملف الصفحة الرئيسية suggestion.php ملف صفحة عرض النتيجة style.css ملف تنسيقات CSS لتكون بنية المجلد والملفات ضمنه كالتالي: recipe-php/ ├─ index.php ├─ suggestion.php ├─ style.css ملاحظة: تحتاج إلى أن تملك خبرة أساسية بلغة PHP، وإن كنت جديدًا عليها، فارجع إلى مقال تمهيد إلى لغة PHP ومقال الدليل السريع إلى لغة البرمجة PHP للتعرف على أساسيات اللغة. نبدأ ببناء صفحة الموقع الرئيسية ضمن الملف index.php، وفيها سنطلب من المستخدم إدخال معلومات حول الوصفة، كاختيار المطبخ الذي تنتمي إليه وكتابة بعض المكونات التي قد تكون لدى مستخدم التطبيق ويريد تحضير وجبة طعامه منها، ونبدأ بربط ملف التنسيقات style.css في بداية الملف باستخدام العنصر link، ثم نموذجًا باستخدام العنصر form سيرسل محتوياته إلى ملف صفحة النتيجة suggestion.php بالطريقة POST، ويحوي على حقل اسم المطبخ للوجبة المقترحة نضع فيها خيارات مسبقة مثل (سعودي - سوري - مغربي - يمني - مصري)، ثم حقل نصي اختياري يدخل فيه المستخدم المكونات التي لديه وز لإرسال الطلب، ليصبح ملف الصفحة كالتالي: <!-- index.php --> <head> <!-- استيراد ملف التنسيقات --> <link rel="stylesheet" href="style.css"> <!-- عنوان الصفحة --> <title>تطبيق وصفة</title> </head> <div class="logo">??‍?</div> <form action="suggestion.php" method="post" dir="rtl"> <!-- اختيار المطبخ --> <fieldset> <legend>المطبخ</legend> <input type="radio" name="cuisine" id="cuisine_SA" value="سعودي" required> <label for="cuisine_SA">?? سعودي</label> <input type="radio" name="cuisine" id="cuisine_SY" value="سوري" required> <label for="cuisine_SY">?? سوري</label> <input type="radio" name="cuisine" id="cuisine_MA" value="مغربي" required> <label for="cuisine_MA">?? مغربي</label> <input type="radio" name="cuisine" id="cuisine_YE" value="يمني" required> <label for="cuisine_YE">?? يمني</label> <input type="radio" name="cuisine" id="cuisine_EG" value="مصري" required> <label for="cuisine_EG">?? مصري</label> </fieldset> <!-- مكونات الوصفة --> <div> <label for="ingredients">المكونات</label> <input type="text" name="ingredients" id="ingredients" placeholder="هل لديك مكونات محددة؟ مثال: رز بصل ..."> </div> <!-- إرسال المدخلات --> <button type="submit">اقترح وصفة ?</button> </form> نتوجه الآن لملف عرض النتيجة suggestion.php ونحضر فيه قالب عرض النتيجة، المكون من اسم الوصفة المقترحة وصورة لها ووصف سيحوي على المكونات وطريقة التحضير، وفي النهاية زر للرجوع للصفحة الرئيسية في حال رغب المستخدم اقتراح وصفة جديدة، ولا ننسى ربط ملف التنسيقات style.css في بداية الصفحة كما فعلنا سابقًا، ونحضر بعض المتغيرات الفارغة مبدأيًا سنضع فيها محتويات الصفحة بعد أن تولدها لنا نماذج الذكاء الاصطناعي في الفقرة التالية، ليصبح ملف صفحة النتيجة كالتالي: <!-- suggestion.php --> <?php $name = ''; // اسم الوصفة $recipe = ''; // المكونات وطريقة التحضير $image_url = ''; // رابط صورة الوصفة ?> <head> <!-- استيراد ملف التنسيقات --> <link rel="stylesheet" href="style.css"> <!-- عنوان الصفحة --> <title>اقتراح الوصفة</title> </head> <main class="suggestion"> <!-- اسم الوصفة --> <h2><?= $name ?></h2> <!-- صورة للوصفة --> <img src="<?= $image_url ?>" /> <!-- المكونات وطريقة التحضير --> <div class="recipe" dir="rtl"><?= $recipe ?></div> <footer> <!-- زر الرجوع للصفحة الرئيسية --> <a href="/"> <button>وصفة جديدة ??‍?</button> </a> </footer> </main> أما ملف التنسيقات style.css يهتم بالخطوط والألوان وتنسيق العناصر ضمن الصفحات ليجعلها أجمل ويحوي التالي: /* تنسيق الخطوط */ @import url("https://fonts.googleapis.com/css2?family=Noto+Kufi+Arabic:wght@400;500;700&family=Noto+Naskh+Arabic:wght@400;500;700&display=swap"); @font-face { font-family: "Flags"; font-style: normal; font-weight: 400; font-display: swap; src: url(https://fonts.gstatic.com/s/notocoloremoji/v24/Yq6P-KqIXTD0t4D9z1ESnKM3-HpFabsE4tq3luCC7p-aXxcn.0.woff2) format("woff2"); unicode-range: U+1f1e6-1f1ff; } :root { --font-heading: "Noto Kufi Arabic", "Flags", sans-serif; --font-body: "Noto Naskh Arabic", "Flags", sans-serif; } * { font-family: var(--font-body); } h1, h2, button, label, legend { font-family: var(--font-heading); } /* تنسيقات عامة */ body { display: flex; flex-direction: column; justify-content: center; align-items: center; font-size: x-large; min-height: 90vh; background-color: rgb(237, 240, 244); direction: rtl; } /* تنسيق عناصر الصفحة الرئيسية */ fieldset { border: none; padding: 0; } .logo { border-radius: 999rem; background-color: seagreen; width: 11rem; height: 11rem; text-align: center; line-height: 2em; font-size: 6rem; } form { display: flex; flex-direction: column; gap: 1.5rem; } label, legend { display: block; margin-bottom: 1rem; } input[type="radio"] ~ label { font-family: var(--font-body); display: inline-block; margin-bottom: 0; } button, input { padding: 1rem 2rem; font-size: 1.2rem; } input[type="text"] { display: block; width: 100%; } button { border: none; background-color: seagreen; color: white; font-size: 1.5rem; cursor: pointer; transition: all 150ms ease-in-out; } button:hover { background-color: darkgreen; } /* تنسيقات صفحة النتيجة */ .suggestion { display: flex; flex-direction: column; gap: 2rem; margin: 7rem 3rem; max-width: 50ch; } .suggestion h2 { text-align: center; color: #28774a; } .suggestion img { object-fit: cover; border: 1rem solid white; aspect-ratio: 1/1; } .suggestion .description { background-color: white; padding: 3rem; border: 1px solid darkgray; white-space: pre-line; } .suggestion a button { width: 100%; } يمكننا الآن معاينة الصفحات عبر خادم ويب، ويمكننا خلال مرحلة التطوير الاستفادة من خادم الويب الذي توفره بيئة PHP ويأتي مثبتًا معها، وذلك بتنفيذ الأمر php داخل مجلد المشروع مع الخيار S- ونمرر له عنوان الخادم ورقم المنفذ الذي سيتمع إليه، ويمكننا استخدام العنوان المحلي localhost ورقم المنفذ الافتراضي لخوادم الويب 80 ليصبح الأمر كالتالي: php -S localhost:80 يمكننا الآن زيارة العنوان http://localhost:80 من المتصفح ليعالج الخادم افتراضيًا ملف الصفحة الرئيسية index.php ويرسله لنا لنرى التالي: ولمعاينة صفحة النتيجة نختار خيار عشوائي ونضغط "اقترح وصفة"، ويمكننا مؤقتًا إسناد قيم لمتغيرات المتحوى ضمن صفحة suggestion.php لنتمكن من معاينة تنسيقها كالتالي: <!-- suggestion.php --> <?php $name = 'اسم الوصفة'; $description = 'شرح الوصفة...'; $image_url = '#'; ?> لتظهر لنا الصفحة بالمظهر التالي: بذلك أصبحت واجهة التطبيق جاهزة وتعمل وينقصها المحتوى فقط، وهو ما سنبدأ بتطويره في الفقرات القادمة. توليد مفتاح الواجهة البرمجية API والوصول إليه يحتاج تطبيقنا للتواصل مع نماذج الذكاء الاصطناعي المختلفة لتوليد وطلب المحتوى، ويتم ذلك عبر الواجهة البرمجية API التي توفرها الشركة صاحبة تلك النماذج، لذا نحتاج بدايةً لإنشاء حساب على منصتها وإعداد وسيلة الدفع على الحساب لنتمكن من التعامل مع خدماتها المدفوعة، بعدها علينا توليد مفتاح استيثاق خاص لتطبيقنا من صفحة إعداد المفاتيح ليتمكن من إرسال الطلبات، ويمكن تسمية ذلك المفتاح للتعرف عليه لاحقًا، وبعدها سيظهر لنا المفتاح الجديد لمرة واحدة فقط، لذا يجب التأكد من نسخه وحفظه في مكان آمن حيث سنحتاج لتمريره إلى تطبيقنا. يجب التأكيد على ضرورة الحفاظ على ذلك المفتاح وعدم تسريبه، حيث أن الخدمات التي ستتم باستخدامه ستقتطع كلفتها من حساب المستخدم صاحب المفتاح، ويفضل عدم وضع هذه المفاتيح ضمن الشيفرة البرمجية مباشرة، وأفضل طريقة لتمريرها للتطبيق تكون عبر متغيرات البيئة، فيمكننا مثلًا ضمن بيئة التطوير المحلية تعيين متغير بيئة بالاسم OPENAI_API_KEY وذلك ضمن سطر الأوامر وضمن نفس الجلسة قبل تشغيل خادم الويب، ويمكن ذلك ضمن نظام ويندوز مثلًا بتنفيذ الأمر set مع تبديل قيمة المفتاح: set OPENAI_API_KEY=المفتاح وضمن نظام التشغيل لينكس أو ماك بتنفيذ الأمر export كالتالي: export OPENAI_API_KEY=المفتاح ملاحظة: لم نضع قيمة هذا المفتاح في ملف env. فحينذاك سنضطر للاعتماد على مكتبة لتحميل هذا الملف، لذا حاولت أن يكون التطبيق بسيطًا جدًا بلا مكتبات ما أمكن. بعد تنفيذ ذلك الأمر وحصرًا ضمن نفس جلسة سطر الأوامر أي في نفس النافذة يمكن تشغيل خادم الويب، لنتمكن ضمن تطبيقنا في PHP الوصول لذلك المفتاح عبر التابع getenv كالتالي: getenv('OPENAI_API_KEY'); // قيمة المفتاح من متغير البيئة حيث يجب إرسال قيمة ذلك المفتاح مع كل طلب HTTP للواجهة البرمجية، وضمن الترويسة Authorization قيمتها الكلمة Bearer ثم مسافة وبعدها قيمة المفتاح، ويمكن بناء نص تلك الترويسة في PHP عبر استخراج قيمة المفتاح من متغير البيئة كالتالي: "Authorization: Bearer " . getenv('OPENAI_API_KEY'); وبذلك أصبحنا جاهزين لإرسال الطلبات عبر الواجهة البرمجية API للتخاطب مع نماذج الذكاء الاصطناعي لتوليد المحتوى لتطبيقنا وهو ما سنتعرف عليه ضمن الفقرة التالية. توليد الوصفة وصورة لها سنبدأ بتعريف بعض التوابع ضمن صفحة النتيجة suggestion.php سنستدعيها لاحقًا لإسناد قيم المحتوى التي ستولده نماذج الذكاء الاصطناعي إلى المتغيرات التي جهزناها سابقًا لعرضها ضمن قالب الصفحة، ونبدأ بتعريف تابع توليد النصوص chatGPT والذي يقبل متغير التعليمة النصية prompt$ كمعامل له سيرسلها ضمن طلب HTTP ليطلب من نموذج بالاسم gpt-3.5-turbo توليد جواب نصي من تلك التعليمة، يمكن التعامل مع هذا النموذج بصيغة دردشة بين المستخدم والنموذج، في حالتنا لن نحتاج سوى لرسالة واحدة من طرف المستخدم سنبنيها بناءًا على مدخلات المستخدم لاقتراح وصفة وشرح عنها. يرسل الطلب مع ترويسة الاستيثاق التي تحوي مفتاح الواجهة البرمجية API كما تعرفنا سابقًا، وترويسة للتعريف بنوع المحتوى بجسم الطلب Content-type وهو application/json، وبالطريقة POST ويحوي جسم الطلب على اسم النموذج ضمن الحقل model ومصفوفة رسائل الدردشة الحالية بين المستخدم والنموذج ضمن الحقل messages ، حيث تحتوي كل رسالة على اسم صاحب الرسالة ضمن الحقل role ومحتوى الرسالة ضمن content، وفي حالتنا نحتاج لرسالة واحدة فقط من طرف المستخدم أي user ومحتواها هو التعليمة المٌمررة للتابع ضمن المتغير prompt$ ، وبالاستفادة من التابعين file_get_contents و stream_context_create في PHP يمكننا إرسال طلب HTTP دون الحاجة لأي مكتبات إضافية، أما صيغة الجواب فهي JSON بالشكل التالي وما يهمنا منها هو رسالة النموذج: { ... "choices": [{ ... "message": { "role": "assistant", "content": "...", // رسالة النموذج }, }], } يمكننا استخراجها بعد تمرير جواب الطلب للتابع json_decode لتحويله لكائن PHP نستخرج منه القيمة التي نريدها، ليصبح التابع كاملًا كالتالي: /** * توليد نص باستخدام نموذج الدردشة * @param string $prompt التعليمة * @return string النص المُولد */ function chatGPT($prompt) { $result = file_get_contents('https://api.openai.com/v1/chat/completions', false, stream_context_create([ 'http' => [ 'header' => "Content-type: application/json\r\n" . "Authorization: Bearer " . getenv('OPENAI_API_KEY'), 'method' => 'POST', 'content' => json_encode([ 'model' => "gpt-3.5-turbo", // اسم النموذج 'messages' => [ ['role' => "user", 'content' => $prompt], // رسالة المستخدم ] ]) ] ])); // استخراج النتيجة return json_decode($result)->choices[0]->message->content; } ولتوليد الصور سنعرف التابع dalle والذي يقبل وصفًا نصيًا لمحتوى الصورة، ويرسلها في طلب HTTP بالطريقة POST لمسار توليد الصور الخاص، حيث نحتاج فقط ضمن جسم الطلب لتمرير توصيف الصورة ضمن الحقل prompt ولتحديد قياس الصورة في حالتنا هو 512x512 وعدد الصور التي نحتاجها في حالتنا يكفي صورة واحدة لذا نحدد قيمة n بواحد، ولا ننسى ترويستي الاستيثاق ونوع جسم الطلب، أما عن شكل جواب الطلب فهو بصيغة JSON يهمنا منه رابط الصورة التي تم توليدها: { ... "data": [ { "url": "https://..." // رابط الصورة } ] } نمرره أيضًا للتابع json_decode لتحويلها لكائن PHP ونستخرج منه رابط الصورة التي تم توليدها ليصبح التابع كاملًا كالتالي: /** * توليد صورة باستخدام نموذج توليد الصور * @param string $prompt وصف للصورة * @return string رابط للصورة المُولّدة */ function dalle($prompt) { $result = file_get_contents('https://api.openai.com/v1/images/generations', false, stream_context_create([ 'http' => [ 'header' => "Content-type: application/json\r\n" . "Authorization: Bearer " . getenv('OPENAI_API_KEY'), 'method' => 'POST', 'content' => json_encode([ "n" => 1, // عدد الصور "size" => "512x512", // قياس الصورة 'prompt' => $prompt, // توصيف الصورة ]) ] ])); // استخراج رابط الصورة return json_decode($result)->data[0]->url; } لنبدأ باستخدام تلك التوابع لتوليد محتوى الوصفة المقترحة ونعرف التابع recipe والذي سيقبل اسم المطبخ الذي حدده المستخدم كمعامل أول والمكونات التي أدخلها، حيث سنجمع هاتين القيمتين ضمن تعليمة نشرح بها للنموذج ما نريد أن يولده لنا، ليكون قالب هذه التعليمة كالتالي: بحيث نبدل اسم المطبخ والمكونات بالقيم الممررة للتابع، ونمرر تلك التعليمة للتابع chatGPT الذي عرفناه سابقًا، ليعيد لنا اقتراح النموذج، نعالج ذلك الاقتراح باستخراج اسم الوصفة من أول سطر منه بعد تقسيمه باستخدام التابع explode وبقية الأسطر ستحوي على شرح مكونات وطريقة تحضير الوصفة نحددها باستخدام التابع array_slice ونجمعها مجددًا باستخدام التابع implode، ونعيد هاتين القيمتين بعد تمريرهما للتابع trim لإزالة أي محارف ومسافات زائدة، كنتيجة لاستدعاء التابع تحوي الحقل name اسم الوصفة والحقل description شرح الوصفة ليكون التابع كالتالي: /** * اقتراح وصفة * @param string $cuisine اسم المطبخ الذي تنتمي إليه الوصفة * @param string|null $ingredients مكونات اختيارية تتضمنها الوصفة * @return array اسم وشرح الوصفة */ function recipe($cuisine, $ingredients) { // التوصيف $rules = implode(' ', [ // تحديد المطبخ "من وصفات المطبخ ال" . $cuisine . " المشهورة", // شرط المكونات $ingredients ? "يمكن تحضيرها بالمكونات " . $ingredients : // المكونات "", // بلا مكونات محددة ]); // بناء رسالة طلب المستخدم $recipe_prompt = "اقترح وصفة $rules اذكر اسم الوصفة ثم المكونات ثم طريقة التحضير"; // توليد الاقتراح $suggestion = chatGPT($recipe_prompt); // تقسيم الاقتراح لأسطر $lines = explode("\n", $suggestion); return [ // استخراج اسم الوصفة 'name' => trim(str_replace("اسم الوصفة:", "", $lines[0])), // استخراج المكونات والتفاصيل 'description' => trim(implode("\n", array_slice($lines, 1))), ]; } ولتوليد صورة للوصفة المقترحة يجب أن نصف بصريًا ماذا تحوي تلك الصورة، فنذكر المكونات التي تظهر والطبق والمشهد ونمرر ذلك الوصف للتابع dalle الذي عرفناه سابقًا، لكن المشكلة أننا نحتاج لكتابة توصيف خاص بكل وصفة مقترحة من أين سنأتي بذلك التوصيف؟ بما أن التوصيف عبارة عن نص لما لا نطلب ذلك من GPT حيث نمرر له اسم الوصفة مع شرحها، مع الأخذ بالاعتبار أن التوصيف يجب أن يكون باللغة الإنكليزية حيث لحين تاريخ كتابة هذا المقال لا يفهم DALL-E سوى التعليمات باللغة الإنكليزية، فنرسل التعليمة التالية لتوليد وصف للصورة: وترجمتها هي التالي: نعرف التابع recipeImage الذي يقبل اسم وشرح الوصفة ويطلب من GPT شرح لصورة تحوي طبق منها، ثم يمرر ذلك الوصف إلى DALL-E لتوليد الصورة والحصول على رابطها ونعيده كنتيجة لتنفيذ التابع كالتالي: /** * توليد صورة من اسم وتفاصيل وصفة * @param mixed $name اسم الوصفة * @param mixed $description شرح الوصفة * @return string رابط صورة للوصفة */ function recipeImage($name, $description) { // توليد وصف للصورة $image_desc = chatGPT("write a two sentence description of a dish that contains the following recipe \n $name \n $description"); // توليد الصورة return dalle($image_desc); } أصبحت جميع التوابع اللازمة جاهزة، لنستخدمها لتوليد المحتوى وإسناد القيم لمتغيرات واجهة المستخدم لعرضها، حيث يمكن استخراج القيم التي أدخلها المستخدم من المتغير العام POST_$ بحسب اسم الحقول في الصفحة الرئيسية، ونمرر تلك القيم بداية للتابع recipe لاقتراح وصفة جديدة، ثم نستخرج اسم وشرح الوصفة ونسندها للمتغيرات name$ و description$، ولتوليد الصورة نمرر تلك المتغيرات للتابع recipeImage ونسند قيمة رابط الصورة المولدة التي سيعيدها للمتغير image_url$ كالتالي: // اقتراح وصفة من مدخلات المستخدم $recipe = recipe($_POST['cuisine'], $_POST['ingredients']); $name = $recipe['name']; // اسم الوصفة $description = $recipe['description']; // شرح الوصفة $image_url = recipeImage($name, $description); // رابط صورة الوصفة أصبح التطبيق جاهزًا لنختبر بعض النتائج، لا ننسى التأكد من تعيين المفتاح ضمن متغيرات البيئة قبل إعادة تشغيل خادم الويب مجددًا، والتالي بعض النتائج: وصفة فتة حمص بالطحينة وصفة الكبسة ونلاحظ الأجواء العربية ضمن الصورة وصفة الطاجين المغربي وصفة الكشري وبعض صور الوجبات التي استطاع توليدها: تطويرات إضافية ممكنة ونقاط الضعف الحالية يمكن تطوير التطبيق بإضافة بعض المزايا إليه، مثلًا إضافة خيار لتحديد نوع الوصفة (حلويات - وجبات - مشروبات)، أو إضافة عدد السعرات الحرارية التي ستحتويها الوجبة، أو تحديد عدد الأشخاص وبالتالي ستعدل المقادير من قبل النموذج لمراعاة ذلك، أو حفظ الوجبات ضمن مفضلة لكل مستخدم. يُلاحظ أحيانًا اختراع النموذج لوصفات غير موجودة في الواقع، أو شرح طريقة تحضيرها بطريقة خاطئة، وهذا طبيعي نتيجة ضعف المحتوى العربي الذي دُربت عليه تلك النماذج، قد تُطور لاحقًا وتصبح أقوى من تلك الناحية، لذا لا تعتمد على نتائجه دومًا ونبه المستخدمين لذلك، ويمكن تحسين جودة المحتوى عبرة تغيير صيغ التعليمات المرسلة للنماذج فلا زلنا نكتشف العديد من التقنيات والأساليب للتعامل معها للحصول على نتائج أفضل ما يمكن. دورة الذكاء الاصطناعي احترف برمجة الذكاء الاصطناعي AI وتحليل البيانات وتعلم كافة المعلومات التي تحتاجها لبناء نماذج ذكاء اصطناعي متخصصة. اشترك الآن الختام تعرفنا في هذا المقال على كل من نموذج توليد النصوص GPT ونموذج توليد الصور DALL-E واستفدنا من قوة وسهولة استخدامهما في إضافة بعد جديد لتفاعل المستخدم مع التطبيق والحصول على نتائج لا حصر لها تناسب المستخدم، يمكنك توظيف قوة تلك النماذج في العديد من الأفكار فقط أطلق العنان لخيالك. اقرأ أيضًا إعداد شبكة عصبية صنعية وتدريبها للتعرف على الوجوه تصنيف الشخصيات بالاعتماد على تغريداتهم العربية
×
×
  • أضف...