Spaces:
Sleeping
Sleeping
| # ============================================================================= | |
| # كود Ollama لـ Hugging Face Space مع Ngrok | |
| # نسخة محسّنة ومستقرة | |
| # ============================================================================= | |
| import sys | |
| import subprocess | |
| import time | |
| import os | |
| import signal | |
| import threading | |
| import gradio as gr | |
| # ----------------------------------------------------------------------------- | |
| # الجزء الأول: تثبيت المكتبات الضرورية و Ollama | |
| # ----------------------------------------------------------------------------- | |
| print("✅ [الخطوة 1/5]: تثبيت المكتبات الضرورية و Ollama...") | |
| sys.stdout.flush() | |
| # تثبيت pyngrok | |
| print(" - تثبيت pyngrok...", end="") | |
| sys.stdout.flush() | |
| try: | |
| subprocess.run([sys.executable, '-m', 'pip', 'install', 'pyngrok', '-q'], check=True) | |
| print(" تم.") | |
| sys.stdout.flush() | |
| except subprocess.CalledProcessError as e: | |
| print(f"\n[❌ خطأ فادح]: فشل تثبيت pyngrok. رمز الخروج: {e.returncode}") | |
| sys.exit(1) | |
| from pyngrok import ngrok | |
| # تثبيت Ollama | |
| print(" - تثبيت Ollama بالطريقة الرسمية...") | |
| sys.stdout.flush() | |
| try: | |
| install_command = "curl -fsSL https://ollama.com/install.sh | sh" | |
| subprocess.run(install_command, shell=True, check=True, capture_output=True, text=True) | |
| print(" - تم تثبيت Ollama بنجاح.") | |
| sys.stdout.flush() | |
| except subprocess.CalledProcessError as e: | |
| print(f"\n[❌ خطأ فادح]: فشل تثبيت Ollama. رمز الخروج: {e.returncode}") | |
| print(e.stderr) | |
| sys.exit(1) | |
| except Exception as e: | |
| print(f"\n[❌ خطأ فادح]: حدث خطأ غير متوقع أثناء تثبيت Ollama. الخطأ: {e}") | |
| sys.exit(1) | |
| print("✅ [الخطوة 1/5]: تم تثبيت المكتبات و Ollama بنجاح!\n") | |
| sys.stdout.flush() | |
| # ----------------------------------------------------------------------------- | |
| # الجزء الثاني: إعداد Ngrok وتشغيل خادم Ollama | |
| # ----------------------------------------------------------------------------- | |
| print("✅ [الخطوة 2/5]: إعداد Ngrok وتشغيل خادم Ollama...") | |
| sys.stdout.flush() | |
| # استخدم Hugging Face Secrets لتخزين التوكن بشكل آمن | |
| NGROK_AUTH_TOKEN = os.getenv("NGROK_AUTH_TOKEN", "") | |
| try: | |
| if not NGROK_AUTH_TOKEN: | |
| raise ValueError("⚠️ يرجى إضافة NGROK_AUTH_TOKEN في إعدادات Secrets للـ Space") | |
| print(" - إعداد Ngrok Auth Token...", end="") | |
| ngrok.set_auth_token(NGROK_AUTH_TOKEN) | |
| print(" تم.") | |
| sys.stdout.flush() | |
| except Exception as e: | |
| print(f"\n[❌ خطأ فادح]: فشل إعداد Ngrok Auth Token. الخطأ: {e}") | |
| sys.exit(1) | |
| # تشغيل خادم Ollama في الخلفية | |
| print(" - تشغيل خادم Ollama في الخلفية...", end="") | |
| sys.stdout.flush() | |
| os.environ['OLLAMA_HOST'] = '0.0.0.0:11434' | |
| ollama_serve_process = None | |
| try: | |
| ollama_serve_process = subprocess.Popen( | |
| ['ollama', 'serve'], | |
| stdout=subprocess.PIPE, | |
| stderr=subprocess.PIPE, | |
| preexec_fn=os.setsid | |
| ) | |
| print(" جاري البدء...", end="") | |
| time.sleep(10) | |
| check_process = subprocess.run(['ollama', 'list'], capture_output=True, text=True, timeout=20) | |
| if check_process.returncode == 0: | |
| print(" يعمل بنجاح.") | |
| else: | |
| print(f"\n - [❌] فشل تشغيل خادم Ollama بشكل صحيح.") | |
| stderr_output = ollama_serve_process.stderr.read().decode('utf-8') | |
| print(f" الخطأ من الخادم: {stderr_output.strip()}") | |
| raise Exception("الخادم لم يبدأ بشكل صحيح.") | |
| except Exception as e: | |
| print(f"\n[❌ خطأ فادح]: فشل تشغيل خادم Ollama. الخطأ: {e}") | |
| sys.exit(1) | |
| print("✅ [الخطوة 2/5]: تم تشغيل خادم Ollama بنجاح.\n") | |
| sys.stdout.flush() | |
| # ----------------------------------------------------------------------------- | |
| # الجزء الثالث: تشغيل ngrok وإنشاء الرابط العام | |
| # ----------------------------------------------------------------------------- | |
| print("✅ [الخطوة 3/5]: جاري تشغيل ngrok لتعريض Ollama API...") | |
| sys.stdout.flush() | |
| ngrok_tunnel = None | |
| public_url_str = None | |
| try: | |
| print(" - إنشاء نفق ngrok...", end="") | |
| ngrok_tunnel = ngrok.connect(11434, "http") | |
| public_url_str = ngrok_tunnel.public_url | |
| print(" تم.") | |
| sys.stdout.flush() | |
| print("\n🔗 الـ API متاح الآن على الرابط العام التالي:") | |
| print(f" {public_url_str}") | |
| print("\n") | |
| sys.stdout.flush() | |
| except Exception as e: | |
| print(f"\n[❌ خطأ فادح]: حدث خطأ أثناء تشغيل ngrok. الخطأ: {e}") | |
| sys.exit(1) | |
| print("✅ [الخطوة 3/5]: تم تشغيل النفق بنجاح وتم عرض الرابط.\n") | |
| sys.stdout.flush() | |
| # ----------------------------------------------------------------------------- | |
| # الجزء الرابع: فحص مساحة التخزين وسحب النماذج | |
| # ----------------------------------------------------------------------------- | |
| print("✅ [الخطوة 4/5]: فحص مساحة التخزين وسحب النماذج المطلوبة...") | |
| sys.stdout.flush() | |
| print(" - فحص مساحة التخزين المتاحة...") | |
| subprocess.run(['df', '-h', '/']) | |
| print("") | |
| sys.stdout.flush() | |
| models_to_pull = [ | |
| "hf.co/Mungert/VibeThinker-1.5B-GGUF:BF16", | |
| "hf.co/Mungert/Qwen3-30B-A1.5B-High-Speed-GGUF:IQ3_M", | |
| ] | |
| successfully_pulled = [] | |
| failed_to_pull = [] | |
| print(" - ستبدأ عملية سحب النماذج بشكل تسلسلي (واحد تلو الآخر) لضمان الاستقرار.") | |
| print(" - ستظهر لك نسبة التقدم لكل نموذج بشكل مباشر. قد يستغرق هذا وقتًا طويلاً.\n") | |
| sys.stdout.flush() | |
| for model_name in models_to_pull: | |
| print(f"--- [⏳] جاري سحب النموذج: {model_name} ---") | |
| sys.stdout.flush() | |
| try: | |
| subprocess.run( | |
| ['ollama', 'pull', model_name], | |
| check=True | |
| ) | |
| print(f"--- [✔️] تم سحب النموذج {model_name} بنجاح ---\n") | |
| successfully_pulled.append(model_name) | |
| except subprocess.CalledProcessError as e: | |
| print(f"--- [❌] فشل سحب النموذج {model_name}. رمز الخروج: {e.returncode} ---\n") | |
| failed_to_pull.append(model_name) | |
| except Exception as e: | |
| print(f"--- [❌] حدث خطأ استثنائي عند سحب النموذج {model_name}. الخطأ: {e} ---\n") | |
| failed_to_pull.append(model_name) | |
| sys.stdout.flush() | |
| print("✅ [الخطوة 4/5]: انتهت عملية سحب النماذج!\n") | |
| print("--- ملخص عملية السحب ---") | |
| if successfully_pulled: | |
| print(f"✔️ نماذج تم سحبها بنجاح ({len(successfully_pulled)}): {', '.join(successfully_pulled)}") | |
| if failed_to_pull: | |
| print(f"❌ نماذج فشل سحبها ({len(failed_to_pull)}): {', '.join(failed_to_pull)}") | |
| print("-------------------------\n") | |
| sys.stdout.flush() | |
| # ----------------------------------------------------------------------------- | |
| # الجزء الخامس: إنشاء واجهة Gradio | |
| # ----------------------------------------------------------------------------- | |
| print("✅ [الخطوة 5/5]: إنشاء واجهة Gradio...") | |
| def get_models_list(): | |
| """الحصول على قائمة النماذج المثبتة""" | |
| try: | |
| result = subprocess.run(['ollama', 'list'], capture_output=True, text=True, timeout=10) | |
| return result.stdout | |
| except Exception as e: | |
| return f"❌ خطأ في الحصول على قائمة النماذج: {e}" | |
| # إنشاء محتوى تعليمات الاستخدام | |
| instructions = f""" | |
| # ✨ خادم Ollama جاهز للاستخدام ✨ | |
| ## 🔗 رابط API العام: | |
| ``` | |
| {public_url_str} | |
| ``` | |
| ## 📋 تعليمات الاستخدام في RikkaHub: | |
| 1. انسخ الرابط أعلاه | |
| 2. في RikkaHub، اذهب إلى إعدادات المزود (Provider Settings) | |
| 3. اختر نوع المزود 'OpenAI-Compatible' | |
| 4. في خانة 'Base URL'، الصق الرابط وأضف له /v1: | |
| ``` | |
| {public_url_str}/v1 | |
| ``` | |
| 5. في خانة 'Model'، اكتب اسم النموذج الذي تريد استخدامه | |
| ## 📊 قائمة النماذج المثبتة: | |
| ``` | |
| {get_models_list()} | |
| ``` | |
| ## ⚠️ ملاحظات مهمة: | |
| - يجب إبقاء هذا Space قيد التشغيل للحفاظ على الاتصال | |
| - الرابط العام سيتغير إذا أعيد تشغيل Space | |
| - استخدم النماذج الخفيفة للحصول على أداء أفضل | |
| """ | |
| # إنشاء واجهة Gradio | |
| with gr.Blocks(title="Ollama Server on Hugging Face", theme=gr.themes.Soft()) as demo: | |
| gr.Markdown(instructions) | |
| with gr.Row(): | |
| refresh_btn = gr.Button("🔄 تحديث قائمة النماذج", size="sm") | |
| models_output = gr.Textbox( | |
| label="النماذج المثبتة حاليًا", | |
| value=get_models_list(), | |
| lines=10, | |
| interactive=False | |
| ) | |
| refresh_btn.click(fn=get_models_list, outputs=models_output) | |
| gr.Markdown(""" | |
| --- | |
| ### 💡 نصائح للاستخدام الأمثل: | |
| - استخدم النماذج الصغيرة (1B-3B) للحصول على استجابة سريعة | |
| - تأكد من استقرار الاتصال بالإنترنت | |
| - راقب استخدام الذاكرة في Logs | |
| """) | |
| print("✅ تم إنشاء واجهة Gradio بنجاح!") | |
| print("⏳ الخادم يعمل الآن ومتاح للاستخدام...") | |
| sys.stdout.flush() | |
| # إطلاق Gradio في thread منفصل للسماح بالتشغيل المستمر | |
| if __name__ == "__main__": | |
| try: | |
| demo.launch( | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| share=False, | |
| show_error=True | |
| ) | |
| except KeyboardInterrupt: | |
| print('\n\n⏳ تم طلب الإيقاف. جاري إغلاق العمليات...') | |
| finally: | |
| if ollama_serve_process: | |
| try: | |
| pgid = os.getpgid(ollama_serve_process.pid) | |
| os.killpg(pgid, signal.SIGTERM) | |
| print(" - تم إيقاف خادم Ollama.") | |
| except OSError: | |
| print(" - ⚠️ لم يتم العثور على عملية خادم Ollama.") | |
| if ngrok_tunnel: | |
| try: | |
| ngrok.disconnect(public_url_str) | |
| print(" - تم إيقاف نفق ngrok.") | |
| except Exception as e: | |
| print(f" - ⚠️ فشل إيقاف ngrok: {e}") | |
| try: | |
| ngrok.kill() | |
| print(" - تم إيقاف ngrok daemon.") | |
| except Exception as e: | |
| print(f" - ⚠️ فشل إيقاف ngrok daemon: {e}") | |
| print('✅ تم إيقاف جميع العمليات بنجاح.') |