Spaces:
Sleeping
Sleeping
Upload 5 files
Browse files- README.md +51 -19
- app.py +1191 -0
- ena_data.json +138 -0
- requirements.txt +21 -3
- scraper.py +129 -0
README.md
CHANGED
|
@@ -1,19 +1,51 @@
|
|
| 1 |
-
---
|
| 2 |
-
title: ENA Chatbot
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
-
sdk:
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: ENA Chatbot
|
| 3 |
+
emoji: 🎓
|
| 4 |
+
colorFrom: blue
|
| 5 |
+
colorTo: yellow
|
| 6 |
+
sdk: streamlit
|
| 7 |
+
sdk_version: 1.37.1
|
| 8 |
+
app_file: app.py
|
| 9 |
+
pinned: false
|
| 10 |
+
---
|
| 11 |
+
|
| 12 |
+
# 🎓 ENA Chatbot — v13.27
|
| 13 |
+
**المدرسة الوطنية للإدارة | تونس**
|
| 14 |
+
|
| 15 |
+
بوت ذكي للإجابة على أسئلة المناظرات والتكوين في ENA تونس.
|
| 16 |
+
|
| 17 |
+
## الميزات
|
| 18 |
+
- ✅ إجابات بالعربية والفرنسية
|
| 19 |
+
- ✅ Real-time من موقع ena.tn
|
| 20 |
+
- ✅ RAG + BM25 Hybrid Search
|
| 21 |
+
- ✅ Cross-Encoder Reranking
|
| 22 |
+
- ✅ Self-Correction
|
| 23 |
+
- ✅ Cache للإجابات المتكررة
|
| 24 |
+
|
| 25 |
+
## طريقة النشر
|
| 26 |
+
|
| 27 |
+
### 1. جهّز الملفات
|
| 28 |
+
```
|
| 29 |
+
ena-chatbot/
|
| 30 |
+
├── app.py
|
| 31 |
+
├── requirements.txt
|
| 32 |
+
├── ena_data.json ← شغّل scraper.py أولاً
|
| 33 |
+
└── README.md
|
| 34 |
+
```
|
| 35 |
+
|
| 36 |
+
### 2. جمع البيانات
|
| 37 |
+
```bash
|
| 38 |
+
pip install requests beautifulsoup4
|
| 39 |
+
python scraper.py
|
| 40 |
+
```
|
| 41 |
+
|
| 42 |
+
### 3. أضف GROQ_TOKEN
|
| 43 |
+
في Hugging Face Space → Settings → Variables and secrets:
|
| 44 |
+
```
|
| 45 |
+
GROQ_TOKEN = gsk_xxxxxxxxxxxx
|
| 46 |
+
```
|
| 47 |
+
|
| 48 |
+
## التواصل
|
| 49 |
+
- 📞 71 848 300
|
| 50 |
+
- ✉️ info@ena.tn
|
| 51 |
+
- 🌐 www.ena.tn
|
app.py
ADDED
|
@@ -0,0 +1,1191 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ╔══════════════════════════════════════════════════════════╗
|
| 2 |
+
# ║ ENA Chatbot — app.py v13.27 | نسخة نهائية موحدة ║
|
| 3 |
+
# ║ ✅ llama-3.3-70b ✅ HTTPS ✅ Citations ✅ Proactive ║
|
| 4 |
+
# ║ ✅ PersistentDB ✅ كود موحد بدون رقع ║
|
| 5 |
+
# ╚══════════════════════════════════════════════════════════╝
|
| 6 |
+
|
| 7 |
+
import streamlit as st
|
| 8 |
+
import numpy as np
|
| 9 |
+
import json, os, re, difflib, requests
|
| 10 |
+
import chromadb
|
| 11 |
+
from bs4 import BeautifulSoup
|
| 12 |
+
from sklearn.metrics.pairwise import cosine_similarity
|
| 13 |
+
from rank_bm25 import BM25Okapi
|
| 14 |
+
from langchain_huggingface import HuggingFaceEmbeddings
|
| 15 |
+
from langchain_chroma import Chroma
|
| 16 |
+
from groq import Groq
|
| 17 |
+
|
| 18 |
+
st.set_page_config(
|
| 19 |
+
page_title="ENA Chatbot | المدرسة الوطنية للإدارة",
|
| 20 |
+
page_icon="🎓", layout="wide",
|
| 21 |
+
initial_sidebar_state="expanded"
|
| 22 |
+
)
|
| 23 |
+
|
| 24 |
+
st.markdown("""
|
| 25 |
+
<style>
|
| 26 |
+
@import url('https://fonts.googleapis.com/css2?family=Cairo:wght@300;400;600;700;900&display=swap');
|
| 27 |
+
:root {
|
| 28 |
+
--primary: #0A2647; --accent: #205295;
|
| 29 |
+
--gold: #C9A84C; --gold-light: #E8C97A;
|
| 30 |
+
--bg: #F7F9FC; --border: #E2E8F0;
|
| 31 |
+
--muted: #6B7A8D; --shadow: 0 4px 24px rgba(10,38,71,0.10);
|
| 32 |
+
}
|
| 33 |
+
html, body, [class*="css"] { font-family: 'Cairo', sans-serif !important; background: var(--bg) !important; }
|
| 34 |
+
#MainMenu, footer, header { visibility: hidden; }
|
| 35 |
+
[data-testid="stSidebar"] {
|
| 36 |
+
background: var(--primary) !important;
|
| 37 |
+
display: flex !important; visibility: visible !important; min-width: 280px !important;
|
| 38 |
+
}
|
| 39 |
+
[data-testid="collapsedControl"] { display: flex !important; visibility: visible !important; color: white !important; }
|
| 40 |
+
[data-testid="stSidebar"] * { color: rgba(255,255,255,0.90) !important; }
|
| 41 |
+
[data-testid="stSidebar"] h2 { color: var(--gold-light) !important; font-weight:700; }
|
| 42 |
+
[data-testid="stSidebar"] hr { border-color: rgba(255,255,255,0.15) !important; }
|
| 43 |
+
[data-testid="stSidebar"] .stButton button {
|
| 44 |
+
background: rgba(201,168,76,0.18) !important; color: var(--gold-light) !important;
|
| 45 |
+
border: 1px solid var(--gold) !important; border-radius: 10px !important;
|
| 46 |
+
font-weight: 600 !important; width: 100%;
|
| 47 |
+
}
|
| 48 |
+
[data-testid="stSidebar"] .stButton button:hover { background: var(--gold) !important; color: var(--primary) !important; }
|
| 49 |
+
.sidebar-contact {
|
| 50 |
+
background: rgba(255,255,255,0.07); border: 1px solid rgba(255,255,255,0.12);
|
| 51 |
+
border-radius: 12px; padding: 14px 16px; font-size:0.88em; line-height:2; direction:rtl;
|
| 52 |
+
}
|
| 53 |
+
.sidebar-contact a { color: var(--gold-light) !important; text-decoration:none; }
|
| 54 |
+
.main-header {
|
| 55 |
+
background: linear-gradient(135deg, var(--primary) 0%, var(--accent) 100%);
|
| 56 |
+
border-radius: 20px; padding: 28px 36px; margin-bottom: 24px; box-shadow: var(--shadow);
|
| 57 |
+
}
|
| 58 |
+
.main-header h1 { color:white !important; font-size:2em !important; font-weight:900 !important; margin:0 !important; text-align:right; direction:rtl; }
|
| 59 |
+
.main-header .subtitle { color:rgba(255,255,255,0.75); font-size:0.92em; margin-top:6px; text-align:right; direction:rtl; }
|
| 60 |
+
.header-badge { display:inline-block; background:var(--gold); color:var(--primary); font-size:0.72em; font-weight:700; padding:3px 10px; border-radius:20px; margin-right:8px; vertical-align:middle; }
|
| 61 |
+
.user-row { display:flex; justify-content:flex-end; margin:10px 0; align-items:flex-end; gap:10px; }
|
| 62 |
+
.user-bubble { background: linear-gradient(135deg, #0A2647 0%, #205295 100%); color:white; padding:13px 18px; border-radius:20px 20px 4px 20px; max-width:72%; text-align:right; direction:rtl; font-size:0.96em; line-height:1.6; box-shadow:0 2px 12px rgba(10,38,71,0.25); word-break:break-word; }
|
| 63 |
+
.user-avatar { width:36px; height:36px; background:var(--accent); border-radius:50%; display:flex; align-items:center; justify-content:center; font-size:1.1em; flex-shrink:0; }
|
| 64 |
+
.bot-row { display:flex; justify-content:flex-start; margin:10px 0; align-items:flex-start; gap:10px; }
|
| 65 |
+
.bot-avatar { width:36px; height:36px; background:var(--gold); border-radius:50%; display:flex; align-items:center; justify-content:center; font-size:1.1em; flex-shrink:0; }
|
| 66 |
+
.bot-bubble { background:#FFFFFF; color:var(--primary); padding:14px 18px; border-radius:20px 20px 20px 4px; max-width:78%; text-align:right; direction:rtl; font-size:0.95em; line-height:1.8; border:1px solid var(--border); box-shadow:var(--shadow); word-break:break-word; white-space:pre-wrap; }
|
| 67 |
+
.conf-wrap { margin:6px 0 0 46px; max-width:78%; }
|
| 68 |
+
.conf-label { font-size:0.76em; color:var(--muted); direction:rtl; text-align:right; margin-bottom:3px; }
|
| 69 |
+
.conf-bg { background:#E2E8F0; border-radius:6px; height:5px; overflow:hidden; }
|
| 70 |
+
.conf-fill { height:5px; border-radius:6px; }
|
| 71 |
+
.source-wrap { margin:8px 0 0 46px; direction:rtl; }
|
| 72 |
+
.source-label { font-size:0.76em; color:var(--muted); margin-bottom:4px; text-align:right; }
|
| 73 |
+
.source-chips { display:flex; flex-wrap:wrap; gap:6px; justify-content:flex-end; }
|
| 74 |
+
.source-chip { background:#EBF4FF; border:1px solid #BEE3F8; color:#2C5282; font-size:0.74em; padding:4px 12px; border-radius:20px; font-weight:600; text-decoration:none; transition:all 0.2s; }
|
| 75 |
+
.source-chip:hover { background:#2C5282; color:white !important; border-color:#2C5282; }
|
| 76 |
+
.proactive-wrap { margin:10px 0 4px 46px; direction:rtl; }
|
| 77 |
+
.proactive-label { font-size:0.80em; color:#205295; font-weight:700; margin-bottom:6px; text-align:right; }
|
| 78 |
+
.llm-badge { display:inline-block; font-size:0.7em; background:#F0FFF4; color:#276749; border:1px solid #C6F6D5; border-radius:10px; padding:1px 8px; margin-left:6px; font-weight:700; }
|
| 79 |
+
.sc-badge { display:inline-block; font-size:0.7em; background:#FAF5FF; color:#553C9A; border:1px solid #D6BCFA; border-radius:10px; padding:1px 8px; margin-left:4px; font-weight:700; }
|
| 80 |
+
.rag-badge { display:inline-block; font-size:0.7em; background:#EBF8FF; color:#2C5282; border:1px solid #BEE3F8; border-radius:10px; padding:1px 8px; margin-left:6px; font-weight:700; }
|
| 81 |
+
.rt-badge { display:inline-block; font-size:0.7em; background:#FFFBEB; color:#92400E; border:1px solid #FDE68A; border-radius:10px; padding:1px 8px; margin-left:6px; font-weight:700; }
|
| 82 |
+
.sug-label { font-size:0.82em; color:var(--muted); text-align:right; direction:rtl; margin-bottom:8px; }
|
| 83 |
+
.stButton button { background:white !important; color:var(--primary) !important; border:1.5px solid var(--border) !important; border-radius:12px !important; font-size:0.85em !important; font-family:'Cairo',sans-serif !important; font-weight:600 !important; width:100% !important; }
|
| 84 |
+
.stButton button:hover { background:var(--primary) !important; color:white !important; }
|
| 85 |
+
[data-testid="stForm"] { background:white; border-radius:16px; border:2px solid var(--border); padding:10px 14px; box-shadow:var(--shadow); }
|
| 86 |
+
[data-testid="stForm"] .stButton button { background:var(--primary) !important; color:white !important; border:none !important; border-radius:12px !important; font-weight:700 !important; }
|
| 87 |
+
.stTextInput input { background:transparent !important; border:none !important; box-shadow:none !important; font-family:'Cairo',sans-serif !important; font-size:0.97em !important; direction:rtl !important; text-align:right !important; }
|
| 88 |
+
.chat-divider { border:none; border-top:1px solid var(--border); margin:16px 0; }
|
| 89 |
+
</style>
|
| 90 |
+
""", unsafe_allow_html=True)
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
# ══════════════════════════════════════════════════════════
|
| 94 |
+
# 🔗 خريطة URLs للاستشهادات (Citations) — HTTPS
|
| 95 |
+
# ══════════════════════════════════════════════════════════
|
| 96 |
+
PAGE_URLS = {
|
| 97 |
+
"concours_superieur": "https://www.ena.tn/fr/concours/cycle-superieur/le-concours-dentree-au-cycle-superieur/",
|
| 98 |
+
"concours_general": "https://www.ena.tn/fr/concours/informations-generales/",
|
| 99 |
+
"concours_preparation": "https://www.ena.tn/fr/concours/cycle-superieur/preparation-au-concours/",
|
| 100 |
+
"concours_a2": "https://www.ena.tn/fr/concours/cycle-moyen/concours-dentree-au-cycle-de-formation-des-cadres-moyens-de-la-sous-categorie-a2-2/",
|
| 101 |
+
"concours_a2_prep": "https://www.ena.tn/fr/concours/cycle-moyen/preparation-au-concours/",
|
| 102 |
+
"concours_a3": "https://www.ena.tn/fr/concours/agents-de-la-sous-categorie-a3/",
|
| 103 |
+
"formation_superieur": "https://www.ena.tn/fr/formation-de-base/cycle-superieur/",
|
| 104 |
+
"formation_a2": "https://www.ena.tn/fr/formation-de-base/cycle-de-formation-des-cadres-moyens-de-la-sous-categorie-a2/",
|
| 105 |
+
"formation_a3": "https://www.ena.tn/fr/formation-de-base/cycle-de-formation-des-agents-de-la-sous-categorie-a3/",
|
| 106 |
+
"formation_continue": "https://www.ena.tn/fr/formation-continue/formation-continue-a-distance-et-presentielle/",
|
| 107 |
+
"formation_courte": "https://www.ena.tn/fr/formation-continue/sessions-de-formation-de-courte-duree/",
|
| 108 |
+
"gouvernance": "https://www.ena.tn/fr/gouvernance/lacademie-internationale-de-la-bonne-gouvernance/",
|
| 109 |
+
"ar_concours_general": "https://www.ena.tn/ar/concours-ar/informations-generales-ar/",
|
| 110 |
+
"ar_contact": "https://www.ena.tn/ar/contact/",
|
| 111 |
+
"ar_concours_a2_detail": "https://www.ena.tn/ar/concours-ar/cycle-moyen-ar/entree-au-cycle-de-formation-des-cadres-moyens-ar/",
|
| 112 |
+
"ar_concours_a3_detail": "https://www.ena.tn/ar/concours-ar/agents-categorie-a3-ar/",
|
| 113 |
+
"ar_concours_superieur_detail": "https://www.ena.tn/ar/concours-ar/cycle-superieur-arr/concours-entree-cycle-superieur-ar/",
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
|
| 118 |
+
# ══════════════════════════════════════════════════════════
|
| 119 |
+
# 💡 اقتراحات استباقية (Proactive Suggestions)
|
| 120 |
+
# ══════════════════════════════════════════════════════════
|
| 121 |
+
PROACTIVE_MAP = {
|
| 122 |
+
"concours": [
|
| 123 |
+
"📄 الوثائق المطلوبة للتسجيل",
|
| 124 |
+
"ماهي الشهادات العلمية المستوجبة",
|
| 125 |
+
"متى تفتح مناظرة الدخول إلى المرحلة العليا",
|
| 126 |
+
],
|
| 127 |
+
"مناظرة": [
|
| 128 |
+
"📄 الوثائق المطلوبة للتسجيل",
|
| 129 |
+
"ماهي الشهادات العلمية المستوجبة",
|
| 130 |
+
"ماهي الاختبارات تشتمل مناظرة الدخول إلى المرحلة العليا",
|
| 131 |
+
],
|
| 132 |
+
"شروط": [
|
| 133 |
+
"ماهي الشهادات العلمية المستوجبة",
|
| 134 |
+
"📄 الوثائق المطلوبة للتسجيل",
|
| 135 |
+
"متى تفتح مناظرة الدخول إلى المرحلة العليا",
|
| 136 |
+
],
|
| 137 |
+
"condition": [
|
| 138 |
+
"ماهي الشهادات العلمية المستوجبة",
|
| 139 |
+
"📄 الوثائق المطلوبة للتسجيل",
|
| 140 |
+
"متى تفتح مناظرة الدخول إلى المرحلة العليا",
|
| 141 |
+
],
|
| 142 |
+
"تسجيل": [
|
| 143 |
+
"📄 الوثائق المطلوبة للتسجيل",
|
| 144 |
+
"شروط السن والشهادة",
|
| 145 |
+
"متى تفتح مناظرة الدخول إلى المرحلة العليا",
|
| 146 |
+
],
|
| 147 |
+
"inscription": [
|
| 148 |
+
"📄 الوثائق المطلوبة للتسجيل",
|
| 149 |
+
"شروط السن والشهادة",
|
| 150 |
+
"🏆 concours.ena.tn",
|
| 151 |
+
],
|
| 152 |
+
"وثائق": [
|
| 153 |
+
"شروط السن والشهادة",
|
| 154 |
+
"ماهي الشهادات العلمية المستوجبة",
|
| 155 |
+
"متى تفتح مناظرة الدخول إلى المرحلة العليا",
|
| 156 |
+
],
|
| 157 |
+
"document": [
|
| 158 |
+
"شروط السن والشهادة",
|
| 159 |
+
"ماهي الشهادات العلمية المستوجبة",
|
| 160 |
+
"📞 الاتصال بـ ENA",
|
| 161 |
+
],
|
| 162 |
+
"اختبار": [
|
| 163 |
+
"الاختبارات و ضواربها",
|
| 164 |
+
"الاختبارات الكتابية للقبول الأولي",
|
| 165 |
+
"ماهي الشهادات العلمية المستوجبة",
|
| 166 |
+
],
|
| 167 |
+
"formation": [
|
| 168 |
+
"📅 مواعيد دورات التكوين المستمر",
|
| 169 |
+
"شروط الالتحاق بالتكوين المستمر",
|
| 170 |
+
"📞 التسجيل في التكوين",
|
| 171 |
+
],
|
| 172 |
+
"أ2": [
|
| 173 |
+
"ماهي شروط مناظرة الإطارات المتوسطة أ2",
|
| 174 |
+
"ماهي الشهادات المطلوبة لمناظرة أ2",
|
| 175 |
+
"ماهي الاختبارات في مناظرة أ2",
|
| 176 |
+
],
|
| 177 |
+
"إطارات": [
|
| 178 |
+
"ماهي شروط مناظرة الإطارات المتوسطة أ2",
|
| 179 |
+
"ماهي الشهادات المطلوبة لمناظرة أ2",
|
| 180 |
+
"ماهي الاختبارات في مناظرة أ2",
|
| 181 |
+
],
|
| 182 |
+
"تكوين": [
|
| 183 |
+
"شروط الالتحاق بالتكوين المستمر",
|
| 184 |
+
"📅 مواعيد دورات التكوين",
|
| 185 |
+
"📞 التواصل مع ENA",
|
| 186 |
+
],
|
| 187 |
+
}
|
| 188 |
+
|
| 189 |
+
def get_proactive(question: str) -> list:
|
| 190 |
+
q = question.lower()
|
| 191 |
+
for kw, sugs in PROACTIVE_MAP.items():
|
| 192 |
+
if kw in q:
|
| 193 |
+
return sugs
|
| 194 |
+
return []
|
| 195 |
+
|
| 196 |
+
|
| 197 |
+
# ══════════════════════════════════════════════════════════
|
| 198 |
+
# ✅ Cache reset
|
| 199 |
+
# ══════════════════════════════════════════════════════════
|
| 200 |
+
|
| 201 |
+
# ══════════════════════════════════════════════════════════
|
| 202 |
+
# 🔤 Arabic Normalization — تطبيع النصوص العربية
|
| 203 |
+
# يعامل أشكال الحروف المختلفة كحرف واحد
|
| 204 |
+
# ══════════════════════════════════════════════════════════
|
| 205 |
+
import re as _re
|
| 206 |
+
import unicodedata as _ud
|
| 207 |
+
|
| 208 |
+
def normalize_arabic(text: str) -> str:
|
| 209 |
+
"""
|
| 210 |
+
تطبيع النص العربي:
|
| 211 |
+
- توحيد أشكال الألف (أ إ آ ا) → ا
|
| 212 |
+
- توحيد التاء المربوطة (ة) والهاء (ه) → ه
|
| 213 |
+
- حذف التشكيل (الحركات)
|
| 214 |
+
- توحيد الهمزات
|
| 215 |
+
- توحيد الياء (ي ى) → ي
|
| 216 |
+
"""
|
| 217 |
+
if not text:
|
| 218 |
+
return text
|
| 219 |
+
|
| 220 |
+
# حذف التشكيل (الحركات)
|
| 221 |
+
text = _re.sub(r'[\u064B-\u065F\u0670]', '', text)
|
| 222 |
+
|
| 223 |
+
# توحيد أشكال الألف
|
| 224 |
+
text = _re.sub(r'[أإآٱ]', 'ا', text)
|
| 225 |
+
|
| 226 |
+
# ت��حيد التاء المربوطة مع الهاء
|
| 227 |
+
text = text.replace('ة', 'ه')
|
| 228 |
+
|
| 229 |
+
# توحيد الياء
|
| 230 |
+
text = text.replace('ى', 'ي')
|
| 231 |
+
|
| 232 |
+
# توحيد الواو مع الهمزة
|
| 233 |
+
text = text.replace('ؤ', 'و')
|
| 234 |
+
|
| 235 |
+
# توحيد الهمزة على الياء
|
| 236 |
+
text = text.replace('ئ', 'ي')
|
| 237 |
+
|
| 238 |
+
# حذف المسافات الزائدة
|
| 239 |
+
text = _re.sub(r'\s+', ' ', text).strip()
|
| 240 |
+
|
| 241 |
+
return text
|
| 242 |
+
|
| 243 |
+
if "cache_cleared" not in st.session_state:
|
| 244 |
+
st.cache_resource.clear()
|
| 245 |
+
st.session_state["cache_cleared"] = True
|
| 246 |
+
|
| 247 |
+
|
| 248 |
+
# ══════════════════════════════════════════════════════════
|
| 249 |
+
# LLM — ✅ llama-3.3-70b-versatile (الموديل الصحيح)
|
| 250 |
+
# ══════════════════════════════════════════════════════════
|
| 251 |
+
@st.cache_resource(show_spinner=False)
|
| 252 |
+
def load_llm_client():
|
| 253 |
+
groq_token = os.environ.get("GROQ_TOKEN")
|
| 254 |
+
if not groq_token:
|
| 255 |
+
try:
|
| 256 |
+
groq_token = st.secrets["GROQ_TOKEN"]
|
| 257 |
+
except:
|
| 258 |
+
groq_token = None
|
| 259 |
+
if not groq_token:
|
| 260 |
+
st.sidebar.warning("⚠️ GROQ_TOKEN غير موجود")
|
| 261 |
+
return None
|
| 262 |
+
try:
|
| 263 |
+
c = Groq(api_key=groq_token)
|
| 264 |
+
st.sidebar.success("✨ Groq AI مفعّل")
|
| 265 |
+
return c
|
| 266 |
+
except Exception as e:
|
| 267 |
+
st.sidebar.error(f"❌ {e}")
|
| 268 |
+
return None
|
| 269 |
+
|
| 270 |
+
|
| 271 |
+
# ══════════════════════════════════════════════════════════
|
| 272 |
+
# 🔍 Self-Correction — البوت يراجع إجابته قبل إرسالها
|
| 273 |
+
# ══════════════════════════════════════════════════════════
|
| 274 |
+
def calibrate_confidence(raw_score: float, answer: str) -> str:
|
| 275 |
+
score = raw_score * 100
|
| 276 |
+
weak = ["للاطلاع على التفاصيل", "لا يوجد في السياق",
|
| 277 |
+
"غير متوفر", "pour les details", "non disponible"]
|
| 278 |
+
if any(p in answer for p in weak):
|
| 279 |
+
score = min(score, 55.0)
|
| 280 |
+
if len(answer) > 300:
|
| 281 |
+
score = min(score + 5, 100)
|
| 282 |
+
if score >= 85: return f"{score:.0f}% 🟢"
|
| 283 |
+
elif score >= 65: return f"{score:.0f}% 🟡"
|
| 284 |
+
else: return f"{score:.0f}% 🔴"
|
| 285 |
+
|
| 286 |
+
|
| 287 |
+
@functools.lru_cache(maxsize=128)
|
| 288 |
+
def suggest_better_question(question: str) -> str:
|
| 289 |
+
groq_key = os.environ.get("GROQ_TOKEN", "")
|
| 290 |
+
if not groq_key: return ""
|
| 291 |
+
try:
|
| 292 |
+
from groq import Groq as _G
|
| 293 |
+
pages = "\n".join([f"- {n}" for n in PAGE_URLS.keys()])
|
| 294 |
+
c = _G(api_key=groq_key)
|
| 295 |
+
r = c.chat.completions.create(
|
| 296 |
+
model="llama-3.3-70b-versatile",
|
| 297 |
+
messages=[{"role":"user","content":
|
| 298 |
+
"السؤال: \"" + question + "\"\n"
|
| 299 |
+
"الصفحات المتاحة:\n" + pages + "\n\n"
|
| 300 |
+
"اقترح سؤالاً واحداً أكثر دقة. أجب بالسؤال فقط."}],
|
| 301 |
+
max_tokens=60, temperature=0.3,
|
| 302 |
+
)
|
| 303 |
+
return r.choices[0].message.content.strip()
|
| 304 |
+
except:
|
| 305 |
+
return ""
|
| 306 |
+
|
| 307 |
+
|
| 308 |
+
CONCOURS_NAMES = {
|
| 309 |
+
"العليا": "مناظرة الدخول إلى المرحلة العليا (ماجستير/مهندس)",
|
| 310 |
+
"أ2": "مناظرة تكوين الإطارات المتوسطة (أستاذية/إجازة)",
|
| 311 |
+
"أ3": "مناظرة تكوين الأعوان (شهادة المرحلة الأولى)",
|
| 312 |
+
}
|
| 313 |
+
|
| 314 |
+
def needs_clarification(question: str):
|
| 315 |
+
q = question.lower()
|
| 316 |
+
specific = ["عليا","superieur","أ2","a2","إطارات","أ3","a3","أعوان","cadres","agents"]
|
| 317 |
+
if any(k in q for k in specific):
|
| 318 |
+
return None
|
| 319 |
+
general = ["مناظرة","concours"]
|
| 320 |
+
ambiguous= ["شروط","اختبار","شهادة","وثائق","تسجيل","conditions","epreuve","inscription"]
|
| 321 |
+
if any(g in q for g in general) and any(a in q for a in ambiguous):
|
| 322 |
+
opts = "\n".join([f"- **{k}**: {v}" for k, v in CONCOURS_NAMES.items()])
|
| 323 |
+
return (
|
| 324 |
+
"سؤالك يحتمل أكثر من مناظرة \U0001f914\n\n"
|
| 325 |
+
"أي مناظرة تقصد؟\n" + opts + "\n\n"
|
| 326 |
+
"مثال: اكتب **شروط مناظرة أ2** أو **اختبارات المرحلة العليا**"
|
| 327 |
+
)
|
| 328 |
+
return None
|
| 329 |
+
|
| 330 |
+
|
| 331 |
+
def self_correct(question: str, draft: str, context: str, llm_client) -> str:
|
| 332 |
+
"""
|
| 333 |
+
يراجع الـ LLM إجابته مقارنةً بالسياق الأصلي:
|
| 334 |
+
- يصحح المعلومات الخاطئة
|
| 335 |
+
- يكمل المعلومات الناقصة
|
| 336 |
+
- يحذف المعلومات المخترعة
|
| 337 |
+
إذا كانت الإجابة صحيحة يعيدها كما هي.
|
| 338 |
+
"""
|
| 339 |
+
if not llm_client or not draft or len(draft) < 30:
|
| 340 |
+
return draft
|
| 341 |
+
|
| 342 |
+
arabic_chars = sum(1 for ch in question if '\u0600' <= ch <= '\u06FF')
|
| 343 |
+
if arabic_chars > 2:
|
| 344 |
+
review_prompt = (
|
| 345 |
+
f"السياق:\n{context[:2000]}\n\n"
|
| 346 |
+
f"السؤال: {question}\n\n"
|
| 347 |
+
f"الإجابة المقترحة:\n{draft}\n\n"
|
| 348 |
+
f"مهمتك: راجع الإجابة مقارنةً بالسياق فقط.\n"
|
| 349 |
+
f"- إذا كانت صحيحة وكاملة → أعدها كما هي بدون تغيير\n"
|
| 350 |
+
f"- إذا فيها معلومة خاطئة → صحّحها من السياق\n"
|
| 351 |
+
f"- إذا فيها معلومة مخترعة غير موجودة في السياق → احذفها\n"
|
| 352 |
+
f"- إذا فيها نقص مهم موجود في السياق → أضفه\n"
|
| 353 |
+
f"أجب بالإجابة النهائية فقط بدون أي شرح."
|
| 354 |
+
)
|
| 355 |
+
else:
|
| 356 |
+
review_prompt = (
|
| 357 |
+
f"Contexte:\n{context[:2000]}\n\n"
|
| 358 |
+
f"Question: {question}\n\n"
|
| 359 |
+
f"Réponse proposée:\n{draft}\n\n"
|
| 360 |
+
f"Ta mission: Vérifie la réponse par rapport au contexte uniquement.\n"
|
| 361 |
+
f"- Si correcte et complète → retourne-la telle quelle\n"
|
| 362 |
+
f"- Si elle contient une erreur → corrige depuis le contexte\n"
|
| 363 |
+
f"- Si elle contient une info inventée → supprime-la\n"
|
| 364 |
+
f"- Si elle manque un élément important du contexte → ajoute-le\n"
|
| 365 |
+
f"Réponds avec la réponse finale uniquement, sans explication."
|
| 366 |
+
)
|
| 367 |
+
|
| 368 |
+
try:
|
| 369 |
+
response = llm_client.chat.completions.create(
|
| 370 |
+
model="llama-3.3-70b-versatile",
|
| 371 |
+
messages=[{"role": "user", "content": review_prompt}],
|
| 372 |
+
max_tokens=800, temperature=0.0,
|
| 373 |
+
)
|
| 374 |
+
corrected = response.choices[0].message.content.strip()
|
| 375 |
+
return corrected if len(corrected) > 20 else draft
|
| 376 |
+
except Exception as e:
|
| 377 |
+
print(f"⚠️ self_correct error: {e}")
|
| 378 |
+
return draft # fallback للإجابة الأصلية
|
| 379 |
+
|
| 380 |
+
def generate_answer(question, chunks, llm_client, chat_history=None):
|
| 381 |
+
if not llm_client or not chunks:
|
| 382 |
+
return None
|
| 383 |
+
# أسئلة تفصيلية → نرسل 5 chunks | باقي الأسئلة → 3 chunks
|
| 384 |
+
DETAIL_KW = ["اختبار","épreuve","ضارب","détail","برنامج","programme","تفصيل","شروط","conditions"]
|
| 385 |
+
top_n = 5 if any(k in question.lower() for k in DETAIL_KW) else 3
|
| 386 |
+
context = "\n\n---\n\n".join([
|
| 387 |
+
f"[Source: {c.get('source','')} | URL: {c.get('url','')}]\n{c['content']}"
|
| 388 |
+
for c in chunks[:top_n]
|
| 389 |
+
])
|
| 390 |
+
arabic_chars = sum(1 for ch in question if '\u0600' <= ch <= '\u06FF')
|
| 391 |
+
|
| 392 |
+
if arabic_chars > 2:
|
| 393 |
+
system_msg = (
|
| 394 |
+
"أنت المساعد الرسمي للمدرسة الوطنية للإدارة بتونس. "
|
| 395 |
+
"أجب بالعربية الفصحى فقط اعتماداً على السياق المقدم حصراً. "
|
| 396 |
+
"قاعدة صارمة جداً: لا تستخدم أي كلمة فرنسية أو إنجليزية أو صينية أو أجنبية تحت أي ظرف — "
|
| 397 |
+
"حتى المصطلحات التقنية يجب ترجمتها للعربية. "
|
| 398 |
+
"لا تخترع معلومات من عندك. "
|
| 399 |
+
"قاعدة: إذا كانت المعلومة غير موجودة في السياق، قل فقط: "
|
| 400 |
+
"'للاطلاع على التفاصيل الكاملة راجع www.ena.tn' ولا تخمّن. "
|
| 401 |
+
"قاعدة التنسيق: استخرج كل النقاط الموجودة في السياق وقدّمها "
|
| 402 |
+
"بعناوين بالخط العريض (**العنوان:**) وتحتها نقاط بشرطة (-). "
|
| 403 |
+
"لا تكرر نفس المعلومة. "
|
| 404 |
+
"اختم دائماً بـ: للمزيد من المعلومات اتصل بـ 71 848 300 أو www.ena.tn"
|
| 405 |
+
)
|
| 406 |
+
user_msg = f"السياق:\n{context}\n\nالسؤال: {question}\n\nأجب بالعربية الفصحى:"
|
| 407 |
+
else:
|
| 408 |
+
system_msg = (
|
| 409 |
+
"Tu es l'assistant officiel de l'ENA Tunisie. "
|
| 410 |
+
"Réponds uniquement en français en te basant exclusivement sur le contexte fourni. "
|
| 411 |
+
"Règle stricte: n'invente aucune information — si une donnée est absente du contexte, "
|
| 412 |
+
"dis uniquement: 'Pour les détails complets, consultez www.ena.tn'. "
|
| 413 |
+
"Format: extrais tous les points présents dans le contexte et présente-les avec "
|
| 414 |
+
"des titres en gras (**Titre:**) et des tirets (-) pour les sous-points. "
|
| 415 |
+
"Ne répète pas la même information. "
|
| 416 |
+
"Termine par: Pour plus d'informations, contactez l'ENA au 71 848 300 ou www.ena.tn"
|
| 417 |
+
)
|
| 418 |
+
user_msg = f"Contexte:\n{context}\n\nQuestion: {question}\n\nRéponds en français:"
|
| 419 |
+
|
| 420 |
+
try:
|
| 421 |
+
# ✅ llama-3.3-70b-versatile — موجود ومستقر على Groq
|
| 422 |
+
# ✅ Chat History — آخر 3 محادثات مع تقليص الإجابات الطويلة
|
| 423 |
+
history_msgs = []
|
| 424 |
+
if chat_history:
|
| 425 |
+
for msg in chat_history[-6:]: # آخر 3 أسئلة + 3 أجوبة
|
| 426 |
+
if msg["role"] == "user":
|
| 427 |
+
history_msgs.append({"role": "user", "content": msg["content"]})
|
| 428 |
+
elif msg["role"] == "bot":
|
| 429 |
+
# نقلص الإجابات الطويلة حتى لا يضيع الـ context
|
| 430 |
+
bot_content = msg["content"]
|
| 431 |
+
if len(bot_content) > 400:
|
| 432 |
+
bot_content = bot_content[:400] + "..."
|
| 433 |
+
history_msgs.append({"role": "assistant", "content": bot_content})
|
| 434 |
+
|
| 435 |
+
response = llm_client.chat.completions.create(
|
| 436 |
+
model="llama-3.3-70b-versatile",
|
| 437 |
+
messages=[
|
| 438 |
+
{"role": "system", "content": system_msg},
|
| 439 |
+
*history_msgs,
|
| 440 |
+
{"role": "user", "content": user_msg}
|
| 441 |
+
],
|
| 442 |
+
max_tokens=800, temperature=0.1, top_p=0.9,
|
| 443 |
+
)
|
| 444 |
+
answer = response.choices[0].message.content.strip()
|
| 445 |
+
if len(answer) < 30:
|
| 446 |
+
return None
|
| 447 |
+
# 🔍 Self-Correction — مراجعة الإجابة قبل الإرسال
|
| 448 |
+
corrected = self_correct(question, answer, context, llm_client)
|
| 449 |
+
return corrected
|
| 450 |
+
except Exception as e:
|
| 451 |
+
print(f"⚠️ LLM error: {e}")
|
| 452 |
+
return None
|
| 453 |
+
|
| 454 |
+
|
| 455 |
+
# ══════════════════════════════════════════════════════════
|
| 456 |
+
# Real-time Search — ✅ HTTPS
|
| 457 |
+
# ══════════════════════════════════════════════════════════
|
| 458 |
+
KEYWORD_TO_URLS = {
|
| 459 |
+
"concours": ["https://www.ena.tn/fr/concours/informations-generales/",
|
| 460 |
+
"https://www.ena.tn/fr/concours/cycle-superieur/le-concours-dentree-au-cycle-superieur/"],
|
| 461 |
+
"مناظرة": ["https://www.ena.tn/fr/concours/informations-generales/",
|
| 462 |
+
"https://www.ena.tn/ar/concours-ar/cycle-superieur-arr/concours-entree-cycle-superieur-ar/"],
|
| 463 |
+
"formation": ["https://www.ena.tn/fr/formation-continue/formation-continue-a-distance-et-presentielle/"],
|
| 464 |
+
"تكوين": ["https://www.ena.tn/fr/formation-continue/formation-continue-a-distance-et-presentielle/"],
|
| 465 |
+
"document": ["https://www.ena.tn/fr/concours/informations-generales/"],
|
| 466 |
+
"وثائق": ["https://www.ena.tn/fr/concours/informations-generales/"],
|
| 467 |
+
"inscription":["https://www.ena.tn/fr/concours/informations-generales/"],
|
| 468 |
+
"تسجيل": ["https://www.ena.tn/fr/concours/informations-generales/"],
|
| 469 |
+
"a2": ["https://www.ena.tn/fr/concours/cycle-moyen/concours-dentree-au-cycle-de-formation-des-cadres-moyens-de-la-sous-categorie-a2-2/",
|
| 470 |
+
"https://www.ena.tn/ar/concours-ar/cycle-moyen-ar/entree-au-cycle-de-formation-des-cadres-moyens-ar/"],
|
| 471 |
+
"إطارات": ["https://www.ena.tn/ar/concours-ar/cycle-moyen-ar/entree-au-cycle-de-formation-des-cadres-moyens-ar/"],
|
| 472 |
+
"متوسطة": ["https://www.ena.tn/ar/concours-ar/cycle-moyen-ar/entree-au-cycle-de-formation-des-cadres-moyens-ar/"],
|
| 473 |
+
"أ2": ["https://www.ena.tn/ar/concours-ar/cycle-moyen-ar/entree-au-cycle-de-formation-des-cadres-moyens-ar/"],
|
| 474 |
+
"a3": ["https://www.ena.tn/fr/concours/agents-de-la-sous-categorie-a3/",
|
| 475 |
+
"https://www.ena.tn/ar/concours-ar/agents-categorie-a3-ar/"],
|
| 476 |
+
"أعوان": ["https://www.ena.tn/ar/concours-ar/agents-categorie-a3-ar/"],
|
| 477 |
+
"أ3": ["https://www.ena.tn/ar/concours-ar/agents-categorie-a3-ar/"],
|
| 478 |
+
"شهادات": ["https://www.ena.tn/ar/concours-ar/cycle-superieur-arr/concours-entree-cycle-superieur-ar/"],
|
| 479 |
+
"اختبارات": ["https://www.ena.tn/ar/concours-ar/cycle-superieur-arr/concours-entree-cycle-superieur-ar/"],
|
| 480 |
+
"ماجستير": ["https://www.ena.tn/ar/concours-ar/cycle-superieur-arr/concours-entree-cycle-superieur-ar/"],
|
| 481 |
+
"مهندس": ["https://www.ena.tn/ar/concours-ar/cycle-superieur-arr/concours-entree-cycle-superieur-ar/"],
|
| 482 |
+
}
|
| 483 |
+
|
| 484 |
+
NAV_WORDS = ["L'ENA SE PRESENTE","Formation de Base","Formation Continue",
|
| 485 |
+
"Concours","LeaderShip","Gouvernance","Accueil","Français","العربية"]
|
| 486 |
+
|
| 487 |
+
HEADERS_HTTP = {
|
| 488 |
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/124.0.0.0",
|
| 489 |
+
"Accept-Language": "fr-FR,fr;q=0.9",
|
| 490 |
+
}
|
| 491 |
+
|
| 492 |
+
def realtime_search_url(url: str, question: str) -> list:
|
| 493 |
+
"""يكشط URL محدد مباشرةً بدون keyword matching"""
|
| 494 |
+
try:
|
| 495 |
+
resp = requests.get(url, headers=HEADERS_HTTP, timeout=10, allow_redirects=True)
|
| 496 |
+
resp.encoding = "utf-8"
|
| 497 |
+
soup = BeautifulSoup(resp.text, "html.parser")
|
| 498 |
+
for tag in soup(["script","style","nav","footer","header","aside","form","button","iframe","img","noscript"]):
|
| 499 |
+
tag.decompose()
|
| 500 |
+
text = soup.get_text("\n", strip=True)
|
| 501 |
+
lines = text.split("\n")
|
| 502 |
+
seen, clean = set(), []
|
| 503 |
+
for line in lines:
|
| 504 |
+
line = line.strip()
|
| 505 |
+
if (len(line) > 15 and line not in seen
|
| 506 |
+
and not any(n in line for n in NAV_WORDS)
|
| 507 |
+
and "©" not in line and len(line) < 1000):
|
| 508 |
+
seen.add(line)
|
| 509 |
+
clean.append(line)
|
| 510 |
+
content = "\n".join(clean[:60])
|
| 511 |
+
if len(content) > 100:
|
| 512 |
+
return [{"content": content, "source": "ena.tn",
|
| 513 |
+
"page_name": "realtime", "url": url,
|
| 514 |
+
"langue": "ar", "score": 0.95}]
|
| 515 |
+
except Exception as e:
|
| 516 |
+
print(f"⚠️ realtime_url {url}: {e}")
|
| 517 |
+
return []
|
| 518 |
+
|
| 519 |
+
def realtime_search(question):
|
| 520 |
+
question_norm = normalize_arabic(question)
|
| 521 |
+
q_low = question_norm.lower()
|
| 522 |
+
urls = []
|
| 523 |
+
for kw, kw_urls in KEYWORD_TO_URLS.items():
|
| 524 |
+
if kw in q_low:
|
| 525 |
+
urls.extend(kw_urls)
|
| 526 |
+
if not urls:
|
| 527 |
+
if any(k in q_low for k in ["متى","تاريخ","موعد","quand","date","ouverture"]):
|
| 528 |
+
urls = ["https://www.ena.tn/ar/concours-ar/informations-generales-ar/",
|
| 529 |
+
"https://www.ena.tn/fr/concours/informations-generales/"]
|
| 530 |
+
else:
|
| 531 |
+
urls = ["https://www.ena.tn/fr/concours/informations-generales/"]
|
| 532 |
+
urls = list(dict.fromkeys(urls))[:2]
|
| 533 |
+
results = []
|
| 534 |
+
for url in urls:
|
| 535 |
+
try:
|
| 536 |
+
resp = requests.get(url, headers=HEADERS_HTTP, timeout=10, allow_redirects=True)
|
| 537 |
+
resp.encoding = "utf-8"
|
| 538 |
+
soup = BeautifulSoup(resp.text, "html.parser")
|
| 539 |
+
for tag in soup(["script","style","nav","footer","header","aside","form","button","iframe","img","noscript"]):
|
| 540 |
+
tag.decompose()
|
| 541 |
+
h2 = soup.find("h2")
|
| 542 |
+
if h2:
|
| 543 |
+
parts = [e.get_text(strip=True) for e in h2.find_all_next() if len(e.get_text(strip=True)) > 15]
|
| 544 |
+
text = "\n".join(parts)
|
| 545 |
+
else:
|
| 546 |
+
text = soup.get_text("\n", strip=True)
|
| 547 |
+
lines = text.split("\n")
|
| 548 |
+
seen, clean = set(), []
|
| 549 |
+
for line in lines:
|
| 550 |
+
line = line.strip()
|
| 551 |
+
if (len(line) > 15 and line not in seen
|
| 552 |
+
and not any(n in line for n in NAV_WORDS)
|
| 553 |
+
and "©" not in line and len(line) < 1000):
|
| 554 |
+
seen.add(line)
|
| 555 |
+
clean.append(line)
|
| 556 |
+
content = "\n".join(clean[:30])
|
| 557 |
+
if len(content) > 100:
|
| 558 |
+
results.append({
|
| 559 |
+
"content": content, "source": "ena.tn",
|
| 560 |
+
"page_name": "realtime", "url": url,
|
| 561 |
+
"langue": "fr", "score": 0.75
|
| 562 |
+
})
|
| 563 |
+
except Exception as e:
|
| 564 |
+
print(f"⚠️ RT {url}: {e}")
|
| 565 |
+
return results
|
| 566 |
+
|
| 567 |
+
|
| 568 |
+
# ══════════════════════════════════════════════════════════
|
| 569 |
+
# RAG System — ✅ PersistentClient
|
| 570 |
+
# ══════════════════════════════════════════════════════════
|
| 571 |
+
@st.cache_resource(show_spinner=False)
|
| 572 |
+
def load_system():
|
| 573 |
+
emb = HuggingFaceEmbeddings(
|
| 574 |
+
model_name="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
|
| 575 |
+
model_kwargs={"device": "cpu"},
|
| 576 |
+
encode_kwargs={"normalize_embeddings": True}
|
| 577 |
+
)
|
| 578 |
+
chunks, metas = [], []
|
| 579 |
+
|
| 580 |
+
# ── Section-aware Chunking (نفس منطق Cell 3) ──────────
|
| 581 |
+
SKIP_SEC = [
|
| 582 |
+
"محتوى برنامج اختبار","الإختصــــــــــــاص",
|
| 583 |
+
"المحور الأول","المحور الثاني","المحور الثالث",
|
| 584 |
+
"المحور الرابع","المحور الخامس","المحور السادس",
|
| 585 |
+
"المحور السابع","المحور الثامن",
|
| 586 |
+
"contenu du programme",
|
| 587 |
+
]
|
| 588 |
+
|
| 589 |
+
def _is_heading(line):
|
| 590 |
+
if len(line) > 80: return False
|
| 591 |
+
import re as _r
|
| 592 |
+
for p in [r"^#{1,4}\s+", r"^\*\*[^*]+\*\*$"]:
|
| 593 |
+
if _r.match(p, line.strip()): return True
|
| 594 |
+
if len(line) < 60 and not line.strip().endswith("."):
|
| 595 |
+
ar = sum(1 for c in line if "\u0600" <= c <= "\u06FF")
|
| 596 |
+
if ar > len(line)*0.4: return True
|
| 597 |
+
return False
|
| 598 |
+
|
| 599 |
+
def _sec_chunk(page, max_size=None):
|
| 600 |
+
if max_size is None: max_size = page.get("_csz", 1200)
|
| 601 |
+
out, cur_sec, cur_title = [], "", page["page_name"]
|
| 602 |
+
base = {"page_name":page["page_name"],"url":page["url"],
|
| 603 |
+
"source":page["source"],"langue":page.get("langue","fr")}
|
| 604 |
+
for line in page["content"].split("\n"):
|
| 605 |
+
line = line.strip()
|
| 606 |
+
if not line: continue
|
| 607 |
+
if page.get("_skip_enabled", True) and any(s in line for s in SKIP_SEC): continue
|
| 608 |
+
if _is_heading(line) and cur_sec:
|
| 609 |
+
if len(cur_sec.strip()) > 80:
|
| 610 |
+
txt = f"{cur_title}\n{cur_sec.strip()}"
|
| 611 |
+
for i in range(0, len(txt), max_size):
|
| 612 |
+
p = txt[i:i+max_size]
|
| 613 |
+
if len(p.strip()) > 80:
|
| 614 |
+
out.append({**base,"content":p})
|
| 615 |
+
cur_title, cur_sec = line, ""
|
| 616 |
+
else:
|
| 617 |
+
cur_sec += line + "\n"
|
| 618 |
+
if cur_sec.strip() and len(cur_sec.strip()) > 80:
|
| 619 |
+
out.append({**base,"content":f"{cur_title}\n{cur_sec.strip()}"})
|
| 620 |
+
return out or [{**base,"content":page["content"][:max_size]}]
|
| 621 |
+
|
| 622 |
+
with open("ena_data.json", "r", encoding="utf-8") as f:
|
| 623 |
+
data = json.load(f)
|
| 624 |
+
# صفحات تفصيلية → chunk_size=500 | باقي الصفحات → 1200
|
| 625 |
+
_DET = ["ar_concours_superieur_detail", "concours_superieur"]
|
| 626 |
+
_QCM_PAGES = ["ar_concours_a2_detail", "ar_concours_a3_detail", "concours_a2", "concours_a3"]
|
| 627 |
+
for page in data:
|
| 628 |
+
page["_csz"] = 500 if page["page_name"] in _DET else 1200
|
| 629 |
+
page["_skip_enabled"] = page["page_name"] not in _QCM_PAGES
|
| 630 |
+
for pc in _sec_chunk(page):
|
| 631 |
+
chunks.append(pc["content"])
|
| 632 |
+
metas.append({"page_name":pc["page_name"],"source":pc["source"],
|
| 633 |
+
"url":pc["url"],"langue":pc["langue"]})
|
| 634 |
+
|
| 635 |
+
# ✅ PersistentClient — لا تفقد البيانات عند إغلاق المتصفح
|
| 636 |
+
CHROMA_PATH = "./chroma_ena_db"
|
| 637 |
+
chroma_client = chromadb.PersistentClient(path=CHROMA_PATH)
|
| 638 |
+
try:
|
| 639 |
+
chroma_client.delete_collection("ena_collection")
|
| 640 |
+
except:
|
| 641 |
+
pass
|
| 642 |
+
vdb = Chroma(
|
| 643 |
+
client=chroma_client,
|
| 644 |
+
collection_name="ena_collection",
|
| 645 |
+
embedding_function=emb
|
| 646 |
+
)
|
| 647 |
+
vdb.add_texts(texts=chunks, metadatas=metas)
|
| 648 |
+
b25 = BM25Okapi([normalize_arabic(c).lower().split() for c in chunks])
|
| 649 |
+
return emb, vdb, chunks, metas, b25
|
| 650 |
+
|
| 651 |
+
|
| 652 |
+
with st.spinner("🔄 تحميل النظام..."):
|
| 653 |
+
embeddings, vectordb, all_chunks, all_metadatas, bm25 = load_system()
|
| 654 |
+
llm_client = load_llm_client()
|
| 655 |
+
|
| 656 |
+
|
| 657 |
+
# ══════════════════════════════════════════════════════════
|
| 658 |
+
# دوال RAG + Reranking + قاموس ENA
|
| 659 |
+
# ══════════════════════════════════════════════════════════
|
| 660 |
+
# ══════════════════════════════════════════════════════════
|
| 661 |
+
# 🧠 expand_query_llm — توسيع ذكي بدون أي كلمة يدوية
|
| 662 |
+
# الـ LLM يولد صياغات بديلة تلقائياً بالعربية والفرنسية
|
| 663 |
+
# ══════════════════════════════════════════════════════════
|
| 664 |
+
import functools
|
| 665 |
+
|
| 666 |
+
@functools.lru_cache(maxsize=256)
|
| 667 |
+
def expand_query_llm_cached(question: str, groq_api_key: str) -> tuple:
|
| 668 |
+
"""توسيع السؤال بالـ LLM مع cache لتفادي استدعاءات مكررة"""
|
| 669 |
+
try:
|
| 670 |
+
from groq import Groq as _Groq
|
| 671 |
+
client = _Groq(api_key=groq_api_key)
|
| 672 |
+
response = client.chat.completions.create(
|
| 673 |
+
model="llama-3.3-70b-versatile",
|
| 674 |
+
messages=[{
|
| 675 |
+
"role": "user",
|
| 676 |
+
"content": (
|
| 677 |
+
f'السؤال التالي موجه لنظام بحث في قاعدة بيانات المدرسة الوطنية للإدارة بتونس (ENA).\n'
|
| 678 |
+
f'السؤال: "{question}"\n\n'
|
| 679 |
+
f'مهمتك: أنشئ 4 صياغات بديلة لهذا السؤال تساعد في البحث الدلالي.\n'
|
| 680 |
+
f'القواعد:\n'
|
| 681 |
+
f'- صياغة 1: ترجم السؤال للفرنسية\n'
|
| 682 |
+
f'- صياغة 2: استخدم مصطلحات تقنية مختلفة لنفس المعنى\n'
|
| 683 |
+
f'- صياغة 3: صغ السؤال بطريقة أكثر عمومية\n'
|
| 684 |
+
f'- صياغة 4: أضف كلمة ENA أو concours أو formation حسب السياق\n'
|
| 685 |
+
f'أجب بـ JSON فقط بدون أي شرح: ["صياغة1","صياغة2","صياغة3","صياغة4"]'
|
| 686 |
+
)
|
| 687 |
+
}],
|
| 688 |
+
max_tokens=200,
|
| 689 |
+
temperature=0.3,
|
| 690 |
+
)
|
| 691 |
+
raw = response.choices[0].message.content.strip()
|
| 692 |
+
# استخراج الـ JSON
|
| 693 |
+
import re as _re, json as _json
|
| 694 |
+
match = _re.search(r'\[.*?\]', raw, _re.DOTALL)
|
| 695 |
+
if match:
|
| 696 |
+
variants = _json.loads(match.group())
|
| 697 |
+
return tuple(v for v in variants if isinstance(v, str) and len(v) > 3)
|
| 698 |
+
except Exception as e:
|
| 699 |
+
print(f"⚠️ expand_query_llm: {e}")
|
| 700 |
+
return ()
|
| 701 |
+
|
| 702 |
+
def expand_query(question, llm_client=None):
|
| 703 |
+
"""
|
| 704 |
+
توسيع ذكي للسؤال:
|
| 705 |
+
1. السؤال الأصلي دائماً
|
| 706 |
+
2. صياغات بديلة من الـ LLM (عربي + فرنسي + مصطلحات تقنية)
|
| 707 |
+
3. fallback بسيط إذا فشل الـ LLM
|
| 708 |
+
"""
|
| 709 |
+
expanded = [question]
|
| 710 |
+
|
| 711 |
+
# محاولة التوسيع بالـ LLM
|
| 712 |
+
groq_key = os.environ.get("GROQ_TOKEN", "")
|
| 713 |
+
if groq_key:
|
| 714 |
+
variants = expand_query_llm_cached(normalize_arabic(question), groq_key)
|
| 715 |
+
expanded.extend(variants)
|
| 716 |
+
|
| 717 |
+
# fallback: ترجمة بسيطة إذا لم يعمل الـ LLM
|
| 718 |
+
if len(expanded) == 1:
|
| 719 |
+
expanded.append(f"ENA Tunisie {question}")
|
| 720 |
+
if any(c in question for c in "abcdefghijklmnopqrstuvwxyz"):
|
| 721 |
+
expanded.append(f"ENA تونس {question}")
|
| 722 |
+
|
| 723 |
+
return list(dict.fromkeys(expanded))
|
| 724 |
+
|
| 725 |
+
|
| 726 |
+
def hybrid_search(question, k=5):
|
| 727 |
+
# تطبيع السؤال قبل البحث
|
| 728 |
+
question_n = normalize_arabic(question)
|
| 729 |
+
vr = vectordb.similarity_search(question_n, k=k)
|
| 730 |
+
bs = bm25.get_scores(question_n.lower().split())
|
| 731 |
+
idx = np.argsort(bs)[::-1][:k]
|
| 732 |
+
seen, res = set(), []
|
| 733 |
+
for d in vr:
|
| 734 |
+
if d.page_content not in seen:
|
| 735 |
+
meta = d.metadata
|
| 736 |
+
res.append({
|
| 737 |
+
"content": d.page_content,
|
| 738 |
+
"source": meta.get("page_name", ""),
|
| 739 |
+
"url": meta.get("url", ""),
|
| 740 |
+
"langue": meta.get("langue", "fr")
|
| 741 |
+
})
|
| 742 |
+
seen.add(d.page_content)
|
| 743 |
+
for i in idx:
|
| 744 |
+
if all_chunks[i] not in seen:
|
| 745 |
+
res.append({
|
| 746 |
+
"content": all_chunks[i],
|
| 747 |
+
"source": all_metadatas[i].get("page_name", ""),
|
| 748 |
+
"url": all_metadatas[i].get("url", ""),
|
| 749 |
+
"langue": all_metadatas[i].get("langue", "fr")
|
| 750 |
+
})
|
| 751 |
+
seen.add(all_chunks[i])
|
| 752 |
+
return res[:k]
|
| 753 |
+
|
| 754 |
+
# ══════════════════════════════════════════════════════════
|
| 755 |
+
# 🎯 Cross-Encoder Reranking — بدون أي يدوي
|
| 756 |
+
# يقرأ السؤال والـ chunk معاً ويقيّم مدى الإجابة
|
| 757 |
+
# أدق بكثير من cosine similarity أو bonus يدوي
|
| 758 |
+
# ══════════════════════════════════════════════════════════
|
| 759 |
+
@st.cache_resource(show_spinner=False)
|
| 760 |
+
def load_cross_encoder():
|
| 761 |
+
try:
|
| 762 |
+
from sentence_transformers import CrossEncoder
|
| 763 |
+
model = CrossEncoder(
|
| 764 |
+
"cross-encoder/ms-marco-MiniLM-L-6-v2",
|
| 765 |
+
max_length=512
|
| 766 |
+
)
|
| 767 |
+
return model
|
| 768 |
+
except Exception as e:
|
| 769 |
+
print(f"⚠️ CrossEncoder load error: {e}")
|
| 770 |
+
return None
|
| 771 |
+
|
| 772 |
+
def rerank(question, candidates, top_k=3):
|
| 773 |
+
if not candidates:
|
| 774 |
+
return []
|
| 775 |
+
|
| 776 |
+
cross_encoder = load_cross_encoder()
|
| 777 |
+
|
| 778 |
+
if cross_encoder is not None:
|
| 779 |
+
# ✅ Cross-Encoder — يقرأ السؤال + الـ chunk معاً
|
| 780 |
+
try:
|
| 781 |
+
pairs = [(question, c["content"][:512]) for c in candidates]
|
| 782 |
+
scores = cross_encoder.predict(pairs)
|
| 783 |
+
# تطبيع الـ scores إلى [0, 1]
|
| 784 |
+
import scipy.special
|
| 785 |
+
scores_norm = scipy.special.expit(scores)
|
| 786 |
+
for item, score in zip(candidates, scores_norm):
|
| 787 |
+
item["score"] = round(float(score), 4)
|
| 788 |
+
return sorted(candidates, key=lambda x: x["score"], reverse=True)[:top_k]
|
| 789 |
+
except Exception as e:
|
| 790 |
+
print(f"⚠️ CrossEncoder predict error: {e}")
|
| 791 |
+
|
| 792 |
+
# Fallback — cosine similarity بسيط بدون bonus
|
| 793 |
+
q_emb = np.array(embeddings.embed_query(question))
|
| 794 |
+
c_embs = np.array(embeddings.embed_documents([c["content"] for c in candidates]))
|
| 795 |
+
sims = cosine_similarity(q_emb.reshape(1,-1), c_embs)[0]
|
| 796 |
+
scored = [{**item, "score": round(float(sim), 4)}
|
| 797 |
+
for item, sim in zip(candidates, sims)]
|
| 798 |
+
return sorted(scored, key=lambda x: x["score"], reverse=True)[:top_k]
|
| 799 |
+
|
| 800 |
+
def clean_chunks(ranked, threshold=0.82):
|
| 801 |
+
if not ranked: return []
|
| 802 |
+
clean = [ranked[0]]
|
| 803 |
+
for chunk in ranked[1:]:
|
| 804 |
+
if not any(difflib.SequenceMatcher(None, chunk["content"], c["content"]).ratio() > threshold for c in clean):
|
| 805 |
+
clean.append(chunk)
|
| 806 |
+
return clean
|
| 807 |
+
|
| 808 |
+
|
| 809 |
+
# ══════════════════════════════════════════════════════════
|
| 810 |
+
# 🤖 LLM Router — يختار URL المناسب لكل سؤال تلقائياً
|
| 811 |
+
# بدون أي keywords أو قواميس يدوية
|
| 812 |
+
# ══════════════════════════════════════════════════════════
|
| 813 |
+
@functools.lru_cache(maxsize=256)
|
| 814 |
+
def get_best_url_for_question(question: str) -> str | None:
|
| 815 |
+
"""
|
| 816 |
+
يسأل الـ LLM: أي URL من PAGE_URLS يجيب على هذا السؤال؟
|
| 817 |
+
بدون أي keywords يدوية — الـ LLM يفهم السؤال ويختار.
|
| 818 |
+
يعيد None إذا لم يجد صفحة مناسبة.
|
| 819 |
+
"""
|
| 820 |
+
groq_key = os.environ.get("GROQ_TOKEN", "")
|
| 821 |
+
if not groq_key: return None
|
| 822 |
+
try:
|
| 823 |
+
from groq import Groq as _G
|
| 824 |
+
pages_list = "\n".join([
|
| 825 |
+
f"- {name}: {url}"
|
| 826 |
+
for name, url in PAGE_URLS.items()
|
| 827 |
+
])
|
| 828 |
+
c = _G(api_key=groq_key)
|
| 829 |
+
r = c.chat.completions.create(
|
| 830 |
+
model="llama-3.3-70b-versatile",
|
| 831 |
+
messages=[{"role":"user","content":
|
| 832 |
+
f'لديك هذه الصفحات من موقع ENA تونس:\n{pages_list}\n\n'
|
| 833 |
+
f'السؤال: "{question}"\n\n'
|
| 834 |
+
f'مهمتك: اختر الصفحة الأنسب للإجابة على هذا السؤال.\n'
|
| 835 |
+
f'قواعد مهمة:\n'
|
| 836 |
+
f'1. إذا السؤال بالعربية → فضّل الصفحات التي تبدأ بـ ar_\n'
|
| 837 |
+
f'2. إذا السؤال بالفرنسية → فضّل الصفحات التي لا تبدأ بـ ar_\n'
|
| 838 |
+
f'3. أسئلة التواريخ والمواعيد (متى/quand/date) → اختر ar_concours_general أو concours_general\n'
|
| 839 |
+
f'4. إذا وجدت صفحة مناسبة → أجب باسمها فقط\n'
|
| 840 |
+
f'5. إذا السؤال عام لا يتعلق بصفحة محددة → أجب بـ none'
|
| 841 |
+
}],
|
| 842 |
+
max_tokens=30, temperature=0.0,
|
| 843 |
+
)
|
| 844 |
+
result = r.choices[0].message.content.strip().lower()
|
| 845 |
+
return PAGE_URLS.get(result, None)
|
| 846 |
+
except Exception as e:
|
| 847 |
+
print(f"⚠️ get_best_url: {e}")
|
| 848 |
+
return None
|
| 849 |
+
|
| 850 |
+
|
| 851 |
+
# ══════════════════════════════════════════════════════════
|
| 852 |
+
# الدالة الرئيسية — النظام الهجين الكامل
|
| 853 |
+
# ══════════════════════════════════════════════════════════
|
| 854 |
+
def get_best_answer(question, confidence_threshold=70.0):
|
| 855 |
+
question_norm = normalize_arabic(question)
|
| 856 |
+
q_low = question_norm.lower()
|
| 857 |
+
all_c, seen = [], set()
|
| 858 |
+
|
| 859 |
+
# ✅ LLM يقرر أي URL يناسب السؤال — بدون أي keywords يدوية
|
| 860 |
+
best_url = get_best_url_for_question(question)
|
| 861 |
+
if best_url:
|
| 862 |
+
rt = realtime_search_url(best_url, question)
|
| 863 |
+
if rt:
|
| 864 |
+
# اسم الصفحة من PAGE_URLS بدل "ena.tn" الثابت
|
| 865 |
+
page_name = next((k for k, v in PAGE_URLS.items() if v == best_url), "ena.tn")
|
| 866 |
+
srcs = [{"name": page_name, "url": best_url}]
|
| 867 |
+
ans = generate_answer(question, rt, llm_client,
|
| 868 |
+
chat_history=st.session_state.get("history",[]))
|
| 869 |
+
final_ans = ans if ans else rt[0]["content"]
|
| 870 |
+
return {
|
| 871 |
+
"answer": final_ans,
|
| 872 |
+
"sources": srcs,
|
| 873 |
+
"confidence": calibrate_confidence(0.95, final_ans),
|
| 874 |
+
"proactive": get_proactive(question),
|
| 875 |
+
"reflection": {"status":"🌐 Real-time","score":0.95},
|
| 876 |
+
"used_llm": bool(ans), "used_realtime": True
|
| 877 |
+
}
|
| 878 |
+
for q in expand_query(question, llm_client):
|
| 879 |
+
for c in hybrid_search(q, k=3):
|
| 880 |
+
if c["content"] not in seen:
|
| 881 |
+
all_c.append(c)
|
| 882 |
+
seen.add(c["content"])
|
| 883 |
+
|
| 884 |
+
ranked = rerank(question, all_c, top_k=5)
|
| 885 |
+
arabic_chars = sum(1 for ch in question if '\u0600' <= ch <= '\u06FF')
|
| 886 |
+
q_lang = "ar" if arabic_chars > 2 else "fr"
|
| 887 |
+
used_realtime = False
|
| 888 |
+
|
| 889 |
+
if ranked:
|
| 890 |
+
lang_sorted = sorted(ranked, key=lambda c: (0 if c.get("langue","fr")==q_lang else 1, -c["score"]))
|
| 891 |
+
deduped = clean_chunks(lang_sorted)
|
| 892 |
+
top_chunks = deduped[:3]
|
| 893 |
+
conf = round(float(deduped[0]["score"]) * 100, 1)
|
| 894 |
+
else:
|
| 895 |
+
top_chunks, conf = [], 0.0
|
| 896 |
+
|
| 897 |
+
if conf < confidence_threshold:
|
| 898 |
+
rt_chunks = realtime_search(question)
|
| 899 |
+
if rt_chunks:
|
| 900 |
+
top_chunks = rt_chunks + top_chunks[:2]
|
| 901 |
+
used_realtime = True
|
| 902 |
+
conf = max(conf, 72.0)
|
| 903 |
+
|
| 904 |
+
if not top_chunks:
|
| 905 |
+
suggestion = suggest_better_question(question)
|
| 906 |
+
fallback_msg = (
|
| 907 |
+
f"لم أجد إجابة دقيقة.\n\n💡 جرّب:\n**{suggestion}**\n\n📞 71 848 300"
|
| 908 |
+
if suggestion else "📞 71 848 300 | info@ena.tn"
|
| 909 |
+
)
|
| 910 |
+
return {
|
| 911 |
+
"answer": fallback_msg, "sources": [],
|
| 912 |
+
"confidence": "0% 🔴", "proactive": [],
|
| 913 |
+
"reflection": {"status":"❌","score":0.0},
|
| 914 |
+
"used_llm": False, "used_realtime": False
|
| 915 |
+
}
|
| 916 |
+
|
| 917 |
+
# بناء sources مع روابط مباشرة
|
| 918 |
+
seen_src, seen_url, sources = set(), set(), []
|
| 919 |
+
for r in top_chunks:
|
| 920 |
+
name = r.get("source", r.get("page_name",""))
|
| 921 |
+
url = r.get("url","") or PAGE_URLS.get(name,"")
|
| 922 |
+
if name not in seen_src and url not in seen_url:
|
| 923 |
+
seen_src.add(name); seen_url.add(url)
|
| 924 |
+
sources.append({"name": name, "url": url})
|
| 925 |
+
|
| 926 |
+
llm_answer = generate_answer(question, top_chunks, llm_client, chat_history=st.session_state.get("history", []))
|
| 927 |
+
|
| 928 |
+
if llm_answer:
|
| 929 |
+
return {
|
| 930 |
+
"answer": llm_answer, "sources": sources,
|
| 931 |
+
"confidence": f"{conf}%", "proactive": get_proactive(question),
|
| 932 |
+
"reflection": {"status":"✅ إجابة AI","score":0.9},
|
| 933 |
+
"used_llm": True, "used_realtime": used_realtime
|
| 934 |
+
}
|
| 935 |
+
else:
|
| 936 |
+
answer = "\n\n".join([c["content"] for c in top_chunks])
|
| 937 |
+
if conf < 50:
|
| 938 |
+
answer += "\n\n📞 71 848 300 | info@ena.tn"
|
| 939 |
+
return {
|
| 940 |
+
"answer": answer, "sources": sources,
|
| 941 |
+
"confidence": f"{conf}%", "proactive": get_proactive(question),
|
| 942 |
+
"reflection": {"status":"⚠️ جزئية","score":0.6},
|
| 943 |
+
"used_llm": False, "used_realtime": used_realtime
|
| 944 |
+
}
|
| 945 |
+
|
| 946 |
+
|
| 947 |
+
# ══════════════════════════════════════════════════════════
|
| 948 |
+
# ✅ Cache للإجابات النهائية — يمنع الكشط المكرر لنفس السؤال
|
| 949 |
+
# ══════════════════════════════════════════════════════════
|
| 950 |
+
@functools.lru_cache(maxsize=256)
|
| 951 |
+
def get_best_answer_cached(question: str, threshold: float):
|
| 952 |
+
"""
|
| 953 |
+
نفس get_best_answer لكن مع cache:
|
| 954 |
+
- أول مرة → يكشط + يسأل Groq → يحفظ الجواب
|
| 955 |
+
- المرات التالية → يقرأ من الذاكرة فوراً
|
| 956 |
+
"""
|
| 957 |
+
return get_best_answer(question, threshold)
|
| 958 |
+
|
| 959 |
+
|
| 960 |
+
# ══════════════════════════════════════════════════════════
|
| 961 |
+
# Guardrails
|
| 962 |
+
# ══════════════════════════════════════════════════════════
|
| 963 |
+
OUT_OF_SCOPE = [
|
| 964 |
+
r"météo|weather|طقس", r"\bfoot\b|football|كرة",
|
| 965 |
+
r"bitcoin|crypto|بورصة", r"\bfilm\b|فيلم|سينما",
|
| 966 |
+
r"وصفة|طبخ", r"حب|زواج|طلاق"
|
| 967 |
+
]
|
| 968 |
+
GREETINGS = {
|
| 969 |
+
r"^(bonjour|bonsoir|salut|hello|hi)\b": "Bonjour! Je suis l'assistant ENA Tunisie.\n📞 71 848 300 | ✉️ info@ena.tn",
|
| 970 |
+
r"^(مرحبا|السلام|أهلا|هاي|مساء|صباح)": "مرحباً! 👋 أنا مساعد ENA تونس.\nكيف يمكنني مساعدتك؟",
|
| 971 |
+
}
|
| 972 |
+
|
| 973 |
+
def guardrails(question):
|
| 974 |
+
q = question.strip().lower()
|
| 975 |
+
for pattern, response in GREETINGS.items():
|
| 976 |
+
if re.search(pattern, q): return "greeting", response
|
| 977 |
+
for pattern in OUT_OF_SCOPE:
|
| 978 |
+
if re.search(pattern, q): return "rejected", "عذراً، أنا مخصص فقط لـ ENA تونس.\n📞 71 848 300"
|
| 979 |
+
return "valid", None
|
| 980 |
+
|
| 981 |
+
|
| 982 |
+
# ══════════════════════════════════════════════════════════
|
| 983 |
+
# SIDEBAR
|
| 984 |
+
# ══════════════════════════════════════════════════════════
|
| 985 |
+
with st.sidebar:
|
| 986 |
+
st.markdown("## 🎓 ENA Chatbot")
|
| 987 |
+
st.markdown("*المدرسة الوطنية للإدارة — تونس*")
|
| 988 |
+
st.markdown("---")
|
| 989 |
+
if llm_client:
|
| 990 |
+
st.success("✨ Groq AI (Llama 3.3) مفعّل")
|
| 991 |
+
else:
|
| 992 |
+
st.warning("⚠️ RAG فقط — أضف GROQ_TOKEN")
|
| 993 |
+
st.markdown("---")
|
| 994 |
+
show_sources = st.toggle("🔗 مصادر المعلومة", value=True)
|
| 995 |
+
show_conf = st.toggle("📊 مؤشر الثقة", value=True)
|
| 996 |
+
show_proactive = st.toggle("💡 الاقتراحات الاستباقية", value=True)
|
| 997 |
+
show_reflect = st.toggle("🔍 تقييم تقني", value=False)
|
| 998 |
+
st.markdown("---")
|
| 999 |
+
threshold = st.slider("🎯 حد الهجين (%)", 50, 90, 70)
|
| 1000 |
+
st.caption("إذا الثقة أقل من هذا → يفتح الموقع لحظياً")
|
| 1001 |
+
st.markdown("---")
|
| 1002 |
+
total_q = len([m for m in st.session_state.get("history",[]) if m["role"]=="user"])
|
| 1003 |
+
st.metric("💬 عدد الأسئلة", total_q)
|
| 1004 |
+
st.markdown("<br>", unsafe_allow_html=True)
|
| 1005 |
+
if st.button("🗑️ مسح المحادثة"):
|
| 1006 |
+
st.session_state.history = []
|
| 1007 |
+
st.rerun()
|
| 1008 |
+
st.markdown("---")
|
| 1009 |
+
st.markdown("""
|
| 1010 |
+
<div class="sidebar-contact">
|
| 1011 |
+
<div>📍 24 نهج الدكتور كالمات، 1082 تونس</div>
|
| 1012 |
+
<div>📞 <a href="tel:+21671848300">71 848 300</a></div>
|
| 1013 |
+
<div>✉️ <a href="mailto:info@ena.tn">info@ena.tn</a></div>
|
| 1014 |
+
<div>🌐 <a href="https://www.ena.tn" target="_blank">www.ena.tn</a></div>
|
| 1015 |
+
<div>🏆 <a href="https://concours.ena.tn" target="_blank">concours.ena.tn</a></div>
|
| 1016 |
+
</div>
|
| 1017 |
+
""", unsafe_allow_html=True)
|
| 1018 |
+
st.caption("ENA v13.26 | Llama 3.3 🏆")
|
| 1019 |
+
|
| 1020 |
+
|
| 1021 |
+
# ══════════════════════════════════════════════════════════
|
| 1022 |
+
# HEADER
|
| 1023 |
+
# ══════════════════════════════════════════════════════════
|
| 1024 |
+
st.markdown("""
|
| 1025 |
+
<div class="main-header">
|
| 1026 |
+
<h1>🎓 بوت مناظرات ENA <span class="header-badge">v13.26</span></h1>
|
| 1027 |
+
<div class="subtitle">
|
| 1028 |
+
اسألني عن شروط الترشح · الوثائق المطلوبة · برامج التكوين<br>
|
| 1029 |
+
<small>Posez vos questions sur les concours, formations et procédures ENA</small>
|
| 1030 |
+
</div>
|
| 1031 |
+
</div>
|
| 1032 |
+
""", unsafe_allow_html=True)
|
| 1033 |
+
|
| 1034 |
+
|
| 1035 |
+
# ══════════════════════════════════════════════════════════
|
| 1036 |
+
# تهيئة المحادثة
|
| 1037 |
+
# ══════════════════════════════════════════════════════════
|
| 1038 |
+
if "history" not in st.session_state:
|
| 1039 |
+
st.session_state.history = [{
|
| 1040 |
+
"role": "bot",
|
| 1041 |
+
"content": "مرحباً! 👋 أنا بوت ENA تونس (v13.26 — Llama 3.3 ⚡).\n\n• شروط المناظرات\n• الوثائق المطلوبة\n• برامج التكوين\n\nكيف يمكنني مساعدتك؟",
|
| 1042 |
+
"sources": [], "confidence": None, "reflection": None,
|
| 1043 |
+
"used_llm": False, "used_realtime": False, "proactive": [],
|
| 1044 |
+
}]
|
| 1045 |
+
|
| 1046 |
+
|
| 1047 |
+
# ══════════════════════════════════════════════════════════
|
| 1048 |
+
# عرض المحادثة
|
| 1049 |
+
# ══════════════════════════════════════════════════════════
|
| 1050 |
+
for msg_idx, msg in enumerate(st.session_state.history):
|
| 1051 |
+
if msg["role"] == "user":
|
| 1052 |
+
st.markdown(
|
| 1053 |
+
f'<div class="user-row"><div class="user-bubble">{msg["content"]}</div>'
|
| 1054 |
+
f'<div class="user-avatar">🧑</div></div>',
|
| 1055 |
+
unsafe_allow_html=True
|
| 1056 |
+
)
|
| 1057 |
+
else:
|
| 1058 |
+
if msg.get("used_realtime"): badge = '<span class="rt-badge">🌐 هجين</span>'
|
| 1059 |
+
elif msg.get("used_llm"): badge = '<span class="llm-badge">✨ Llama 3.3</span><span class="sc-badge">🔍 مراجَع</span>'
|
| 1060 |
+
else: badge = '<span class="rag-badge">📚 RAG</span>'
|
| 1061 |
+
|
| 1062 |
+
st.markdown(
|
| 1063 |
+
f'<div class="bot-row"><div class="bot-avatar">🎓</div>'
|
| 1064 |
+
f'<div class="bot-bubble">{badge} {msg["content"]}</div></div>',
|
| 1065 |
+
unsafe_allow_html=True
|
| 1066 |
+
)
|
| 1067 |
+
|
| 1068 |
+
# مؤشر الثقة
|
| 1069 |
+
if show_conf and msg.get("confidence") and msg["confidence"] != "—":
|
| 1070 |
+
try:
|
| 1071 |
+
val = float(msg["confidence"].replace("%",""))
|
| 1072 |
+
color = "#2E7D5E" if val>=80 else "#B7791F" if val>=50 else "#C0392B"
|
| 1073 |
+
st.markdown(
|
| 1074 |
+
f'<div class="conf-wrap">'
|
| 1075 |
+
f'<div class="conf-label">الثقة: {msg["confidence"]}</div>'
|
| 1076 |
+
f'<div class="conf-bg"><div class="conf-fill" style="width:{min(val,100)}%;background:{color};"></div></div>'
|
| 1077 |
+
f'</div>',
|
| 1078 |
+
unsafe_allow_html=True
|
| 1079 |
+
)
|
| 1080 |
+
except:
|
| 1081 |
+
pass
|
| 1082 |
+
|
| 1083 |
+
# 🔗 مصادر قابلة للنقر
|
| 1084 |
+
if show_sources and msg.get("sources"):
|
| 1085 |
+
chips_html = ""
|
| 1086 |
+
for s in msg["sources"]:
|
| 1087 |
+
if isinstance(s, dict):
|
| 1088 |
+
name, url = s.get("name",""), s.get("url","")
|
| 1089 |
+
else:
|
| 1090 |
+
name, url = s, ""
|
| 1091 |
+
if url:
|
| 1092 |
+
chips_html += f'<a href="{url}" target="_blank" class="source-chip">🔗 {name}</a>'
|
| 1093 |
+
else:
|
| 1094 |
+
chips_html += f'<span class="source-chip">🔗 {name}</span>'
|
| 1095 |
+
if chips_html:
|
| 1096 |
+
st.markdown(
|
| 1097 |
+
f'<div class="source-wrap">'
|
| 1098 |
+
f'<div class="source-label">📌 مصدر المعلومة:</div>'
|
| 1099 |
+
f'<div class="source-chips">{chips_html}</div>'
|
| 1100 |
+
f'</div>',
|
| 1101 |
+
unsafe_allow_html=True
|
| 1102 |
+
)
|
| 1103 |
+
|
| 1104 |
+
# 💡 اقتراحات استباقية
|
| 1105 |
+
proactive = msg.get("proactive", [])
|
| 1106 |
+
if show_proactive and proactive:
|
| 1107 |
+
st.markdown(
|
| 1108 |
+
'<div class="proactive-wrap"><div class="proactive-label">💡 هل تريد معرفة المزيد؟</div></div>',
|
| 1109 |
+
unsafe_allow_html=True
|
| 1110 |
+
)
|
| 1111 |
+
pcols = st.columns(len(proactive))
|
| 1112 |
+
for pi, (pcol, psug) in enumerate(zip(pcols, proactive)):
|
| 1113 |
+
with pcol:
|
| 1114 |
+
if st.button(psug, key=f"pro_{msg_idx}_{pi}"):
|
| 1115 |
+
clean_sug = re.sub(r'^[^\w\u0600-\u06FF]+', '', psug).strip()
|
| 1116 |
+
st.session_state["pending"] = clean_sug
|
| 1117 |
+
st.rerun()
|
| 1118 |
+
|
| 1119 |
+
# تقييم تقني
|
| 1120 |
+
if show_reflect and msg.get("reflection"):
|
| 1121 |
+
r = msg["reflection"]
|
| 1122 |
+
with st.expander("🔍 تقييم تقني"):
|
| 1123 |
+
st.write(f"**{r['status']}** | Score: {r['score']}")
|
| 1124 |
+
|
| 1125 |
+
|
| 1126 |
+
# ══════════════════════════════════════════════════════════
|
| 1127 |
+
# أسئلة مقترحة
|
| 1128 |
+
# ══════════════════════════════════════════════════════════
|
| 1129 |
+
st.markdown('<hr class="chat-divider">', unsafe_allow_html=True)
|
| 1130 |
+
st.markdown('<div class="sug-label">💡 أسئلة مقترحة:</div>', unsafe_allow_html=True)
|
| 1131 |
+
|
| 1132 |
+
suggestions = [
|
| 1133 |
+
"ماهي الشهادات العلمية المستوجبة",
|
| 1134 |
+
"📄 الوثائق المطلوبة للتسجيل",
|
| 1135 |
+
"ماهي الاختبارات تشتمل مناظرة الدخول إلى المرحلة العليا",
|
| 1136 |
+
"متى تفتح مناظرة الدخول إلى المرحلة العليا",
|
| 1137 |
+
]
|
| 1138 |
+
cols = st.columns(4)
|
| 1139 |
+
for i, (col, sug) in enumerate(zip(cols, suggestions)):
|
| 1140 |
+
with col:
|
| 1141 |
+
if st.button(sug, key=f"sug_{i}"):
|
| 1142 |
+
st.session_state["pending"] = re.sub(r'^[^\w\u0600-\u06FF]+', '', sug).strip()
|
| 1143 |
+
st.rerun()
|
| 1144 |
+
|
| 1145 |
+
|
| 1146 |
+
# ══════════════════════════════════════════════════════════
|
| 1147 |
+
# خانة الإدخال
|
| 1148 |
+
# ══════════════════════════════════════════════════════════
|
| 1149 |
+
with st.form("chat_form", clear_on_submit=True):
|
| 1150 |
+
c1, c2 = st.columns([6,1])
|
| 1151 |
+
with c1:
|
| 1152 |
+
user_input = st.text_input(
|
| 1153 |
+
"", label_visibility="collapsed",
|
| 1154 |
+
placeholder="اكتب سؤالك هنا... | Posez votre question..."
|
| 1155 |
+
)
|
| 1156 |
+
with c2:
|
| 1157 |
+
submitted = st.form_submit_button("إرسال ✈️")
|
| 1158 |
+
|
| 1159 |
+
if "pending" in st.session_state:
|
| 1160 |
+
user_input = st.session_state.pop("pending")
|
| 1161 |
+
submitted = True
|
| 1162 |
+
|
| 1163 |
+
|
| 1164 |
+
# ══════════════════════════════════════════════════════════
|
| 1165 |
+
# معالجة السؤال
|
| 1166 |
+
# ══════════════════════════════════════════════════════════
|
| 1167 |
+
if submitted and user_input and user_input.strip():
|
| 1168 |
+
st.session_state.history.append({"role":"user","content":user_input.strip()})
|
| 1169 |
+
|
| 1170 |
+
with st.spinner("🔍 جاري البحث..."):
|
| 1171 |
+
status, guard_msg = guardrails(user_input.strip())
|
| 1172 |
+
if status in ["greeting","rejected"]:
|
| 1173 |
+
result = {
|
| 1174 |
+
"answer": guard_msg, "sources": [], "confidence": "—",
|
| 1175 |
+
"reflection": {"status":"🛡️","score":1.0},
|
| 1176 |
+
"used_llm": False, "used_realtime": False, "proactive": []
|
| 1177 |
+
}
|
| 1178 |
+
else:
|
| 1179 |
+
result = get_best_answer_cached(user_input.strip(), float(threshold))
|
| 1180 |
+
|
| 1181 |
+
st.session_state.history.append({
|
| 1182 |
+
"role": "bot",
|
| 1183 |
+
"content": result["answer"],
|
| 1184 |
+
"sources": result.get("sources", []),
|
| 1185 |
+
"confidence": result.get("confidence"),
|
| 1186 |
+
"reflection": result.get("reflection"),
|
| 1187 |
+
"used_llm": result.get("used_llm", False),
|
| 1188 |
+
"used_realtime": result.get("used_realtime", False),
|
| 1189 |
+
"proactive": result.get("proactive", []),
|
| 1190 |
+
})
|
| 1191 |
+
st.rerun()
|
ena_data.json
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"page_name": "concours_superieur",
|
| 4 |
+
"url": "https://www.ena.tn/fr/concours/cycle-superieur/le-concours-dentree-au-cycle-superieur/",
|
| 5 |
+
"source": "ena.tn",
|
| 6 |
+
"langue": "fr",
|
| 7 |
+
"content": "Le concours d’entrée au Cycle Supérieur\nCycle Supérieur\nLe concours d’entrée au Cycle Supérieur\n35 ans au maximum au 1er janvier de l'année d'ouverture du concours\nLes diplômes requis\nLes diplômes nationaux de mastères à caractère juridique ou politique tels que définis par les textes en vigueur ou les diplômes équivalents,\nLes diplômes nationaux de mastères à caractère économique ou de gestion tels que définis par les textes en vigueur ou les diplômes équivalents,\nLes diplômes nationaux d’ingénieurs tels que définis par les textes en vigueur ou les diplômes équivalents\nLe concours d’entrée au cyclke supérieur est ouvert chaque année par arrêté du Premier Ministre qui comprend notamment :\nLes diplômes, et le cas échéant les spécialités requise\nLe nombre de postes ouvertes et le cas échéant leur répartition selon les domaines de spécialité des candidats\nLes épreuves\nLe concours d’entrée au cycle supérieur de l’école nationale d’administration comporte les épreuves suivantes : trois épreuves écrites d’admissibilité, une épreuve orale d’admission définitive. Les épreuves écrites d’admissibilité une épreuve de spécialité portant, au choix du candidat, sur un ou plusieurs sujets à caractère juridique ou économique et de gestion. une épreuve de culture générale sous forme d’une dissertation sur les questions politiques, économiques, sociales ou culturelles du monde contemporain, une épreuve de langue anglaise.\nLe concours d’entrée au cycle supérieur de l’école nationale d’administration comporte les épreuves suivantes :\ntrois épreuves écrites d’admissibilité,\nune épreuve orale d’admission définitive.\nLes épreuves écrites d’admissibilité\nune épreuve de spécialité portant, au choix du candidat, sur un ou plusieurs sujets à caractère juridique ou économique et de gestion.\nune épreuve de culture générale sous forme d’une dissertation sur les questions politiques, économiques, sociales ou culturelles du monde contemporain,\nune épreuve de langue anglaise.\nDéclaration d’admissibilité\nSauf dispositions contraires inhérentes aux spécificités de chaque concours, les épreuves écrites sont soumises à une double correction. La note définitive est égale à la moyenne arithmétique des deux notes attribuées, lorsque l’écart entre ces deux notes est supérieur à trois (3) points, l’épreuve sera soumise à l’appréciation d’un troisième correcteur. Dans ce cas, la note définitive est calculée sur la base de la moyenne arithmétique des trois (3) notes.\nToute note inférieure à (7) sur vingt est éliminatoire,\nAucun candidat ne peut être déclaré admissible s’il n’a obtenu aux épreuves écrites au moins une moyenne égale à dix (10) sur vingt (20).\nL’épreuve orale d’admission définitive\nCette épreuve consiste en un exposé suivi d’une discussion avec les membres du jury du concours sur un sujet à caractère général relatif à l’organisation politique de la Tunisie ou à la politique générale dans les domaines économique, social, culturel, administratif, ou touchant les questions relatives aux organisations et relations internationales.\nL’épreuve orale d’admission définitive comprend un exposé de dix (10) minutes suivi d’une discussion avec les membres de jury de vingt (20) minutes après une préparation de trente (30) minutes.\nAucun candidat ne peut être admis définitivement s’il n’a obtenu une moyenne égale à dix (10) sur vingt (20) au moins dans les épreuves d’admissibilité et d’admission.\nLorsque plusieurs candidats obtiennent la même moyenne, la priorité est accordée au plus âgé d’entre eux.\nLes épreuves et les coefficients\nLa durée et les coefficients des épreuves sont fixés comme suit :\nNature de l’épreuve\nCoefficient\nI – Les épreuves écrites d’admissibilité\nI – Les épreuves écrites d’admissibilité\n1-Epreuve de spécialité\n1-Epreuve de spécialité\n2-Epreuve de culture générale\n2-Epreuve de culture générale\n3- Epreuve de langue anglaise\n3- Epreuve de langue anglaise\nII- L’épreuve d’admission définitive\nII- L’épreuve d’admission définitive\n– L’épreuve orale\n– L’épreuve orale\nProgramme de l’épreuve de spécialité\nEconomie et gestion\nRemarque:\nL’indication (I) concerne les axes et les thèmes sur lesquels porte l’épreuve de spécialité destinée aux candidats titulaires du diplôme d’ingénieur ayant choisi l’option «économie et gestion». Les candidats autres que les titulaires du diplôme d’ingénieur sont concernés par l’ensemble des axes et des thèmes de cette option.\nPopulation et population active (I)\nStructure et croissance du PIB (I)\nLes indices de prix (I)\nAgrégats de la comptabilité nationale (I)\nBudget de l’Etat (I)\nRessources et emplois du système financier.\nLes diverses approches de l’entreprise (I)\nL’organisation de l’entreprise (I)\nCombinaisons productives et la fonction de production (I)\nFormation des prix et les différentes formes de concurrence (I)\nChoix d’investissement et de financement\nLes stratégies de l’entreprise.\nLes revenus des ménages\nLa consommation et l’épargne des ménages (I)\nLa demande d’un bien (I)\nLe rôle des anticipations.\nLes cycles économiques\nLa croissance équilibrée\nLa croissance endogène\nLe développement durable. (I)\nLes fonctions de la monnaie (I)\nL’offre et la demande de monnaie (I)\nLa masse monétaire (I)\nLes taux d’intérêt (I)\nLe système financier (institutions financières et marché des capitaux)\nLe financement de l’économie\nLa balance des paiements et les mouvements de capitaux (I)\nLa mondialisation (aspects financiers).\nFondements de l’économie internationale (I)\nLa balance des biens et des services (I)\nLes termes de l’échange (I)\nLes zones de libre échange\nLa mondialisation (aspects économiques).\nLes biens et services publics (I)\nLes effets externes (I)\nLa politique budgétaire et fiscale (I)\nLa politique monétaire\nLa politique de l’emploi\nLa politique industrielle\nLa politique de la concurrence\nL’intégration économique.\nLa probabilité conditionnelle et la règle de Bayes\nLes variables aléatoires: loi de probabilité d’une variable aléatoire\nLes moments d’une variable aléatoire: espérance mathématique, variance, écart-type\nLois de variables discrètes: loi de Bernoulli, loi binomiale, loi de Poisson\nLois de variables continues: loi normale, loi de Student-Fisher, loi c2 (chi-carré)\nEstimateur sans biais, convergent\nMéthode de maximum de vraisemblance\nAjustement d’une distribution observée à une distribution théorique (test du c2)\nAnalyse statistique de la liaison entre plusieurs variables (régression et corrélation).\nRemarque:\n* L’indication (I) concerne les axes et les thèmes sur lesquels porte l’épreuve de spécialité destinée aux candidats titulaires du diplôme d’ingénieur ayant choisi l’option «droit». Les candidats autres que les titulaires du diplôme d’ingénieur sont concernés par l’ensemble des axes et des thèmes de cette option.\nLes sources du droit constitutionnel (I)\nL’Etat (éléments constitutifs et formes) (I)\nLe principe de la séparation des pouvoirs (I)\nLes régimes politiques (I)\nLes partis politiques et les institutions de la société civile\nLes modes de scrutin\nLe contrôle de constitutionnalité\nLes droits fondamentaux et les libertés publiques (I)\nLes sources du droit administratif (I)\nL’organisation administrative (l’administration centrale, l’administration déconcentrée, les collectivités locales) (I)\nLe service public (notion, catégorie, principes fondamentaux, modes de gestion)\nLes actes administratifs (l’acte administratif unilatéral, le contrat administratif)\nLa police administrative\nLes principes généraux du budget de l’Etat (principes budgétaires, comptables et fiscaux) (I)\nLes lois de finances (I)\nL’élaboration et le vote du budget de l’Etat (I)\nL’exécution du budget de l’Etat\nLes fonds budgétaires\nLe contrôle des finances publiques (typologie, organes et modalités).\nLes sources du droit fiscal (I)\nLes fonction de la fiscalité (I)\nLa typologie des impôts (I)\nL’administration fiscale\nLe recouvrement des impôts\nLes domaines public et privé des personnes publiques (notion, régimes juridiques de délimitation, d’incorporation, d’utilisation et de protection)\nL’expropriation (finalités et procédure)\nLe contentieux de l’expropriation\nLes travaux publics (notion, exécution, dommages)\nL’organisation de la justice administrative et la répartition du contentieux de l’administration\nLes sources du contentieux administratif\nLes différents recours et mesures d’urgence\nLes règles de procédure juridictionnelles (introduction et déroulement de l’instance, le prononcé de la décision).\nLes grands principes juridiques des relations internationales\nLes Etats (souveraineté, égalité, indépendance, compétences)\nLes organisations internationales (L’ONU et les institutions spécialisées, les organisations régionales et spéciales)\nLes traités internationaux, régionaux et bilatéraux\nLe contentieux international (juridictions internationales, modes de règlement des différents internationaux).\nL’Ecole Nationale d’Administration est un établissement public à caractère administratif placé sous la tutelle de la présidence du gouvernement et dont le budget est rattaché pour ordre au budget de l’Etat.\nLiens rapides\nPlatforme E-Learning\nBibliothéque en Ligne\nConcours en Ligne\nFAD en Ligne\n24, Avenue Docteur Calmette\nMutuelleville 1082 Tunis\nTél: 71 848 300 Fax: 71 794 188\nEmail : info@ena.tn\nSite Web : www.ena.tn\nActualités\nServices en Ligne\nPlan du site\nReset Password",
|
| 8 |
+
"chars": 9324
|
| 9 |
+
},
|
| 10 |
+
{
|
| 11 |
+
"page_name": "concours_general",
|
| 12 |
+
"url": "https://www.ena.tn/fr/concours/informations-generales/",
|
| 13 |
+
"source": "ena.tn",
|
| 14 |
+
"langue": "fr",
|
| 15 |
+
"content": "Informations générales\nInformations générales\nRéférences juridiques\nLe décret n° 2004-78 du 14 janvier 2004 relatif aux concours d'entrée aux cycles de formation à l'école nationale d'administration tel qu'il a été modifié et complété par le décret n°2007-1938 du 30 juillet 2007 et le décret n°2010-3465 du 28 décembre 2010\nL'arrêté du premier ministre du 07 août 2007 fixant les épreuves des concours d'entrée aux cycles de formation à l'école nationale d'administration\nL'arrêté du premier ministre du 07 août 2007 fixant les diplômes nationaux requis pour les concours d'entrée aux cycles de formation à l'école nationale d'administration tel qu'il a été modifié par l'arrêté du premier ministre du 01 mars 2010\nInformations générales\nL’entrée aux différents cycles de formation dispensés par l’Ecole se fait par voie de concours sur épreuves. L’Ecole organise annuellement trois (03) concours pour l’entrée :\nau cycle supérieur\nau cycle de formation des cadres moyens de la sous-catégorie \"A2\"\nau cycle de formation des agents de la sous-catégorie\" A3\"\nLes informations générales qui se rapportent à l’ouverture du concours , à l’âge de candidature requis et aux pièces du dossier de candidature sont :\n1- Ouverture des concours\nChaque concours est ouvert par arrêté du Président du Gouvernement. Cet arrêté comprend notamment:\nle grade ou l’ensemble des grades équivalents objet du concours\nles diplômes et le cas échéant les spécialités requises\nune épreuve de sciences économique et de gestion\nle nombre de postes mis en concours et le cas échéant, leur répartition selon les domaines de formation des candidats\nla date de clôture de la liste des candidatures\nla date de déroulement de l’épreuve ou des épreuves d’admissibilité\nl’adresse électronique pour s’inscrire à distance et le lieu de dépôt des dossiers de candidature et l’adresse administrative de l’école nationale d’administration pour l’envoi des dossiers par voie recommandée avec accusé de réception\nL’examen oral a lieu devant un jury dont les membres sont désignés par décision du directeur de l’école.\nL’âge maximum des candidats titulaires des diplômes de l’enseignement supérieur est fixé à trente cinq (35) ans au plus au 1er janvier de l’année de l’ouverture du concours.\nAu cas où le candidat dépasse l’âge maximum, de par les textes en vigueur, il est octroyé une dérogation à la participation aux concours d’entrée aux cycles de formation à l’ENA comme suit :\nL’âge maximum est apprécié à compter de l’année d’inscription du candidat sous-réserve de son actualisation dans un bureau de l’emploi et du travail indépendant à titre de demandeur d’emploi ou d’un stage d’initiation à la vie professionnelle; et ce pour tous les concours qui seront ouverts durant les cinq (5) années qui suivent cette inscription.\nEst défalqué de l’âge du candidat la durée d’exercice du service civil effectif égale à celle effectuée dans les administrations publiques ou les collectivités locales ou les établissements publics à caractère non administratif, en qualité d’agents stagiaires, titulaires, temporaires ou contractuels.\nDans ces deux cas , le candidat dépassant l’âge de trente cinq (35) ans doit présenter une pièce administrative officielle attestant le droit à la candidature : un relevé de service actualisé et daté conformément aux textes en vigueur ou une attestation d’inscription dans un bureau de l’emploi et du travail indépendant actualisé et daté conformément aux textes en vigueur.\nL’Ecole Nationale d’Administration est un établissement public à caractère administratif placé sous la tutelle de la présidence du gouvernement et dont le budget est rattaché pour ordre au budget de l’Etat.\nLiens rapides\nPlatforme E-Learning\nBibliothéque en Ligne\nConcours en Ligne\nFAD en Ligne\n24, Avenue Docteur Calmette\nMutuelleville 1082 Tunis\nTél: 71 848 300 Fax: 71 794 188\nEmail : info@ena.tn\nSite Web : www.ena.tn\nActualités\nServices en Ligne\nPlan du site\nReset Password",
|
| 16 |
+
"chars": 3947
|
| 17 |
+
},
|
| 18 |
+
{
|
| 19 |
+
"page_name": "concours_preparation",
|
| 20 |
+
"url": "https://www.ena.tn/fr/concours/cycle-superieur/preparation-au-concours/",
|
| 21 |
+
"source": "ena.tn",
|
| 22 |
+
"langue": "fr",
|
| 23 |
+
"content": "Préparation au concours – Ecole Nationale d'Administration\nPréparation au concours\nCycle Supérieur\nSupports pédagogiques destinés aux ingénieurs\nEconomie et gestion\nAxe 1: Données de base de l’économie tunisienne\nAxe 2: L’entreprise\nAxe 3: Les ménages\nAxe 4: Fluctuations et croissance\nAxe 5: Monnaie et financement\nAxe 6: Les échanges extérieurs\nAxe 7: Politique Economique\nAxe 8: Statistiques\nAxe 1: Droit constitutionnel et institutions politiques\nAxe 2: Droit administratif et institutions administratives\nAxe 3: Finances publiques\nAxe 4: Droit fiscal\nÉpreuves des sessions précédentes\nEconomie (Ingénieurs)\nDroit (Ingénieurs)\nCulture générale\nL’Ecole Nationale d’Administration est un établissement public à caractère administratif placé sous la tutelle de la présidence du gouvernement et dont le budget est rattaché pour ordre au budget de l’Etat.\nLiens rapides\nPlatforme E-Learning\nBibliothéque en Ligne\nFAD en Ligne\n24, Avenue Docteur Calmette\nMutuelleville 1082 Tunis\nTél: 71 848 300\nFax: 71 794 188\nEmail : info@ena.tn\nSite Web : www.ena.tn\nServices en Ligne\nPlan du site\nReset Password\nDon't have an account\nAlready have an account?",
|
| 24 |
+
"chars": 1144
|
| 25 |
+
},
|
| 26 |
+
{
|
| 27 |
+
"page_name": "concours_a2",
|
| 28 |
+
"url": "https://www.ena.tn/fr/concours/cycle-moyen/concours-dentree-au-cycle-de-formation-des-cadres-moyens-de-la-sous-categorie-a2-2/",
|
| 29 |
+
"source": "ena.tn",
|
| 30 |
+
"langue": "fr",
|
| 31 |
+
"content": "Cycle moyen\nLes diplômes requis\nLes diplômes nationaux de maîtrise ou de licence à caractère économique ou de gestion, tels que définis par les textes en vigueur ou les diplômes équivalents\nLes diplômes nationaux de maîtrise ou de license à caractère juridique ou politique, tels que définis par les textes en vigueur ou les diplômes équivalents\nLes épreuves\nLe concours d’entrée au cycle de formation des cadres moyens de la sous-catégorie « A2 » comporte les épreuves suivantes :\nune épreuve d’admissibilité selon la technique des questions à choix multiples;\nune épreuve écrite et une épreuve orale d’admission définitive.\nL’épreuve d’admissibilité selon la technique des questions à choix multiples.\nEpreuve de spécialité portant, au choix du candidat, sur un ou plusieurs sujets à caractère juridique ou économique et de gestion. Cette épreuve comporte cinquante (50) questions. La réponse à ces questions consiste à choisir une ou plusieurs des réponses exactes parmi les réponses proposées.\nAucun candidat ne peut être déclaré admissible s’il n’a obtenu un score égal ou supérieur à quatre vingt pour cent (80%) des réponses exactes .Le jury du concours peut, le cas échéant, procéder à la réduction de ce score dans la limite de soixante pour cent (60%) des réponses exactes.\nL’épreuve écrite et l’épreuve orale d’admission définitive\nL’épreuve écrite\n: Cette épreuve porte sur la culture générale sous forme d’une dissertation sur les questions politiques, économiques, sociales ou culturelles du monde contemporain.\nSauf dispositions contraires inhérentes aux spécificités de chaque concours, les épreuves écrites sont soumises à une double correction. La note définitive est égale à la moyenne arithmétique des deux notes attribuées. Lorsque l’écart entre ces deux notes est supérieur à trois (3) points, l’épreuve sera soumise à l’appréciation d’un troisième correcteur. Dans ce cas, la note définitive est calculée sur la base de la moyenne arithmétique des trois (3) notes.\nL’épreuve orale\n: Cette épreuve consiste en un exposé suivi d’une discussion avec les membres du jury du concours sur un sujet d’ordre général relatif à l’organisation politique de la Tunisie ou se rapportant à sa politique générale dans les domaines économique, social, culturel, administratif ou touchant les questions relatives aux organisations et relations internationales.\nDéclaration d’admissibilité\nToute note inférieure à (7) sur vingt est éliminatoire.\nAucun candidat ne peut être admis définitivement s’il n’a obtenu une moyenne égale à dix (10) sur vingt (20) au moins.\nLorsque plusieurs candidats obtiennent la même moyenne, la priorité est accordée au plus âgé d’entre eux.\nLes épreuves et les coefficients\nLa durée et les coefficients des épreuves sont fixés comme suit :\nNature de l’épreuve\nCoefficient\nI – L’épreuve d’admissibilité\n– Epreuve de spécialité selon la technique des questions à choix multiples.\nII-Les épreuves d’admission définitive\n– Epreuve écrite de culture générale\n– Epreuve orale\nProgramme de l’épreuve de spécialité\nEconomie et gestion\nAxe 1: Données de base de l’économie tunisienne\nPopulation et population active\nStructure et croissance du PIB\nLes indices de prix\nAgrégats de la comptabilité nationale\nBudget de l’Etat\nRessources et emplois du système financier.\nAxe 2: L’entreprise\nLes diverses approches de l’entreprise\nL’organisation de l’entreprise\nCombinaisons productives et la fonction de production\nFormation des prix et les différentes formes de concurrence\nChoix d’investissement et de financement\nLes stratégies de l’entreprise.\nAxes 3: Croissance et développement\nLa croissance équilibrée\nLa croissance endogène\nLe développement durable.\nAxe 4: Monnaie et financement\nLes fonctions de la monnaie\nL’offre et la demande de monnaie\nLa masse monétaire\nLe système financier (institutions financières et marché des capitaux)\nLe financement de l’économie\nLa balance des paiements et les mouvements de capitaux.\nAxe 5: Les échanges extérieurs\nFondements de l’économie internationale\nLa balance des biens et des services\nLes termes de l’échange\nLes zones de libre échange.\nAxe 6: Politique économique\nLes biens et services publics\nLes effets externes\nLa politique budgétaire et fiscale\nLa politique monétaire.\nAxe 1: Droit constitutionnel et institutions politiques\nLes sources du droit constitutionnel\nL’Etat (éléments constitutifs et formes)\nLe principe de la séparation des pouvoirs\nLes régimes politiques\nLes partis politiques et les institutions de la société civile\nLe contrôle de constitutionnalité\nLes libertés publiques et les droits fondamentaux.\nAxe 2: Droit administratif et institutions administratives\nLes sources du droit administratif\nL’organisation administrative (l’administration centrale, l’administration déconcentrée, les collectivités locales)\nLe service public (notion, catégorie, principes fondamentaux, modes de gestion)\nLes actes administratifs (l’acte administratif unilatéral, le contrat administratif).\nAxe 3: Finances publiques\nLes principes généraux du budget de l’Etat (principes budgétaires, comptables et fiscaux)\nLes lois de finances\nL’élaboration et le vote du budget de l’Etat.*\nAxe 4: Droit fiscal\nLes sources du droit fiscal (les conventions internationales, la constitution, la loi…)\nLes fonctions de la fiscalité\nLa typologie des impôts.\nL’administration fiscale\nAxe 5: Droit administratif des biens\nLes domaines public et privé des personnes publiques (notion et consistance, régimes juridiques de délimitation, d’incorporation, d’utilisation et de protection)\nL’expropriation (finalités, acteurs, objet, procédure)\nLe contentieux de l’expropriation\nTravaux publics (notion, exécution, dommages)\nAxe 6: Contentieux administratif\nL’organisation de la justice administrative et la répartition du contentieux de l’administration\nLes sources du contentieux administratif\nLes différents recours et mesures d’urgence\nLes règles de procédure juridictionnelles (introduction et déroulement de l’instance, le prononcé de la décision).\nAxe 7: Relations internationales\nLes grands principes juridiques des relations internationales\nLes Etats (souveraineté, égalité, indépendance, compétences)\nLes organisations internationales (L’ONU et les institutions spécialisées, les organisations régionales et spéciales)\nLes traités internationaux, régionaux et bilatéraux\nLe contentieux international (juridictions internationales, modes de règlement des différents internationaux).\nL’Ecole Nationale d’Administration est un établissement public à caractère administratif placé sous la tutelle de la présidence du gouvernement et dont le budget est rattaché pour ordre au budget de l’Etat.\nLiens rapides\nPlatforme E-Learning\nBibliothéque en Ligne\nFAD en Ligne\n24, Avenue Docteur Calmette\nMutuelleville 1082 Tunis\nTél: 71 848 300\nFax: 71 794 188\nEmail : info@ena.tn\nSite Web : www.ena.tn\nServices en Ligne\nPlan du site\nReset Password\nDon't have an account\nAlready have an account?",
|
| 32 |
+
"chars": 6934
|
| 33 |
+
},
|
| 34 |
+
{
|
| 35 |
+
"page_name": "concours_a2_prep",
|
| 36 |
+
"url": "https://www.ena.tn/fr/concours/cycle-moyen/preparation-au-concours/",
|
| 37 |
+
"source": "ena.tn",
|
| 38 |
+
"langue": "fr",
|
| 39 |
+
"content": "Préparation au concours – Ecole Nationale d'Administration\nPréparation au concours\nCycle moyen\nÉpreuves des sessions précédentes\nCulture générale\nL’Ecole Nationale d’Administration est un établissement public à caractère administratif placé sous la tutelle de la présidence du gouvernement et dont le budget est rattaché pour ordre au budget de l’Etat.\nLiens rapides\nPlatforme E-Learning\nBibliothéque en Ligne\nFAD en Ligne\n24, Avenue Docteur Calmette\nMutuelleville 1082 Tunis\nTél: 71 848 300\nFax: 71 794 188\nEmail : info@ena.tn\nSite Web : www.ena.tn\nServices en Ligne\nPlan du site\nReset Password\nDon't have an account\nAlready have an account?",
|
| 40 |
+
"chars": 642
|
| 41 |
+
},
|
| 42 |
+
{
|
| 43 |
+
"page_name": "concours_a3",
|
| 44 |
+
"url": "https://www.ena.tn/fr/concours/agents-de-la-sous-categorie-a3/",
|
| 45 |
+
"source": "ena.tn",
|
| 46 |
+
"langue": "fr",
|
| 47 |
+
"content": "Agents de la sous catégorie A3 – Ecole Nationale d'Administration\nAgents de la sous catégorie A3\nLes diplômes requis\nLes diplômes nationaux du premier cycle de l’enseignement supérieur, tels que définis par les textes en vigueur et quelle qu’en soit la spécialité ou les diplômes équivalents.\nLes épreuves\nLe concours d’entrée au cycle de formation des agents de la sous-catégorie » A3″ comporte les deux épreuves suivantes :\nune épreuve d’admissibilité selon la technique des questions à choix multiples\nune épreuve orale d’admission définitive.\nL’épreuve d’admissibilité selon la technique des questions à choix multiples.\nCette épreuve porte sur la culture générale sur les questions politiques, économiques, sociales ou culturelles de la Tunisie, et du monde contemporain.\nCette épreuve comporte cinquante (50) questions. La réponse à ces questions consiste à choisir une ou plusieurs des réponses exactes parmi les réponses proposées.\nL’épreuve orale d’admission définitive\nCette épreuve consiste en un exposé suivi d’une discussion avec les membres du jury du concours sur un sujet à caractère général relatif aux domaines économique, social, culturel, ou administratif.\nLes épreuves et les coefficients\nLa durée et les coefficients des épreuves sont fixés comme suit :\nNature de l’épreuve\nCoefficient\nI- L’épreuve d’admissibilité\n– Epreuve de culture générale selon la technique des questions à choix multiples\nII- L’épreuve d’admission définitive\n– Epreuve orale\nL’Ecole Nationale d’Administration est un établissement public à caractère administratif placé sous la tutelle de la présidence du gouvernement et dont le budget est rattaché pour ordre au budget de l’Etat.\nLiens rapides\nPlatforme E-Learning\nBibliothéque en Ligne\nFAD en Ligne\n24, Avenue Docteur Calmette\nMutuelleville 1082 Tunis\nTél: 71 848 300\nFax: 71 794 188\nEmail : info@ena.tn\nSite Web : www.ena.tn\nServices en Ligne\nPlan du site\nReset Password\nDon't have an account\nAlready have an account?",
|
| 48 |
+
"chars": 1967
|
| 49 |
+
},
|
| 50 |
+
{
|
| 51 |
+
"page_name": "formation_superieur",
|
| 52 |
+
"url": "https://www.ena.tn/fr/formation-de-base/cycle-superieur/",
|
| 53 |
+
"source": "ena.tn",
|
| 54 |
+
"langue": "fr",
|
| 55 |
+
"content": "Cycle Supérieur – Ecole Nationale d'Administration\nCycle Supérieur\nFormation de base\nLes textes juridiques\nDécret n°2004-79 du 14 janvier 2004 relatif aux cycles de formation à l’école nationale d’administration ensemble les textes qui l’ont modifié ou complété et notamment le décret n°2007-1939 du 30 juillet 2007\nArrêté du Premier Ministre du 11 mars 2008 fixant le régime des études au cycle supérieur de l’école nationale d’administration tel qu’il est modifié par l’arrêté du président du gouvernement du 12 octobre 2012\nL’accès au cycle supérieur\nL’accès au cycle supérieur se fait par voie de concours ouvert aux candidats titulaires du diplôme national de mastère à caractère économique ou de gestion et à caractère juridique ou politique et aussi aux candidats titulaires du diplôme national d’ingénieurs dans certaines spécialités fixées par arrêté du président du gouvernement portant ouverture du concours.\nGuide Pédagogique\nStatistiques des sortants du cycle supérieur\nLa formation des cadres supérieurs chargés des fonctions de conception, d’encadrement, d’animation et de contrôle; appelés à exercer des fonctions administratives dans le grade de conseiller des services publics ou autres grades équivalents de la sous catégorie A1 prévus par les statuts particuliers, dans les services de l’Etat, des établissements publics à caractère administratif et des collectivités locales\nL’acquisition des qualifications professionnelles facilitant l’exercice des hautes fonctions dans les administrations et les établissements publics\nLe renforcement de la qualité des ressources humaines dans le domaine d’encadrement et de gestion selon les objectifs de la politique de l’Etat.\nDurée de la formation\nLa formation au cycle supérieur de l’école nationale d’administration dure (30) mois consécutifs répartis en trois périodes.\nLa durée de formation est répartie comme suit :\nLa première période\ndure douze (12) mois dont un (1) mois au titre de congé annuel, et trois (3) mois au plus pour effectuer un stage. La période restante est consacrée aux études et aux examens\nLa deuxième période\ndure douze (12) mois dont un (1) mois au titre de congé annuel, et trois (3) mois au plus pour effectuer un stage. La période restante est consacrée aux études et aux examen\nLa troisième période\ndure six (6) mois, dont deux (2) mois au moins pour effectuer un stage. La période restante est consacrée aux examens de fin du cycle, à la préparation et à la soutenance des mémoires de stage et de fin d’études\nRégime des études\nLe cadre enseignant\nLes différentes missions de formation sont assurées par universitaires, des hauts cadres et des experts des secteurs publics et privé.\nLes programmes des études\nPremière période\nLes études en première période comportent des unités de formation générales regroupées autour des axes fondamentaux suivants :\nsciences juridiques et politiques;\nsciences économiques et de gestion;\ngestion publique;\nunités supplémentaires.\nLes unités de formation générales visent :\nL’approfondissement des connaissances de base qui sont en étroite relation avec le travail administratif et notamment dans les domaines juridiques, économiques et de gestion,\nLa maîtrise des sciences et techniques administratives fondamentales, des langues vivantes et de l’informatique,\nL’initiation au travail administratif et l’acquisition des qualifications professionnelles facilitant l’intégration directe des élèves sortants du cycle dans la vie active.\nDeuxième période\nLes études en deuxième période comportent des unités spécifiques regroupées autour des axes fondamentaux suivants:\nLes unités de formation spécifiques sont en rapport avec la nature des attributions dévolues aux sortants du cycle supérieur et visent directement la préparation à l’exercice des fonctions requises par les emplois administratifs relatifs au grade de conseillers des services publics ou aux grades équivalents régis par d’autres statuts particuliers.\nDes unités de formation spécifiques peuvent être organisées, dans la limite des domaines de formation suivants:\nl’administration générale qui comprend en particulier les fonctions d’administration, de gestion et de représentation à l’étranger;\nl’administration économique et financière qui englobe les différentes fonctions relatives à la participation, à l’élaboration des stratégies de développement et des politiques y afférentes ainsi qu’à l’identification des voies et moyens du suivi de leur exécution, aux fonctions administratives et financières et à la maîtrise des techniques modernes applicables en ce domaine;\nl’administration régionale et locale et les services extérieurs qui comprend notamment les fonctions d’encadrement, de conception et de direction visant le renforcement de la déconcentration et de la décentralisation;\nles fonctions de contrôle d’inspection et de juridiction dans les domaines administratifs et financiers et des instances administratives à vocation juridictionnelle ou organisationnelle dans les différents domaines et activités.\nLes élèves sont orientés vers les domaines de formation visés ci-dessus, au début de la deuxième période sur la base des résultats globaux obtenus pendant la première période de formation et le cas échéant selon leurs domaines de formation universitaire.\nLes élèves sont avisés quinze (15) jours au moins avant la date arrêtée pour l’orientation, du nombre de postes offerts pour chaque domaine de formation, tout en signalant que le nombre d’élèves, ne peut être inférieur à dix (10).\nLe programme des études au cycle supérieur peut comporter des visites aux institutions administratives spécialisées, aux établissements et entreprises publics ou privés…ainsi que l’organisation des conférences ou des séminaires scientifiques ou des colloques de courte durée sur des sujets en rapport avec le programme de formation.\nLa direction de l’école organise dans le cadre de la chaire des études administratives des conférences données par des personnalités qualifiées, tunisiennes ou étrangères, sur des questions importantes à caractère prospectif ou stratégique.\nLa présence aux enseignements, aux stages organisés dans le cadre du cycle de formation y compris les colloques, les séminaires et les autres activités de formation est obligatoire.\nLe régime d’évaluation\nLes composantes de l’évaluation annuelle\nL’évaluation des élèves au cours de la première et de la deuxième période est composée des éléments suivants :\nContrôle continu\nExamen de fin de période\n– Epreuves écrites\n– Epreuve orale\n– Mémoire de stage\n– Soutenance\nAssiduité et comportement\n– Assisuité\n– Comportement\nLe contrôle continu désigne un système d’évaluation et de suivi du degré d’assimilation du contenu de la formation sur la base d’examens impromptus, de travaux à réaliser ou de dossiers à établir sur des sujets en rapport avec le programme des études.\nLe contrôle continu peut prendre la forme d’épreuves écrites ou d’interrogations orales ou les deux à la fois.\nL’examen de fin de première et deuxième périodes :\nL’examen de fin de première et deuxième périodes comporte des épreuves écrites et une épreuve orale portant sur les unités de formation prévues au programme des études.\nLes épreuves écrites portent sur :\ncinq (05) unités de formation fixées par décision du directeur de l’école à raison d’une unité au moins par axe de formation et réparties sur les sciences juridiques et politiques, les sciences économiques et de gestion ainsi que la gestion publique;\nune épreuve de langue anglaise\nLes copies des épreuves écrites sont soumises à une double correction à l’exception de la langue anglaise qui est soumise à une seule correction.\nLorsque l’écart entre les notes attribuées par les deux correcteurs est supérieur à trois (3) points, la copie d’examen est soumise à un troisième correcteur/ Dans ce cas, la note définitive est calculée sur la base de la moyenne arithmétique des trois (03) notes attribuées.\nL’examen oral\nL’examen porte sur un nombre déterminé d’unités de formation et sur les questions traitées dans le cadre de la chaire des études administratives ou les autres activités de formation.\nL’élève procède au tirage au sort d’un sujet. Au cas où il décide de tirer un deuxième sujet, il ne lui sera attribué que la moitié de la note qu’il mérité.\nChaque élève dispose d’un temps de préparation de trente (30) minutes avant son passage devant le jury.\nL’examen oral a lieu devant un jury dont les membres sont désignés par décision du directeur de l’école.\nL’école accorde une grande importance à l’assiduité et au comportement des élèves tout au long de la période de formation.\nA cet effet, le directeur de l’école attribue à chaque élève une note au titre de l’assiduité et de la conduite sur la base d’éléments d’évaluation fixés par décision du directeur de l’école.\nEvaluation des résultats de fin de période\nLes résultats de fin de période sont proclamés par un jury dont les membres sont désignés par décision du directeur de l’école.\nTout élève ne peut passer de la première à la deuxième période s’il n’a obtenu une moyenne annuelle égale au moins à onze (11) sur vingt (20).\nLes élèves qui n’ont pas obtenu la moyenne requise en première période sont exclus.\nLes élèves qui n’ont pas obtenu la moyenne requise en deuxième période de formation à une nomination dans l’un des services administratifs dans le grade d’administrateur conseiller ou dans un grade équivalent.\nTout élève ne peut participer aux examens de sortie organisés au cours de la troisième période s’il n’a pas obtenu en deuxième période une moyenne annuelle égale au moins à 11 sur 20.\nL’examen de fin de scolarité\nL’examen de fin de scolarité comporte trois (3) épreuves écrites et une épeurve orale portant sur les unités de formation du programme d’études de la première et de la deuxième période de formation.\nLes épreuves écrites consistent en :\nune épreuve de sciences juridiques et politiques\nune épreuve de gestion publique\nune épreuve de sciences économique et de gestion\nL’examen oral a lieu devant un jury dont les membres sont désignés par décision du directeur de l’école.\nMémoire de fin d’études\nDurant la deuxième période de formation, les élèves préparent le mémoire de fin d’études à charge de le présenter au cours de la troisième période de formation.\nLe directeur de l’école choisit pour chaque élève le sujet du mémoire de fin d’études revêtant un caractère pratique parmi les sujets proposés par l’élève ou un autre sujet fixé par le directeur de l’école.\nUn encadreur chargé de l’orienter durant la préparation du mémoire.\nChaque élève soutient son mémoire de fin d’études devant un jury présidé par le directeur de l’école ou son représentant et comprend notamment les deux correcteurs et l’encadreur du mémoire.\nEléments de l’évaluation des résultats finals de sortie\nMoyenne de la première période de formation\nMoyenne de la deuxième période de formation\nStage durant la troisième période de formation\n– Soutenance\nExamen de fin de scolarité\n– Contenu écrit\nUn jury spécial, dont les membres sont désignés par arrêté du Président du gouvernement sur proposition du directeur de l’école nationale d’administration, procède à la proclamation des résultats définitifs de la scolarité au cycle supérieur.\nLe jury propose les élèves ayant obtenu à la fin de leur scolarité une moyenne générale égale ou supérieure à 11 sur 20 à la nomination dans le grade de conseiller des services publics ou grade équivalent.\nL’affectation des sortants aux postes d’emploi offerts s’effectue sur la base de leur choix et compte tenu de leur classement définitif dans leur domaine de formation.\nLe jury peut proposer la nomination des élèves qui n’ont pas obtenu la moyenne requise dans le grade d’administrateur conseiller ou dans un grade équivalent.\nL’école organise au profit des élèves du cycle supérieur trois stages pratiques à raison d’un stage par période d’études auprès des administrations régionales et locales, des entreprises publiques et auprès des institutions à caractère administratif ou financier à l’étranger.\nLes stages se déroulent comme suit :\n1ère période:\nles élèves de la première période effectuent un stage auprès des gouvernorats et des municipalités (chef lieu du gouvernorat).Le dit stage dure trois mois à raison de deux mois auprès du gouvernorat et s’en suit un mois auprès de la municipalité (chef lieu du gouvernorat)\n2ème période:\nce stage se déroule auprès d’entreprises publiques d’une durée de trois mois\n3ème période:\nles élèves sont affectés en stage à l’étranger auprès de structures administratives ou financières, d’organismes régionaux à l’étranger.\nA la fin de chaque stage, l’élève est appelé à préparer un mémoire de stage qui revêt un aspect pratique et porte sur une problématique en rapport avec les spécificités de la région, de l’entreprise ou de la structure à l’��tranger auprès de laquelle il a été affecté pour effectuer son stage. Le dit mémoire sert de base pour l’évaluation du stage.\nL’évaluation du stage s’effectue sur la base d’une note attribuée au titre de l’évaluation du contenu écrit du mémoire et une note au titre de l’évaluation de la soutenance du mémoire de stage en présence de membres de jury désignés par le directeur de l’ENA.\nLe stage représente la moyenne de 25 % lors du calcul de la moyenne générale de la première et deuxième période de la formation à savoir 15% pour la note de l’écrit et 10% pour la note de l’oral.\nQuant au stage de la troisième période, il représente 10% lors du calcul de la moyenne générale de fin de cycle de formation dont 5% pour l’écrit et 5% pour l’oral.\nL’Ecole Nationale d’Administration est un établissement public à caractère administratif placé sous la tutelle de la présidence du gouvernement et dont le budget est rattaché pour ordre au budget de l’Etat.\nLiens rapides\nPlatforme E-Learning\nBibliothéque en Ligne\nFAD en Ligne\n24, Avenue Docteur Calmette\nMutuelleville 1082 Tunis\nTél: 71 848 300\nFax: 71 794 188\nEmail : info@ena.tn\nSite Web : www.ena.tn\nServices en Ligne\nPlan du site\nReset Password\nDon't have an account\nAlready have an account?",
|
| 56 |
+
"chars": 14075
|
| 57 |
+
},
|
| 58 |
+
{
|
| 59 |
+
"page_name": "formation_a2",
|
| 60 |
+
"url": "https://www.ena.tn/fr/formation-de-base/cycle-de-formation-des-cadres-moyens-de-la-sous-categorie-a2/",
|
| 61 |
+
"source": "ena.tn",
|
| 62 |
+
"langue": "fr",
|
| 63 |
+
"content": "Cycle de formation des cadres moyens de la sous catégorie A2 – Ecole Nationale d'Administration\nCycle de formation des cadres moyens de la sous catégorie A2\nFormation de base\nLes textes juridiques\nDécret 2004-79 du 14 janvier 2004 relatif aux cycles de formation à l’école nationale d’administration tel qu’il a été modifié et complété par le décret n° 2007-1939 du 30 juillet 2007\nDécrets et Arrêtés parus dans le JORT en 2004 relatifs aux cycles de formation à l’école nationale d’administration\nObjectis de la formation\nLa formation des cadres moyens de la sous catégorie A2 a pour but la préparation des agents à l’accomplissement des fonctions et tâches assignées à cette sous catégorie de grades administratifs notamment dans les domaines de la gestion administrative et financière dans les services centraux, régionaux ou locaux.\nDurée de la formation\nLa formation des cadres moyens de la sous catégorie A2 dure douze (12) mois répartis comme suit:\n09 mois d’études\nrépartis comme suit :\nun tronc commun d’une durée de six (06) mois au cours desquels les élèves reçoivent une formation de base dans les principaux domaines de l’activité administrative;\nune spécialisation pendant 3 mois dans l’une des filières suivantes :\ngestion des ressources humaines ;\naffaires juridiques et contentieux ;\naffaires financières et marchés publics ;\nadministration régionale et locale et services extérieurs\n03 mois de stage\nL’évaluation\nLa présence des élèves dans différents enseignements et programmes de formation y compris le stage est obligatoire.\nLe directeur de l’école attribue à chaque élève une note comprise entre 0 et 20 relative à l’assiduité et au comportement.\nL’acquisition des connaissances par les élèves est évaluée par le régime du contrôle continu durant la période d’études ; l’examen mi-parcours et l’examen de sortie.\nLe contrôle continu\npeut se faire par tests écrits ou oraux ou les deux à la fois. Le même coefficient est attribué à tous les modules de formation.\nL’examen mi-parcours\ndurant la formation au tronc commun les élèves sont soumis à un examen de mi-parcours. L’examen mi-parcours comprend des épreuves écrites se rapportant aux modules prévus dans les axes fondamentaux de formation en tronc commun.\nL’examen de sortie\nl’examen de sortie comprend six (6) épreuves écrites dont trois (3) épreuves se rapportant aux modules parmi ceux prévus aux axes fondamentaux de la formation en tronc commun et trois (3) épreuves se rapportant aux modules prévus aux programmes de la formation dans les filières de spécialisation.\nLe directeur de l’école choisit les sujets de ces épreuves parmi les sujets proposés par les enseignants et fixe, par décision, la liste des modules sur lesquels portent l’examen mi-parcours et l’examen de sortie.\nLes composantes de l’évaluation globale se répartissent comme suit:\nContrôle continu\nExamen de mi-parcours\nExamen de sortie\nAssiduité et comportement\nLes élèves dudit cycle sont appelés à effectuer un stage pratique d’une durée de trois (03) mois programmé auprès des départements ministériels au niveau central régional et local en adéquation avec la filière de spécialisation à laquelle ils appartiennent.\nChaque élève est tenu de préparer, au terme de sont stage, un rapport d’activités qui sert de base pour l’évaluation de son stage.\nL’évaluation du stage s’effectue sur la base de deux notes : une note attribuée au titre de l’évaluation du contenu écrit du rapport d’activités, cette note représente 15% lors du calcul de la moyenne du stage.\nLe directeur de l’école attribue à chaque élève sur la base des observations émises par le chef de stage une note au titre de l’évaluation de la conduite et de l’assiduité de l’élève durant le stage. Cette note représente 5% lors du calcul de la moyenne du stage.\nL’évaluation du stage représente 20 % lors du calcul de la moyenne générale de fin de formation.\nFin de formation\nLes résultats de fin de formation au cycle sont proclamés par un jury dont les membres sont désignés par arrêté du Premier ministre sur proposition du directeur de l’école nationale d’administration.\nLe jury classe les élèves par ordre de mérite dans chaque spécialisation.\nLes élèves ayant obtenu une moyenne générale égale ou supérieure à dix (10) sur vingt (20) sont proposés pour être nommés dans l’un des grades de la sous-catégorie A2.\nTout élève n’ayant pas obtenu la moyenne requise citée au paragraphe précédent est exclu.\nStatistiques des sortants du Cycle de formation des cadres moyens de la sous-catégorie A2\nL’Ecole Nationale d’Administration est un établissement public à caractère administratif placé sous la tutelle de la présidence du gouvernement et dont le budget est rattaché pour ordre au budget de l’Etat.\nLiens rapides\nPlatforme E-Learning\nBibliothéque en Ligne\nFAD en Ligne\n24, Avenue Docteur Calmette\nMutuelleville 1082 Tunis\nTél: 71 848 300\nFax: 71 794 188\nEmail : info@ena.tn\nSite Web : www.ena.tn\nServices en Ligne\nPlan du site\nReset Password\nDon't have an account\nAlready have an account?",
|
| 64 |
+
"chars": 5012
|
| 65 |
+
},
|
| 66 |
+
{
|
| 67 |
+
"page_name": "formation_a3",
|
| 68 |
+
"url": "https://www.ena.tn/fr/formation-de-base/cycle-de-formation-des-agents-de-la-sous-categorie-a3/",
|
| 69 |
+
"source": "ena.tn",
|
| 70 |
+
"langue": "fr",
|
| 71 |
+
"content": "Cycle de formation des agents de la sous catégorie A3 – Ecole Nationale d'Administration\nCycle de formation des agents de la sous catégorie A3\nFormation de base\nL’Ecole Nationale d’Administration assure la formation des agents appelés à occuper des fonctions administratives de la sous catégorie «A3» dans les administrations centrales, régionales et locales et dans les établissements publics à caractère administratif.\nCette formation s’effectue dans le cadre d’un cycle de formation ayant pour but la préparation des élèves aux tâches et fonctions qui leur seront dévolues et notamment la prise en charge des cellules de secrétariat et l’assistance des cadres administratifs supérieurs et les aider dans l’accomplissement des missions et fonctions qui leur sont assignées.\nDiplômes requis\nLes diplômes requis pour participer au concours d’accès sont ceux du premier cycle de l’enseignement supérieur, tels que définis par les textes en vigueur et quelle qu’en soit la spécialité ou les diplômes équivalents.\nLa durée de formation\nLa formation des agents de la sous catégorie « A3 » dure neuf (9) mois consécutifs, répartis ainsi :\n7 mois : cours pratiques avec des modules à caractère professionnel ayant un lien avec l’organisation de l’administration et des procédures et modes de gestion y afférents\n2 mois : travaux pratiques en rapport avec le programme de formation et les besoins des structures administratives\nL’évaluation\nLes résultats de la formation des élèves sont évalués sur la base :\nLe contrôle continu\nle contrôle continu peut se faire par tests écrits ou tests oraux ou les deux à la fois\nest conférée à la moyenne du contrôle continu 50 % de la moyenne générale\nL’examen de sortie\nl’examen de sortie est composé de 5 épreuves écrites basées chacune sur un module de chaque axe fondamental de formation choisi par le directeur de l’école et fixé par décision\nles élèves sont informés du calendrier de l’examen et de la liste des modules sur lesquels porteront les épreuves écrites, quinze jours au moins avant la date de leur déroulement\nla moyenne de l’examen final est considérée à raison de 20% de la moyenne générale\nLes travaux pratiques d’initiation à la vie professionnelle (stage)\nLe stage représente 20 % lors du calcul de la moyenne générale de fin de cycle de formation.\nAssiduité et comportement\nLa présence des élèves aux différents enseignements et programmes de formation y compris le stage est obligatoire.\nLe directeur de l’école attribut à chaque élève une note comprise entre 0 et 20 relative à l’assiduité et au comportement. Cette note représente 10% de la moyenne générale de sortie.\nMoyenne Générale\nA l’issue de la formation, l’élève ayant obtenu une moyenne générale de sortie égale ou supérieure à 10 sur 20 est nommé au grade d’attaché d’administration ou dans un autre grade équivalent.\nTout élève qui n’a pas obtenu cette moyenne générale est exclu.\nLes composantes de l’évaluation globale se répartissent ainsi :\nContrôle continu\n– Moyenne des tests écrits\n– Moyenne des tests oraux\nExamen de sortie\n– Epreuves écrites\nTravaux pratiques d’initiation à la vie professionnelle\n– Evaluation du rapport\n– Conduite et assiduité\nLes élèves dudit cycle sont appelés à effectuer un stage pratique d’une durée de deux (02) mois d’initiation à la vie professionnelle qui se déroule auprès de structures de l’administration centrale régionale et locale particulièrement auprès de structures chargées de la gestion du personnel, du matériel et des bâtiments et les services financiers ainsi que les bureaux de relations avec le citoyen.\nChaque élève est tenu de présenter au terme de son stage un rapport d’activités servant de base pour l’évaluation dudit stage.\nUne note est attribuée au titre de l’évaluation du contenu écrit du rapport qui représente la moyenne de 15% lors du calcul de la moyenne du stage.\nLe Directeur de l’école attribue à chaque élève, sur la base des observations émises par le chef de stage, une note au titre de l’évaluation de la conduite et de l’assiduité de l’élève durant le stage. Cette note représente 5% lors du calcul de la moyenne du stage.\nL’Ecole Nationale d’Administration est un établissement public à caractère administratif placé sous la tutelle de la présidence du gouvernement et dont le budget est rattaché pour ordre au budget de l’Etat.\nLiens rapides\nPlatforme E-Learning\nBibliothéque en Ligne\nFAD en Ligne\n24, Avenue Docteur Calmette\nMutuelleville 1082 Tunis\nTél: 71 848 300\nFax: 71 794 188\nEmail : info@ena.tn\nSite Web : www.ena.tn\nServices en Ligne\nPlan du site\nReset Password\nDon't have an account\nAlready have an account?",
|
| 72 |
+
"chars": 4620
|
| 73 |
+
},
|
| 74 |
+
{
|
| 75 |
+
"page_name": "formation_continue",
|
| 76 |
+
"url": "https://www.ena.tn/fr/formation-continue/formation-continue-a-distance-et-presentielle/",
|
| 77 |
+
"source": "ena.tn",
|
| 78 |
+
"langue": "fr",
|
| 79 |
+
"content": "Formation continue à distance et présentielle – Ecole Nationale d'Administration\nFormation continue à distance et présentielle\nCadre réglementaire\nConformément au décret n°93-1220 du 7 juin 1993 tel qu’il a été modifié par le décret n° 95-299 du 20 février 1995, portant organisation de la formation continue des fonctionnaires et des ouvriers de l’Etat, des Collectivités publiques locales et des établissements publics à caractère administratif, la formation continue est dispensée dans le cadre de cycles organisés par l’administration au profit des fonctionnaires et ouvriers titulaires en activité.\nL’organisation des cycles de formation continue, leur durée ainsi que la nature des enseignements qui y sont dispensés sont fixés pour chaque grade ou catégorie, par arrêté du ministre concerné.\nDans ce cadre, l’ENA assure l’organisation des cycles indiqués au tableau suivant:\nCycle de formation continue pour la promotion au grade d’administrateur conseiller et grades équivalents\nCycle de formation continue pour la promotion au grade d’administrateur et grades équivalents\nCycle de formation continue pour la promotion au grade d’attaché d’administration et grades équivalents\nGrades administratifs concernés par la promotion\nRéférences réglementaires\nAdministrateur du corps administratif commun\nArrêté du Premier Ministre du 7 juillet 1995\nAdministrateur de la santé publique\nArrêté du Ministre de la Santé Publique du 28 janvier 1998\nInspecteur de la conservation de la propriété foncière\nArrêté du Ministre des Domaines de l’Etat et des Affaires Foncières du 6 novembre 1998\nAdministrateur de la Chambre des Députés\nArrêté du Président de la Chambre des Députés du 22 mars 1994\nAdministrateur de la Greffe de la Cour des Comptes\nArrêté du Président du Gouvernement du 19 Octobre 2012\nAdministrateur des Domaines de l’Etat et des Affaires Foncières\nArrêté du Ministre de la Culture du 08 Février 2013\nSecrétaire Culturel\nArrêté du Ministre des Domaines de l’Etat et des Affaires Foncières\nAttaché du corps administratif commun et attaché de direction\nAttaché de la Santé Publique\nAdministrateur adjoint de la Chambre des Députés\nAttaché d’Inspection de la Conservation de la Propriété Foncière\nAttaché d’administration des affaires étrangères\nArrêté du Ministre des Affaires Etrangères du 11 novembre 1999\nGreffiers Principal de la Cour des Comptes\nAttaché d’Administration des Domaines de l’Etat et des Affaires Foncières\nArrêté du Ministre des Domaines de l’Etat et des Affaires Foncières du 24 Octobre 2013\nSecrétaires Culturels Adjoints\nArrêté du Ministre de la Culture du 8 février 2013\nSecrétaire d’administration du corps administratif commun et secrétaire de direction\nSecrétaire d’administration de la santé publique\nSecrétaire de la Chambre des Députés\nArrêté du Président de la Chambre des Députés du 24 juin 1997\nSecrétaire d’administration des affaires étrangères\nContrôleur de la propriété de la conservation foncière\nGreffiers de la Cour des Comptes\nSecrétaire d’administration des Domaines de l’Etat et des Affaires Foncières\nAttachés Culturels Adjoints\nLe système de la formation continue\nPhase préparatoire à distance\nInscription des nouvelles candidatures aux différents cycles de formation continue\nPour l’accès aux cycles de formation continue préparatoire, les candidats sont tenus de préparer à distance et de valider selon les modalités fixées par les articles 14 et 15 du décret sus visé des unités de valeurs préparatoires (UVP) dont le total des crédits (équivalents à des coefficients) est fixé à 15 (entre 8 et 12 unités) dans la mesure où il est alloué à chacune des unités un crédit égal à un (01) à deux (02) ou à trois (03).\nLa liste complète des unités de valeurs préparatoires ainsi que les crédits qui leur sont alloués sont fixés pour chaque grade ou catégorie par arrêté du ministre concerné. Pour les grades appartenant au cadre administratif commun, ils sont fixés par arrêté du Premier Ministre.\nLa liste des UVP, fixée pour chaque candidat, est établie quant à elle sur la base de :\n75% au moins du total des crédits exigés doit se rapporter à des unités de valeurs choisies par une commission ad hoc dont les membres sont désignés par le Directeur de l’école\nle reste des crédits (25%) concerne des unités de valeurs choisies par le candidat\nLes candidats qui désirent préparer un cycle de formation continue doivent adresser une demande dans ce sens au nom du directeur de l’ENA deux fois par an les dates seront fixées par la Direction de l’ENA.\nLe dossier de candidature doit comprendre les pièces suivantes :\nune demande écrite au nom du directeur de l’ENA ( le candidat peut retirer cette demande sur site de l’ENA)\nune copie de l’attestation de scolarité ou du diplôme obtenu\nune copie de l’arrêté de titularisation\nune copie de l’arrêté du dernier avancement\nun relevé de service signé par le chef de l’administration du candidat\nTrois (03) enveloppes timbrées portant l’adresse du candidat\nInscription aux examens des unités de valeurs\nL’Ecole est tenue d’organiser périodiquement et au moins une fois tous les six(06) mois des sessions de validation des unités de valeurs préparatoires.\nLe candidat doit fournir dans les délais prescrits soit directement aux services compétents de l’école, ou par voie postale, la liste des unités de valeurs préparatoires qu’il entend valider.\nLes frais d’inscription aux examens des UVP sont fixés par arrêté du Premier Ministre du 29 Avril 1995 a raison de quatre (04) dinars pour chaque unité de valeur préparatoire .\nPour des raisons d’organisation et en prenant en considération le nombre des UVP retenus ainsi que celui des inscrits à la session, l’école peut reporter la période des examens à une date ultérieure.\nPendant les examens les candidats sont tenus de respecter le règlement intérieur de l’école; étant signalé que toute fraude ou tentative de fraude entraîne la suspension de l’inscription au régime de la formation continue.\nAucune unité de valeur préparatoire ne peut être considérée comme validée, si le candidat n’a pas obtenu à l’examen une note au moins égale à dix sur vingt (10/20); étant précisé que les copies sont corrigées deux fois. Une troisième correction s’impose en cas utile.\nLa validation des unités de valeurs préparatoires n’a aucune incidence administrative ou pécuniaire sur la situation de l’agent. Elle lui permet, toutefois, de s’inscrire au cycle de formation continue présentielle (phase présentielle à l’Ecole).\nPhase présentielle\nLes cycles de formation continue sont ouverts par arrêté du Premier Ministre, compte tenu du nombre d’agents inscrits ayant validé la totalité des crédits exigés au titre des unités de valeurs préparatoires à distance.\nLe directeur de l’école peut toutefois, pour des raisons de capacité d’accueil décider de reporter certaines inscriptions aux sessions suivantes.\nL’objectif principal de la formation dispensée dans le cadre des cycles de formation continue présentielle est d’initier les candidats aux nouvelles techniques de gestion et de les préparer à assumer les fonctions des l’emplois auxquels ils postulent.\nPendant la durée du cycle pour la formation continue, les candidats sont placés par le chef de l’administration dont ils relèvent en congé pour formation continue.\nDans cette situation, les candidats sont considérés en position d’activité, et continuent à percevoir de la part de leur administration l’intégralité de leur rémunération.\nDurant la période de congé de formation, les agents doivent se conformer aux prescriptions du règlement intérieur de l’école.\nLa durée des cycles de formation continue ne peut être inférieur à :\nsix (6) mois pour les cycles permettant d’accéder aux grades des sous-catégories «A1» et «A2»\nquatre (4) mois pour les cycles permettant d’accéder aux grades de la sous-catégories «A3»\nL’Ecole Nationale d’Administration est un établissement public à caractère administratif placé sous la tutelle de la présidence du gouvernement et dont le budget est rattaché pour ordre au budget de l’Etat.\nLiens rapides\nPlatforme E-Learning\nBibliothéque en Ligne\nFAD en Ligne\n24, Avenue Docteur Calmette\nMutuelleville 1082 Tunis\nTél: 71 848 300\nFax: 71 794 188\nEmail : info@ena.tn\nSite Web : www.ena.tn\nServices en Ligne\nPlan du site\nReset Password\nDon't have an account\nAlready have an account?",
|
| 80 |
+
"chars": 8305
|
| 81 |
+
},
|
| 82 |
+
{
|
| 83 |
+
"page_name": "formation_courte",
|
| 84 |
+
"url": "https://www.ena.tn/fr/formation-continue/sessions-de-formation-de-courte-duree/",
|
| 85 |
+
"source": "ena.tn",
|
| 86 |
+
"langue": "fr",
|
| 87 |
+
"content": "Sessions de formation de courte durée – Ecole Nationale d'Administration\nSessions de formation de courte durée\nL’Ecole organise des sessions de formation de courte durée en management public au profit des cadres et agents des départements ministériels. La formation est asurée conformément à un arrêté du Président du gouvernement et porte sur deux axes:\nle droit et l’administration\nla gestion publique\nL’Ecole fait appel à des universitaires, des experts et des cadres de l’administration pour assurer ces formations.\nSessions (2013-2014)\nBénéficiaires\nCadres du Ministère de l’intérieur\n2 janvier 2014 au 29 janvier 2014\nCadres du Ministère des affaires religieuses\n4 novembre 2013 au 4 décembre 2013\n2 décembre 2013 au 28 décembre 2013\n16 septembre 2013 au 14 octobre 2013\n10 juin 2013 au 10 juillet 2013\n15 avril 2013 au 15 mai 2013\n4 mars 2013 au 5 avril 2013\nCadres du Ministère de la santé publique\n5 janvier 2013 au 19 février 2013\nL’Ecole Nationale d’Administration est un établissement public à caractère administratif placé sous la tutelle de la présidence du gouvernement et dont le budget est rattaché pour ordre au budget de l’Etat.\nLiens rapides\nPlatforme E-Learning\nBibliothéque en Ligne\nFAD en Ligne\n24, Avenue Docteur Calmette\nMutuelleville 1082 Tunis\nTél: 71 848 300\nFax: 71 794 188\nEmail : info@ena.tn\nSite Web : www.ena.tn\nServices en Ligne\nPlan du site\nReset Password\nDon't have an account\nAlready have an account?",
|
| 88 |
+
"chars": 1438
|
| 89 |
+
},
|
| 90 |
+
{
|
| 91 |
+
"page_name": "gouvernance",
|
| 92 |
+
"url": "https://www.ena.tn/fr/gouvernance/lacademie-internationale-de-la-bonne-gouvernance/",
|
| 93 |
+
"source": "ena.tn",
|
| 94 |
+
"langue": "fr",
|
| 95 |
+
"content": "chargée de renforcer et développer les capacités des hauts cadres de l’administration, aux niveaux central, régional et local, ainsi que la promotion de l’échange entre eux. Financée par le gouvernement allemand, c’est la\nDeutsche Gesellschaft für Internationale Zusammenarbeit (GIZ\nqui soutient la mise en œuvre de l’Académie.\nLes textes juridiques portant création de l’Académie\nDécret n°2014-4568 du 31 décembre 2014, complétant le décret 2007-1885 du 23 juillet 2007, fixant l’organisation administrative et financière de l’ENA.\nMissions de l’Académie\norganiser des sessions de formation continue au profit des hauts cadres de l’administration\norganiser des visites d’études en Allemagne\norganiser des séminaires et conférences scientifiques, ouvertes à la société civile et le secteur privé\neffectuer des recherches et des études pour l'innovation dans le domaine de la bonne gouvernance\néchanger les expériences et l'expertise, aussi en créant un réseau d’alumni\nrenforcer la communication entre l'expertise tunisienne et étrangère dans le domaine de la bonne gouvernance\nétablir des relations de partenariat et de coopération avec les structures et les organismes similaires\nLes activités de l’Académie\n1- Session de formation continue\nPour chaque année académique il y a une formation continue de huit mois,s’adressant à 25-35 participant(e)s et traitant chacune d’un thème prioritaire dans le domaine de la bonne gouvernance. La formation comprend principalement des conférences, des séminaires, des ateliers de travail, des visites de terrain et des visites d’études en Allemagne. L’organisation des conférences se fait en alternance avec les séminaires, les ateliers de travail et les visites d’études et sur terrain.\nLe thème, les dates de démarrage et de clôture de la session sont fixés par par arrêté du chef de gouvernement sur proposition du directeur de l’Ecole Nationale d’Administration.\nLe programme de la première session de formation 2015-2016 a porté sur les concepts de base relatifs à la bonne gouvernance, la gouvernance des marchés publics et la gestion des conflits d’intérêts dans le secteur de la santé.\n2- Sessions de formation à courte durée\nElles comprennent les :\nSéminaires régionaux qui couvrent la totalité des gouvernorats\nConférences internationalesdes gouvernorats\nMissions techniques en Allemagne*: Ouvert à tous ceux ayant participé à la formation continue, mais également à d’autres groupes. Cela permet entre autres l’échange direct entre expert(e)s, ainsi que la visite d’institutions allemandes pour transmettre les expériences pratiques.\nRéunions de mise en réseau* *des alumni.\nLes réalisations de l'Académie\nDepuis 2015, l’Académie a formé 35 participants de la formation continue et organisé deux visites d’études.\nPlus de 500 personnes ont participé à 7 séminaires régionau\nDate des séances\nGouvernorats(*)\nNombre de participants\n05 mars 2016\nNabeul -Tunis -Bizerte-Ariana-Manouba-Ben arous-Zaghouan\n19 mars 2016\nJendouba-Beja-Le kef-Siliana\n23 avril 2016\nKairouan-Kasserine-Sidi bouzid\n30 avril 2016\nMahdia-Sousse-Monastir\n21 mai 2016\nGabès-Sfax-Médnine-Tataouine\n28 mai 2016\nGafsa-Tozeur-Kébili\nAutres ateliers réalisés :\nAtelier de travail organisé par l’Académie en collaboration avec les services de la gouvernance du ministère de la fonction publique, de la gouvernance et de la lutte contre la corruption et le PNUD, du 21 au 25 mars 2016, à l’intention d’une trentaine de cadres tunisiens et de représentants de la société civile.\nL’Ecole Nationale d’Administration est un établissement public à caractère administratif placé sous la tutelle de la présidence du gouvernement et dont le budget est rattaché pour ordre au budget de l’Etat.\nLiens rapides\nPlatforme E-Learning\nBibliothéque en Ligne\nFAD en Ligne\n24, Avenue Docteur Calmette\nMutuelleville 1082 Tunis\nTél: 71 848 300\nFax: 71 794 188\nEmail : info@ena.tn\nSite Web : www.ena.tn\nServices en Ligne\nPlan du site\nReset Password\nDon't have an account\nAlready have an account?",
|
| 96 |
+
"chars": 3987
|
| 97 |
+
},
|
| 98 |
+
{
|
| 99 |
+
"page_name": "ar_concours_general",
|
| 100 |
+
"url": "https://www.ena.tn/ar/concours-ar/informations-generales-ar/",
|
| 101 |
+
"source": "ena.tn",
|
| 102 |
+
"langue": "ar",
|
| 103 |
+
"content": "معلومات عامة\nمعلومات عامة\nالإطار القانوني للمناظرات\nالأمر عدد 78 لسنة 2004 المؤرخ في 14 جانفي 2004 المتعلق بمناظرات الدخول إلى مراحل التكوين بالمدرسة الوطنية للإدارة كما تنقيحه وإتمامه بالأمر عدد 1938 لسنة 2007 والمؤرخ في 30 جويلية 2007 والأمر عدد 3465 لسنة 2010 المؤرخ في 28 ديسمبر 2010 و الأمر الحكومي عدد 657 لسنة 2019 المؤرخ في 05 أوت 2019\nقرار الوزير الأول المؤرّخ في 07 أوت 2007 المتعلق بضبط اختبارات مناظرات الدخول إلى مراحل التكوين بالمدرسة الوطنية للإدارة كما تم تنقيحه و إتمامه بقرار رئيس الحكومة المؤرخ في 05 أوت 2019\nقرار الوزير الأوّل المؤرخ في 7 أوت 2007 المتعلق بضبط الشهادات الوطنية المستوجبة لمناظرات الدخول إلى مراحل التكوين بالمدرسة الوطنية للإدارة كما تم تنقيحه بقرار الوزير الأول المؤرخ في 01 مارس 2010 و قرار رئيس الحكومة المؤرخ في 04 سبتمبر 2012\nالمعلومات العامة والمشتركة\nفتح المناظرة\nتفتح كل مناظرة بقرار من رئيس الحكومة و يتضمن هذا القرار خاصة :\nالرتبة أو مجموعة الرتب المعادلة موضوع المناظرة\nالشهادات العلمية و عند الاقتضاء الاختصاصات المطلوبة\nعدد البقاع المفتوحة للتناظر وتوزيعها عند الاقتضاء حسب مجالات التكوين الجامعي للمترشحين\nتاريخ غلق قائمة الترشحات\nتاريخ إجراء اختبار أو اختبارات مرحلة القبول الأولي\nالعنوان الإلكتروني للتسجيل عن بعد www.concours-ena.nat.tn و مكان إيداع ملف الترشح والعنوان الإداري للمدرسة الوطنية للإدارة لإرسال الملفات بواسطة البريد مضمون الوصول مع الإشعار بالبلوغ .\nسن الترشح\nتضبط السن القصوى للمترشحين حاملي الشهادات العليا بخمسة و ثلاثين (35) سنة على الأكثر في أول جانفي من سنة فتح مناظرة الدخول إلى المرحلة العليا.عادلة موضوع المناظرة\nتضبط السن القصوى للمترشحين حاملي الشهادات العليا بأربعين (40) سنة على الأكثر في أول جانفي من سنة فتح مناظرة الدخول إلى مراحل التكوين التي تعد إلى رتب من الصنفين الفرعيين أ2 وأ3.\nيمنح في صورة تجاوز المترشح السن القصوى المحددة بالنصوص الجاري بها العمل إستثناء للمشاركة في مناظرات الدخول الى مراحل التكوين بالمدرسة الوطنية للإدارة:\nتحتسب السن القصوى ابتداء من سنة تسجيل المترشح بمكتب التشغيل و العمل المستقل بعنوان طالب شغل أو تربص تأهيل للحياة المهنية و ذلك بالنسبة لكل المناظرات التي تفتح خلال الخمس سنوات التي تلي سنة التسجيل شرط تحيينها.\nتطرح من سن المترشح المدة المساوية لفترة العمل المدني الفعلي و المقضات بصفة عون متربص أو مترسم أو وقتي أو متعاقد بالإدارات العمومية أو الجماعات المحلية أو بالمؤسسات العمومية التي تكتسي الصبغة الإدارية.\nوفي كلتا الحالتين يجب على المترشح الذي تجاوز سن الترشح أن يستظهر:\nبشهادة أو وثيقة إدارية رسمية تثبت حق المترشح في المشاركة (قائمة في الخدمات ) طبقا للنصوص الجاري بها العمل.\nشهادة تسجيل بمكتب التشغيل و العمل المستقل (طبقا للنصوص الجاري بها العمل) .\nالوثائق المطلوبة\nيتعين على المترشحين للمناظرة أن يقوموا بالتسجيل عن بعد عن طريق موقع الأنترنات الخاص بالمدرسة الوطنية للإدارة www.concours-ena.nat.tn ثم يتولوا في أجل أقصاه تاريخ ختم قائمة الترشحات تقديم ملف ترشحهم بمقر المدرسة أو بواسطة البريد المضمون الوصول مع الإشعار بالبلوغ إلى المدرسة الوطنية للإدارة : 24 شارع الحكيم كلمات ميتوال-فيل 1082 تونس متضمنا الوثائق التالية :\nعند تقديم الترشحات :\nاستمارة التسجيل عن بعد وتتضمن معلومات حول المترشح وعملية الدفع الإلكتروني لمعلوم التسجيل طبقا للترتيب الجاري بها العمل .\nنسخة مصورة من بطاقة التعريف الوطنية معفاة من الإشهاد بمطابقتها للأصل،\nنسخة مصورة مطابقة للأصل من الشهادة العلمية النهائية والرسمية\nوثيقة تثبت عند الاقتضاء حق الترشح بعد تجاوز السن القصوى القانونية طبقا لأحكام الأمر عدد 1031 بسنة 2006 المؤرخ في 13 أفريل 2006 المتعلق بضبط أحكام خاصة لتحديد السن القصوى وضبط كيفية احتسابه لتمكين حاملي الشهادات العليا من المشاركة في المناظرات الخارجية أو مناظرات الدخول إلى مراحل التكوين للانتداب في القطاع العمومي :شهادة تسجيل بمكتب التشغيل و العمل المستقل محينة و مؤرخة - قائمة في الخدمات الإدارية محينة و مؤرخة\nبعد النجاح في اختبار أو اختبارات مرحلة القبول الأولي و قبل إجراء الاختبار الشفاهي للقبول النهائي :\nيتعين على المترشح إتمام ملف ترشحه بمضمون من سجل السوابق العدلية لم يمض على تاريخ تسليمه أكثر من سنة ،\nكما يتعين إخضاع المترشحين الناجحين في الاختبارات الكتابية وقبل إجراء اختبار أو اختبارات القبول النهائي، إلى تدقيق للمؤهلات البدنية والنفسانية الضرورية لممارسة الوظائف والمهام المتصلة بالرتبة في كامل تراب الجمهورية من قبل طبيب بمؤسسة استشفائية عمومية تعينها المدرسة الوطنية للإدارة، في إطار اتفاقية تبرم للغرض.\nأ - التصريح بقائمة في المترشحين المقبولين أوليا :\nمناظرة المرحلة العليا : المتحصلين على معدل يساوي 10 من 20 على الأقل في الاختبارات الكتابية للقبول الأولي ما لم يتحصل المترشح على عدد أقل من 7 من 20 قي أحد الاختبارات أو حرر اختباري الثقافة العامة و الاختصاص بنفس اللغة . مناظرة الدخول إلي مرحلتي تكوين الإطارات المتوسطة من الصنف الفرعي أ2 و الأعوان من الصنف الفرعي أ3 : المتحصلين على مجموع يساوي أو يفوق ثمانين بالمائة (% 80) من الإجابات الصحيحة في الاختبار بواسطة تقنية الأسئلة متعددة الاختيارات للقبول الأولي. و يمكن للجنة المناظرة عند الاقتضاء النزول بهذا المجموع إلى حد 60 % من الإجابات الصحيحة.\nب – التصريح بقائمة المقبولين نهائيا (القائمة الأصلية و التكميلية )\nلا يمكن التصريح بالقبول النهائي لآي مترشح إن لم يحصل على معدل عام يساوي 10 من 20 على الأقل في اختبارات القبول الأولي و النهائي .\nو تعد لجنة المناظرة حسب الترتيب التفاضلي قائمتين في المترشحين الذين يمكن قبولهم بصفة نهائية .\nالقائمة الأصلية : تتضمن عددا أقصى يساوي عدد الخطط المفتوحة للتناظر .\nقائمة انتظار أو القائمة التكميلية : تمكن من تعويض المترشحين المتخلين من بين المسجلين بالقائمة الأصلية . و يتم إعداد هذه القائمة في حدود % 50 على أقصى تقدير من المترشحين المسجلين بالقائمة الأصلية.\nمدة التكوين\nالمرحلة العليا (أ1) : 30 شهرا\nمرحلة تكوين الإطارات المتوسطة من الصنف الفرعي أ2 : 12 شهرا\nمرحلة تكوين الأعوان من الصنف الفرعي أ3 : 9 اشهر\nالرتب عند التخرج\nالمرحلة العليا (أ1) : مستشار المصالح العمومية أو الرتب المعادلة\nمرحلة تكوين الإطارات المتوسطة من الصنف الفرعي أ2 : متصرف أو الرتب المعادلة\nمرحلة تكوين الأعوان من الصنف الفرعي أ3 :ملحق إدارة او الرتب المعادلة\nالمدرسة الوطنية للإدارة هي مؤسسة عمومية ذات صبغة إدارية تحت إشراف رئاسة الحكومة وذات ميزانية ملحقة بالميزانية العامة للدولة\nروابط سريعة\nمنظومة التعلم عن بعد\nالمكتبة على الخط\nالمناظرات على الخط\nالتكوين عن بعد\nالاستقبال\nالمستجدات\nخدمات على الخط\nخريطة الموقع\nReset Password",
|
| 104 |
+
"chars": 5853
|
| 105 |
+
},
|
| 106 |
+
{
|
| 107 |
+
"page_name": "ar_contact",
|
| 108 |
+
"url": "https://www.ena.tn/ar/contact/",
|
| 109 |
+
"source": "ena.tn",
|
| 110 |
+
"langue": "ar",
|
| 111 |
+
"content": "إتصال – Ecole Nationale d'Administration\n24 نهج الدكتور كلمات\nميتيال فيل تونس\nالهاتف :100 161 70 (+216)\n,300 848 71 (+216)\nالفاكس : 188 794 71 (+216)\nالبريد الالكتروني\ninfo@ena.tn\nالتوقيت الإداري\nـ أيّام الاثنين والثلاثاء والأربعاء والخميس : من الساعة الثامنة صباحا (8.00) إلى الساعة الثانية والنصف بعد الزوال (14.30).\nـ يوم الجمعة : من الساعة الثامنة صباحا (8.00) إلى الساعة الواحدة والنصف بعد الزوال (13.30).\nالبريد الالكتروني : info@ena.tn\nالهاتف : +216 71848 300\nالموقع الالكتروني : www.ena.tn\nروابط سريعة\nمنظومة التعلم عن بعد\nالمكتبة على الخط\nالمناظرات على الخط\nالتكوين عن بعد\nالمدرسة الوطنية للإدارة هي مؤسسة عمومية ذات صبغة إدارية تحت إشراف رئاسة الحكومة وذات ميزانية ملحقة بالميزانية العامة للدولة\nخدمات على الخط\nخريطة الموقع\nالمدرسة الوطنية للإدارة – 2021\nReset Password\nDon't have an account\nAlready have an account?",
|
| 112 |
+
"chars": 843
|
| 113 |
+
},
|
| 114 |
+
{
|
| 115 |
+
"page_name": "ar_concours_a2_detail",
|
| 116 |
+
"url": "https://www.ena.tn/ar/concours-ar/cycle-moyen-ar/entree-au-cycle-de-formation-des-cadres-moyens-ar/",
|
| 117 |
+
"source": "ena.tn",
|
| 118 |
+
"langue": "ar",
|
| 119 |
+
"content": "مناظرة تكوين الإطارات المتوسطة من الصنف الفرعي أ2 – Ecole Nationale d'Administration\nمناظرة تكوين الإطارات المتوسطة من الصنف الفرعي أ2\nالمرحلة المتوسطة\n40 سنة على الأكثر في غرة جانفي من سنة فتح المناظرة\nالشهادة المطلوبة\nشهادات الأستاذية والإجازة الوطنية على الأقل في العلوم ذات الصبغة الاقتصادية و التصرف كما تم تعريفها بالنصوص الجاري بها العمل أو الشهادات المعادلة لها\nشهادات الأستاذية والإجازة الوطنية على الأقل في العلوم ذات الصبغة القانونية و السياسية كما تم تعريفها بالنصوص الجاري بها العمل أو الشهادات المعادلة لها\nتشتمل مناظرة الدخول إلى مرحلة تكوين الإطارات المتوسطة من الصنف ��لفرعي أ2 على اختبار للقبول الأولي يعتمد تقنية الأسئلة متعددة الاختيارات واختبار كتابي واختبار شفاهي للقبول النهائي.\nالاختبار بواسطة تقنية الأسئلة متعددة الاختيارات للقبول الأولي\nيتعلق هذا الاختبار بالاختصاص حسب اختيار المترشح بموضوع أو عدة مواضيع ذات صبغة قانونية أو اقتصادية وتصرف. و يشتمل هذا الاختبار على خمسين (50) سؤالا و تكون الأجوبة عنها باختيار إجابة صحيحة واحدة أو أكثر من الأجوبة المقترحة\nلا يمكن التصريح بالقبول الأولي لأي مترشح لم يتحصل على مجموع يساوي أو يفوق ثمانين بالمائة (80 %) من الإجابات الصحيحة. ويمكن للجنة المناظرة عند الاقتضاء النزول بهذا المجموع إلى حدّ ستين بالمائة (60 %)من الإجابات الصحيحة.\nالاختبار الكتابي والاختبار الشفاهي للقبول النهائي\nالاختبار الكتابي :\nيتعلق هذا الاختبار بالثقافة العامة في صيغـة مقال حـول المسائل السياسيـة أو الاقتصاديـة أو الاجتماعية أو الثقافية للعالم المعاصر.\nباستثناء أحكام مخالفة تتصل بخصوصيات كل مناظرة تعرض الاختبارات الكتابية على مصححين اثنين ويكون العدد النهائي مساويا للمعدل الحسابي للعددين المسندين. وإذا كان الفارق بين هذين العددين يفوق الثلاث (3) نقاط يتم عرض الاختبار على مصحح ثالث. وعندئذ يحتسب العدد النهائي على أساس المعدل الحسابي للأعداد الثلاثة (3) المسندة.\nيتم آليا رفض كل مترشح تحصل على عدد دون سبعة (7) من عشرين (20) في الاختبار الكتابي\nالاختبار الشفاهي :\nيتمثل الاختبار في عرض تليه مناقشة مع أعضاء لجنة المناظرة حول موضوع عام يتصل بالتنظيم السياسي للبلاد التونسية أو بالسياسة العامة في الميادين الاقتصادية أو الاجتماعية أو الثقافية أو الإدارية أو بالمسائل المتصلة بالمنظمات والعلاقات الدولية.\nلا يمكن التصريح بالقبول النهائي لأي مترشح لم يتحصل على معدل عام يساوي عشرة (10) من عشرين (20) على الأقل في اختبارات القبول الأولي والنهائي.\nوإذا تحصل عدة مترشحين على نفس المعدل فإن الأولوية تمنح لأكبرهم سنا.\nالاختبارات و ضواربها\nيبرز الجدول مجموع الإختبارات وضواربها\nنوعية الاختبار\nI – اختبار القبول الأولي\n-اختبار في الاختصاص بواسطة تقنية الأسئلة متعددة الاختيارات\nII – اختبارا القبول النهائي\n– اختبار كتابي في الثقافة العامة\n– الاختبار الشفاهي\nمحتــــــــوى برنــامج اختبـــار الإختصـــاص\nالإختصـــــــاص : اقتصاد وتصرف\n01-المحور الأول: المعطيات الأساسية للاقتصاد التونسي\nالسكان و الفئة النشيطة\nهيكلة الناتج الداخلي الخام و نموه\nمؤشرات الأسعار\nمجموعات المحاسبة الوطنية\nميزانية الدولة\nموارد و استعمالات الجهاز المالي.\n02-المحور الثاني: المنشأة\nالمقاربات المختلفة للمنشأة\nتنظيم المنشاة\nتركيبات الإنتاج و دالة الإنتاج\nتكوين الأسعار و مختلف أشكال المنافسة\nاختيار الاستثمار و التمويل\nاستراتيجيات المنشأة\n03-المحور الثالث: التقلبات و النمو\nالنمو المتوازن\nالنمو الباطني\nالتنمية المستديمة\n04-المحور الرابع: النقد و التمويل\nوظائف النقد\nالعرض والطلب للنقد\nمجموع النقد\nالجهاز المالي ( المؤسسات المالية و السوق المالية)\nتمويل الاقتصاد\nميزان الدفوعات و الحركات المالية\n05-المحور الخامس: المبادلات الخارجية\nأسس الاقتصاد الدولي\nميزان الخيرات و الخدمات\nحدود التبادل\nمناطق التبادل الحر\n06-المحور السادس: السياسة الاقتصادية\nالخيرات و الخدمات العمومية\nالتأثيرات الخارجية\nسياسة الميزانية و الجباية\nالسياسة النقدية\nالإختصـــاص : قــــانون\nالمدرسة الوطنية للإدارة هي مؤسسة عمومية ذات صبغة إدارية تحت إشراف رئاسة الحكومة وذات ميزانية ملحقة بالميزانية العامة للدولة\nروابط سريعة\nمنظومة التعلم عن بعد\nالمكتبة على الخط\nالمناظرات على الخط\nالتكوين عن بعد\nخدمات على الخط\nخريطة الموقع\nالمدرسة الوطنية للإدارة – 2021\nReset Password\nDon't have an account\nAlready have an account?",
|
| 120 |
+
"chars": 3802
|
| 121 |
+
},
|
| 122 |
+
{
|
| 123 |
+
"page_name": "ar_concours_a3_detail",
|
| 124 |
+
"url": "https://www.ena.tn/ar/concours-ar/agents-categorie-a3-ar/",
|
| 125 |
+
"source": "ena.tn",
|
| 126 |
+
"langue": "ar",
|
| 127 |
+
"content": "مناظرة الدخول إلى مرحلة تكوين الأعوان من الصنف الفرعي أ3 – Ecole Nationale d'Administration\nمناظرة الدخول إلى مرحلة تكوين الأعوان من الصنف الفرعي أ3\n* 40 سنة على الأكثر في غرة جانفي من سنة فتح المناظرة\nالشهادة المطلوبة\nالشهادات الوطنية للمرحلة الأولى من التعليم العالي مهما كان موضوع اختصاصها كما تم تعريفها بالنصوص الجاري بها العمل أو الشهادات المعادلة له\nتشتمل مناظرة الدخول إلى مرحلة تكوين الأعوان من الصنف الفرعي “أ3 ” على اختبار للقبول الأولي يعتمد تقنية الأسئلة متعددة الاختيارات واختبار شفاهي للقبول النهائي.\nالاختبار بواسطة تقنية الأسئلة متعددة الاختيارات للقبول الأولي\nيتعلق هذا الاختبار بالثقافة العامة حول المسائل السياسية أو الاقتصادية أو الاجتماعية أو الثقافية للبلاد التونسية أو للعالم المعاصر. و يشتمل هذا الاختبار على خمسين (50) سؤالا و تكون الأجوبة عنها باختيار إجابة صحيحة واحدة أو أكثر من الأجوبة المقترحة.\nالاختبار الشفاهي للقبول النهائي\nيتمثل هذا الاختبار في عرض تليه مناقشة مع أعضاء لجنة المناظرة حول موضوع عام يتصل بالميادين الاقتصادية أو الاجتماعية أو الثقافية أو الإدارية.\nالاختبارات وضواربها\nنوعية الاختبار\n– اختبار القبول الأولي\nاختبار في الثقافة العامة بواسطة تقنية الأسئلة متعددة الاختيارات\n– اختبار القبول النهائي\n— الاختبار الشفاهي\nالمدرسة الوطنية للإدارة هي مؤسسة عمومية ذات صبغة إدارية تحت إشراف رئاسة الحكومة وذات ميزانية ملحقة بالميزانية العامة للدولة\nروابط سريعة\nمنظومة التعلم عن بعد\nالمكتبة على الخط\nالمناظرات على الخط\nالتكوين عن بعد\nخدمات على الخط\nخريطة الموقع\nالمدرسة الوطنية للإدارة – 2021\nReset Password\nDon't have an account\nAlready have an account?",
|
| 128 |
+
"chars": 1491
|
| 129 |
+
},
|
| 130 |
+
{
|
| 131 |
+
"page_name": "ar_concours_superieur_detail",
|
| 132 |
+
"url": "https://www.ena.tn/ar/concours-ar/cycle-superieur-arr/concours-entree-cycle-superieur-ar/",
|
| 133 |
+
"source": "ena.tn",
|
| 134 |
+
"langue": "ar",
|
| 135 |
+
"content": "مناظرة الدخول إلى المرحلة العليا\nالمرحلة العليا\nمناظرة الدخول إلى المرحلة العليا\n35 سنة على الأكثر في غرة جانفي من سنة فتح المناظرة بالنسبة إلى مناظرة الدخول إلى المرحلة العليا\nإلا أنه بالنسبة إلى المترشحين الذين سبق لهم العمل بالإدارات والجماعات المحلية والمؤسسات العمومية وبالنسبة إلى المترشحين المسجلين بمكتب تشغيل، يتم تقدير السن القصوى وفق أحكام الفصل 2 من الأمر عدد 1031 لسنة 2006 المؤرخ في 13 أفريل 2006.\nالشهادات المطلوبة\nشهادات الماجستير الوطنية في العلوم ذات الصبغة الاقتصادية أو التصرف كما تم تعريفها بالنصوص الجاري بها العمل أو الشهادات المعادلة لها\nشهادات الماجستير الوطنية في العلوم ذات الصبغة القانونية أو السياسية كما تم تعريفها بالنصوص الجاري بها العمل أو الشهادات المعادلة لها\nالشهادات الوطنية لمهندس في عدد من الإختصاصات تحدد بقرار من رئيس الحكومة المتعلق بفتح المناظرة.\nتفتح مناظرة الدخول إلى المرحلة العليا خلال النصف الثــاني من كل سنة بقرار من رئيس الحكومة الذي يتضمن بالخصوص :\nالشهادات العلمية المستوجبة والإختصاصات المطلوبة عند الإقتضاء\nعدد البقاع المعروضة للتناظر وتوزيعها ،عند الإقتضاء، حسب الشهادات العلمية\nالاختبارات\nتشتمل مناظرة الدخول إلى المرحلة العليا بالمدرسة الوطنية للإدارة على ثلاثة إختبارات كتابية للقبول الأولي وإختبار شفاهي للقبول النهائي\nويتم إجراء هذه الإختبارات كما يلي:\nإختبار في الإختصاص يتعلق حسب اختيار المترشح بموضوع أو عدة مواضيع ذات صبغة قانونية أوإقتصادية و تصرف.\nويضبط برنامج اختبار الإختصاص بالملحق رقم1 المصاحب للقرار المؤرخ في 7 أوت 2007.\nإختبار في الثقافة العامة في صيغة مقال حول المسائل السياسية أوالإقتصادية أوالإجتماعية أوالثقافية في العالم المعاصر.\nاختبار في اللغة الإنقليزية.\nيتمثل هذا الإختبار في عرض تليه مناقشة مع أعضاء لجنة المناظرة حول موضوع عام أودراسة حالة. ويتصل الإختبار بالتنظيم السياسي للبلاد التونسية أو بالسياسة العامة في الميادين الإقتصادية أوالإجتماعية أوالثقافية أوالإدارية أوبالمسائل المتصلة بالمنظمات والعلاقات الدولية.\nيجرى العرض والمناقشة في لغتين مختلفتين إما بالعربية أو بالفرنسية، كما تطرح على المترشح أسئلة باللغة الإنقليزية في مستوى المناقشة تكون الإجابة عليها بنفس اللغة وجوبا.\nويتم سحب موضوع الإختبار عن طريق القرعة. وفي صورة ما إذا رغب المترشح في إبدال السؤال يقسم العدد الذي يسند إليه على إثنين.\nالاختبارات و ضواربها\nنوعية الاختبار\nI – الاختبارات الكتابية للقبول الأولي\n– اختبار في الاختصاص\n– اختبار في الثقافة العامة\n– اختبار في اللغة الانقليزية\n3 ساعات\n3 ساعات\nساعتان\nII – الإختبار الشفاهي للقبول النهائي\n– الاختبار الشفاهي\nساعة واحدة (إعداد 30دق، مناقشة 20 دق، عرض 10 دق)\nإعداد النتائج والتصريح بها\nباستثناء أحكام مخالفة تتصل بخصوصيات كل مناظرة تعرض الاختبارات الكتابية على مصححين إثنين ويكون العدد النهائي مساويا للمعدل الحسابي للعددين المسندين. وإذا كان الفارق بين هذين العددين يفوق الثلاث (3) نقاط يتم عرض الاختبار على مصحح ثالث. وعندئذ يحتسب العدد النهائي على أساس المعدل الحسابي للأعداد الثلاثة (3) المسندة. يتم آليا رفض كل مترشح تحصل على عدد دون سبعة (7) من عشرين (20)أو حرر الاختبارين الكتابيين ( الاختصاص والثقافة العامة) بنفس اللغة. لا يمكن التصريح بالقبول الأولي لأي مترشح لم يتحصل على معدل يساوي عشرة (10) من عشرين (20) على الأقل في الاختبارات الكتابية.\nباستثناء أحكام مخالفة تتصل بخصوصيات كل مناظرة تعرض الاختبارات الكتابية على مصححين إثنين ويكون العدد النهائي مساويا للمعدل الحسابي للعددين المسندين. وإذا كان الفارق بين هذين العددين يفوق الثلاث (3) نقاط يتم عرض الاختبار على مصحح ثالث. وعندئذ يحتسب العدد النهائي على أساس المعدل الحسابي للأعداد الثلاثة (3) المسندة.\nيتم آليا رفض كل مترشح تحصل على عدد دون سبعة (7) من عشرين (20)أو حرر الاختبارين الكتابيين ( الاختصاص والثقافة العامة) بنفس اللغة.\nلا يمكن التصريح بالقبول الأولي لأي مترشح لم يت��صل على معدل يساوي عشرة (10) من عشرين (20) على الأقل في الاختبارات الكتابية.\nبعد النجاح في إختبار أو في إختبارات مرحلة القبول الأولي وقبل إجراء الاختبار الشفاهي للقبول النهائي، يتعين على المترشح المعني بالأمر إتمام ملف ترشحه بمضمون من سجل السوابق العدلية لم يمض على تاريخ تسليمه أكثر من سنة. كما يتعين إخضاع المترشحين الناجحين في الاختبارات الكتابية وقبل إجراء إختبار أو إختبارات القبول النهائي، إلى تدقيق للمؤهلات البدنية والنفسانية الضرورية لممارسة الوظائف والمهام المتصلة بالرتبة في كامل تراب الجمهورية من قبل طبيب بمؤسسة إستشفائية عمومية تعينها المدرسة الوطنية للإدارة، في إطار اتفاقية تبرم للغرض.\nلا يمكن التصريح بالقبول النهائي لأي مترشح إن لم يتحصل على معدل عام يساوي عشرة (10) من عشرين (20) على الأقل في إختبارات القبول الأولي والنهائي.\nالمدرسة الوطنية للإدارة هي مؤسسة عمومية ذات صبغة إدارية تحت إشراف رئاسة الحكومة وذات ميزانية ملحقة بالميزانية العامة للدولة\nروابط سريعة\nمنظومة التعلم عن بعد\nالمكتبة على الخط\nالمناظرات على الخط\nالتكوين عن بعد\nالاستقبال\nالمستجدات\nخدمات على الخط\nخريطة الموقع\nReset Password",
|
| 136 |
+
"chars": 4480
|
| 137 |
+
}
|
| 138 |
+
]
|
requirements.txt
CHANGED
|
@@ -1,3 +1,21 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
requests==2.31.0
|
| 2 |
+
beautifulsoup4==4.12.3
|
| 3 |
+
aiohttp==3.9.5
|
| 4 |
+
langchain==0.2.16
|
| 5 |
+
langchain-community==0.2.16
|
| 6 |
+
langchain-openai==0.1.25
|
| 7 |
+
langchain-text-splitters==0.2.4
|
| 8 |
+
langchain-huggingface==0.0.3
|
| 9 |
+
langchain-chroma==0.1.4
|
| 10 |
+
chromadb==0.5.5
|
| 11 |
+
sentence-transformers==3.0.1
|
| 12 |
+
rank-bm25==0.2.2
|
| 13 |
+
PyMuPDF==1.24.9
|
| 14 |
+
openai==1.40.0
|
| 15 |
+
python-dotenv==1.0.1
|
| 16 |
+
tiktoken==0.7.0
|
| 17 |
+
huggingface_hub==0.24.5
|
| 18 |
+
streamlit==1.37.1
|
| 19 |
+
scikit-learn==1.5.1
|
| 20 |
+
groq==0.9.0
|
| 21 |
+
scipy==1.14.0
|
scraper.py
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
scraper.py — شغّل هذا السكريبت مرة واحدة لجمع البيانات من ena.tn
|
| 3 |
+
الناتج: ena_data.json (ارفعه مع app.py على Hugging Face)
|
| 4 |
+
|
| 5 |
+
تشغيل: python scraper.py
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
+
import json, requests, time
|
| 9 |
+
from bs4 import BeautifulSoup
|
| 10 |
+
|
| 11 |
+
HEADERS = {
|
| 12 |
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/124.0.0.0",
|
| 13 |
+
"Accept-Language": "fr-FR,fr;q=0.9,ar;q=0.8",
|
| 14 |
+
}
|
| 15 |
+
|
| 16 |
+
SOURCES = {
|
| 17 |
+
"ena.tn": {
|
| 18 |
+
"concours_superieur": "https://www.ena.tn/fr/concours/cycle-superieur/le-concours-dentree-au-cycle-superieur/",
|
| 19 |
+
"concours_general": "https://www.ena.tn/fr/concours/informations-generales/",
|
| 20 |
+
"concours_preparation": "https://www.ena.tn/fr/concours/cycle-superieur/preparation-au-concours/",
|
| 21 |
+
"concours_a2": "https://www.ena.tn/fr/concours/cycle-moyen/concours-dentree-au-cycle-de-formation-des-cadres-moyens-de-la-sous-categorie-a2-2/",
|
| 22 |
+
"concours_a2_prep": "https://www.ena.tn/fr/concours/cycle-moyen/preparation-au-concours/",
|
| 23 |
+
"concours_a3": "https://www.ena.tn/fr/concours/agents-de-la-sous-categorie-a3/",
|
| 24 |
+
"formation_superieur": "https://www.ena.tn/fr/formation-de-base/cycle-superieur/",
|
| 25 |
+
"formation_a2": "https://www.ena.tn/fr/formation-de-base/cycle-de-formation-des-cadres-moyens-de-la-sous-categorie-a2/",
|
| 26 |
+
"formation_a3": "https://www.ena.tn/fr/formation-de-base/cycle-de-formation-des-agents-de-la-sous-categorie-a3/",
|
| 27 |
+
"formation_continue": "https://www.ena.tn/fr/formation-continue/formation-continue-a-distance-et-presentielle/",
|
| 28 |
+
"formation_courte": "https://www.ena.tn/fr/formation-continue/sessions-de-formation-de-courte-duree/",
|
| 29 |
+
"gouvernance": "https://www.ena.tn/fr/gouvernance/lacademie-internationale-de-la-bonne-gouvernance/",
|
| 30 |
+
"ar_concours_general": "https://www.ena.tn/ar/concours-ar/informations-generales-ar/",
|
| 31 |
+
"ar_contact": "https://www.ena.tn/ar/contact/",
|
| 32 |
+
"ar_concours_a2_detail": "https://www.ena.tn/ar/concours-ar/cycle-moyen-ar/entree-au-cycle-de-formation-des-cadres-moyens-ar/",
|
| 33 |
+
"ar_concours_a3_detail": "https://www.ena.tn/ar/concours-ar/agents-categorie-a3-ar/",
|
| 34 |
+
"ar_concours_superieur_detail": "https://www.ena.tn/ar/concours-ar/cycle-superieur-arr/concours-entree-cycle-superieur-ar/",
|
| 35 |
+
},
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
NAV_WORDS = ["L'ENA SE PRESENTE","Formation de Base","Formation Continue",
|
| 39 |
+
"Concours","LeaderShip","Gouvernance","Accueil","Français","العربية"]
|
| 40 |
+
|
| 41 |
+
SKIP_SECTIONS = [
|
| 42 |
+
"محتوى برنامج اختبار", "الإختصــــــــــــاص",
|
| 43 |
+
"المحور الأول", "المحور الثاني", "المحور الثالث",
|
| 44 |
+
"المحور الرابع", "المحور الخامس", "المحور السادس",
|
| 45 |
+
"المحور السابع", "المحور الثامن",
|
| 46 |
+
"contenu du programme", "programme de l'épreuve",
|
| 47 |
+
]
|
| 48 |
+
|
| 49 |
+
def smart_scrape(soup, name):
|
| 50 |
+
skip_mode = False
|
| 51 |
+
lines_out = []
|
| 52 |
+
for tag in soup.find_all(["h1","h2","h3","h4","p","li","td","th"]):
|
| 53 |
+
text = tag.get_text(" ", strip=True)
|
| 54 |
+
if not text or len(text) < 5:
|
| 55 |
+
continue
|
| 56 |
+
if any(skip in text for skip in SKIP_SECTIONS):
|
| 57 |
+
skip_mode = True
|
| 58 |
+
if skip_mode and tag.name in ["h2","h3"] and not any(skip in text for skip in SKIP_SECTIONS):
|
| 59 |
+
skip_mode = False
|
| 60 |
+
if not skip_mode and len(text) > 8:
|
| 61 |
+
lines_out.append(text)
|
| 62 |
+
return "\n".join(lines_out)
|
| 63 |
+
|
| 64 |
+
def scrape_page(name, url, source):
|
| 65 |
+
try:
|
| 66 |
+
resp = requests.get(url, headers=HEADERS, timeout=15, allow_redirects=True)
|
| 67 |
+
resp.encoding = "utf-8"
|
| 68 |
+
soup = BeautifulSoup(resp.text, "html.parser")
|
| 69 |
+
for tag in soup(["script","style","nav","footer","header","aside","form","button","iframe","img","noscript"]):
|
| 70 |
+
tag.decompose()
|
| 71 |
+
|
| 72 |
+
QCM_PAGES = ["ar_concours_a2_detail", "concours_a2", "concours_a3", "ar_concours_a3"]
|
| 73 |
+
if name in QCM_PAGES:
|
| 74 |
+
text = soup.get_text("\n", strip=True)
|
| 75 |
+
lines = text.split("\n")
|
| 76 |
+
seen, clean = set(), []
|
| 77 |
+
for line in lines:
|
| 78 |
+
line = line.strip()
|
| 79 |
+
is_nav = any(kw in line for kw in NAV_WORDS)
|
| 80 |
+
if len(line) > 10 and line not in seen and not is_nav and "©" not in line and len(line) < 2000:
|
| 81 |
+
seen.add(line)
|
| 82 |
+
clean.append(line)
|
| 83 |
+
content = "\n".join(clean)
|
| 84 |
+
elif name in ["ar_concours_superieur_detail", "concours_superieur", "concours_general", "ar_concours_general"]:
|
| 85 |
+
content = smart_scrape(soup, name)
|
| 86 |
+
else:
|
| 87 |
+
text = soup.get_text("\n", strip=True)
|
| 88 |
+
lines = text.split("\n")
|
| 89 |
+
seen, clean = set(), []
|
| 90 |
+
for line in lines:
|
| 91 |
+
line = line.strip()
|
| 92 |
+
is_nav = any(kw in line for kw in NAV_WORDS)
|
| 93 |
+
if len(line) > 10 and line not in seen and not is_nav and "©" not in line and len(line) < 2000:
|
| 94 |
+
seen.add(line)
|
| 95 |
+
clean.append(line)
|
| 96 |
+
content = "\n".join(clean)
|
| 97 |
+
|
| 98 |
+
if len(content) < 50:
|
| 99 |
+
return None
|
| 100 |
+
|
| 101 |
+
langue = "ar" if name.startswith("ar_") else "fr"
|
| 102 |
+
return {
|
| 103 |
+
"page_name": name, "url": url, "source": source,
|
| 104 |
+
"langue": langue, "content": content, "chars": len(content)
|
| 105 |
+
}
|
| 106 |
+
except Exception as e:
|
| 107 |
+
print(f"❌ {name}: {e}")
|
| 108 |
+
return None
|
| 109 |
+
|
| 110 |
+
if __name__ == "__main__":
|
| 111 |
+
print("🔄 جمع البيانات من ena.tn...\n")
|
| 112 |
+
all_data = []
|
| 113 |
+
for source, pages in SOURCES.items():
|
| 114 |
+
print(f"🌐 {source}:")
|
| 115 |
+
for name, url in pages.items():
|
| 116 |
+
time.sleep(0.8)
|
| 117 |
+
result = scrape_page(name, url, source)
|
| 118 |
+
if result:
|
| 119 |
+
all_data.append(result)
|
| 120 |
+
print(f" ✅ {name}: {result['chars']} حرف [{result['langue']}]")
|
| 121 |
+
else:
|
| 122 |
+
print(f" ⚠️ {name}: فارغة")
|
| 123 |
+
|
| 124 |
+
with open("ena_data.json", "w", encoding="utf-8") as f:
|
| 125 |
+
json.dump(all_data, f, ensure_ascii=False, indent=2)
|
| 126 |
+
|
| 127 |
+
print(f"\n📊 إجمالي: {len(all_data)} صفحة")
|
| 128 |
+
print(f"📊 أحرف: {sum(p['chars'] for p in all_data):,}")
|
| 129 |
+
print(f"\n✅ تم الحفظ في ena_data.json — ارفعه مع app.py على Hugging Face")
|