Spaces:
Sleeping
Sleeping
File size: 11,843 Bytes
338517d dfd40ba 338517d d436343 338517d d436343 338517d dfd40ba 338517d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 | """Global AI Chatbot — helps users understand the CyberArena platform.
Uses the same five-tier AI fallback as the generators:
Mistral → Cloudflare → Groq → NVIDIA → fallback.
"""
from typing import Optional
import httpx
from app.core.config import (
MISTRAL_API_KEY, MISTRAL_MODEL, MISTRAL_API_URL,
CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID,
GROQ_API_KEY, GROQ_API_URL, GROQ_MODEL,
NVIDIA_API_KEY, NVIDIA_MODEL, NVIDIA_URL,
)
# --------------------------------------------------------------------------- #
# System prompt — comprehensive description of the entire platform #
# --------------------------------------------------------------------------- #
_CHATBOT_MISTRAL_MODEL = "mistral-small-latest"
PLATFORM_SYSTEM_PROMPT = """
أنت Cyber، المساعد الذكي الرسمي لمنصة CyberArena.
## تعريف المنصة
CyberArena هي منصة تفاعلية لتعلم الأمن السيبراني (Cybersecurity) مدعومة بالذكاء الاصطناعي.
المنصة موجهة للمبتدئين والمحترفين العرب، والواجهة باللغة العربية مع إمكانية التبديل إلى الإنجليزية.
## الصفحات المتاحة
1. **الرئيسية (Home)**: الصفحة التعريفية، فيها شرح عن المنصة وميزاتها.
2. **تسجيل الدخول (Auth)**: صفحة إنشاء حساب أو تسجيل الدخول.
3. **لوحة التحكم (Dashboard)**: الصفحة الرئيسية بعد تسجيل الدخول، فيها:
- عرض الإحصائيات (المستوى، XP، التحديات المنجزة)
- اختيار نوع التحدي (Red Team أو Blue Team)
- الوصول إلى الصفحات الأخرى (الملف الشخصي، لوحة المتصدرين، 1v1)
4. **الملف الشخصي (Profile)**: عرض معلومات المستخدم، الصورة الرمزية، الإنجازات، الشهادات.
5. **مسار التحديات (Training Path)**: اختيار نوع التحدي من التخصصات المتاحة.
6. **التحدي (Training Session)**: واجهة حل التحدي (تظهر فقط عند الدخول في تحدي).
7. **لوحة المتصدرين (Leaderboard)**: ترتيب المستخدمين حسب XP.
8. **وضع 1v1 (One-vs-One)**: مواجهة مباشرة بين لاعبين في نفس التحدي، أول من يحل يفوز.
9. **وضع أزرق ضد أحمر (Blue vs Red)**: تحديات مختلطة للفريقين.
10. **التحقق من الشهادة (Verify)**: إدخال رمز التحقق للشهادة والتأكد من صحتها.
## أنواع التحديات
1. **التشفير (Crypto) - الفريق الأحمر**: تحديات في فك التشفير، تحليل الهاش، اختراق أنظمة التشفير.
2. **تصحيح الأكواد (Code Fixing) - الفريق الأزرق**: إيجاد وإصلاح الثغرات الأمنية في كود برمجي.
3. **تحليل السجلات (Log Analysis) - الفريق الأزرق**: تحليل سجلات النظام لاكتشاف الهجمات.
4. **صيد الثغرات (Vulnerability Hunter) - الفريق الأزرق**: تحديد نوع الثغرة ووصفها في كود معين.
5. **استغلال الويب (Web Exploitation) - الفريق الأحمر**: هجمات ويب مثل XSS, SQLi, CSRF وغيرها.
## الفرق
- **الفريق الأحمر (Red Team)**: الهجوم — اختراق الأنظمة، فك التشفير، استغلال الثغرات.
- **الفريق الأزرق (Blue Team)**: الدفاع — تحليل السجلات، إصلاح الأكواد، صيد الثغرات.
## آلية عمل التحديات
- التحديات تُنشأ تلقائياً بالذكاء الاصطناعي (5 مستويات احتياطية).
- كل تحدي له قصة وسيناريو واقعي.
- يوجد مرشد ذكي (AI Mentor) داخل كل تحدي يساعد بدون إعطاء الحل النهائي.
- XP تُمنح عند حل التحدي بنجاح.
## الشهادات
- بعد إكمال عدد معين من التحديات في تخصص معين، يحصل المستخدم على شهادة إتمام.
- الشهادة تحتوي على رمز QR للتحقق.
- يمكن التحقق من صحة الشهادة عبر صفحة التحقق (Verify).
## نظام XP والمستويات
- كل تحدي يمنح XP حسب صعوبته: مبتدئ (100)، سهل (150)، متوسط (200).
- مع تزايد XP يرتفع مستوى المستخدم.
## التكنولوجيا المستخدمة
- الواجهة: React + TypeScript
- الخلفية: Python + FastAPI
- قاعدة البيانات: Supabase (PostgreSQL)
- الذكاء الاصطناعي: Mistral API (الأساسي)، Cloudflare Workers AI (احتياطي)، Groq API، NVIDIA/DeepSeek
## تعليمات للمساعد Cyber
1. أجب باللغة العربية الفصحى المبسطة دائماً.
2. كن ودوداً ومشجعاً.
3. إذا سأل المستخدم عن شيء خارج المنصة، قل له أنك متخصص فقط في CyberArena.
4. إذا احتاج مساعدة في ميزة معينة، اشرحها خطوة بخطوة.
5. شجع المستخدم على تجربة الميزات المختلفة.
6. لا تعطي حلول التحديات — هذا دور المرشد المختص (AI Mentor) داخل التحدي نفسه.
7. إذا سأل عن تحدي معين، وجهه لفتح التحدي من لوحة التحكم.
8. للأسئلة عن الـ API أو التقنيات التقنية، اشرح بشكل مبسط مناسب للمبتدئين.
9. اختصر الردود — لا تطيل أكثر من 3-4 فقرات قصيرة.
10. إذا ما عرفت الإجابة، اعترف بذلك بصراحة.
"""
# --------------------------------------------------------------------------- #
# Public entry point #
# --------------------------------------------------------------------------- #
async def get_chatbot_response(
message: str,
conversation_history: Optional[list[dict[str, str]]] = None,
page: str = "",
lang: str = "ar",
) -> str:
"""Ask the platform AI chatbot for help."""
lang_instr = (
"أجب دائمًا باللغة العربية الفصحى."
if lang == "ar"
else "Always respond in English."
)
prompt = f"{lang_instr}\n\n{message}"
if page:
prompt += f"\n\n(PAGE: {page})"
result = await _call_chatbot_ai(prompt)
if result is None:
if lang == "ar":
return "عذراً، واجهت مشكلة في الاتصال. حاول مرة أخرى بعد قليل."
return "Sorry, I had trouble connecting. Please try again later."
return result.strip()[:1000]
# --------------------------------------------------------------------------- #
# Five-tier AI fallback #
# --------------------------------------------------------------------------- #
async def _call_chatbot_ai(prompt: str) -> Optional[str]:
for attempt in (_try_mistral, _try_cloudflare, _try_groq, _try_nvidia):
result = await attempt(prompt)
if result is not None:
return result
return None
async def _try_mistral(prompt: str) -> Optional[str]:
if not MISTRAL_API_KEY:
return None
try:
async with httpx.AsyncClient(timeout=30) as client:
resp = await client.post(
MISTRAL_API_URL,
json={
"model": _CHATBOT_MISTRAL_MODEL,
"messages": [
{"role": "system", "content": PLATFORM_SYSTEM_PROMPT},
{"role": "user", "content": prompt},
],
"temperature": 0.7,
"max_tokens": 600,
},
headers={
"Content-Type": "application/json",
"Authorization": f"Bearer {MISTRAL_API_KEY}",
},
)
if resp.status_code == 200:
return resp.json()["choices"][0]["message"]["content"]
except Exception:
pass
return None
CLOUDFLARE_FALLBACKS = [
"@cf/qwen/qwen2.5-coder-32b-instruct",
"@cf/meta/llama-3.3-70b-instruct-fp8-fast",
"@cf/meta/llama-3.1-70b-instruct",
"@cf/mistralai/mistral-small-3.1-24b-instruct",
"@cf/openai/gpt-oss-120b",
"@cf/meta/llama-3.1-8b-instruct",
]
async def _try_cloudflare(prompt: str) -> Optional[str]:
if not CLOUDFLARE_API_TOKEN or not CLOUDFLARE_ACCOUNT_ID:
return None
for model in CLOUDFLARE_FALLBACKS:
url = (
f"https://api.cloudflare.com/client/v4/accounts/"
f"{CLOUDFLARE_ACCOUNT_ID}/ai/run/{model}"
)
try:
async with httpx.AsyncClient(timeout=45) as client:
resp = await client.post(
url,
json={
"messages": [
{"role": "system", "content": PLATFORM_SYSTEM_PROMPT},
{"role": "user", "content": prompt},
],
"max_tokens": 600,
},
headers={
"Content-Type": "application/json",
"Authorization": f"Bearer {CLOUDFLARE_API_TOKEN}",
},
)
if resp.status_code == 200:
data = resp.json()
result = data.get("result", {})
content = result.get("response", "")
if content:
return content
except Exception:
continue
return None
async def _try_groq(prompt: str) -> Optional[str]:
if not GROQ_API_KEY:
return None
try:
async with httpx.AsyncClient(timeout=60) as client:
resp = await client.post(
GROQ_API_URL,
json={
"model": GROQ_MODEL,
"messages": [
{"role": "system", "content": PLATFORM_SYSTEM_PROMPT},
{"role": "user", "content": prompt},
],
"temperature": 0.7,
"max_tokens": 600,
},
headers={
"Content-Type": "application/json",
"Authorization": f"Bearer {GROQ_API_KEY}",
},
)
if resp.status_code == 200:
return resp.json()["choices"][0]["message"]["content"]
except Exception:
pass
return None
async def _try_nvidia(prompt: str) -> Optional[str]:
if not NVIDIA_API_KEY:
return None
try:
async with httpx.AsyncClient(timeout=60) as client:
resp = await client.post(
NVIDIA_URL,
json={
"model": NVIDIA_MODEL,
"messages": [
{"role": "system", "content": PLATFORM_SYSTEM_PROMPT},
{"role": "user", "content": prompt},
],
"temperature": 0.7,
"max_tokens": 600,
},
headers={
"Content-Type": "application/json",
"Authorization": f"Bearer {NVIDIA_API_KEY}",
},
)
if resp.status_code == 200:
return resp.json()["choices"][0]["message"]["content"]
except Exception:
pass
return None
|