كل الأنشطة
- الساعة الماضية
-
Abdullah Shmeit2 اشترك بالأكاديمية
-
Abdelrahman Emohh اشترك بالأكاديمية
-
خالد الصبري اشترك بالأكاديمية
-
عبدالله الغزالي مرزوقي اشترك بالأكاديمية
-
آية عبدالمنعم اشترك بالأكاديمية
-
وجدان بخاري اشترك بالأكاديمية
- اليوم
-
سيف الغزاوي اشترك بالأكاديمية
-
شهد توفيق اشترك بالأكاديمية
-
Ahmad Abdullah6 اشترك بالأكاديمية
-
عبدالعزيز الحميدي اشترك بالأكاديمية
-
ليس الأمر كما تعتقد حيث أن المبرمج يقضي معظم وقته في القراءة والتفكير، والقليل فقط في الكتابة. بمعنى آخر، السرعة في الكتابة على لوحة المفاتيح ليست العامل المحدد لإنتاجيتك. لكن هناك فرق بين "الكتابة السريعة جدًا" و"الكتابة المريحة". ما تحتاجه حقًا هو مستوى معقول من الراحة في استخدام لوحة المفاتيح . إذا كنت تستطيع كتابة الكود بسرعة معقولة دون النظر كثيرًا للوحة المفاتيح فذلك ممتاز وهو ما عليه معظم المبرمجون . وأعتقد أنه لا يوجد مدير توظيف أو مقابل عمل سيطلب منك اختبار سرعة كتابة على لوحة المفاتيح للحصول على وظيفة برمجة. ما يهمهم هو قدرتك على حل المشكلات، فهمك للخوارزميات، معرفتك بالأدوات والتقنيات، وقدرتك على العمل ضمن فريق.
-
بالفعل هذه المشكلة بسبب قلة التطبيق العملي وهذه المشكلة طبيعية في البداية ولذلك البدء بمشاريع صغيرة . صفحة هبوط بسيطة من ثلاثة أقسام أفضل من محاولة بناء موقع معقد. مع كل مشروع صغير، تقدر اتخاذ القرارات الصحيحة عند استخدام التقنيات مثل css و html ولاحظ أن المشكلة ببساطة عندما تعرف أن margin و padding و gap كلها تخلق مسافات، لكن لا تعرف متى تستخدم كل واحدة منها بالضبط، هنا تحدث الحيرة. والتطبيق العملي هو ما يحل ذلك مع مع الاستفسار دائماً عن الخصائص التي نستخدمها مثلاً لماذا نستخدم grid وليس flex؟ لماذا padding وليس margin؟ هذا التحليل هو ما يجعلك تعتمد على نفسك بفهم عميق لهذه الخصائص.
-
بالإضافة لما سبق معظم اللغات والتقنيات الكبيرة زي JavaScript أو Python أو React لها نشرات بريدية (newsletters) تشترك بها وتصلك التحديثات المهمة تلقائياً على الإيميل. مثلاً في "JavaScript Weekly" أو "Python Weekly" والتي تجمع أهم الأخبار والتحديثات كل أسبوع. وذلك بالإضافة للمجتمع التقني الذي يجعلك على علم بجميع التحديثات . وأخيراً لا يتم تحديث المشاريع القديمة لأحدث إصدار مبشارة. إنما الأفضل البقاء على إصدار مستقر يعمل بشكل جيد، وغالباً يتم استخدام الإصدارات الحديثة عند إنشاء مشروع جديد والمشاريع القديمة يتم تحديثها تدريجياً.
-
كما تم الشرح في التعليقات السابقة فإنه يمكنك الحصول على الصور التي تريدها من خلال مواقع الصور المجانية فتحتوي على صور احترافية مثل. Unsplash Pexels Pixabay وابحث عن "MacBook" أو "Laptop on desk" وستجد نتائج جيدة. أما بالنسبة ل Gemini Pro فيقوم بإنتاج صور احترافية ولكن تحتاج تحسين طريقة كتابة "الأمر" أو الـ (Prompt). للحصول على صور احترافية، عليك أن تكون محدداً جداً. لا تكتب: "صورة جهاز ماك بوك" (A picture of a MacBook) بل اكتب وصفاً تفصيلياً كأنك تصف الصورة لمصور محترف: مثال على Prompt احترافي: "صورة واقعية لمنتج، أحدث جهاز MacBook Pro باللون الرمادي الفلكي، موضوع على مكتب خشبي بسيط ونظيف، إضاءة استوديو احترافية ناعمة من الجانب، خلفية بيضاء تماماً، زاوية تصوير منخفضة قليلاً لإظهار فخامة الجهاز، دقة عالية 8K، تفاصيل دقيقة."
- 5 اجابة
-
- 1
-
-
يمكنك رفع المشاريع التي تقوم بها على github بدون أي مشكلة والمقصد أن github هو سيرتك الذاتية ولذلك يجب أن يتضمن عدة مشاريع قوية ولذلك اختر 3 إلى 5 مشاريع قوية، واكتب لها توثيقًا (Documentation) ممتازًا، وقم بتثبيتها (Pin) في صفحتك الرئيسية. أما بقية التمارين والمشاريع الصغيرة، فاحفظها للتدريب الشخصي أو في مستودعات خاصة.
-
ليس بالضرورة دمج المجالين كما تعتقد وإنما يمكنك الإستفادة من البرمجة في مجال المحاسبة فمثلاً تعلم الأتمتة (Automation) مهم فكتير من المهام المحاسبية المتكررة ممكن تتبرمج وتوفر وقت ومجهود وأيضاً ال Database Management SQL ضروري جداً لأي محاسب محترف كالتعامل مع قواعد البيانات المالية الضخمة واستخراج التقارير المالية بكفاءة . وأيضاً من أهم اللغات التي يمكن استخدامها في مجالك هي Python والتي تساعدك في مجال مثل Data Analysis والذي ربما يكون بعيداً عن البرمجة ولذلك يمكنك لاحقاً تعلم Python و SQL كبداية،ثم الدخول في مجالات أخرى حسب اهتمامك!
-
Hussain Albloshi بدأ بمتابعة كتب برمجة
- البارحة
-
حليت مشكلة اخي مصطفى لا داعي للارسال مشروع شكرا جزيلا لك
-
أرفق المشروع لديك مع أحدث تعديل لتفقده
-
اوك اخي مصطفى مشكور بس وقت حطيت شرط يلي يتحقق من وجود id وقت استخدمت دالة PATCH و DELETE في مجلد [id] ظهرت استجابة invalid id بس انا عرفت id ب params ومع ذالك يوجد خطأ if (!mongoose.Types.ObjectId.isValid(params.id)) { return NextResponse.json({ error: "Invalid id" }, { status: 400 }); }
-
توقيع الدوال في [id]/route.ts غير صحيح قمت بتعريفها كـ PATCH(request, params) وDELETE(request, params) بدلًا من PATCH(request, { params }) وDELETE(request, { params }). بالتالي params.id يصبح undefined، عند إنشاء مشروع Next.js (App Router)، فدوال المسارات الديناميكية تستقبل params داخل كائن ثانٍ بشكل هيكلي، والتوقيع الصحيح هو (request, { params }) وليس (request, params) import { connectDB } from "@/app/libs/connectDB"; import { NextRequest, NextResponse } from "next/server"; import jwt from 'jsonwebtoken'; import User from "@/app/models/User"; import Todos from "@/app/models/Todos"; import mongoose from "mongoose"; type Params = { id: string; } export async function GET(request:NextRequest, {params} : {params: Params }){ try{ await connectDB(); const authHeader = request.headers.get("authorization"); if(!authHeader || !authHeader.startsWith("Bearer ")){ return NextResponse.json({error: "Unauthorized"}, {status:401}) } const token = authHeader.split(" ")[1]; const decoded = jwt.verify(token , process.env.JWT_SECRET); const userId = (decoded as {userId?: string}).userId; if(!userId){ return NextResponse.json({error: "Unauthorized"}, {status:401}) } const user = await User.findById(userId); if(!user){ return NextResponse.json({error: "User not found!"}, {status: 404}); } if (!mongoose.Types.ObjectId.isValid(params.id)) { return NextResponse.json({ error: "Invalid id" }, { status: 400 }); } const task = await Todos.findOne({_id: params.id , userId}); if(!task){ return NextResponse.json({error: "Task not found"}, {status: 404}); } return NextResponse.json({task}) }catch(e:any){ return NextResponse.json({error: e.message}, {status:500}) } } export async function PATCH(request:NextRequest, { params }: { params: Params }){ try{ await connectDB(); const {title , content} = await request.json(); const authHeader = request.headers.get("authorization"); if(!authHeader || !authHeader.startsWith("Bearer ")){ return NextResponse.json({error: "Unauthorized"}, {status:401}) } const token = authHeader.split(" ")[1]; const decoded = jwt.verify(token , process.env.JWT_SECRET) const userId = (decoded as {userId?: string}).userId; if(!userId){ return NextResponse.json({error: "Unauthorized"}, {status:401}) } const user = await User.findById(userId).select("-password"); if(!user){ return NextResponse.json({error: "User not found!"}, {status: 404}); } if (!mongoose.Types.ObjectId.isValid(params.id)) { return NextResponse.json({ error: "Invalid id" }, { status: 400 }); } const taskUpdate = await Todos.findOneAndUpdate( {_id: params.id , userId}, { title , content }, {new: true} ); if(!taskUpdate){ return NextResponse.json({error: "Task not found"}, {status: 404}); } return NextResponse.json(taskUpdate); }catch(e:any){ return NextResponse.json({error: e.message}, {status:500}) } } export async function DELETE(request:NextRequest, { params }: { params: Params }){ try{ await connectDB(); const authHeader = request.headers.get("authorization"); if(!authHeader || !authHeader.startsWith("Bearer ")){ return NextResponse.json({error: "Unauthorized"}, {status:401}) } const token = authHeader.split(" ")[1]; const decoded = jwt.verify(token , process.env.JWT_SECRET); const userId = (decoded as {userId?: string}).userId; if(!userId){ return NextResponse.json({error: "Unauthorized"}, {status:401}) } const user = await User.findById(userId); if(!user){ return NextResponse.json({error: "User not found!"}, {status: 404}); } if (!mongoose.Types.ObjectId.isValid(params.id)) { return NextResponse.json({ error: "Invalid id" }, { status: 400 }); } const taskDelete = await Todos.findOneAndDelete({_id: params.id, userId}); if(!taskDelete){ return NextResponse.json({error: "Task not found"}, {status: 404}); } return NextResponse.json(taskDelete); }catch(e:any){ return NextResponse.json({error: e.message}, {status:500}) } }
-
بسبب أنك أرسلت طلب للمسار GET /api/auth/todos/id مع قيمة نصية للـ id وليس رقم من نوع ObjectId أي 24 حرف سداسي. فمكتبة Mongoose تعمل على تحويل الـ id إلى ObjectId لذا يجب تمرير قيمة صحيحة. لذا مرر معرف todo الصحيح في الـ URL بدل "id"، أي كالتالي /api/auth/todos/66f6a6b13f0d8b1a2c1c1234 ثم إضافة تحقق من صلاحية المعرف قبل الاستعلام لتجنب خطأ 500 وإرجاع 400 في حال المعرف غير الصحيح. أيضًا عند إنشاء مشروع Next.js (App Router)، فدوال المسارات الديناميكية تستقبل params داخل كائن ثانٍ بشكل هيكلي، والتوقيع الصحيح هو: (request, { params }) وليس (request, params) ليصبح ملف route.ts: import { connectDB } from "@/app/libs/connectDB"; import { NextRequest, NextResponse } from "next/server"; import jwt from 'jsonwebtoken'; import User from "@/app/models/User"; import Todos from "@/app/models/Todos"; import mongoose from "mongoose"; type Params = { id: string; } export async function GET(request:NextRequest, {params} : {params: Params }){ try{ await connectDB(); const authHeader = request.headers.get("authorization"); if(!authHeader || !authHeader.startsWith("Bearer ")){ return NextResponse.json({error: "Unauthorized"}, {status:401}) } const token = authHeader.split(" ")[1]; const decoded = jwt.verify(token , process.env.JWT_SECRET); const userId = (decoded as {userId?: string}).userId; if(!userId){ return NextResponse.json({error: "Unauthorized"}, {status:401}) } const user = await User.findById(userId); if(!user){ return NextResponse.json({error: "User not found!"}, {status: 404}); } if (!mongoose.Types.ObjectId.isValid(params.id)) { return NextResponse.json({ error: "Invalid id" }, { status: 400 }); } const task = await Todos.findOne({_id: params.id , userId}); if(!task){ return NextResponse.json({error: "Task not found"}, {status: 404}); } return NextResponse.json({task}) }catch(e:any){ return NextResponse.json({error: e.message}, {status:500}) } } export async function PATCH(request:NextRequest, { params }: { params: Params }){ try{ await connectDB(); const {title , content} = await request.json(); const authHeader = request.headers.get("authorization"); if(!authHeader || !authHeader.startsWith("Bearer ")){ return NextResponse.json({error: "Unauthorized"}, {status:401}) } const token = authHeader.split(" ")[1]; const decoded = jwt.verify(token , process.env.JWT_SECRET) const userId = (decoded as {userId?: string}).userId; if(!userId){ return NextResponse.json({error: "Unauthorized"}, {status:401}) } const user = await User.findById(userId).select("-password"); if(!user){ return NextResponse.json({error: "User not found!"}, {status: 404}); } if (!mongoose.Types.ObjectId.isValid(params.id)) { return NextResponse.json({ error: "Invalid id" }, { status: 400 }); } const taskUpdate = await Todos.findOneAndUpdate( {_id: params.id , userId}, { title , content }, {new: true} ); if(!taskUpdate){ return NextResponse.json({error: "Task not found"}, {status: 404}); } return NextResponse.json(taskUpdate); }catch(e:any){ return NextResponse.json({error: e.message}, {status:500}) } } export async function DELETE(request:NextRequest, { params }: { params: Params }){ try{ await connectDB(); const authHeader = request.headers.get("authorization"); if(!authHeader || !authHeader.startsWith("Bearer ")){ return NextResponse.json({error: "Unauthorized"}, {status:401}) } const token = authHeader.split(" ")[1]; const decoded = jwt.verify(token , process.env.JWT_SECRET); const userId = (decoded as {userId?: string}).userId; if(!userId){ return NextResponse.json({error: "Unauthorized"}, {status:401}) } const user = await User.findById(userId); if(!user){ return NextResponse.json({error: "User not found!"}, {status: 404}); } if (!mongoose.Types.ObjectId.isValid(params.id)) { return NextResponse.json({ error: "Invalid id" }, { status: 400 }); } const taskDelete = await Todos.findOneAndDelete({_id: params.id, userId}); if(!taskDelete){ return NextResponse.json({error: "Task not found"}, {status: 404}); } return NextResponse.json(taskDelete); }catch(e:any){ return NextResponse.json({error: e.message}, {status:500}) } }
-
انا حليت مشكلة url لكن توجد مشكلة لم افهمها والتي هي ان دالة PATCH ترجع null بدل من تعديل اما دالة DELETE ترجع استجابة خاظئة ولم افهم ما مشكلة import { connectDB } from "@/app/libs/connectDB"; import { NextRequest, NextResponse } from "next/server"; import Todos from "@/app/models/Todos"; import { authenticate } from "@/app/libs/authenticate"; import mongoose from "mongoose"; type Params = { id: mongoose.Types.ObjectId; } export async function GET(request:NextRequest, {params} : {params: Params }){ try{ await connectDB(); const userId = await authenticate(request); const task = await Todos.findOne({_id: params.id , userId}); return NextResponse.json({task}) }catch(e:any){ return NextResponse.json({error: e.message}, {status:500}) } } export async function PATCH(request:NextRequest , params:Params){ try{ await connectDB(); const {title , content} = await request.json(); const userId = await authenticate(request); const taskUpdate = await Todos.findOneAndUpdate({_id: params.id , userId}, { title , content }, {new: true}); return NextResponse.json(taskUpdate); }catch(e:any){ return NextResponse.json({error: e.message}, {status:500}) } } export async function DELETE(request:NextRequest , params:Params){ try{ await connectDB(); const userId = await authenticate(request); const taskDelete = await Todos.findOneAndDelete({_id: params.id, userId}); if(!taskDelete){ return NextResponse.json({error: "Task not found"}, {status: 404}); } return NextResponse.json(taskDelete); }catch(e:any){ return NextResponse.json({error: e.message}, {status:500}) } }
- 1 جواب
-
- 1
-
-
- 4 اجابة
-
- 1
-
-
ستجد أسفل فيديو الدرس في نهاية الصفحة صندوق تعليقات كما هنا، أرجو طرح الأسئلة أسفل الدرس وليس هنا في قسم أسئلة البرمجة حيث نطرح الأسئلة العامة الغير متعلقة بمحتوى الدورة أو الدرس، وذلك لمساعدتك بشكل أفضل.
-
tabibi.انا سويت نفس الفيديو وكل شيء تمام ولكن في اخر الحلقة اصبح لا يظهر عندي اي شيء لما اضغط على زر تسجيل مستخدم جديد ارجوا المساعدة جزاكم الله خير
- 1 جواب
-
- 1
-
-
لا داعي للتردد، المهم هو القدرة على تنفيذ مشاريع، وتستطيع إعادة الإختبار لحين إجتيازه، لكن الأفضل الاستعداد
-
انا اعرف منطق ب جافا سكريبت واعرف كيف اربط فرونت اند ب خادم لكني متردد صراحة
-
أهم نقطة يجب التركيز عليها هي القدرة على تنفيذ مشاريع بنفسك حتى لو بنسبة 70%، والمشروع المُسند إليك لن يكون معقد لتلك الدرجة، لكن يجب أن تمتلك القدرة على استيعاب المطلوب وتقسيم ذلك إلى مهام والعمل على تنفيذها لإنهاء المشروع، أي الربط ما بين تعلمته والتطبيق العملي، وليس التركيز على الجانب النظري أو المشاهدة. آلية الإختبار هي كالتالي: بعد إنهاء 4 مسارات من الدورة على الأقل، أو الدورة بالكامل عليك رفع المشاريع التي قمت بها بالدورة على حسابك في github، ثم التحدث لمركز المساعدة وإخبارهم أنك تريد التقدم للإختبار وتوفير روابط المشاريع على github. ثم الإنتظار لبعض الوقت لحين مراجعة المشاريع وسيتم الرد عليك، وتحديد موعد لإجراء مقابلة، وبها يتم: إجراء محادثة صوتيّة لمدة 30 دقيقة يطرح المدرّب عليك أسئلة متعلّقة بالدورة والأمور التي نفّذتها خلالها. يحدد لك المدرّب مشروعًا مرتبطًا بما قمت به أثناء الدورة لتنفيذه خلال فترة محددة تتراوح بين أسبوع إلى أسبوعين. إجراء محادثة صوتيّة أخرى لمدّة 30 دقيقة يناقش بها مشروعك وما نفذته وتطرح أسئلة خلالها. إن سارت على جميع الخطوات السابقة بشكل صحيح، تحصل على الشهادة أو يرشدك المدرّب لأماكن القصور ويطلب منك تداركها ثم التواصل معنا من جديد. في حال قمت بتدوين ملاحظات أثناء دراستك للدورة فاعتمد عليها للمراجعة، ثم حاول تنفيذ مشروع من خلال Next.js للمراجعة على ما تعلمته. وعليك استيعاب كيف يتواصل تطبيق React (الواجهة الأمامية) مع خادم Node.js (الواجهة الخلفية)؟ كيف يتم إرسال واستقبال البيانات (API calls)؟ كيف يمكن استخدام TypeScript في كل من React و Node.js لتحسين الكود؟ كيف يمكن لـ GraphQL أن تكون بديلاً لـ REST API في ذلك التواصل؟ وذلك في حال درست الواجهة الأمامية والخلفية. وابحث عبر الإنترنت عن JavaScript assessment questions أو React quiz أو Node.js interview questions، لتكون فكرة عن نوعية الأسئلة التي ستواجهها بالإمتحان، وبالطبع الإختبار بالأكاديمية سيكون شفهيًا ثم اسناد مشروع إليك.
-
الان اصبحت جاهز لتقدم للأمتحان لكن اريد نصائح قبل استعجال ودخول للامتحان كي اطلع ب استفادة
- 3 اجابة
-
- 1
-
-
في حال أردت إنشاء واجهة إنجليزية، فأبسط طريقة بالنسبة للمواقع الثابتة static والتي تتكون من ملف واحد كما لديك وهو index.html، هي من خلال إنشاء ملف html آخر مُنفصل index-en.html ثم ترجمة ما به واستخدام نسخة LTR من بوتستراب وهي النسخة العادية، ثم تعديل التنسيقات بما يُناسب تلك الواجهة وتخصيص ملف Style-en.css مُنفصل في حال هناك الكثير من التخصيصات. ووضع زر في كل ملف للتحويل للواجهة الأخرى كالتالي: <a href="index-en.html">English</a>
-
السؤال كيف احول الموقع من RTL الي LTR انا قمت بتغير اللغة و الاتجاة من <html lang="en"dir="ltr"> ولم اغير لينك البوتستراب فتغيرت ولاكن اريد تغير لينك البوتستراب تحدث مشاكل في تنسيق الصفحة Agency project.rar
- 1 جواب
-
- 1
-
- آخر أسبوع
-
ستجد أسفل فيديو الدرس في نهاية الصفحة صندوق تعليقات كما هنا، أرجو طرح الأسئلة أسفل الدرس وليس هنا في قسم أسئلة البرمجة حيث نطرح الأسئلة العامة الغير متعلقة بمحتوى الدورة أو الدرس، وذلك لمساعدتك بشكل أفضل.
-
سويت نفس الخطوات المدرب بالفيديو بس مايتحرك الثعبان
- 1 جواب
-
- 1
-
-
ربما حجم الصورة كبير، فالصو الملتقطة بالكاميرا أو المختارة من المعرض، دقتها عالية جداً مثلاً 4000x3000 بكسل، وعند تحميلها في الذاكرة كـ Bitmap، تستهلك مساحة كبيرة. أو تمرر الصورة كـ Bitmap كامل بين صفحة 2 وصفحة 3 عبر Intent Extras، فتواجه خطأ TransactionTooLargeException. لذا قبل إرسال الصورة إلى Gemini API، يجب تصغير حجمها وضغطها، فنماذج Gemini لا تحتاج إلى صور بدقة 4K للتعرف عليها، يكفي دقة 720p أو 1080p. وإليك مثال: import android.graphics.Bitmap import android.graphics.BitmapFactory import java.io.ByteArrayOutputStream fun resizeAndCompressImage(bitmap: Bitmap, maxDimension: Int = 1024, quality: Int = 80): Bitmap { val originalWidth = bitmap.width val originalHeight = bitmap.height var resizedWidth = originalWidth var resizedHeight = originalHeight // Resize the image (تصغير الأبعاد) if (originalHeight > maxDimension || originalWidth > maxDimension) { if (originalWidth > originalHeight) { resizedWidth = maxDimension resizedHeight = (resizedWidth * originalHeight / originalWidth.toFloat()).toInt() } else { resizedHeight = maxDimension resizedWidth = (resizedHeight * originalWidth / originalHeight.toFloat()).toInt() } } val resizedBitmap = Bitmap.createScaledBitmap(bitmap, resizedWidth, resizedHeight, false) // Compress the image (ضغط الجودة) val outputStream = ByteArrayOutputStream() resizedBitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream) val compressedBytes = outputStream.toByteArray() return BitmapFactory.decodeByteArray(compressedBytes, 0, compressedBytes.size) } val originalBitmap: Bitmap = // الصورة الأصلية val optimizedBitmap = resizeAndCompressImage(originalBitmap) كذلك يجب أن تتم كل عمليات معالجة الصورة والاتصال بالـ API في thread خلفي لتجنب تجميد واجهة المستخدم، وأفضل طريقة للقيام بذلك في أندرويد هي بواسطة Coroutines import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.google.ai.client.generativeai.GenerativeModel import com.google.ai.client.generativeai.type.content import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import android.graphics.Bitmap class ChatViewModel : ViewModel() { private val generativeModel: GenerativeModel = // تهيئة النموذج هنا fun analyzeImage(prompt: String, image: Bitmap) { viewModelScope.launch { try { val optimizedImage = withContext(Dispatchers.Default) { resizeAndCompressImage(image, maxDimension = 768, quality = 75) } val inputContent = content { image(optimizedImage) text(prompt) } val response = generativeModel.generateContent(inputContent) withContext(Dispatchers.Main) { _chatResponse.value = response.text } } catch (e: Exception) { withContext(Dispatchers.Main) { } } } } } ولا تقم بتمرير الـ Bitmap مباشرة، بل تمرير مسار URI للصورة كـ String من صفحة 1 إلى 2 ثم إلى 3، وفي صفحة 3، قم بقراءة الـ Bitmap من الـ URI ثم قم بمعالجته وإرساله. وبعد التصنيف في صفحة 1، قم بحفظ النسخة المصغرة في ذاكرة التخزين المؤقت للتطبيق ومرر مسار الملف الجديد إلى الصفحات التالية. النموذج المحلي سيعمل على جهاز المستخدم للتصنيف الأولي، لكن مهمة الشات مع Gemini تستطيع نقلها إلى الخادم باستخدام Cloud Functions for Firebase والتي هي أساس Firebase AI Extensions و Genkit. أي في التطبيق سيقوم المستخدم بتصنيف الصورة باستخدام النموذج المحلي، وعند الانتقال لصفحة الشات، ثم يعمل التطبيق على رفع الصورة المُصغّرة إلى Cloud Storage for Firebase. وعند كتابة المستخدم لسؤال، سيقوم التطبيق بإرساله ورابط الصورة في Cloud Storage إلى Cloud Function. وفي الخادم Firebase Cloud Function سيتم تفعيل الـ Function عند استدعائها من التطبيق، سواء مكتوبة بـ Node.js وTypeScript أو Python لتستقبل السؤال ورابط الصورة. ثم تقوم باستدعاء Gemini API من الخادم وذلك أفضل من حيث الأمان، ثم تستقبل الرد من Gemini، ثم إرسال الرد مرة أخرى إلى التطبيق، إما مباشرة كرد على الاستدعاء أو عن طريق كتابته في Firestore أو Realtime Database حيث يستمع التطبيق للتحديثات.
- 2 اجابة
-
- 1
-