جاري تحميل الشجرة...

100%
Profile Picture
// ========================================== // ذاكرة المحادثة (History) مع توجيهات الروابط // ========================================== let aiConversationHistory = []; // 1. دالة حفظ المحادثة في المتصفح function saveChatHistory() { if (aiConversationHistory.length === 0) return; let systemPrompt = aiConversationHistory[0]; let recentHistory = aiConversationHistory.slice(1); // الحد الأقصى 20 رسالة (للحفاظ على الأداء وتجنب استهلاك التوكنز) if (recentHistory.length > 20) { recentHistory = recentHistory.slice(-20); // تنظيف الرسائل: لا يجب أن تبدأ الذاكرة المقطوعة بأداة (Tool) بدون الطلب الخاص بها لتجنب أخطاء OpenAI API while(recentHistory.length > 0 && (recentHistory[0].role === 'tool' || (recentHistory[0].role === 'assistant' && recentHistory[0].tool_calls))) { recentHistory.shift(); } } aiConversationHistory = [systemPrompt, ...recentHistory]; localStorage.setItem('familyTreeAIChatHistory', JSON.stringify(aiConversationHistory)); localStorage.setItem('familyTreeAILastActivity', Date.now().toString()); } // 2. دالة استرجاع المحادثة عند تحميل الصفحة function loadChatHistory(systemContent) { const savedHistoryStr = localStorage.getItem('familyTreeAIChatHistory'); const lastActivityStr = localStorage.getItem('familyTreeAILastActivity'); let now = Date.now(); let oneHour = 60 * 60 * 1000; // ساعة واحدة بالملي ثانية // إذا كانت هناك ذاكرة محفوظة ولم يمر عليها أكثر من ساعة if (savedHistoryStr && lastActivityStr && (now - parseInt(lastActivityStr) < oneHour)) { try { let parsedHistory = JSON.parse(savedHistoryStr); if (parsedHistory.length > 0) { // تحديث رسالة النظام (System Prompt) دائماً لضمان تحديث التاريخ parsedHistory[0].content = systemContent; aiConversationHistory = parsedHistory; // إعادة رسم المحادثة في الشاشة chatMessages.innerHTML = '
أهلاً بك! أنا المساعد الذكي، كيف يمكنني مساعدتك في استكشاف شجرة العائلة اليوم؟
'; for (let i = 1; i < aiConversationHistory.length; i++) { let msg = aiConversationHistory[i]; // نظهر فقط رسائل المستخدم والذكاء الاصطناعي (ونتجاهل رسائل بحث قاعدة البيانات المخفية) if (msg.role === 'user' && msg.content) { appendMessage(msg.content, 'user'); } else if (msg.role === 'assistant' && msg.content && !msg.tool_calls) { appendMessage(msg.content, 'ai'); } } // تحديث وقت النشاط localStorage.setItem('familyTreeAILastActivity', Date.now().toString()); return; } } catch (e) { console.error("Error parsing history", e); } } // إذا مرت أكثر من ساعة أو لا توجد ذاكرة، نبدأ من جديد localStorage.removeItem('familyTreeAIChatHistory'); localStorage.removeItem('familyTreeAILastActivity'); aiConversationHistory = [ { role: "system", content: systemContent } ]; } // 3. تحديث دالة البدء لاستخدام الذاكرة async function startApp() { let systemContent = ""; try { const response = await fetch('http://imiwandrat.com/chajara-arabic-22/prompt.php?read=true'); if (!response.ok) throw new Error('Network error'); const prompt_web_txt = await response.text(); // توليد تاريخ اليوم بواسطة جافاسكربت ليتوافق مع جميع الصفحات let d = new Date(); let date_today = ("0" + d.getDate()).slice(-2) + "/" + ("0" + (d.getMonth() + 1)).slice(-2) + "/" + d.getFullYear(); systemContent = "Date today is " + date_today + " (Format d/m/Y) Use this date for calculating (example calculate the age) \n " + prompt_web_txt + "\nأنت مساعد ذكي لشجرة عائلة مغربية. لكي تجيب بشكل صحيح، استخدم أداة البحث search_family_database. نتيجة البحث ستحتوي على معلومات الأشخاص وعلاقاتهم (آباء، أبناء، إخوة...) مكتوبة بصيغة روابط ماركداون (Markdown Links). من الضروري جداً عندما تذكر اسم أي شخص في إجابتك أن تستخدم صيغة الرابط المرفقة معه حرفياً (مثال: [الاسم](رابط_الشجرة?id=معرف_الشخص)) لكي يتمكن المستخدم من الضغط عليه. لا تخمن الإجابات واستخدم الروابط دائمًا."; } catch (error) { console.error("Failed to load prompt:", error); systemContent = "أنت مساعد ذكي لشجرة عائلة مغربية. لكي تجيب بشكل صحيح، استخدم أداة البحث search_family_database. نتيجة البحث ستحتوي على معلومات الأشخاص وعلاقاتهم (آباء، أبناء، إخوة...) مكتوبة بصيغة روابط ماركداون (Markdown Links). من الضروري جداً عندما تذكر اسم أي شخص في إجابتك أن تستخدم صيغة الرابط المرفقة معه حرفياً (مثال: [الاسم](رابط_الشجرة?id=معرف_الشخص)) لكي يتمكن المستخدم من الضغط عليه. لا تخمن الإجابات واستخدم الروابط دائمًا."; } // استدعاء دالة تحميل الذاكرة loadChatHistory(systemContent); } // Initialize the app when the script loads startApp(); // 4. (Leave appendMessage exactly as it is in your current code) function appendMessage(text, sender) { const msgDiv = document.createElement('div'); msgDiv.className = `message ${sender === 'user' ? 'user-message' : 'ai-message'}`; if (sender === 'ai') { let formatted = text; formatted = formatted.replace(/]*?\s+)?href=["']([^"']+)["'][^>]*>(.*?)<\/a>/gi, "[$2]($1)"); formatted = formatted.replace(/\[([^\]]+)\]\s*\(([^)]+)\)/g, (match, name, url) => { let linkClass = 'ai_name_male'; let linkColor = '#1d4ed8'; try { let idMatch = url.match(/id=([a-zA-Z0-9_\-]+)/i); if (idMatch && idMatch[1]) { let rawId = idMatch[1].replace(/^(c_|t_|t2_)/, ''); let person = familyMap['c_' + rawId] || familyMap['t_' + rawId] || familyMap['t2_' + rawId] || familyMap[rawId] || familyMap[idMatch[1]]; if (person) { if (person.alive === false || String(person.alive).toUpperCase() === 'FALSE') { linkClass = 'ai_name_dead'; linkColor = '#64748b'; } else if (person.sex === 'أنثى' || String(person.sex).trim().toLowerCase() === 'female') { linkClass = 'ai_name_female'; linkColor = '#db2777'; } } } } catch (e) { console.error(e); } return `${name}`; }); formatted = formatted.replace(/\n/g, '
'); msgDiv.innerHTML = formatted; } else { msgDiv.innerText = text; } chatMessages.appendChild(msgDiv); chatMessages.scrollTop = chatMessages.scrollHeight; } // 5. تحديث دالة إرسال الرسالة لحفظ المحادثة async function sendAiMessage() { const text = aiChatInput.value.trim(); if (!text) return; // التحقق من مرور ساعة قبل إرسال الرسالة الجديدة const lastActivityStr = localStorage.getItem('familyTreeAILastActivity'); if (lastActivityStr && (Date.now() - parseInt(lastActivityStr) >= 60 * 60 * 1000)) { aiConversationHistory = [aiConversationHistory[0]]; // إبقاء رسالة النظام فقط chatMessages.innerHTML = '
انتهت الجلسة السابقة. أهلاً بك من جديد! كيف يمكنني مساعدتك؟
'; } appendMessage(text, 'user'); aiChatInput.value = ''; const loadingMsg = document.createElement('div'); loadingMsg.className = 'message ai-message'; loadingMsg.innerText = 'جاري البحث وإعداد الإجابة...'; chatMessages.appendChild(loadingMsg); chatMessages.scrollTop = chatMessages.scrollHeight; const dbObjects = await prepareDatabaseForAi(); if (!dbObjects) { chatMessages.removeChild(loadingMsg); appendMessage("عذراً، هناك مشكلة في قراءة الملفات.", 'ai'); return; } aiConversationHistory.push({ role: "user", content: text }); saveChatHistory(); // الحفظ المبدئي لرسالة المستخدم const aiTools = [ { type: "function", function: { name: "search_family_database", description: "ابحث في الشجرة للعثور على شخص (ومعرفة عائلته وإخوته وأعمامه وأبناء عمه) أو لحساب العدد.", parameters: { type: "object", properties: { action: { type: "string", enum: ["search", "count"] }, full_name: { type: "string" }, last_name: { type: "string" }, gender: { type: "string", enum: ["ذكر", "أنثى"] }, is_alive: { type: "boolean", description: "ابحث عن الأحياء أو الأموات (true للأحياء، false للأموات)" }, city: { type: "string", description: "المدينة" } }, required: ["action"] } } } ]; try { let response = await fetch('https://api.openai.com/v1/chat/completions', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${OPENAI_API_KEY}` }, body: JSON.stringify({ model: "gpt-4o-mini", messages: aiConversationHistory, tools: aiTools, temperature: 0.1 }) }); let data = await response.json(); let message = data.choices[0].message; if (message.tool_calls && message.tool_calls.length > 0) { aiConversationHistory.push(message); for (const toolCall of message.tool_calls) { if (toolCall.function.name === 'search_family_database') { const args = JSON.parse(toolCall.function.arguments); let results = dbObjects.filter(p => { if (args.full_name && !p.الاسم_للبحث.includes(args.full_name)) return false; if (args.last_name && !p.النسب.includes(args.last_name)) return false; if (args.gender && p.الجنس !== args.gender) return false; if (typeof args.is_alive !== 'undefined') { const pAlive = (p.الحالة_على_قيد_الحياة === 'حي(ة)'); if (pAlive !== args.is_alive) return false; } if (args.city && !p.مدينة_الإقامة.includes(args.city)) return false; return true; }); if (args.last_name) { if (args.last_name.includes("تكايوت")) { results.sort((a, b) => { let aIsT = a.id && String(a.id).startsWith('t_'); let bIsT = b.id && String(b.id).startsWith('t_'); return (aIsT === bIsT) ? 0 : aIsT ? -1 : 1; }); } else if (args.last_name.includes("شرورو")) { results.sort((a, b) => { let aIsC = a.id && String(a.id).startsWith('c_'); let bIsC = b.id && String(b.id).startsWith('c_'); return (aIsC === bIsC) ? 0 : aIsC ? -1 : 1; }); } } let finalResult = ""; if (args.action === 'count') { finalResult = `العدد الدقيق والمؤكد هو: ${results.length} شخص.`; } else { if (results.length === 0) { finalResult = "لم يتم العثور على أي شخص."; } else { let limitedResults = results.length > 8 ? results.slice(0, 8) : results; let groupedOutput = [{ "شجرة أيت محمد بن عبد الله": limitedResults.filter(p => p.العائلة === 'شجرة أيت محمد بن عبد الله'), "شجرة تكايوت": limitedResults.filter(p => p.العائلة === 'شجرة تكايوت') }]; if (results.length > 8) { finalResult = `تم العثور على ${results.length} شخص يطابق المواصفات. إليك أول 8 فقط:\n` + JSON.stringify(groupedOutput); } else { finalResult = JSON.stringify(groupedOutput); } } } aiConversationHistory.push({ role: "tool", tool_call_id: toolCall.id, name: toolCall.function.name, content: finalResult }); } } response = await fetch('https://api.openai.com/v1/chat/completions', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${OPENAI_API_KEY}` }, body: JSON.stringify({ model: "gpt-4o-mini", messages: aiConversationHistory, temperature: 0.1 }) }); data = await response.json(); message = data.choices[0].message; } if (message.content) { aiConversationHistory.push({ role: "assistant", content: message.content }); } chatMessages.removeChild(loadingMsg); appendMessage(message.content || "عذراً، حدث خطأ.", 'ai'); saveChatHistory(); // الحفظ النهائي بعد وصول إجابة الذكاء الاصطناعي } catch (error) { console.error(error); if(chatMessages.contains(loadingMsg)) chatMessages.removeChild(loadingMsg); appendMessage("فشل الاتصال بخادم الذكاء الاصطناعي.", 'ai'); } } }