al00sakkaf's picture
قم بتطوير التطبيق واضف التحسينات واجعل اسم التطبيق "المساعد الذكي" واضف اسفل الشاشة النص التالي "تصميم المهندس احمد السقاف"
c3f9420 verified
<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>المساعد الذكي - الدردشة الذكية</title>
<link rel="icon" type="image/x-icon" href="/static/favicon.ico">
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
<script src="https://unpkg.com/feather-icons"></script>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#6366f1',
secondary: '#8b5cf6',
accent: '#06b6d4'
}
}
}
}
</script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Tajawal:wght@300;400;500;700;800&display=swap');
* {
font-family: 'Tajawal', sans-serif;
}
.gradient-bg {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.chat-bubble-user {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border-radius: 20px 20px 0 20px;
}
.chat-bubble-ai {
background: #f8fafc;
border: 1px solid #e2e8f0;
border-radius: 20px 20px 20px 0;
}
.sidebar-item {
transition: all 0.3s ease;
}
.sidebar-item:hover {
background: #f1f5f9;
transform: translateX(-5px);
}
.character-card {
transition: all 0.3s ease;
border: 2px solid transparent;
}
.character-card:hover {
border-color: #6366f1;
transform: translateY(-2px);
box-shadow: 0 10px 25px rgba(99, 102, 241, 0.15);
}
.fade-in {
animation: fadeIn 0.3s ease-in-out;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.markdown-content h1, .markdown-content h2, .markdown-content h3 {
margin-top: 1rem;
margin-bottom: 0.5rem;
font-weight: bold;
}
.markdown-content h1 { font-size: 1.5rem; }
.markdown-content h2 { font-size: 1.25rem; }
.markdown-content h3 { font-size: 1.125rem; }
.markdown-content code {
background: #f1f5f9;
padding: 0.25rem 0.5rem;
border-radius: 0.375rem;
font-family: 'Courier New', monospace;
}
.markdown-content pre {
background: #1e293b;
color: #e2e8f0;
padding: 1rem;
border-radius: 0.5rem;
overflow-x: auto;
margin: 1rem 0;
}
.loading-spinner {
border: 3px solid #f3f3f3;
border-top: 3px solid #6366f1;
border-radius: 50%;
width: 20px;
height: 20px;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.page-container {
display: none;
opacity: 0;
transition: opacity 0.3s ease-in-out;
}
.active-page {
display: block;
opacity: 1;
}
</style>
</head>
<body class="bg-gray-50 min-h-screen flex flex-col">
<!-- Navigation -->
<nav class="bg-white shadow-lg border-b">
<div class="max-w-7xl mx-auto px-4">
<div class="flex justify-between items-center h-16">
<div class="flex items-center space-x-4 space-x-reverse">
<i data-feather="message-circle" class="text-primary w-8 h-8"></i>
<h1 class="text-xl font-bold text-gray-800">المساعد الذكي</h1>
</div>
<div class="flex items-center space-x-4 space-x-reverse">
<button onclick="showPage('settings')" class="text-gray-600 hover:text-primary transition-colors">
<i data-feather="settings"></i>
</button>
<button onclick="showPage('characters')" class="text-gray-600 hover:text-primary transition-colors">
<i data-feather="users"></i>
</button>
<button onclick="showPage('conversations')" class="text-gray-600 hover:text-primary transition-colors">
<i data-feather="message-square"></i>
</button>
<button onclick="showPage('voice-chat')" class="text-gray-600 hover:text-primary transition-colors">
<i data-feather="mic"></i>
</button>
<button onclick="showPage('chat')" class="text-gray-600 hover:text-primary transition-colors">
<i data-feather="message-circle"></i>
</button>
</div>
</div>
</div>
</nav>
<!-- Home Page -->
<div id="home" class="page-container active-page">
<div class="max-w-4xl mx-auto py-8 px-4">
<!-- Welcome Section -->
<div class="text-center mb-12">
<h2 class="text-3xl font-bold text-gray-800 mb-4">مرحباً بك في المساعد الذكي</h2>
<p class="text-gray-600 text-lg">تطبيق الدردشة الذكي الذي يتقمص الشخصيات باستخدام نماذج الذكاء الاصطناعي المتقدمة</p>
</div>
<!-- Quick Actions -->
<div class="grid grid-cols-1 md:grid-cols-4 gap-6 mb-12">
<button onclick="showPage('chat')" class="bg-white p-6 rounded-xl shadow-md border border-gray-200 hover:shadow-lg transition-shadow group">
<div class="text-center">
<i data-feather="message-square" class="w-12 h-12 text-primary mx-auto mb-4 group-hover:scale-110 transition-transform"></i>
<h3 class="text-xl font-semibold text-gray-800 mb-2">بدء محادثة جديدة</h3>
<p class="text-gray-600">ابدأ محادثة مع الذكاء الاصطناعي</p>
</div>
</button>
<button onclick="showPage('voice-chat')" class="bg-white p-6 rounded-xl shadow-md border border-gray-200 hover:shadow-lg transition-shadow group">
<div class="text-center">
<i data-feather="mic" class="w-12 h-12 text-green-500 mx-auto mb-4 group-hover:scale-110 transition-transform"></i>
<h3 class="text-xl font-semibold text-gray-800 mb-2">المحادثة الصوتية</h3>
<p class="text-gray-600">تحدث مع الذكاء الاصطناعي صوتياً</p>
</div>
</button>
<button onclick="showPage('characters')" class="bg-white p-6 rounded-xl shadow-md border border-gray-200 hover:shadow-lg transition-shadow group">
<div class="text-center">
<i data-feather="users" class="w-12 h-12 text-secondary mx-auto mb-4 group-hover:scale-110 transition-transform"></i>
<h3 class="text-xl font-semibold text-gray-800 mb-2">إدارة الشخصيات</h3>
<p class="text-gray-600">أنشئ وعدّل الشخصيات الافتراضية</p>
</div>
</button>
<button onclick="showPage('conversations')" class="bg-white p-6 rounded-xl shadow-md border border-gray-200 hover:shadow-lg transition-shadow group">
<div class="text-center">
<i data-feather="archive" class="w-12 h-12 text-accent mx-auto mb-4 group-hover:scale-110 transition-transform"></i>
<h3 class="text-xl font-semibold text-gray-800 mb-2">المحادثات السابقة</h3>
<p class="text-gray-600">راجع محادثاتك المحفوظة</p>
</div>
</button>
</div>
<!-- Features Section -->
<div class="bg-white rounded-xl shadow-md p-8 mb-8">
<h3 class="text-2xl font-bold text-gray-800 mb-6 text-center">المميزات الرئيسية</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div class="flex items-start space-x-4 space-x-reverse">
<i data-feather="zap" class="w-6 h-6 text-green-500 mt-1"></i>
<div>
<h4 class="font-semibold text-gray-800 mb-2">نماذج الذكاء الاصطناعي المتقدمة</h4>
<p class="text-gray-600">استخدم أحدث نماذج الذكاء الاصطناعي المتقدمة</p>
</div>
</div>
<div class="flex items-start space-x-4 space-x-reverse">
<i data-feather="user" class="w-6 h-6 text-blue-500 mt-1"></i>
<div>
<h4 class="font-semibold text-gray-800 mb-2">تقمص الشخصيات</h4>
<p class="text-gray-600">تحدث مع شخصيات افتراضية مختلفة</p>
</div>
</div>
<div class="flex items-start space-x-4 space-x-reverse">
<i data-feather="save" class="w-6 h-6 text-purple-500 mt-1"></i>
<div>
<h4 class="font-semibold text-gray-800 mb-2">حفظ تلقائي</h4>
<p class="text-gray-600">المحادثات تحفظ تلقائياً في قاعدة البيانات المحلية</p>
</div>
</div>
<div class="flex items-start space-x-4 space-x-reverse">
<i data-feather="code" class="w-6 h-6 text-orange-500 mt-1"></i>
<div>
<h4 class="font-semibold text-gray-800 mb-2">دعم Markdown</h4>
<p class="text-gray-600">عرض المحادثات بتنسيق Markdown متقدم</p>
</div>
</div>
<div class="flex items-start space-x-4 space-x-reverse">
<i data-feather="mic" class="w-6 h-6 text-red-500 mt-1"></i>
<div>
<h4 class="font-semibold text-gray-800 mb-2">المحادثة الصوتية</h4>
<p class="text-gray-600">تحدث مع الذكاء الاصطناعي صوتياً باستخدام Web Speech API</p>
</div>
</div>
<div class="flex items-start space-x-4 space-x-reverse">
<i data-feather="download" class="w-6 h-6 text-indigo-500 mt-1"></i>
<div>
<h4 class="font-semibold text-gray-800 mb-2">تصدير المحادثات</h4>
<p class="text-gray-600">حفظ المحادثات بصيغة PDF أو نصية</p>
</div>
</div>
</div>
</div>
<!-- Statistics Section -->
<div class="bg-gradient-to-r from-primary to-secondary rounded-xl shadow-md p-8 text-white mb-8">
<h3 class="text-2xl font-bold mb-6 text-center">إحصائيات التطبيق</h3>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 text-center">
<div>
<div class="text-3xl font-bold mb-2" id="totalCharacters">0</div>
<p class="text-blue-100">شخصية مضافة</p>
</div>
<div>
<div class="text-3xl font-bold mb-2" id="totalConversations">0</div>
<p class="text-blue-100">محادثة محفوظة</p>
</div>
<div>
<div class="text-3xl font-bold mb-2" id="totalMessages">0</div>
<p class="text-blue-100">رسالة مرسلة</p>
</div>
</div>
</div>
</div>
</div>
<!-- Characters Page -->
<div id="characters" class="page-container">
<div class="max-w-6xl mx-auto py-8 px-4">
<!-- Header with Add Button -->
<div class="flex justify-between items-center mb-8">
<div>
<h2 class="text-2xl font-bold text-gray-800">شخصياتك الافتراضية</h2>
<p class="text-gray-600 mt-1">إدارة وتعديل الشخصيات الافتراضية التي يمكنك الدردشة معها</p>
</div>
<button onclick="openAddCharacterModal()" class="bg-primary text-white px-6 py-3 rounded-lg hover:bg-primary/90 transition-colors flex items-center space-x-2 space-x-reverse">
<i data-feather="plus" class="w-4 h-4"></i>
<span>إضافة شخصية جديدة</span>
</button>
</div>
<!-- Search and Filter -->
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-4 mb-6">
<div class="flex flex-col md:flex-row gap-4">
<div class="flex-1">
<input type="text" id="searchInput" placeholder="ابحث عن شخصية..."
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent">
</div>
<div class="flex gap-2">
<select id="sortSelect" class="px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent">
<option value="name">الاسم (أ-ي)</option>
<option value="nameDesc">الاسم (ي-أ)</option>
<option value="recent">الأحدث</option>
<option value="oldest">الأقدم</option>
</select>
<button onclick="exportCharacters()" class="bg-green-600 text-white px-4 py-2 rounded-lg hover:bg-green-700 transition-colors flex items-center space-x-2 space-x-reverse">
<i data-feather="download" class="w-4 h-4"></i>
<span>تصدير</span>
</button>
</div>
</div>
</div>
<!-- Characters Grid -->
<div id="charactersGrid" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<!-- Characters will be loaded here -->
</div>
<!-- Load More Button -->
<div id="loadMoreContainer" class="text-center mt-8 hidden">
<button onclick="loadMoreCharacters()" class="bg-gray-200 text-gray-700 px-6 py-3 rounded-lg hover:bg-gray-300 transition-colors">
تحميل المزيد
</button>
</div>
<!-- Empty State -->
<div id="emptyState" class="text-center py-12 hidden">
<i data-feather="users" class="w-16 h-16 text-gray-300 mx-auto mb-4"></i>
<h3 class="text-xl font-semibold text-gray-600 mb-2">لا توجد شخصيات</h3>
<p class="text-gray-500 mb-6">ابدأ بإضافة أول شخصية افتراضية لك</p>
<button onclick="openAddCharacterModal()" class="bg-primary text-white px-6 py-3 rounded-lg hover:bg-primary/90 transition-colors">
إضافة شخصية جديدة
</button>
</div>
</div>
</div>
<!-- Chat Page -->
<div id="chat" class="page-container">
<div class="max-w-4xl mx-auto h-[calc(100vh-4rem)] flex flex-col">
<!-- Chat Header -->
<div class="bg-white border-b p-4">
<div class="flex justify-between items-center">
<div>
<h2 class="text-xl font-bold text-gray-800" id="chatTitle">المحادثة الجديدة</h2>
<p class="text-gray-600 text-sm" id="characterInfo">اختر شخصية للبدء</p>
</div>
<div class="flex space-x-2 space-x-reverse">
<button onclick="saveConversation()" class="bg-green-600 text-white px-4 py-2 rounded-lg hover:bg-green-700 transition-colors flex items-center space-x-2 space-x-reverse">
<i data-feather="save" class="w-4 h-4"></i>
<span>حفظ</span>
</button>
<button onclick="clearChat()" class="bg-red-600 text-white px-4 py-2 rounded-lg hover:bg-red-700 transition-colors flex items-center space-x-2 space-x-reverse">
<i data-feather="trash-2" class="w-4 h-4"></i>
<span>مسح</span>
</button>
<button onclick="exportChat()" class="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors flex items-center space-x-2 space-x-reverse">
<i data-feather="download" class="w-4 h-4"></i>
<span>تصدير</span>
</button>
</div>
</div>
</div>
<!-- Character Selection -->
<div id="characterSelection" class="bg-white border-b p-4">
<select id="characterSelect" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent">
<option value="">اختر شخصية...</option>
</select>
</div>
<!-- Messages Container -->
<div id="messagesContainer" class="flex-1 overflow-y-auto p-4 space-y-4">
<div class="text-center text-gray-500 py-8">
<i data-feather="message-circle" class="w-12 h-12 mx-auto mb-4"></i>
<p>ابدأ محادثة جديدة...</p>
</div>
</div>
<!-- Input Area -->
<div class="bg-white border-t p-4">
<div class="flex space-x-2 space-x-reverse">
<input type="text" id="messageInput" placeholder="اكتب رسالتك هنا..."
class="flex-1 px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent"
disabled>
<button id="sendButton" onclick="sendMessage()" class="bg-primary text-white px-6 py-3 rounded-lg hover:bg-primary/90 transition-colors" disabled>
<i data-feather="send" class="w-4 h-4"></i>
</button>
</div>
</div>
</div>
</div>
<!-- Voice Chat Page -->
<div id="voice-chat" class="page-container">
<div class="max-w-4xl mx-auto h-[calc(100vh-4rem)] flex flex-col">
<!-- Voice Chat Header -->
<div class="bg-white border-b p-4">
<div class="flex justify-between items-center">
<div>
<h2 class="text-xl font-bold text-gray-800">المحادثة الصوتية</h2>
<p class="text-gray-600 text-sm">تحدث مع الذكاء الاصطناعي صوتياً</p>
</div>
<div class="flex space-x-2 space-x-reverse">
<button onclick="toggleListening()" id="listenButton" class="bg-red-600 text-white px-6 py-3 rounded-lg hover:bg-red-700 transition-colors flex items-center space-x-2 space-x-reverse">
<i data-feather="mic" class="w-4 h-4"></i>
<span>بدء الاستماع</span>
</button>
</div>
</div>
</div>
<!-- Character Selection -->
<div class="bg-white border-b p-4">
<select id="voiceCharacterSelect" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent">
<option value="">اختر شخصية...</option>
</select>
</div>
<!-- Messages Container -->
<div id="voiceMessagesContainer" class="flex-1 overflow-y-auto p-4 space-y-4">
<div class="text-center text-gray-500 py-8">
<i data-feather="mic" class="w-12 h-12 mx-auto mb-4"></i>
<p>انقر على "بدء الاستماع" للبدء...</p>
</div>
</div>
<!-- Status -->
<div class="bg-white border-t p-4">
<div id="voiceStatus" class="text-center text-gray-600">
جاهز للاستماع...
</div>
</div>
</div>
</div>
<!-- Conversations Page -->
<div id="conversations" class="page-container">
<div class="max-w-6xl mx-auto py-8 px-4">
<!-- Header -->
<div class="flex justify-between items-center mb-8">
<div>
<h2 class="text-2xl font-bold text-gray-800">المحادثات السابقة</h2>
<p class="text-gray-600 mt-1">راجع وأعد فتح المحادثات المحفوظة</p>
</div>
</div>
<!-- Search and Filter -->
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-4 mb-6">
<div class="flex flex-col md:flex-row gap-4">
<div class="flex-1">
<input type="text" id="conversationSearch" placeholder="ابحث في المحادثات..."
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent">
</div>
<div class="flex gap-2">
<select id="conversationSort" class="px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent">
<option value="recent">الأحدث</option>
<option value="oldest">الأقدم</option>
<option value="title">العنوان (أ-ي)</option>
</select>
<button onclick="exportAllConversations()" class="bg-green-600 text-white px-4 py-2 rounded-lg hover:bg-green-700 transition-colors flex items-center space-x-2 space-x-reverse">
<i data-feather="download" class="w-4 h-4"></i>
<span>تصدير الكل</span>
</button>
</div>
</div>
</div>
<!-- Conversations List -->
<div id="conversationsList" class="space-y-4">
<!-- Conversations will be loaded here -->
</div>
<!-- Empty State -->
<div id="conversationsEmptyState" class="text-center py-12 hidden">
<i data-feather="message-square" class="w-16 h-16 text-gray-300 mx-auto mb-4"></i>
<h3 class="text-xl font-semibold text-gray-600 mb-2">لا توجد محادثات</h3>
<p class="text-gray-500">ابدأ محادثة جديدة لحفظها هنا</p>
</div>
</div>
</div>
<!-- Settings Page -->
<div id="settings" class="page-container">
<div class="max-w-4xl mx-auto py-8 px-4">
<!-- Header -->
<div class="mb-8">
<h2 class="text-2xl font-bold text-gray-800">الإعدادات</h2>
<p class="text-gray-600 mt-1">إعدادات التطبيق والمظهر</p>
</div>
<!-- Settings Sections -->
<div class="space-y-6">
<!-- API Settings -->
<div class="bg-white rounded-xl shadow-md p-6">
<h3 class="text-xl font-semibold text-gray-800 mb-4">إعدادات API</h3>
<div class="space-y-4">
<div>
<label for="apiKey" class="block text-sm font-medium text-gray-700 mb-2">مفتاح Gemini API</label>
<input type="password" id="apiKey"
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent"
placeholder="أدخل مفتاح API الخاص بك">
<p class="text-sm text-gray-500 mt-1">يمكنك الحصول على مفتاح API من <a href="https://aistudio.google.com/" class="text-primary hover:underline" target="_blank">Google AI Studio</a></p>
</div>
<button onclick="saveApiKey()" class="bg-primary text-white px-6 py-3 rounded-lg hover:bg-primary/90 transition-colors">
حفظ الإعدادات
</button>
</div>
</div>
<!-- Appearance Settings -->
<div class="bg-white rounded-xl shadow-md p-6">
<h3 class="text-xl font-semibold text-gray-800 mb-4">الإعدادات العامة</h3>
<div class="space-y-4">
<div>
<label for="language" class="block text-sm font-medium text-gray-700 mb-2">اللغة</label>
<select id="language" class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent">
<option value="ar">العربية</option>
<option value="en">English</option>
</select>
</div>
<div>
<label for="theme" class="block text-sm font-medium text-gray-700 mb-2">المظهر</label>
<select id="theme" class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent">
<option value="light">فاتح</option>
<option value="dark">داكن</option>
<option value="auto">تلقائي</option>
</select>
</div>
<button onclick="saveGeneralSettings()" class="bg-primary text-white px-6 py-3 rounded-lg hover:bg-primary/90 transition-colors">
حفظ الإعدادات
</button>
</div>
</div>
<!-- Data Management -->
<div class="bg-white rounded-xl shadow-md p-6">
<h3 class="text-xl font-semibold text-gray-800 mb-4">إدارة البيانات</h3>
<div class="space-y-4">
<div class="flex justify-between items-center">
<div>
<h4 class="font-medium text-gray-800">مسح جميع البيانات</h4>
<p class="text-sm text-gray-600">سيتم حذف جميع المحادثات والشخصيات والإعدادات</p>
</div>
<button onclick="clearAllData()" class="bg-red-600 text-white px-6 py-3 rounded-lg hover:bg-red-700 transition-colors">
مسح الكل
</button>
</div>
<div class="flex justify-between items-center">
<div>
<h4 class="font-medium text-gray-800">تصدير البيانات</h4>
<p class="text-sm text-gray-600">تحميل نسخة احتياطية من جميع البيانات</p>
</div>
<button onclick="exportAllData()" class="bg-green-600 text-white px-6 py-3 rounded-lg hover:bg-green-700 transition-colors">
تصدير الكل
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Add/Edit Character Modal -->
<div id="characterModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 z-50 hidden">
<div class="bg-white rounded-xl shadow-xl max-w-md w-full max-h-[90vh] overflow-y-auto">
<div class="p-6">
<div class="flex justify-between items-center mb-6">
<h3 id="modalTitle" class="text-xl font-bold text-gray-800">إضافة شخصية جديدة</h3>
<button onclick="closeCharacterModal()" class="text-gray-400 hover:text-gray-600">
<i data-feather="x" class="w-6 h-6"></i>
</button>
</div>
<form id="characterForm" class="space-y-4">
<input type="hidden" id="characterId">
<div>
<label for="characterName" class="block text-sm font-medium text-gray-700 mb-2">اسم الشخصية</label>
<input type="text" id="characterName" required
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent">
</div>
<div>
<label for="characterRole" class="block text-sm font-medium text-gray-700 mb-2">الدور/المهنة</label>
<input type="text" id="characterRole"
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent">
</div>
<div>
<label for="characterDescription" class="block text-sm font-medium text-gray-700 mb-2">الوصف</label>
<textarea id="characterDescription" rows="4"
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent"
placeholder="صف شخصية الذكاء الاصطناعي ودوره وطريقة تحدثه..."></textarea>
</div>
<div>
<label for="characterInstructions" class="block text-sm font-medium text-gray-700 mb-2">التعليمات الخاصة</label>
<textarea id="characterInstructions" rows="4"
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent"
placeholder="أدخل التعليمات الخاصة بالشخصية..."></textarea>
</div>
<div class="flex justify-end space-x-3 space-x-reverse pt-4">
<button type="button" onclick="closeCharacterModal()" class="px-6 py-3 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors">
إلغاء
</button>
<button type="submit" class="px-6 py-3 bg-primary text-white rounded-lg hover:bg-primary/90 transition-colors">
حفظ الشخصية
</button>
</div>
</form>
</div>
</div>
</div>
<script>
// Global variables
let characters = [];
let filteredCharacters = [];
let currentPage = 1;
const charactersPerPage = 9;
let currentSort = 'recent';
let currentConversationId = null;
let isListening = false;
let recognition = null;
// Initialize database
function initDB() {
if (!window.indexedDB) {
console.log("IndexedDB غير مدعوم في هذا المتصفح");
return;
}
const request = indexedDB.open("GeminiPersonaDB", 1);
request.onerror = function(event) {
console.log("خطأ في فتح قاعدة البيانات");
};
request.onupgradeneeded = function(event) {
const db = event.target.result;
// Create conversations store
if (!db.objectStoreNames.contains('conversations')) {
const conversationsStore = db.createObjectStore('conversations', { keyPath: 'id', autoIncrement: true });
conversationsStore.createIndex('title', 'title', { unique: false });
conversationsStore.createIndex('createdAt', 'createdAt', { unique: false });
}
// Create characters store
if (!db.objectStoreNames.contains('characters')) {
const charactersStore = db.createObjectStore('characters', { keyPath: 'id', autoIncrement: true });
charactersStore.createIndex('name', 'name', { unique: false });
}
// Create settings store
if (!db.objectStoreNames.contains('settings')) {
const settingsStore = db.createObjectStore('settings', { keyPath: 'id' });
}
};
}
// Page navigation
function showPage(pageName) {
// Hide all pages with fade out
document.querySelectorAll('.page-container').forEach(page => {
page.classList.remove('active-page');
page.style.opacity = '0';
});
// Show the selected page with fade in
setTimeout(() => {
document.getElementById(pageName).classList.add('active-page');
document.getElementById(pageName).style.opacity = '1';
}, 100);
// Update page-specific content
if (pageName === 'characters') {
loadCharacters();
} else if (pageName === 'conversations') {
loadConversations();
} else if (pageName === 'chat') {
loadCharacterSelect();
} else if (pageName === 'voice-chat') {
loadVoiceCharacterSelect();
initSpeechRecognition();
} else if (pageName === 'settings') {
loadSettings();
} else if (pageName === 'home') {
loadStatistics();
}
feather.replace();
}
// Initialize app
document.addEventListener('DOMContentLoaded', function() {
initDB();
feather.replace();
loadStatistics();
showPage('home');
// Add smooth scroll behavior
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
const target = document.querySelector(this.getAttribute('href'));
if (target) {
target.scrollIntoView({ behavior: 'smooth' });
}
});
});
// Add loading animation
document.querySelectorAll('.page-container').forEach(page => {
page.style.opacity = '0';
page.style.transition = 'opacity 0.3s ease-in-out';
});
});
// Load statistics
function loadStatistics() {
const dbRequest = indexedDB.open("GeminiPersonaDB", 1);
dbRequest.onsuccess = function(event) {
const db = event.target.result;
// Count characters
const characterTransaction = db.transaction(['characters'], 'readonly');
const characterStore = characterTransaction.objectStore('characters');
characterStore.count().onsuccess = function(e) {
document.getElementById('totalCharacters').textContent = e.target.result;
};
// Count conversations and messages
const conversationTransaction = db.transaction(['conversations'], 'readonly');
const conversationStore = conversationTransaction.objectStore('conversations');
conversationStore.count().onsuccess = function(e) {
document.getElementById('totalConversations').textContent = e.target.result;
};
// Count total messages
conversationStore.getAll().onsuccess = function(e) {
const conversations = e.target.result;
const totalMessages = conversations.reduce((sum, conv) => sum + (conv.messages ? conv.messages.length : 0), 0);
document.getElementById('totalMessages').textContent = totalMessages;
};
};
}
// Characters functionality
// Load characters from IndexedDB
function loadCharacters() {
const request = indexedDB.open("GeminiPersonaDB", 1);
request.onsuccess = function(event) {
const db = event.target.result;
const transaction = db.transaction(['characters'], 'readonly');
const store = transaction.objectStore('characters');
const getAllRequest = store.getAll();
getAllRequest.onsuccess = function() {
characters = getAllRequest.result;
sortCharacters(currentSort);
filterCharacters();
renderCharacters();
};
};
}
// Sort characters
function sortCharacters(sortType) {
currentSort = sortType;
switch(sortType) {
case 'name':
characters.sort((a, b) => a.name.localeCompare(b.name));
break;
case 'nameDesc':
characters.sort((a, b) => b.name.localeCompare(a.name));
break;
case 'recent':
characters.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
break;
case 'oldest':
characters.sort((a, b) => new Date(a.createdAt) - new Date(b.createdAt));
break;
}
}
// Filter characters
function filterCharacters() {
const searchTerm = document.getElementById('searchInput').value.toLowerCase();
if (searchTerm) {
filteredCharacters = characters.filter(character =>
character.name.toLowerCase().includes(searchTerm) ||
(character.role && character.role.toLowerCase().includes(searchTerm)) ||
(character.description && character.description.toLowerCase().includes(searchTerm))
);
} else {
filteredCharacters = [...characters];
}
}
// Load more characters
function loadMoreCharacters() {
currentPage++;
renderCharacters();
}
// Render characters grid
function renderCharacters() {
const grid = document.getElementById('charactersGrid');
const emptyState = document.getElementById('emptyState');
const loadMoreContainer = document.getElementById('loadMoreContainer');
filterCharacters();
if (filteredCharacters.length === 0) {
grid.classList.add('hidden');
emptyState.classList.remove('hidden');
loadMoreContainer.classList.add('hidden');
return;
}
grid.classList.remove('hidden');
emptyState.classList.add('hidden');
const startIndex = 0;
const endIndex = currentPage * charactersPerPage;
const charactersToShow = filteredCharacters.slice(0, endIndex);
grid.innerHTML = charactersToShow.map(character => `
<div class="character-card bg-white rounded-xl shadow-md p-6">
<div class="flex justify-between items-start mb-4">
<div>
<h3 class="text-lg font-semibold text-gray-800">${character.name}</h3>
${character.role ? `<p class="text-sm text-gray-600">${character.role}</p>` : ''}
</div>
<div class="flex space-x-2 space-x-reverse">
<button onclick="editCharacter(${character.id})" class="text-blue-600 hover:text-blue-800 transition-colors">
<i data-feather="edit-2" class="w-4 h-4"></i>
</button>
<button onclick="duplicateCharacter(${character.id})" class="text-green-600 hover:text-green-800 transition-colors">
<i data-feather="copy" class="w-4 h-4"></i>
</button>
<button onclick="deleteCharacter(${character.id})" class="text-red-600 hover:text-red-800 transition-colors">
<i data-feather="trash-2" class="w-4 h-4"></i>
</button>
</div>
</div>
${character.description ? `<p class="text-gray-700 text-sm mb-4 line-clamp-3">${character.description}</p>` : ''}
<div class="flex space-x-2 space-x-reverse">
<button onclick="startChatWithCharacter(${character.id})" class="flex-1 bg-primary text-white py-2 px-4 rounded-lg hover:bg-primary/90 transition-colors text-sm">
بدء محادثة
</button>
<button onclick="startVoiceChatWithCharacter(${character.id})" class="bg-green-600 text-white p-2 rounded-lg hover:bg-green-700 transition-colors">
<i data-feather="mic" class="w-4 h-4"></i>
</button>
</div>
</div>
`).join('');
// Show/hide load more button
if (endIndex < filteredCharacters.length) {
loadMoreContainer.classList.remove('hidden');
} else {
loadMoreContainer.classList.add('hidden');
}
feather.replace();
}
// Open add character modal
function openAddCharacterModal() {
document.getElementById('characterModal').classList.remove('hidden');
document.getElementById('modalTitle').textContent = 'إضافة شخصية جديدة';
document.getElementById('characterForm').reset();
document.getElementById('characterId').value = '';
}
// Close character modal
function closeCharacterModal() {
document.getElementById('characterModal').classList.add('hidden');
}
// Edit character
function editCharacter(id) {
const character = characters.find(c => c.id === id);
if (!character) return;
document.getElementById('characterModal').classList.remove('hidden');
document.getElementById('modalTitle').textContent = 'تعديل الشخصية';
document.getElementById('characterId').value = character.id;
document.getElementById('characterName').value = character.name;
document.getElementById('characterRole').value = character.role || '';
document.getElementById('characterDescription').value = character.description || '';
document.getElementById('characterInstructions').value = character.instructions || '';
}
// Delete character
function deleteCharacter(id) {
if (!confirm('هل أنت متأكد من حذف هذه الشخصية؟')) return;
const request = indexedDB.open("GeminiPersonaDB", 1);
request.onsuccess = function(event) {
const db = event.target.result;
const transaction = db.transaction(['characters'], 'readwrite');
const store = transaction.objectStore('characters');
store.delete(id);
transaction.oncomplete = function() {
characters = characters.filter(c => c.id !== id);
renderCharacters();
};
};
}
// Start chat with character
function startChatWithCharacter(characterId) {
const character = characters.find(c => c.id === characterId);
if (character) {
localStorage.setItem('selectedCharacter', JSON.stringify(character));
showPage('chat');
loadCharacterSelect();
}
}
// Start voice chat with character
function startVoiceChatWithCharacter(characterId) {
const character = characters.find(c => c.id === characterId);
if (character) {
localStorage.setItem('selectedCharacter', JSON.stringify(character));
showPage('voice-chat');
loadVoiceCharacterSelect();
}
}
// Duplicate character
function duplicateCharacter(id) {
const character = characters.find(c => c.id === id);
if (!character) return;
const duplicatedCharacter = {
...character,
name: `${character.name} (نسخة)`,
createdAt: new Date().toISOString()
};
delete duplicatedCharacter.id;
const request = indexedDB.open("GeminiPersonaDB", 1);
request.onsuccess = function(event) {
const db = event.target.result;
const transaction = db.transaction(['characters'], 'readwrite');
const store = transaction.objectStore('characters');
store.add(duplicatedCharacter);
transaction.oncomplete = function() {
loadCharacters();
};
};
}
// Export characters
function exportCharacters() {
const dataStr = JSON.stringify(characters, null, 2);
const dataBlob = new Blob([dataStr], {type: 'application/json'});
const url = URL.createObjectURL(dataBlob);
const link = document.createElement('a');
link.href = url;
link.download = `smart-assistant-characters-${new Date().toISOString().split('T')[0]}.json`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
}
// Handle form submission
document.getElementById('characterForm').addEventListener('submit', function(e) {
e.preventDefault();
const characterData = {
name: document.getElementById('characterName').value,
role: document.getElementById('characterRole').value,
description: document.getElementById('characterDescription').value,
instructions: document.getElementById('characterInstructions').value,
createdAt: new Date().toISOString()
};
const characterId = document.getElementById('characterId').value;
const request = indexedDB.open("GeminiPersonaDB", 1);
request.onsuccess = function(event) {
const db = event.target.result;
const transaction = db.transaction(['characters'], 'readwrite');
const store = transaction.objectStore('characters');
if (characterId) {
// Update existing character
characterData.id = parseInt(characterId);
store.put(characterData);
} else {
// Add new character
store.add(characterData);
}
transaction.oncomplete = function() {
closeCharacterModal();
loadCharacters();
};
};
});
// Chat functionality
function loadCharacterSelect() {
const select = document.getElementById('characterSelect');
const request = indexedDB.open("GeminiPersonaDB", 1);
request.onsuccess = function(event) {
const db = event.target.result;
const transaction = db.transaction(['characters'], 'readonly');
const store = transaction.objectStore('characters');
const getAllRequest = store.getAll();
getAllRequest.onsuccess = function() {
const characters = getAllRequest.result;
select.innerHTML = '<option value="">اختر شخصية...</option>';
characters.forEach(character => {
const option = document.createElement('option');
option.value = character.id;
option.textContent = character.name;
select.appendChild(option);
});
// Check if there's a selected character in localStorage
const selectedCharacter = localStorage.getItem('selectedCharacter');
if (selectedCharacter) {
const character = JSON.parse(selectedCharacter);
select.value = character.id;
updateChatUI(character);
}
};
};
}
function updateChatUI(character) {
document.getElementById('characterInfo').textContent = `تتحدث مع: ${character.name}`;
document.getElementById('messageInput').disabled = false;
document.getElementById('sendButton').disabled = false;
}
async function sendMessage() {
const messageInput = document.getElementById('messageInput');
const message = messageInput.value.trim();
if (!message) return;
const characterSelect = document.getElementById('characterSelect');
const characterId = characterSelect.value;
if (!characterId) {
alert('يرجى اختيار شخصية أولاً');
return;
}
// Add user message to chat
addMessageToChat('user', message);
messageInput.value = '';
// Show loading indicator
const loadingDiv = document.createElement('div');
loadingDiv.className = 'flex justify-start';
loadingDiv.innerHTML = '<div class="chat-bubble-ai px-4 py-2"><div class="loading-spinner"></div></div>';
document.getElementById('messagesContainer').appendChild(loadingDiv);
document.getElementById('messagesContainer').scrollTop = document.getElementById('messagesContainer').scrollHeight;
// Get character info
const request = indexedDB.open("GeminiPersonaDB", 1);
request.onsuccess = function(event) {
const db = event.target.result;
const transaction = db.transaction(['characters'], 'readonly');
const store = transaction.objectStore('characters');
const getRequest = store.get(parseInt(characterId));
getRequest.onsuccess = function() {
const character = getRequest.result;
// Remove loading indicator
loadingDiv.remove();
// Simulate AI response with better formatting
setTimeout(() => {
const response = generateSmartResponse(message, character);
addMessageToChat('ai', response, character);
}, 1500);
};
};
}
function generateSmartResponse(message, character) {
const responses = {
doctor: [
"بناءً على ما ذكرت، أنصحك باستشارة الطبيب المختص للحصول على تشخيص دقيق.",
"هذه الأعراض قد تتطلب فحصاً طبياً شاملاً. هل يمكنك توضيح المزيد؟",
"من المهم مراقبة هذه الأعراض وتسجيلها لمساعدة الطبيب في التشخيص."
],
teacher: [
"هذا سؤال ممتاز! دعنا نحلل المفهوم خطوة بخطوة.",
"يمكنني شرح هذا الموضوع بطريقة أبسط. هل تريد التركيز على جانب معين؟",
"هذه نقطة مهمة جداً في الفهم. سأوضحها لك بمثال عملي."
],
friend: [
"أفهم ما تمر به تماماً. هل تريد أن تتحدث عن الأمر أكثر؟",
"أنا هنا للاستماع. شاركني ما يجول في خاطرك.",
"هذا موقف صعب حقاً. كيف تشعر حيال ذلك؟"
],
default: [
"هذا مثير للاهتمام! أخبرني المزيد عن هذا الموضوع.",
"أفهم وجهة نظرك. هل هناك جانب آخر ترغب في مناقشته؟",
"سؤال جيد! دعنا نفكر في هذا معاً."
]
};
const roleResponses = responses[character.role?.toLowerCase()] || responses.default;
return roleResponses[Math.floor(Math.random() * roleResponses.length)];
}
function addMessageToChat(sender, content, character = null) {
const messagesContainer = document.getElementById('messagesContainer');
const messageDiv = document.createElement('div');
messageDiv.className = `flex ${sender === 'user' ? 'justify-end' : 'justify-start'}`;
const bubbleClass = sender === 'user' ? 'chat-bubble-user' : 'chat-bubble-ai';
const bubble = document.createElement('div');
bubble.className = `${bubbleClass} max-w-xs md:max-w-md lg:max-w-lg px-4 py-2`;
if (sender === 'ai' && character) {
const nameDiv = document.createElement('div');
nameDiv.className = 'font-semibold text-sm mb-1';
nameDiv.textContent = character.name;
bubble.appendChild(nameDiv);
}
const contentDiv = document.createElement('div');
contentDiv.className = 'markdown-content';
contentDiv.innerHTML = marked.parse(content);
bubble.appendChild(contentDiv);
messageDiv.appendChild(bubble);
messagesContainer.appendChild(messageDiv);
messagesContainer.scrollTop = messagesContainer.scrollHeight;
}
function saveConversation() {
const messages = document.querySelectorAll('#messagesContainer .flex');
if (messages.length === 0) {
alert('لا توجد رسائل لحفظها');
return;
}
const characterSelect = document.getElementById('characterSelect');
const characterId = characterSelect.value;
const characterName = characterSelect.options[characterSelect.selectedIndex].text;
const conversationData = {
title: `محادثة مع ${characterName}`,
characterId: parseInt(characterId),
characterName: characterName,
messages: Array.from(messages).map(msg => {
const isUser = msg.classList.contains('justify-end');
const content = msg.querySelector('.markdown-content')?.innerHTML || msg.querySelector('div:not(.font-semibold)')?.textContent || '';
return {
sender: isUser ? 'user' : 'ai',
content: content,
timestamp: new Date().toISOString()
};
}),
createdAt: new Date().toISOString()
};
const request = indexedDB.open("GeminiPersonaDB", 1);
request.onsuccess = function(event) {
const db = event.target.result;
const transaction = db.transaction(['conversations'], 'readwrite');
const store = transaction.objectStore('conversations');
store.add(conversationData);
transaction.oncomplete = function() {
alert('تم حفظ المحادثة بنجاح');
};
};
}
function clearChat() {
document.getElementById('messagesContainer').innerHTML = `
<div class="text-center text-gray-500 py-8">
<i data-feather="message-circle" class="w-12 h-12 mx-auto mb-4"></i>
<p>ابدأ محادثة جديدة...</p>
</div>
`;
feather.replace();
}
function exportChat() {
const messages = document.querySelectorAll('#messagesContainer .flex');
if (messages.length === 0) {
alert('لا توجد رسائل لتصديرها');
return;
}
const characterSelect = document.getElementById('characterSelect');
const characterName = characterSelect.options[characterSelect.selectedIndex].text;
let chatContent = `محادثة مع ${characterName}\n`;
chatContent += `التاريخ: ${new Date().toLocaleString('ar-SA')}\n`;
chatContent += '=' .repeat(50) + '\n\n';
messages.forEach(msg => {
const isUser = msg.classList.contains('justify-end');
const sender = isUser ? 'أنت' : characterName;
const content = msg.querySelector('.markdown-content')?.textContent || msg.querySelector('div:not(.font-semibold)')?.textContent || '';
chatContent += `${sender}: ${content}\n\n`;
});
const dataBlob = new Blob([chatContent], {type: 'text/plain'});
const url = URL.createObjectURL(dataBlob);
const link = document.createElement('a');
link.href = url;
link.download = `chat-${characterName}-${new Date().toISOString().split('T')[0]}.txt`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
}
// Voice chat functionality
function loadVoiceCharacterSelect() {
const select = document.getElementById('voiceCharacterSelect');
const request = indexedDB.open("GeminiPersonaDB", 1);
request.onsuccess = function(event) {
const db = event.target.result;
const transaction = db.transaction(['characters'], 'readonly');
const store = transaction.objectStore('characters');
const getAllRequest = store.getAll();
getAllRequest.onsuccess = function() {
const characters = getAllRequest.result;
select.innerHTML = '<option value="">اختر شخصية...</option>';
characters.forEach(character => {
const option = document.createElement('option');
option.value = character.id;
option.textContent = character.name;
select.appendChild(option);
});
// Check if there's a selected character in localStorage
const selectedCharacter = localStorage.getItem('selectedCharacter');
if (selectedCharacter) {
const character = JSON.parse(selectedCharacter);
select.value = character.id;
}
};
};
}
function initSpeechRecognition() {
if ('webkitSpeechRecognition' in window) {
recognition = new webkitSpeechRecognition();
recognition.continuous = false;
recognition.interimResults = false;
recognition.lang = 'ar-SA';
recognition.onstart = function() {
isListening = true;
document.getElementById('listenButton').innerHTML = '<i data-feather="square" class="w-4 h-4"></i><span>إيقاف الاستماع</span>';
document.getElementById('voiceStatus').textContent = 'جاري الاستماع...';
feather.replace();
};
recognition.onresult = function(event) {
const transcript = event.results[0][0].transcript;
addVoiceMessage('user', transcript);
// Simulate AI response
setTimeout(() => {
addVoiceMessage('ai', `تم استقبال رسالتك: "${transcript}"`);
}, 1000);
};
recognition.onerror = function(event) {
console.error('Speech recognition error', event.error);
document.getElementById('voiceStatus').textContent = 'خطأ في التعرف على الصوت';
};
recognition.onend = function() {
isListening = false;
document.getElementById('listenButton').innerHTML = '<i data-feather="mic" class="w-4 h-4"></i><span>بدء الاستماع</span>';
document.getElementById('voiceStatus').textContent = 'جاهز للاستماع...';
feather.replace();
};
} else {
alert('متصفحك لا يدعم التعرف على الصوت');
}
}
function toggleListening() {
if (!recognition) return;
if (isListening) {
recognition.stop();
} else {
const characterSelect = document.getElementById('voiceCharacterSelect');
if (!characterSelect.value) {
alert('يرجى اختيار شخصية أولاً');
return;
}
recognition.start();
}
}
function addVoiceMessage(sender, content) {
const messagesContainer = document.getElementById('voiceMessagesContainer');
const messageDiv = document.createElement('div');
messageDiv.className = `flex ${sender === 'user' ? 'justify-end' : 'justify-start'}`;
const bubbleClass = sender === 'user' ? 'chat-bubble-user' : 'chat-bubble-ai';
const bubble = document.createElement('div');
bubble.className = `${bubbleClass} max-w-xs md:max-w-md lg:max-w-lg px-4 py-2`;
bubble.textContent = content;
messageDiv.appendChild(bubble);
messagesContainer.appendChild(messageDiv);
messagesContainer.scrollTop = messagesContainer.scrollHeight;
}
// Conversations functionality
function loadConversations() {
const request = indexedDB.open("GeminiPersonaDB", 1);
request.onsuccess = function(event) {
const db = event.target.result;
const transaction = db.transaction(['conversations'], 'readonly');
const store = transaction.objectStore('conversations');
const getAllRequest = store.getAll();
getAllRequest.onsuccess = function() {
const conversations = getAllRequest.result;
renderConversations(conversations);
};
};
}
function renderConversations(conversations) {
const container = document.getElementById('conversationsList');
const emptyState = document.getElementById('conversationsEmptyState');
if (conversations.length === 0) {
container.classList.add('hidden');
emptyState.classList.remove('hidden');
return;
}
container.classList.remove('hidden');
emptyState.classList.add('hidden');
container.innerHTML = conversations.map(conv => `
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-4 hover:shadow-md transition-shadow">
<div class="flex justify-between items-start">
<div class="flex-1">
<h3 class="text-lg font-semibold text-gray-800">${conv.title || 'محادثة بدون عنوان'}</h3>
<p class="text-gray-600 text-sm mt-1">${new Date(conv.createdAt).toLocaleString('ar-SA')}</p>
<p class="text-gray-500 text-sm mt-2">${conv.messages ? conv.messages.length + ' رسالة' : 'لا توجد رسائل'}</p>
</div>
<div class="flex space-x-2 space-x-reverse">
<button onclick="loadConversation(${conv.id})" class="bg-primary text-white px-4 py-2 rounded-lg hover:bg-primary/90 transition-colors text-sm">
فتح
</button>
<button onclick="deleteConversation(${conv.id})" class="bg-red-600 text-white px-4 py-2 rounded-lg hover:bg-red-700 transition-colors text-sm">
حذف
</button>
</div>
</div>
</div>
`).join('');
}
function deleteConversation(id) {
if (!confirm('هل أنت متأكد من حذف هذه المحادثة؟')) return;
const request = indexedDB.open("GeminiPersonaDB", 1);
request.onsuccess = function(event) {
const db = event.target.result;
const transaction = db.transaction(['conversations'], 'readwrite');
const store = transaction.objectStore('conversations');
store.delete(id);
transaction.oncomplete = function() {
loadConversations();
};
};
}
function exportAllConversations() {
const request = indexedDB.open("GeminiPersonaDB", 1);
request.onsuccess = function(event) {
const db = event.target.result;
const transaction = db.transaction(['conversations'], 'readonly');
const store = transaction.objectStore('conversations');
const getAllRequest = store.getAll();
getAllRequest.onsuccess = function() {
const conversations = getAllRequest.result;
const dataStr = JSON.stringify(conversations, null, 2);
const dataBlob = new Blob([dataStr], {type: 'application/json'});
const url = URL.createObjectURL(dataBlob);
const link = document.createElement('a');
link.href = url;
link.download = `smart-assistant-conversations-${new Date().toISOString().split('T')[0]}.json`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
};
};
}
// Settings functionality
function loadSettings() {
const request = indexedDB.open("GeminiPersonaDB", 1);
request.onsuccess = function(event) {
const db = event.target.result;
const transaction = db.transaction(['settings'], 'readonly');
const store = transaction.objectStore('settings');
const getRequest = store.get('apiKey');
getRequest.onsuccess = function() {
if (getRequest.result) {
document.getElementById('apiKey').value = getRequest.result.value || '';
}
};
const getSettingsRequest = store.get('general');
getSettingsRequest.onsuccess = function() {
if (getSettingsRequest.result) {
const settings = getSettingsRequest.result;
document.getElementById('language').value = settings.language || 'ar';
document.getElementById('theme').value = settings.theme || 'light';
}
};
};
}
function saveApiKey() {
const apiKey = document.getElementById('apiKey').value;
const request = indexedDB.open("GeminiPersonaDB", 1);
request.onsuccess = function(event) {
const db = event.target.result;
const transaction = db.transaction(['settings'], 'readwrite');
const store = transaction.objectStore('settings');
store.put({ id: 'apiKey', value: apiKey });
transaction.oncomplete = function() {
alert('تم حفظ مفتاح API');
};
};
}
function saveGeneralSettings() {
const language = document.getElementById('language').value;
const theme = document.getElementById('theme').value;
const request = indexedDB.open("GeminiPersonaDB", 1);
request.onsuccess = function(event) {
const db = event.target.result;
const transaction = db.transaction(['settings'], 'readwrite');
const store = transaction.objectStore('settings');
store.put({ id: 'general', language, theme });
transaction.oncomplete = function() {
alert('تم حفظ الإعدادات');
};
};
}
function clearAllData() {
if (!confirm('هل أنت متأكد من مسح جميع البيانات؟ لا يمكن التراجع عن هذا الإجراء.')) return;
const request = indexedDB.open("GeminiPersonaDB", 1);
request.onsuccess = function(event) {
const db = event.target.result;
const transaction = db.transaction(['conversations', 'characters', 'settings'], 'readwrite');
transaction.objectStore('conversations').clear();
transaction.objectStore('characters').clear();
transaction.objectStore('settings').clear();
transaction.oncomplete = function() {
alert('تم مسح جميع البيانات');
location.reload();
};
};
}
function exportAllData() {
const request = indexedDB.open("GeminiPersonaDB", 1);
request.onsuccess = function(event) {
const db = event.target.result;
const transaction = db.transaction(['conversations', 'characters', 'settings'], 'readonly');
const conversationsStore = transaction.objectStore('conversations');
const charactersStore = transaction.objectStore('characters');
const settingsStore = transaction.objectStore('settings');
Promise.all([
new Promise(resolve => conversationsStore.getAll().onsuccess = e => resolve(e.target.result)),
new Promise(resolve => charactersStore.getAll().onsuccess = e => resolve(e.target.result)),
new Promise(resolve => settingsStore.getAll().onsuccess = e => resolve(e.target.result))
]).then(([conversations, characters, settings]) => {
const data = {
conversations,
characters,
settings,
exportDate: new Date().toISOString()
};
const dataStr = JSON.stringify(data, null, 2);
const dataBlob = new Blob([dataStr], {type: 'application/json'});
const url = URL.createObjectURL(dataBlob);
const link = document.createElement('a');
link.href = url;
link.download = `smart-assistant-backup-${new Date().toISOString().split('T')[0]}.json`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
});
};
}
function importData(event) {
const file = event.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function(e) {
try {
const data = JSON.parse(e.target.result);
const request = indexedDB.open("GeminiPersonaDB", 1);
request.onsuccess = function(event) {
const db = event.target.result;
const transaction = db.transaction(['conversations', 'characters', 'settings'], 'readwrite');
// Clear existing data
transaction.objectStore('conversations').clear();
transaction.objectStore('characters').clear();
transaction.objectStore('settings').clear();
// Import new data
if (data.conversations && data.conversations.length > 0) {
const conversationsStore = transaction.objectStore('conversations');
data.conversations.forEach(conv => {
delete conv.id; // Let IndexedDB generate new ID
conversationsStore.add(conv);
});
}
if (data.characters && data.characters.length > 0) {
const charactersStore = transaction.objectStore('characters');
data.characters.forEach(char => {
delete char.id; // Let IndexedDB generate new ID
charactersStore.add(char);
});
}
if (data.settings && data.settings.length > 0) {
const settingsStore = transaction.objectStore('settings');
data.settings.forEach(setting => {
settingsStore.add(setting);
});
}
transaction.oncomplete = function() {
alert('تم استيراد البيانات بنجاح');
location.reload();
};
};
} catch (error) {
alert('خطأ في قراءة الملف. يرجى التأكد من أنه ملف نسخة احتياطية صحيح.');
}
};
reader.readAsText(file);
}
// Add event listeners for search and sort in characters page
document.addEventListener('DOMContentLoaded', function() {
document.getElementById('searchInput')?.addEventListener('input', function() {
currentPage = 1;
renderCharacters();
});
document.getElementById('sortSelect')?.addEventListener('change', function(e) {
sortCharacters(e.target.value);
currentPage = 1;
renderCharacters();
});
document.getElementById('messageInput')?.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
sendMessage();
}
});
});
</script>
<!-- Footer -->
<footer class="bg-gray-800 text-white py-4 mt-auto">
<div class="text-center">
<p class="text-sm">تصميم المهندس احمد السقاف</p>
</div>
</footer>
</body>
</html>