Spaces:
Build error
Build error
| import flet as ft | |
| import speech_recognition as sr | |
| import threading | |
| import webbrowser | |
| import datetime | |
| import json | |
| import os | |
| # قاعدة بيانات محسنة لحفظ الأوامر المتكررة | |
| class CommandMemory: | |
| def __init__(self, file_path="commands.json"): | |
| self.file_path = file_path | |
| self.learned_commands = {} | |
| self.load_commands() | |
| def load_commands(self): | |
| """تحميل الأوامر المحفوظة من ملف""" | |
| try: | |
| if os.path.exists(self.file_path): | |
| with open(self.file_path, 'r', encoding='utf-8') as f: | |
| self.learned_commands = json.load(f) | |
| print(f"[النظام] تم تحميل {len(self.learned_commands)} أمرًا من الذاكرة.") | |
| except Exception as e: | |
| print(f"[خطأ] تعذر تحميل الذاكرة: {e}") | |
| def save_commands(self): | |
| """حفظ الأوامر في ملف""" | |
| try: | |
| with open(self.file_path, 'w', encoding='utf-8') as f: | |
| json.dump(self.learned_commands, f, ensure_ascii=False, indent=2) | |
| except Exception as e: | |
| print(f"[خطأ] تعذر حفظ الذاكرة: {e}") | |
| def learn(self, command): | |
| """تعلم أمر جديد وتحديث العداد""" | |
| command = self.clean_arabic_text(command) | |
| self.learned_commands[command] = self.learned_commands.get(command, 0) + 1 | |
| print(f"[تعلم] '{command}' - عدد مرات الاستخدام: {self.learned_commands[command]}") | |
| self.save_commands() | |
| def count(self, command): | |
| """الحصول على عدد مرات استخدام الأمر""" | |
| command = self.clean_arabic_text(command) | |
| return self.learned_commands.get(command, 0) | |
| def clean_arabic_text(self, text): | |
| """تنظيف وتحسين النص العربي""" | |
| corrections = { | |
| "شغل": "تشغيل", | |
| "افتح": "فتح", | |
| "شغّل": "تشغيل", | |
| "افتحي": "فتح", | |
| "شغلي": "تشغيل" | |
| } | |
| for wrong, correct in corrections.items(): | |
| text = text.replace(wrong, correct) | |
| return text.strip().lower() | |
| def get_most_used_commands(self, limit=5): | |
| """الحصول على أكثر الأوامر استخدامًا""" | |
| sorted_commands = sorted(self.learned_commands.items(), key=lambda x: x[1], reverse=True) | |
| return sorted_commands[:limit] | |
| # الذكاء المحسن للتعامل مع الأوامر | |
| class NoraBrain: | |
| def __init__(self, memory: CommandMemory): | |
| self.memory = memory | |
| def reply(self, command): | |
| command = self.memory.clean_arabic_text(command) | |
| # فتح التطبيقات والوظائف | |
| if any(word in command for word in ["فتح", "تشغيل", "اذهب"]) and "الكاميرا" in command: | |
| try: | |
| webbrowser.open("camera://") | |
| return "تم فتح الكاميرا بنجاح! 📸" | |
| except: | |
| return "عذرًا، لا يمكن فتح الكاميرا حالياً." | |
| elif any(word in command for word in ["تشغيل", "شغل"]) and "الموسيقى" in command: | |
| try: | |
| webbrowser.open("spotify://") | |
| return "تشغيل الموسيقى بأعلى جودة! 🎵" | |
| except: | |
| return "جارٍ تشغيل الموسيقى..." | |
| elif any(word in command for word in ["اتصال", "اتصل"]) and "ب" in command: | |
| contact = self.extract_contact(command) | |
| return f"جارٍ الاتصال بـ {contact}... 📞" | |
| elif "اتصال" in command or "اتصل" in command: | |
| return "من الشخص الذي ترغب في الاتصال به؟" | |
| elif any(word in command for word in ["الوقت", "الساعة", "كم الساعة"]): | |
| current_time = datetime.datetime.now().strftime("%I:%M %p") | |
| return f"الوقت الآن هو: {current_time} 🕒" | |
| elif any(word in command for word in ["التاريخ", "تاريخ", "اليوم"]): | |
| current_date = datetime.datetime.now().strftime("%Y-%m-%d") | |
| return f"تاريخ اليوم هو: {current_date} 📅" | |
| elif any(word in command for word in ["طقس", "الطقس", "الجو"]): | |
| return "جارٍ التحقق من حالة الطقس في موقعك... ☀️" | |
| elif any(word in command for word in ["رسالة", "ارسل", "أرسل"]): | |
| return "ما هي الرسالة التي تريد إرسالها؟ ومن سترسلها إليه؟ 💬" | |
| elif any(word in command for word in ["موعد", "تذكير", "ذكرني"]): | |
| return "سأضيف تذكيرًا لك، ما هو التفاصيل والوقت؟ ⏰" | |
| elif "اذكر أكثر الأوامر استخداما" in command: | |
| most_used = self.memory.get_most_used_commands(3) | |
| if most_used: | |
| response = "أكثر الأوامر استخدامًا:\n" | |
| for i, (cmd, count) in enumerate(most_used, 1): | |
| response += f"{i}. {cmd} ({count} مرات)\n" | |
| return response | |
| else: | |
| return "لا توجد أوامر مستخدمة بعد." | |
| elif "مسح الذاكرة" in command or "انسى كل شيء" in command: | |
| self.memory.learned_commands = {} | |
| self.memory.save_commands() | |
| return "تم مسح الذاكرة بنجاح! 🧹" | |
| elif self.memory.count(command) > 0: | |
| count = self.memory.count(command) | |
| return f"لقد استخدمت هذا الأمر {count} مرّة{'ة' if count == 1 else 'ات'} من قبل. 🔄" | |
| else: | |
| suggestions = [ | |
| "جرب: 'فتح الكاميرا'", | |
| "جرب: 'تشغيل الموسيقى'", | |
| "جرب: 'كم الساعة'", | |
| "جرب: 'اذكر أكثر الأوامر استخداما'" | |
| ] | |
| suggestion = suggestions[hash(command) % len(suggestions)] | |
| return f"عذرًا، لم أفهم الأمر. {suggestion} 🤔" | |
| def extract_contact(self, command): | |
| """استخراج اسم الجهة من أمر الاتصال""" | |
| words = command.split() | |
| if "ب" in words: | |
| index = words.index("ب") | |
| if index + 1 < len(words): | |
| return words[index + 1] | |
| return "الجهة المطلوبة" | |
| # مسؤول محسن عن التعامل مع الصوت | |
| class VoiceController: | |
| def __init__(self, brain: NoraBrain, page: ft.Page, chat_container): | |
| self.recognizer = sr.Recognizer() | |
| self.microphone = sr.Microphone() | |
| self.page = page | |
| self.brain = brain | |
| self.chat_container = chat_container | |
| self.is_listening = False | |
| def add_message(self, text, is_user=False): | |
| """إضافة رسالة إلى واجهة المحادثة""" | |
| color = "#2563eb" if is_user else "#059669" | |
| bg_color = "#dbeafe" if is_user else "#d1fae5" | |
| align = ft.CrossAxisAlignment.END if is_user else ft.CrossAxisAlignment.START | |
| message_content = ft.Container( | |
| content=ft.Text( | |
| text, | |
| color=color, | |
| size=14, | |
| selectable=True | |
| ), | |
| padding=ft.padding.all(12), | |
| bgcolor=bg_color, | |
| border_radius=ft.border_radius.only( | |
| top_left=15, | |
| top_right=15, | |
| bottom_left=0 if is_user else 15, | |
| bottom_right=15 if is_user else 0 | |
| ), | |
| margin=ft.margin.only(bottom=10), | |
| alignment=ft.alignment.center_left, | |
| ) | |
| self.chat_container.controls.append( | |
| ft.Row( | |
| controls=[message_content], | |
| alignment=ft.MainAxisAlignment.END if is_user else ft.MainAxisAlignment.START | |
| ) | |
| ) | |
| self.page.update() | |
| def listen_once(self): | |
| """الاستماع لأمر واحد فقط""" | |
| if self.is_listening: | |
| return | |
| self.is_listening = True | |
| try: | |
| with self.microphone as source: | |
| self.add_message("🎤 أستمع إليك...", is_user=False) | |
| audio = self.recognizer.listen(source, timeout=10, phrase_time_limit=8) | |
| command = self.recognizer.recognize_google(audio, language="ar-AR") | |
| self.add_message(f"{command}", is_user=True) | |
| self.brain.memory.learn(command) | |
| response = self.brain.reply(command) | |
| self.add_message(f"نورا: {response}", is_user=False) | |
| except sr.WaitTimeoutError: | |
| self.add_message("⏰ انتهى وقت الانتظار، لم أسمع أي شيء.", is_user=False) | |
| except sr.UnknownValueError: | |
| self.add_message("❌ لم أتمكن من فهم الصوت، حاول مرة أخرى.", is_user=False) | |
| except Exception as e: | |
| self.add_message(f"⚠️ خطأ في التعرف على الصوت: {str(e)}", is_user=False) | |
| finally: | |
| self.is_listening = False | |
| def listen_loop(self): | |
| """وضع الاستماع المستمر (للخلفية)""" | |
| with self.microphone as source: | |
| self.recognizer.adjust_for_ambient_noise(source) | |
| print("[النظام] تم ضبط حساسية الميكروفون.") | |
| while True: | |
| try: | |
| if not self.is_listening: | |
| with self.microphone as source: | |
| audio = self.recognizer.listen(source, timeout=5, phrase_time_limit=7) | |
| command = self.recognizer.recognize_google(audio, language="ar-AR") | |
| self.page.call_from_thread(lambda: self.add_message(f"{command}", is_user=True)) | |
| self.brain.memory.learn(command) | |
| response = self.brain.reply(command) | |
| self.page.call_from_thread(lambda: self.add_message(f"نورا: {response}", is_user=False)) | |
| except (sr.WaitTimeoutError, sr.UnknownValueError): | |
| continue | |
| except Exception as e: | |
| print(f"[خطأ] {e}") | |
| # الواجهة الرئيسية المحسنة | |
| def main(page: ft.Page): | |
| page.title = "نورا فون - مساعد صوتي عربي ذكي" | |
| page.theme_mode = ft.ThemeMode.LIGHT | |
| page.bgcolor = "#f8fafc" | |
| page.padding = 0 | |
| page.scroll = "auto" | |
| # حاوية المحادثة | |
| chat_container = ft.Column( | |
| scroll="auto", | |
| expand=True, | |
| spacing=10 | |
| ) | |
| # الذاكرة والعقل | |
| memory = CommandMemory() | |
| brain = NoraBrain(memory) | |
| controller = VoiceController(brain, page, chat_container) | |
| # زر الميكروفون | |
| mic_button = ft.ElevatedButton( | |
| content=ft.Row([ | |
| ft.Icon(ft.icons.MIC, color="white", size=24), | |
| ft.Text("اضغط للتحدث", color="white", size=16) | |
| ], alignment=ft.MainAxisAlignment.CENTER), | |
| on_click=lambda e: threading.Thread(target=controller.listen_once, daemon=True).start(), | |
| bgcolor="#7c3aed", | |
| color="white", | |
| width=200, | |
| height=60, | |
| style=ft.ButtonStyle( | |
| shape=ft.RoundedRectangleBorder(radius=15), | |
| padding=20 | |
| ) | |
| ) | |
| # الهيدر | |
| header = ft.Container( | |
| content=ft.Column([ | |
| ft.Row([ | |
| ft.Icon(ft.icons.SMARTPHONE, color="#7c3aed", size=32), | |
| ft.Text("نورا فون", size=28, weight=ft.FontWeight.BOLD, color="#7c3aed"), | |
| ], alignment=ft.MainAxisAlignment.CENTER), | |
| ft.Text("المساعد الصوتي الذكي باللغة العربية", size=16, color="#6b7280"), | |
| ], horizontal_alignment=ft.CrossAxisAlignment.CENTER), | |
| padding=20, | |
| bgcolor="white", | |
| margin=ft.margin.only(bottom=10) | |
| ) | |
| # منطقة المحادثة | |
| chat_area = ft.Container( | |
| content=chat_container, | |
| padding=20, | |
| expand=True, | |
| bgcolor="#f8fafc" | |
| ) | |
| # لوحة التحكم | |
| control_panel = ft.Container( | |
| content=ft.Column([ | |
| ft.Text("الأوامر المتاحة:", size=16, weight=ft.FontWeight.BOLD, color="#374151"), | |
| ft.Text("• 'فتح الكاميرا' - فتح الكاميرا", size=14, color="#6b7280"), | |
| ft.Text("• 'تشغيل الموسيقى' - تشغيل الموسيقى", size=14, color="#6b7280"), | |
| ft.Text("• 'كم الساعة' - معرفة الوقت", size=14, color="#6b7280"), | |
| ft.Text("• 'اذكر أكثر الأوامر استخداما' - إحصائيات", size=14, color="#6b7280"), | |
| ], spacing=5), | |
| padding=15, | |
| bgcolor="#e0e7ff", | |
| border_radius=10, | |
| margin=ft.margin.all(10) | |
| ) | |
| # تجميع الواجهة | |
| page.add( | |
| header, | |
| chat_area, | |
| ft.Container(mic_button, alignment=ft.alignment.center, margin=15), | |
| control_panel | |
| ) | |
| # رسالة ترحيب | |
| chat_container.controls.append( | |
| ft.Row([ | |
| ft.Container( | |
| content=ft.Text( | |
| "مرحبًا! أنا نورا، مساعدتك الصوتية الذكية. اضغط على الزر للتحدث أو استخدم الأوامر الصوتية مباشرة.", | |
| color="#059669", | |
| size=14 | |
| ), | |
| padding=12, | |
| bgcolor="#d1fae5", | |
| border_radius=15, | |
| ) | |
| ], alignment=ft.MainAxisAlignment.START) | |
| ) | |
| # بدء الاستماع في الخلفية | |
| threading.Thread(target=controller.listen_loop, daemon=True).start() | |
| # تشغيل التطبيق | |
| if __name__ == "__main__": | |
| ft.app( | |
| target=main, | |
| view=ft.AppView.WEB_BROWSER, | |
| port=8500 | |
| ) |