sxid003 commited on
Commit
3107242
·
verified ·
1 Parent(s): 2f37f39

Upload 83 files

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .dockerignore +12 -0
  2. .gitattributes +1 -0
  3. dataset/docs_metadata.csv +0 -0
  4. docs/full_graph.png +0 -0
  5. docs/logo.jpg +0 -0
  6. docs/preprocess_script_readme.md +123 -0
  7. docs/questions_rag_test.txt +25 -0
  8. output/.DS_Store +0 -0
  9. output/documents/chunks.json +3 -0
  10. output/documents/embeddings.npy +3 -0
  11. output/documents/faiss_docs.bin +3 -0
  12. output/mcp_pipeline_graph.png +0 -0
  13. output/parlement_titledate_embeddings.npy +3 -0
  14. output/parlement_titledate_metadatas.json +1255 -0
  15. output/title_cat_embeddings.npy +3 -0
  16. output/title_cat_metadatas.json +0 -0
  17. output/youtube/chunks.csv +0 -0
  18. output/youtube/chunks_embedded.pkl +3 -0
  19. output/youtube/faiss_metadata.pkl +3 -0
  20. output/youtube/faiss_ytb.bin +3 -0
  21. output/youtube/parlement_transcript.csv +0 -0
  22. requirements.txt +26 -0
  23. src/.DS_Store +0 -0
  24. src/__init__.py +0 -0
  25. src/__pycache__/__init__.cpython-311.pyc +0 -0
  26. src/agents/__pycache__/main_agent.cpython-311.pyc +0 -0
  27. src/agents/__pycache__/rag_agent.cpython-311.pyc +0 -0
  28. src/agents/main_agent.py +100 -0
  29. src/agents/rag_agent.py +118 -0
  30. src/api/__pycache__/chatbot_api.cpython-311.pyc +0 -0
  31. src/api/chatbot_api.py +36 -0
  32. src/configs/.env +2 -0
  33. src/configs/__pycache__/config.cpython-311.pyc +0 -0
  34. src/configs/config.py +45 -0
  35. src/configs/mcp_config.json +8 -0
  36. src/docs_embd/__pycache__/embed.cpython-311.pyc +0 -0
  37. src/docs_embd/__pycache__/index.cpython-311.pyc +0 -0
  38. src/docs_embd/__pycache__/preprocessing.cpython-311.pyc +0 -0
  39. src/docs_embd/embed.py +42 -0
  40. src/docs_embd/index.py +47 -0
  41. src/docs_embd/preprocessing.py +95 -0
  42. src/main.py +112 -0
  43. src/mcp/__pycache__/client.cpython-311.pyc +0 -0
  44. src/mcp/__pycache__/server.cpython-311.pyc +0 -0
  45. src/mcp/client.py +17 -0
  46. src/mcp/server.py +138 -0
  47. src/models/__pycache__/llm_wrapper.cpython-311.pyc +0 -0
  48. src/models/llm_wrapper.py +32 -0
  49. src/prompts/documents_rag_prompt.txt +14 -0
  50. src/prompts/router_prompt.txt +9 -0
.dockerignore ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ __pycache__/
2
+ *.pyc
3
+ *.pyo
4
+ *.pyd
5
+ *.log
6
+ .git/
7
+ .gitignore
8
+ rag_env/
9
+ logs/
10
+ output/
11
+ dataset/
12
+ .DS_Store
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ output/documents/chunks.json filter=lfs diff=lfs merge=lfs -text
dataset/docs_metadata.csv ADDED
The diff for this file is too large to render. See raw diff
 
docs/full_graph.png ADDED
docs/logo.jpg ADDED
docs/preprocess_script_readme.md ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Script de Prétraitement et Génération d'Embeddings
2
+
3
+ ## 📋 **Vue d'ensemble**
4
+
5
+ Le script `preprocess_titlecat_titledate_embeddings.py` est un pipeline de prétraitement qui génère les embeddings nécessaires au fonctionnement du système MCP. Il traite deux types de données :
6
+
7
+ - **📚 Documents Juridiques** : Génère des embeddings basés sur le titre + catégorie des documents
8
+ - **🏛️ Transcriptions Parlementaires** : Génère des embeddings basés sur le titre + date des transcriptions
9
+
10
+ ## 🔧 **Fonctionnement du Script**
11
+
12
+ ### **Étape 1 : Documents Juridiques (title+category)**
13
+ ```python
14
+ preprocess_and_save_documents()
15
+ ```
16
+
17
+ **Fichier source** : `dataset/documents.csv`
18
+ **Données traitées** :
19
+ - `Nom du document` + `Catégorie`
20
+ - Métadonnées : ID, Nom, Lien, Catégorie, Langue
21
+
22
+ **Fichiers générés** :
23
+ - `output/title_cat_embeddings.npy` : Embeddings des documents
24
+ - `output/title_cat_metadatas.json` : Métadonnées structurées
25
+
26
+ ### **Étape 2 : Transcriptions Parlementaires (title+date)**
27
+ ```python
28
+ preprocess_and_save_parlement()
29
+ ```
30
+
31
+ **Fichier source** : `data/youtube/raw/parlement_transcript.csv`
32
+ **Données traitées** :
33
+ - `titre` + `date`
34
+ - Métadonnées : ID, titre, date, langue, lien
35
+
36
+ **Fichiers générés** :
37
+ - `output/parlement_titledate_embeddings.npy` : Embeddings des transcriptions
38
+ - `output/parlement_titledate_metadatas.json` : Métadonnées structurées
39
+
40
+ ## 🎯 **Modèle d'Embedding Utilisé**
41
+
42
+ - **Modèle** : `paraphrase-multilingual-mpnet-base-v2`
43
+ - **Caractéristiques** : Multilingue (français, arabe)
44
+
45
+ ## 📊 **Logging et Traçabilité**
46
+
47
+ Le script génère des logs détaillés dans :
48
+ ```
49
+ logs/preprocess_titlecat_titledate_embeddings.log
50
+ ```
51
+
52
+ **Format des logs** :
53
+ ```
54
+ 2024-01-15 10:30:00 - INFO - 1/2 Starting preprocessing and embedding for documents (title+category).
55
+ 2024-01-15 10:32:15 - INFO - 2/2 Starting preprocessing and embedding for parliament transcripts (title+date).
56
+ 2024-01-15 10:34:30 - INFO - Preprocessing and embedding completed.
57
+ ```
58
+
59
+ ## 🚀 **Exécution**
60
+
61
+ ### **Prérequis**
62
+ - Fichier `dataset/documents.csv` avec les documents juridiques
63
+ - Fichier `data/youtube/raw/parlement_transcript.csv` avec les transcriptions
64
+ - Modèle SentenceTransformer installé
65
+
66
+ ### **Commande d'exécution**
67
+ ```bash
68
+ python scripts/preprocess_titlecat_titledate_embeddings.py
69
+ ```
70
+
71
+ ### **Sortie attendue**
72
+ ```
73
+ Saved 150 embeddings and metadatas.
74
+ Saved 75 parlement embeddings and metadatas (sans sous-titre).
75
+ ```
76
+
77
+ ## 📁 **Structure des Fichiers Générés**
78
+
79
+ ### **Documents Juridiques**
80
+ ```json
81
+ [
82
+ {
83
+ "Nom du document": "Code pénal",
84
+ "Lien": "https://adala.justice.gov.ma/...",
85
+ "Catégorie": "Codes",
86
+ "Langue": "fr",
87
+ "Id": "1"
88
+ }
89
+ ]
90
+ ```
91
+
92
+ ### **Transcriptions Parlementaires**
93
+ ```json
94
+ [
95
+ {
96
+ "id": "1",
97
+ "titre": "Débat sur l'éducation",
98
+ "date": "2024-01-15",
99
+ "langue": "fr",
100
+ "lien": "https://youtube.com/..."
101
+ }
102
+ ]
103
+ ```
104
+
105
+ ## 🔄 **Intégration avec le Pipeline MCP**
106
+
107
+ Ce script doit être exécuté **avant** d'utiliser le pipeline MCP :
108
+ 1. Exécuter ce script pour générer les embeddings
109
+ 2. Lancer le pipeline MCP qui utilisera ces embeddings
110
+
111
+ ## 🛠️ **Dépannage**
112
+
113
+ ### **Erreur courante : Fichier CSV manquant**
114
+ ```
115
+ FileNotFoundError: [Errno 2] No such file or directory: 'dataset/documents.csv'
116
+ ```
117
+ **Solution** : Vérifier que les fichiers CSV sources existent
118
+
119
+ ### **Erreur courante : Modèle non trouvé**
120
+ ```
121
+ OSError: Model paraphrase-multilingual-mpnet-base-v2 not found
122
+ ```
123
+ **Solution** : Installer SentenceTransformer et télécharger le modèle
docs/questions_rag_test.txt ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 1. Quelles sont les principales nouveautés de la Constitution marocaine de 2011 ?
2
+ 2. Quelle est la différence entre la Constitution de 1996 et celle de 2011 ?
3
+ 3. Parle-moi de la Constitution du Maroc de 1972.
4
+ 4. Que prévoit le Code de procédure civile au Maroc ?
5
+ 5. Qu'est-ce que le Code des Obligations et des Contrats ?
6
+ 6. Quelles sont les règles sur la sécurité des produits et des services au Maroc ?
7
+ 7. Quelles sont les mesures pour garantir la sécurité sanitaire des produits alimentaires au Maroc ?
8
+ 8. Que dit la loi-cadre relative au système national de santé ?
9
+ 9. Quelles sont les obligations concernant la protection sanitaire des élevages avicoles ?
10
+ 10. Quelles sont les principales dispositions du Code pénal marocain ?
11
+ 11. Comment la loi marocaine lutte-t-elle contre le blanchiment de capitaux ?
12
+ 12. Que prévoit la loi sur la lutte contre les violences faites aux femmes ?
13
+ 13. Qu'est-ce que le Code de la famille au Maroc ?
14
+ 14. Quelles sont les conditions pour bénéficier du Fonds d'entraide familiale ?
15
+ 15. Quelles sont les règles concernant la kafala (prise en charge des enfants abandonnés) ?
16
+ 16. Quelles sont les principales dispositions du Code du travail marocain ?
17
+ 17. Quelles sont les conditions de travail des travailleuses et travailleurs domestiques ?
18
+ 18. Que prévoit le Code de commerce marocain ?
19
+ 19. Qu'est-ce que la loi sur le statut de l'auto-entrepreneur ?
20
+ 20. Quelles sont les mesures de défense commerciale au Maroc ?
21
+ 21. Qu'est-ce que la Charte nationale de l'environnement et du développement durable ?
22
+ 22. Quelles sont les normes de qualité de l'air au Maroc ?
23
+ 23. Quelles sont les règles concernant la protection des végétaux ?
24
+ 24. Qu'est-ce que la loi sur la protection des données à caractère personnel au Maroc ?
25
+ 25. Quelles sont les mesures prévues pour la cybersécurité au Maroc ?
output/.DS_Store ADDED
Binary file (8.2 kB). View file
 
output/documents/chunks.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2f16df07ca0aae8bf9f1fc8cd2e60bb5f76fe237921dc9e13f48cfd751a4be3c
3
+ size 61120582
output/documents/embeddings.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9493bc536fd11ecf654dff91732b0b5d8967772ff0a1de7652c06180e5273b7c
3
+ size 42071168
output/documents/faiss_docs.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9bd75ab90c429d3351f3215ed4106d612b54db9c2aeab4d60a5e645a2be26212
3
+ size 42488739
output/mcp_pipeline_graph.png ADDED
output/parlement_titledate_embeddings.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1d1eeff647928e470b49b970772b398590ee040d87eb18941319376514b4cc99
3
+ size 550016
output/parlement_titledate_metadatas.json ADDED
@@ -0,0 +1,1255 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "id": 1,
4
+ "titre": "جلسة عمومية تشريعية الثلاثاء 17 يونيو 2025 - تتمة",
5
+ "date": "2025-06-18",
6
+ "langue": "ar",
7
+ "lien": "https://www.youtube.com/watch?v=fRG4uJfEJBM"
8
+ },
9
+ {
10
+ "id": 2,
11
+ "titre": "جلسة عمومية تشريعية الثلاثاء 17 يونيو 2025",
12
+ "date": "2025-06-18",
13
+ "langue": "ar",
14
+ "lien": "https://www.youtube.com/watch?v=3975CveW0Qw"
15
+ },
16
+ {
17
+ "id": 3,
18
+ "titre": "جلسة عمومية للأسئلة الشفوية الإثنين 16 يونيو 2025",
19
+ "date": "2025-06-17",
20
+ "langue": "ar",
21
+ "lien": "https://www.youtube.com/watch?v=lklLl6ME2fo"
22
+ },
23
+ {
24
+ "id": 4,
25
+ "titre": "جلسة عمومية للأسئلة الشفوية تليها جلسة تشريعية الإثنين 2 يونيو 2025",
26
+ "date": "2025-06-02",
27
+ "langue": "ar",
28
+ "lien": "https://www.youtube.com/watch?v=OWGDRH5xllw"
29
+ },
30
+ {
31
+ "id": 5,
32
+ "titre": "جلسة عمومية للأسئلة الشفوية الإثنين 26 ماي 2025",
33
+ "date": "2025-05-27",
34
+ "langue": "ar",
35
+ "lien": "https://www.youtube.com/watch?v=9JUjCOaXBBc"
36
+ },
37
+ {
38
+ "id": 6,
39
+ "titre": "جلسة عمومية تشريعية الثلاثاء 20 ماي 2025 - تتمة",
40
+ "date": "2025-05-20",
41
+ "langue": "ar",
42
+ "lien": "https://www.youtube.com/watch?v=HGhWWZ9QcM0"
43
+ },
44
+ {
45
+ "id": 7,
46
+ "titre": "جلسة عمومية تشريعية الثلاثاء 20 ماي 2025",
47
+ "date": "2025-05-20",
48
+ "langue": "ar",
49
+ "lien": "https://www.youtube.com/watch?v=XwJ2JjP-Lvo"
50
+ },
51
+ {
52
+ "id": 8,
53
+ "titre": "جلسة عمومية للأسئلة الشفهية الشهرية الموجهة إلى رئيس الحكومة الإثنين 19 ماي 2025",
54
+ "date": "2025-05-20",
55
+ "langue": "ar",
56
+ "lien": "https://www.youtube.com/watch?v=xrryJrf3OFs"
57
+ },
58
+ {
59
+ "id": 9,
60
+ "titre": "جلسة عمومية تشريعية الثلاثاء 13 ماي 2025",
61
+ "date": "2025-05-13",
62
+ "langue": "ar",
63
+ "lien": "https://www.youtube.com/watch?v=AIv3cqxMby8"
64
+ },
65
+ {
66
+ "id": 10,
67
+ "titre": "جلسة عمومية للأسئلة الشفوية الإثنين 12 ماي 2025",
68
+ "date": "2025-05-13",
69
+ "langue": "ar",
70
+ "lien": "https://www.youtube.com/watch?v=5IyRAK07PLo"
71
+ },
72
+ {
73
+ "id": 11,
74
+ "titre": "جلسة عمومية للأسئلة الشفوية الإثنين 5 ماي 2025",
75
+ "date": "2025-05-06",
76
+ "langue": "ar",
77
+ "lien": "https://www.youtube.com/watch?v=k_uN_UXKKt0"
78
+ },
79
+ {
80
+ "id": 12,
81
+ "titre": "جلسة عمومية للأسئلة الشفوية الإثنين 28 أبريل 2025",
82
+ "date": "2025-04-29",
83
+ "langue": "ar",
84
+ "lien": "https://www.youtube.com/watch?v=Ol-Zj9amW6w"
85
+ },
86
+ {
87
+ "id": 13,
88
+ "titre": "جلسة عمومية للأسئلة الشفوية الإثنين 21 أبريل 2025",
89
+ "date": "2025-04-22",
90
+ "langue": "ar",
91
+ "lien": "https://www.youtube.com/watch?v=dCJcYDe24sw"
92
+ },
93
+ {
94
+ "id": 14,
95
+ "titre": "جلسة عمومية لمناقشة تقرير الثلاثاء 15 أبريل 2025",
96
+ "date": "2025-04-16",
97
+ "langue": "ar",
98
+ "lien": "https://www.youtube.com/watch?v=rstIq2N2ElY"
99
+ },
100
+ {
101
+ "id": 15,
102
+ "titre": "جلسة عمومية للأسئلة الشفوية تليها جلسة تشريعية الإثنين 14 أبريل 2025",
103
+ "date": "2025-04-15",
104
+ "langue": "ar",
105
+ "lien": "https://www.youtube.com/watch?v=vXwZS5YwQSI"
106
+ },
107
+ {
108
+ "id": 16,
109
+ "titre": "جلسة عمومية لمناقشة عرض المجلس الأعلى للحسابات تليها جلسة لاختتام الدورة الثلاثاء 11 فبراير 2025",
110
+ "date": "2025-02-11",
111
+ "langue": "ar",
112
+ "lien": "https://www.youtube.com/watch?v=NLuDhe4uiIY"
113
+ },
114
+ {
115
+ "id": 17,
116
+ "titre": "جلسة عمومية للأسئلة الشفوية الاثنين 10 فبراير 2025",
117
+ "date": "2025-02-11",
118
+ "langue": "ar",
119
+ "lien": "https://www.youtube.com/watch?v=ff4MejxR_aU"
120
+ },
121
+ {
122
+ "id": 18,
123
+ "titre": "جلسة عمومية تشريعية الأربعاء 5 فبراير 2025",
124
+ "date": "2025-02-06",
125
+ "langue": "ar",
126
+ "lien": "https://www.youtube.com/watch?v=hrJzNK38748"
127
+ },
128
+ {
129
+ "id": 19,
130
+ "titre": "جلسة عمومية للأسئلة الشفوية تليها جلسة تشريعية الإثنين 3 فبراير 2025",
131
+ "date": "2025-02-03",
132
+ "langue": "ar",
133
+ "lien": "https://www.youtube.com/watch?v=GKvHUULfb0s"
134
+ },
135
+ {
136
+ "id": 20,
137
+ "titre": "جلسة عمومية تشريعية الثلاثاء 28 يناير 2025 - تتمة",
138
+ "date": "2025-01-28",
139
+ "langue": "ar",
140
+ "lien": "https://www.youtube.com/watch?v=aVhSrNfOtFs"
141
+ },
142
+ {
143
+ "id": 21,
144
+ "titre": "جلسة عمومية تشريعية الثلاثاء 28 يناير 2025",
145
+ "date": "2025-01-28",
146
+ "langue": "ar",
147
+ "lien": "https://www.youtube.com/watch?v=19zMyH6ljwM"
148
+ },
149
+ {
150
+ "id": 22,
151
+ "titre": "جلسة عمومية للأسئلة الشفهية الشهرية الموجهة إلى رئيس الحكومة الإثنين 27 يناير 2025",
152
+ "date": "2025-01-28",
153
+ "langue": "ar",
154
+ "lien": "https://www.youtube.com/watch?v=xcFcCBnYCE8"
155
+ },
156
+ {
157
+ "id": 23,
158
+ "titre": "جلسة عمومية للأسئلة الشفوية تليها جلسة تشريعية الإثنين 20 يناير 2025",
159
+ "date": "2025-01-21",
160
+ "langue": "ar",
161
+ "lien": "https://www.youtube.com/watch?v=YrrUnJj9XKM"
162
+ },
163
+ {
164
+ "id": 24,
165
+ "titre": "جلسة عمومية مشتركة الأربعاء 15 يناير 2025 لتقديم عرض عن أعمال المجلس الأعلى للحسابات برسم 2023-2024",
166
+ "date": "2025-01-15",
167
+ "langue": "ar",
168
+ "lien": "https://www.youtube.com/watch?v=MBIO6clHWb8"
169
+ },
170
+ {
171
+ "id": 25,
172
+ "titre": "جلسة عمومية للأسئلة الشفوية الاثنين 13 يناير 2025",
173
+ "date": "2025-01-14",
174
+ "langue": "ar",
175
+ "lien": "https://www.youtube.com/watch?v=KQN6vc1ztwA"
176
+ },
177
+ {
178
+ "id": 26,
179
+ "titre": "جلسة عمومية للأسئلة الشفوية الاثنين 6 يناير 2025",
180
+ "date": "2025-01-07",
181
+ "langue": "ar",
182
+ "lien": "https://www.youtube.com/watch?v=o1VZj8S-RTg"
183
+ },
184
+ {
185
+ "id": 27,
186
+ "titre": "جلسة عمومية للأسئلة الشفوية الإثنين 30 دجنبر 2024",
187
+ "date": "2024-12-31",
188
+ "langue": "ar",
189
+ "lien": "https://www.youtube.com/watch?v=sU9OaEnlBvY"
190
+ },
191
+ {
192
+ "id": 28,
193
+ "titre": "جلسة عمومية تشريعية الثلاثاء 24 دجنبر 2024 - تتمة",
194
+ "date": "2024-12-24",
195
+ "langue": "ar",
196
+ "lien": "https://www.youtube.com/watch?v=uN-ZBXPj8io"
197
+ },
198
+ {
199
+ "id": 29,
200
+ "titre": "جلسة عمومية تشريعية الثلاثاء 24 دجنبر 2024",
201
+ "date": "2024-12-25",
202
+ "langue": "ar",
203
+ "lien": "https://www.youtube.com/watch?v=DxPkUboU8cI"
204
+ },
205
+ {
206
+ "id": 30,
207
+ "titre": "جلسة عمومية للأسئلة الشفوية الإثنين 23 دجنبر 2024",
208
+ "date": "2024-12-24",
209
+ "langue": "ar",
210
+ "lien": "https://www.youtube.com/watch?v=BTHJYxFQM-A"
211
+ },
212
+ {
213
+ "id": 31,
214
+ "titre": "البرلمان المغربي يحتضن ''مؤتمر المستقبل \" يومي 17 و18 دجنبر 2024 - مساء الأربعاء 18 دجنبر 2024",
215
+ "date": "2024-12-19",
216
+ "langue": "ar",
217
+ "lien": "https://www.youtube.com/watch?v=4qnPoHE8QAc"
218
+ },
219
+ {
220
+ "id": 32,
221
+ "titre": "البرلمان المغربي يحتضن ''مؤتمر المستقبل \" يومي 17 و18 دجنبر 2024 - صباح الأربعاء 18 دجنبر 2024",
222
+ "date": "2024-12-18",
223
+ "langue": "ar",
224
+ "lien": "https://www.youtube.com/watch?v=LSZTZqkzMHw"
225
+ },
226
+ {
227
+ "id": 33,
228
+ "titre": "البرلمان المغربي يحتضن ''مؤتمر المستقبل \" يومي 17 و18 دجنبر 2024 - مساء الثلاثاء 17 دجنبر 2024",
229
+ "date": "2024-12-18",
230
+ "langue": "ar",
231
+ "lien": "https://www.youtube.com/watch?v=L0C8mlB5tdc"
232
+ },
233
+ {
234
+ "id": 34,
235
+ "titre": "البرلمان المغربي يحتضن ''مؤتمر المستقبل \" يومي 17 و18 دجنبر 2024 - صباح الثلاثاء 17 دجنبر 2024",
236
+ "date": "2024-12-18",
237
+ "langue": "ar",
238
+ "lien": "https://www.youtube.com/watch?v=NaShuRftnuA"
239
+ },
240
+ {
241
+ "id": 35,
242
+ "titre": "البرلمان المغربي يحتضن ''مؤتمر المستقبل \" يومي 17 و18 دجنبر 2024 - صباح الثلاثاء 17 دجنبر 2024",
243
+ "date": "2024-12-17",
244
+ "langue": "ar",
245
+ "lien": "https://www.youtube.com/watch?v=zRBlZZjBZBE"
246
+ },
247
+ {
248
+ "id": 36,
249
+ "titre": "جلسة عمومية للأسئلة الشفهية الشهرية الموجهة إلى رئيس الحكومة الاثنين 16 دجنبر 2024",
250
+ "date": "2024-12-17",
251
+ "langue": "ar",
252
+ "lien": "https://www.youtube.com/watch?v=h9215NRON-A"
253
+ },
254
+ {
255
+ "id": 37,
256
+ "titre": "جلسة عمومية للأسئلة الشفوية تليها جلسة تشريعية الإثنين 9 دجنبر 2024",
257
+ "date": "2024-12-10",
258
+ "langue": "ar",
259
+ "lien": "https://www.youtube.com/watch?v=KLL98c0deO4"
260
+ },
261
+ {
262
+ "id": 38,
263
+ "titre": "جلسة عمومية تخصص لقراءة ثانية لمشروع قانون المالية 2025 الجمعة 6 دجنبر 2024",
264
+ "date": "2024-12-07",
265
+ "langue": "ar",
266
+ "lien": "https://www.youtube.com/watch?v=ULKdglbGee0"
267
+ },
268
+ {
269
+ "id": 39,
270
+ "titre": "ندوة دولية حول «التجربة المغربية في مجال العدالة الانتقالية» - الجلسة الافتتاحية",
271
+ "date": "2024-12-06",
272
+ "langue": "ar",
273
+ "lien": "https://www.youtube.com/watch?v=wet0t19bGbo"
274
+ },
275
+ {
276
+ "id": 40,
277
+ "titre": "جلسة عمومية للأسئلة الشفوية تليها جلسة تشريعية الإثنين 2 دجنبر 2024",
278
+ "date": "2024-12-03",
279
+ "langue": "ar",
280
+ "lien": "https://www.youtube.com/watch?v=8hUN8LKT7mo"
281
+ },
282
+ {
283
+ "id": 41,
284
+ "titre": "جلسة عمومية للأسئلة الشفوية الإثنين 25 نونبر 2024",
285
+ "date": "2024-11-26",
286
+ "langue": "ar",
287
+ "lien": "https://www.youtube.com/watch?v=eJ6gXoDjzzk"
288
+ },
289
+ {
290
+ "id": 42,
291
+ "titre": "الدورة الوطنية لبرلمان الطفل الأربعاء 20 نونبر 2024",
292
+ "date": "2024-11-21",
293
+ "langue": "ar",
294
+ "lien": "https://www.youtube.com/watch?v=dEBWown1-4Y"
295
+ },
296
+ {
297
+ "id": 43,
298
+ "titre": "جلسة عمومية لجواب الحكومة والتصويت على الجزء 2 وعلى مشروع قانون المالية برمته الجمعة 15 نونبر 2024",
299
+ "date": "2024-11-16",
300
+ "langue": "ar",
301
+ "lien": "https://www.youtube.com/watch?v=O8RkyeFVLd4"
302
+ },
303
+ {
304
+ "id": 44,
305
+ "titre": "تقديم تقارير اللجان حول الميزانيات الفرعية ومناقشة الجزء 2 من مشروع قانون المالية 15/11/2024",
306
+ "date": "2024-11-16",
307
+ "langue": "ar",
308
+ "lien": "https://www.youtube.com/watch?v=EOg4OdFk6bE"
309
+ },
310
+ {
311
+ "id": 45,
312
+ "titre": "جلسة عمومية للتصويت على الجزء الأول من مشروع قانون المالية الخميس 14 نونبر 2024",
313
+ "date": "2024-11-15",
314
+ "langue": "ar",
315
+ "lien": "https://www.youtube.com/watch?v=ivO8kL0gNY8"
316
+ },
317
+ {
318
+ "id": 46,
319
+ "titre": "تقديم تقرير لجنة المالية ومناقشة الجزء 1 من مشروع قانون المالية وجواب الحكومة الخميس 14 نونبر 2024",
320
+ "date": "2024-11-14",
321
+ "langue": "ar",
322
+ "lien": "https://www.youtube.com/watch?v=eEGO97Uc1yY"
323
+ },
324
+ {
325
+ "id": 47,
326
+ "titre": "جلسة عمومية للأسئلة الشفوية الإثنين 11 نونبر 2024",
327
+ "date": "2024-11-12",
328
+ "langue": "ar",
329
+ "lien": "https://www.youtube.com/watch?v=IhfA7RHIx7g"
330
+ },
331
+ {
332
+ "id": 48,
333
+ "titre": "جلسة الأسئلة الشفهية الشهرية تليها جلسة تشريعية الاثنين 4 نونبر 2024",
334
+ "date": "2024-11-04",
335
+ "langue": "ar",
336
+ "lien": "https://www.youtube.com/watch?v=kO8osfodk9g"
337
+ },
338
+ {
339
+ "id": 49,
340
+ "titre": "جلسة مشتركة تخصص للاستماع لخطاب فخامة رئيس الجمهورية الفرنسية يوم الثلاثاء 29 أكتوبر 2024",
341
+ "date": "2024-10-29",
342
+ "langue": "ar",
343
+ "lien": "https://www.youtube.com/watch?v=04FeySn0yMA"
344
+ },
345
+ {
346
+ "id": 50,
347
+ "titre": "جلسة عمومية للأسئلة الشفوية تليها جلسة تخصص لاستكمال تكوين هياكل المجلس الإثنين 28 أكتوبر 2024",
348
+ "date": "2024-10-28",
349
+ "langue": "ar",
350
+ "lien": "https://www.youtube.com/watch?v=28U1wncCBRw"
351
+ },
352
+ {
353
+ "id": 51,
354
+ "titre": "جلسة عمومية للأسئلة الشفوية الإثنين 21 أكتوبر 2024",
355
+ "date": "2024-10-21",
356
+ "langue": "ar",
357
+ "lien": "https://www.youtube.com/watch?v=3aMKOxFLVg4"
358
+ },
359
+ {
360
+ "id": 52,
361
+ "titre": "جلسة عمومية مشتركة بين مجلسي البرلمان لتقديم مشروع قانون المالية للسنة المالية 2025",
362
+ "date": "2024-10-20",
363
+ "langue": "ar",
364
+ "lien": "https://www.youtube.com/watch?v=D2u-zfgvUj0"
365
+ },
366
+ {
367
+ "id": 53,
368
+ "titre": "جلسة عمومية للأسئلة الشفوية الإثنين 14 أكتوبر 2024",
369
+ "date": "2024-10-14",
370
+ "langue": "ar",
371
+ "lien": "https://www.youtube.com/watch?v=TNmhQHD-X8I"
372
+ },
373
+ {
374
+ "id": 54,
375
+ "titre": "جلسة عمومية لافتتاح دورة أكتوبر 2024",
376
+ "date": "2024-10-11",
377
+ "langue": "ar",
378
+ "lien": "https://www.youtube.com/watch?v=HSWFDnONQBA"
379
+ },
380
+ {
381
+ "id": 55,
382
+ "titre": "جلسة تشريعية تليها جلسة اختتام الدورة الخميس 25 يوليوز 2024",
383
+ "date": "2024-07-25",
384
+ "langue": "ar",
385
+ "lien": "https://www.youtube.com/watch?v=OR1C2g5CLuU"
386
+ },
387
+ {
388
+ "id": 56,
389
+ "titre": "مواصلة أشغال الجلسة العمومية التشريعية الثلاثاء 23 يوليوز 2024",
390
+ "date": "2024-07-23",
391
+ "langue": "ar",
392
+ "lien": "https://www.youtube.com/watch?v=sd_UAe3ExXM"
393
+ },
394
+ {
395
+ "id": 57,
396
+ "titre": "جلسة عمومية تشريعية الثلاثاء 23 يوليوز 2024",
397
+ "date": "2024-07-23",
398
+ "langue": "ar",
399
+ "lien": "https://www.youtube.com/watch?v=K2h4rktgGSc"
400
+ },
401
+ {
402
+ "id": 58,
403
+ "titre": "جلسة عمومية للأسئلة الشفوية تليها جلسة تشريعية الاثنين 22 يوليوز 2024",
404
+ "date": "2024-07-23",
405
+ "langue": "ar",
406
+ "lien": "https://www.youtube.com/watch?v=2T2rsDBhO84"
407
+ },
408
+ {
409
+ "id": 59,
410
+ "titre": "جلسة عمومية تشريعية تليها جلسة عمومية لمناقشة تقرير الث��اثاء 16 يوليوز 2024",
411
+ "date": "2024-07-17",
412
+ "langue": "ar",
413
+ "lien": "https://www.youtube.com/watch?v=dYcv2ZxCiZ8"
414
+ },
415
+ {
416
+ "id": 60,
417
+ "titre": "جلسة عمومية للأسئلة الشفهية الشهرية الموجهة إلى رئيس الحكومة الاثنين 15 يوليوز 2024",
418
+ "date": "2024-07-16",
419
+ "langue": "ar",
420
+ "lien": "https://www.youtube.com/watch?v=iko5JRpfxdc"
421
+ },
422
+ {
423
+ "id": 61,
424
+ "titre": "جلسة عمومية للأسئلة الشفوية تليها جلسة تشريعية الاثنين 8 يوليوز 2024",
425
+ "date": "2024-07-08",
426
+ "langue": "ar",
427
+ "lien": "https://www.youtube.com/watch?v=0-7QRBkJRz8"
428
+ },
429
+ {
430
+ "id": 62,
431
+ "titre": "جلسة عمومية للأسئلة الشفوية الإثنين 1 يوليوز 2024",
432
+ "date": "2024-07-02",
433
+ "langue": "ar",
434
+ "lien": "https://www.youtube.com/watch?v=Ng1u9Ss5eP8"
435
+ },
436
+ {
437
+ "id": 63,
438
+ "titre": "جلسة عمومية للأسئلة الشفوية تليها جلسة تشريعية الاثنين 24 يونيو 2024",
439
+ "date": "2024-06-24",
440
+ "langue": "ar",
441
+ "lien": "https://www.youtube.com/watch?v=k8iFP_rwvVc"
442
+ },
443
+ {
444
+ "id": 64,
445
+ "titre": "جلسة عمومية للأسئلة الشفهية الشهرية الموجهة إلى رئيس الحكومة الاثنين 10 يونيو 2024",
446
+ "date": "2024-06-11",
447
+ "langue": "ar",
448
+ "lien": "https://www.youtube.com/watch?v=FFLtXIaj62A"
449
+ },
450
+ {
451
+ "id": 65,
452
+ "titre": "جلسة عمومية للأسئلة الشفوية الإثنين 3 يونيو 2024",
453
+ "date": "2024-06-04",
454
+ "langue": "ar",
455
+ "lien": "https://www.youtube.com/watch?v=itSdUwTBWNU"
456
+ },
457
+ {
458
+ "id": 66,
459
+ "titre": "جلسة عمومية للأسئلة الشفوية الإثنين 27 ماي 2024",
460
+ "date": "2024-05-28",
461
+ "langue": "ar",
462
+ "lien": "https://www.youtube.com/watch?v=8ffOGMfwP9c"
463
+ },
464
+ {
465
+ "id": 67,
466
+ "titre": "جلسة عمومية للأسئلة الشفوية الإثنين 20 ماي 2024",
467
+ "date": "2024-05-21",
468
+ "langue": "ar",
469
+ "lien": "https://www.youtube.com/watch?v=hkBLtBV7McE"
470
+ },
471
+ {
472
+ "id": 68,
473
+ "titre": "جلسة عمومية للأسئلة الشفوية الإثنين 13 ماي 2024",
474
+ "date": "2024-05-14",
475
+ "langue": "ar",
476
+ "lien": "https://www.youtube.com/watch?v=D7WRTmnypTk"
477
+ },
478
+ {
479
+ "id": 69,
480
+ "titre": "جلسة عمومية لمناقشة الحصيلة المرحلية لعمل الحكومة الأربعاء 8 ماي 2024",
481
+ "date": "2024-05-08",
482
+ "langue": "ar",
483
+ "lien": "https://www.youtube.com/watch?v=0a1s4yRdTzU"
484
+ },
485
+ {
486
+ "id": 70,
487
+ "titre": "جلسة عمومية للأسئلة الشفوية يوم الإثنين 6 ماي 2024",
488
+ "date": "2024-05-07",
489
+ "langue": "ar",
490
+ "lien": "https://www.youtube.com/watch?v=J1p6wLdmUaY"
491
+ },
492
+ {
493
+ "id": 71,
494
+ "titre": "جلسة عمومية للأسئلة الشفوية يوم الإثنين 29 أبريل 2024",
495
+ "date": "2024-04-30",
496
+ "langue": "ar",
497
+ "lien": "https://www.youtube.com/watch?v=EFq0qWkzc9U"
498
+ },
499
+ {
500
+ "id": 72,
501
+ "titre": "جلسة عمومية مشتركة لتقديم الحصيلة المرحلية لعمل الحكومة الأربعاء 24 أبريل 2024",
502
+ "date": "2024-04-25",
503
+ "langue": "ar",
504
+ "lien": "https://www.youtube.com/watch?v=f14qnBRXou0"
505
+ },
506
+ {
507
+ "id": 73,
508
+ "titre": "جلسة عمومية تخصص لاستكمال هياكل المجلس الخميس 18 أبريل 2024",
509
+ "date": "2024-04-19",
510
+ "langue": "ar",
511
+ "lien": "https://www.youtube.com/watch?v=Z_f3ToIRU7A"
512
+ },
513
+ {
514
+ "id": 74,
515
+ "titre": "افتتاح الدورة الثانية من السنة التشريعية 2023 – 2024 وانتخاب رئيس مجلس النواب الجمعة 12 أبريل 2024",
516
+ "date": "2024-04-13",
517
+ "langue": "ar",
518
+ "lien": "https://www.youtube.com/watch?v=s2d1wkcSo40"
519
+ },
520
+ {
521
+ "id": 75,
522
+ "titre": "الجلسة الافتتاحية للدورة السابعة عشرة للجمعية البرلمانية للاتحاد من أجل المتوسط",
523
+ "date": "2024-02-16",
524
+ "langue": "ar",
525
+ "lien": "https://www.youtube.com/watch?v=dWbD4LIidfM"
526
+ },
527
+ {
528
+ "id": 76,
529
+ "titre": "جلسة لمناقشة تقرير المجلس الأعلى للحسابات تليها جلسة لاختتام الدورة الثلاثاء 6 فبراير 2024",
530
+ "date": "2024-02-07",
531
+ "langue": "ar",
532
+ "lien": "https://www.youtube.com/watch?v=OETDUlBKIws"
533
+ },
534
+ {
535
+ "id": 77,
536
+ "titre": "جلسة الأسئلة الشهرية الموجهة إلى رئيس الحكومة تليها جلسة تشريعية الاثنين 5 فبراير 2024",
537
+ "date": "2024-02-05",
538
+ "langue": "ar",
539
+ "lien": "https://www.youtube.com/watch?v=1hboI6upyEU"
540
+ },
541
+ {
542
+ "id": 78,
543
+ "titre": "جلسة عمومية مشتركة الثلاثاء 30 يناير 2024 لتقديم عرض عن أعمال المجلس الأعلى للحسابات برسم 2022-2023",
544
+ "date": "2024-01-30",
545
+ "langue": "ar",
546
+ "lien": "https://www.youtube.com/watch?v=hByEvXagRLU"
547
+ },
548
+ {
549
+ "id": 79,
550
+ "titre": "جلسة عمومية للأسئلة الأسبوعية الشفهية تليها جلسة تشريعية الاثنين 29 يناير 2024",
551
+ "date": "2024-01-30",
552
+ "langue": "ar",
553
+ "lien": "https://www.youtube.com/watch?v=VRNsOTF1Bb0"
554
+ },
555
+ {
556
+ "id": 80,
557
+ "titre": "جلسة عمومية للأسئلة الشفوية يوم الإثنين 22 يناير 2024",
558
+ "date": "2024-01-23",
559
+ "langue": "ar",
560
+ "lien": "https://www.youtube.com/watch?v=BzM-HR2SELE"
561
+ },
562
+ {
563
+ "id": 81,
564
+ "titre": "البرلمان المغربي يخلد الذكرى الستين لتأسيسه - الجلسة الأولى - الأربعاء 17 يناير 2024",
565
+ "date": "2024-01-18",
566
+ "langue": "ar",
567
+ "lien": "https://www.youtube.com/watch?v=ArBG6k88o20"
568
+ },
569
+ {
570
+ "id": 82,
571
+ "titre": "البرلمان المغربي يخلد الذكرى الستين لتأسيسه - الأربعاء 17 يناير 2024",
572
+ "date": "2024-01-17",
573
+ "langue": "ar",
574
+ "lien": "https://www.youtube.com/watch?v=JcMgBFOEX68"
575
+ },
576
+ {
577
+ "id": 83,
578
+ "titre": "جلسة عمومية للأسئلة الشفوية يوم الإثنين 15 يناير 2024",
579
+ "date": "2024-01-16",
580
+ "langue": "ar",
581
+ "lien": "https://www.youtube.com/watch?v=9_35vf-YtRc"
582
+ },
583
+ {
584
+ "id": 84,
585
+ "titre": "جلسة عمومية للأسئلة الأسبوعية الشفهية يوم الاثنين 8 يناير 2024",
586
+ "date": "2024-01-09",
587
+ "langue": "ar",
588
+ "lien": "https://www.youtube.com/watch?v=0TFRrA_pYT0"
589
+ },
590
+ {
591
+ "id": 85,
592
+ "titre": "جلسة عمومية للأسئلة الأسبوعية الشفهية تليها جلسة تشريعية يوم الاثنين 25 دجنبر 2023",
593
+ "date": "2023-12-25",
594
+ "langue": "ar",
595
+ "lien": "https://www.youtube.com/watch?v=7JU6l_oTNQY"
596
+ },
597
+ {
598
+ "id": 86,
599
+ "titre": "جلسة عمومية للأسئلة الأسبوعية الشفوية الاثنين 18 دجنبر 2023",
600
+ "date": "2023-12-19",
601
+ "langue": "ar",
602
+ "lien": "https://www.youtube.com/watch?v=n5hI7HiuOq4"
603
+ },
604
+ {
605
+ "id": 87,
606
+ "titre": "جلسة عمومية للأسئلة الأسبوعية الشفوية يوم الاثنين 11 دجنبر 2023",
607
+ "date": "2023-12-12",
608
+ "langue": "ar",
609
+ "lien": "https://www.youtube.com/watch?v=IhTiR8vztZU"
610
+ },
611
+ {
612
+ "id": 88,
613
+ "titre": "جلسة عمومية للدراسة والتصويت على مشروع قانون المالية 2024 في قراءة ثانية الخميس 7 دجنبر 2023",
614
+ "date": "2023-12-07",
615
+ "langue": "ar",
616
+ "lien": "https://www.youtube.com/watch?v=9HaZ5L2SmdQ"
617
+ },
618
+ {
619
+ "id": 89,
620
+ "titre": "جلسة عمومية لمناقشة تقارير الثلاثاء 5 دجنبر 2023",
621
+ "date": "2023-12-05",
622
+ "langue": "ar",
623
+ "lien": "https://www.youtube.com/watch?v=tDg46drstIk"
624
+ },
625
+ {
626
+ "id": 90,
627
+ "titre": "جلسة عمومية للأسئلة الأسبوعية الشفوية يوم الاثنين 4 دجنبر 2023",
628
+ "date": "2023-12-05",
629
+ "langue": "ar",
630
+ "lien": "https://www.youtube.com/watch?v=lYjlVJRZRwI"
631
+ },
632
+ {
633
+ "id": 91,
634
+ "titre": "جلسة للأسئلة الشفهية الشهرية الموجهة إلى رئيس الحكومة تليها جلسة تشريعية الاثنين 27 نونبر 2023",
635
+ "date": "2023-11-27",
636
+ "langue": "ar",
637
+ "lien": "https://www.youtube.com/watch?v=5x9Ju6H9BxE"
638
+ },
639
+ {
640
+ "id": 92,
641
+ "titre": "جلسة عمومية للأسئلة الأسبوعية الشفوية يوم الاثنين 20 نونبر 2023",
642
+ "date": "2023-11-21",
643
+ "langue": "ar",
644
+ "lien": "https://www.youtube.com/watch?v=Gq8BpQULY3k"
645
+ },
646
+ {
647
+ "id": 93,
648
+ "titre": "تقديم تقارير اللجان حول الميزانيات الفرعية ومناقشة والتصويت على الجزء 2 الأربعاء 15 نونبر 2023",
649
+ "date": "2023-11-15",
650
+ "langue": "ar",
651
+ "lien": "https://www.youtube.com/watch?v=rtuCXsWdw-4"
652
+ },
653
+ {
654
+ "id": 94,
655
+ "titre": "جلسة عمومية للتصويت على الجزء الأول من مشروع قانون المالية الثلاثاء 14 نونبر 2023",
656
+ "date": "2023-11-15",
657
+ "langue": "ar",
658
+ "lien": "https://www.youtube.com/watch?v=cRgn5PeSnNA"
659
+ },
660
+ {
661
+ "id": 95,
662
+ "titre": "تقديم تقرير لجنة المالية والمناقشة العامة للجزء 1 من مشروع قانون المالية الثلاثاء 14 نونبر 2023",
663
+ "date": "2023-11-14",
664
+ "langue": "ar",
665
+ "lien": "https://www.youtube.com/watch?v=pIARmRSNGf0"
666
+ },
667
+ {
668
+ "id": 96,
669
+ "titre": "جلسة عمومية للأسئلة الأسبوعية الشفهية تليها جلسة تشريعية يوم الاثنين 13 نونبر 2023",
670
+ "date": "2023-11-14",
671
+ "langue": "ar",
672
+ "lien": "https://www.youtube.com/watch?v=rBrqBhXm8i0"
673
+ },
674
+ {
675
+ "id": 97,
676
+ "titre": "جلسة عمومية تشريعية الجمعة 3 نونبر 2023",
677
+ "date": "2023-11-03",
678
+ "langue": "ar",
679
+ "lien": "https://www.youtube.com/watch?v=WodwRZzXFFQ"
680
+ },
681
+ {
682
+ "id": 98,
683
+ "titre": "جلسة عمومية للأسئلة الأسبوعية الشفوية تليها جلسة تشريعية يوم الاثنين 30 أكتوبر 2023",
684
+ "date": "2023-10-31",
685
+ "langue": "ar",
686
+ "lien": "https://www.youtube.com/watch?v=sAPczXp9fnw"
687
+ },
688
+ {
689
+ "id": 99,
690
+ "titre": "جلسة عمومية تشريعية يوم الثلاثاء 24 أكتوبر 2023 - الفترة المسائية",
691
+ "date": "2023-10-25",
692
+ "langue": "ar",
693
+ "lien": "https://www.youtube.com/watch?v=z029Wu_hLcE"
694
+ },
695
+ {
696
+ "id": 100,
697
+ "titre": "جلسة عمومية تشريعية يوم الثلاثاء 24 أكتوبر 2023",
698
+ "date": "2023-10-25",
699
+ "langue": "ar",
700
+ "lien": "https://www.youtube.com/watch?v=A1nc3ktpU0w"
701
+ },
702
+ {
703
+ "id": 101,
704
+ "titre": "جلسة عمومية مشتركة لتقديم تصريح حول الدعم الاجتماعي المباشر الإثنين 23 أكتوبر 2023",
705
+ "date": "2023-10-24",
706
+ "langue": "ar",
707
+ "lien": "https://www.youtube.com/watch?v=dlhR00GAnmM"
708
+ },
709
+ {
710
+ "id": 102,
711
+ "titre": "جلسة عمومية للأسئلة الأسبوعية الشفوية يوم الاثنين 23 أكتوبر 2023",
712
+ "date": "2023-10-24",
713
+ "langue": "ar",
714
+ "lien": "https://www.youtube.com/watch?v=YCTAwKQY5aA"
715
+ },
716
+ {
717
+ "id": 103,
718
+ "titre": "جلسة عمومية مشتركة لتقديم مشروع قانون المالية 2024 يوم الجمعة 20 أكتوبر 2023",
719
+ "date": "2023-10-21",
720
+ "langue": "ar",
721
+ "lien": "https://www.youtube.com/watch?v=fZmMV9rkExM"
722
+ },
723
+ {
724
+ "id": 104,
725
+ "titre": "جلسة عمومية للأسئلة الأسبوعية الشفوية يوم الاثنين 16 أكتوبر 2023",
726
+ "date": "2023-10-17",
727
+ "langue": "ar",
728
+ "lien": "https://www.youtube.com/watch?v=46w4n-00Qyk"
729
+ },
730
+ {
731
+ "id": 105,
732
+ "titre": "جلسة عمومية لافتتاح دورة أكتوبر 2023",
733
+ "date": "2023-10-14",
734
+ "langue": "ar",
735
+ "lien": "https://www.youtube.com/watch?v=n47Eifd7x04"
736
+ },
737
+ {
738
+ "id": 106,
739
+ "titre": "جلسة الأسئلة الشفهية، تليها جلسة تشريعية تليها جلسة تخصص لاختتام الدورة الاثنين 24 يوليوز 2023",
740
+ "date": "2023-07-25",
741
+ "langue": "ar",
742
+ "lien": "https://www.youtube.com/watch?v=cSWot7-lFw8"
743
+ },
744
+ {
745
+ "id": 107,
746
+ "titre": "تتمة الجلسة السنوية لتقييم السياسات العمومية الثلاثاء 18 يوليوز 2023",
747
+ "date": "2023-07-18",
748
+ "langue": "ar",
749
+ "lien": "https://www.youtube.com/watch?v=Dvm8rJhOQ10"
750
+ },
751
+ {
752
+ "id": 108,
753
+ "titre": "الجلسة السنوية لتقييم السياسات العمومية الثلاثاء 18 يوليوز 2023",
754
+ "date": "2023-07-19",
755
+ "langue": "ar",
756
+ "lien": "https://www.youtube.com/watch?v=MIJekpveSNM"
757
+ },
758
+ {
759
+ "id": 109,
760
+ "titre": "جلسة عمومية للأسئلة الشفهية الشهرية تليها جلسة عمومية تشريعية الاثنين 17 يوليوز 2023",
761
+ "date": "2023-07-17",
762
+ "langue": "ar",
763
+ "lien": "https://www.youtube.com/watch?v=upUFNNlYL00"
764
+ },
765
+ {
766
+ "id": 110,
767
+ "titre": "جلسة عمومية للأسئلة الأسبوعية الشفوية يوم الاثنين 10 يوليوز 2023",
768
+ "date": "2023-07-11",
769
+ "langue": "ar",
770
+ "lien": "https://www.youtube.com/watch?v=ieVbaqGaZnk"
771
+ },
772
+ {
773
+ "id": 111,
774
+ "titre": "جلسة عمومية للأسئلة الشفوية الاثنين 3 يوليوز 2023",
775
+ "date": "2023-07-04",
776
+ "langue": "ar",
777
+ "lien": "https://www.youtube.com/watch?v=BxhFI65T1lE"
778
+ },
779
+ {
780
+ "id": 112,
781
+ "titre": "جلسة عمومية للأسئلة الشفوية تليها جلسة ‏تشريعية الاثنين 26 يونيو 2023",
782
+ "date": "2023-06-26",
783
+ "langue": "ar",
784
+ "lien": "https://www.youtube.com/watch?v=3jSeZi42H0Y"
785
+ },
786
+ {
787
+ "id": 113,
788
+ "titre": "جلسة عمومية لمناقشة تقرير المجلس الأعلى للحسابات الثلاثاء 20 يونيو 2023",
789
+ "date": "2023-06-21",
790
+ "langue": "ar",
791
+ "lien": "https://www.youtube.com/watch?v=OJPiiBOGgOc"
792
+ },
793
+ {
794
+ "id": 114,
795
+ "titre": "جلسة عمومية للأسئلة الشفوية تليها جلسة ‏تشريعية الاثنين 19 يونيو 2023",
796
+ "date": "2023-06-19",
797
+ "langue": "ar",
798
+ "lien": "https://www.youtube.com/watch?v=Selyr7FRFuM"
799
+ },
800
+ {
801
+ "id": 115,
802
+ "titre": "Séance de clôture",
803
+ "date": "2023-06-16",
804
+ "langue": "ar",
805
+ "lien": "https://www.youtube.com/watch?v=UPqqsIq99RU"
806
+ },
807
+ {
808
+ "id": 116,
809
+ "titre": "Closing session",
810
+ "date": "2023-06-16",
811
+ "langue": "ar",
812
+ "lien": "https://www.youtube.com/watch?v=wnL5ZqbQ2Z0"
813
+ },
814
+ {
815
+ "id": 117,
816
+ "titre": "‏الجلسة ‏الختامية",
817
+ "date": "2023-06-16",
818
+ "langue": "ar",
819
+ "lien": "https://www.youtube.com/watch?v=AUzVyJNdxb0"
820
+ },
821
+ {
822
+ "id": 118,
823
+ "titre": "Suite et fin du débat général : Parlements et chefs religieux : promouvoir le dialogue - 2",
824
+ "date": "2023-06-16",
825
+ "langue": "ar",
826
+ "lien": "https://www.youtube.com/watch?v=GjMGZn_HqaI"
827
+ },
828
+ {
829
+ "id": 119,
830
+ "titre": "Continuation and closing of General Debate: Parliaments and religious leaders - 2",
831
+ "date": "2023-06-16",
832
+ "langue": "ar",
833
+ "lien": "https://www.youtube.com/watch?v=Mt8tnRftwJU"
834
+ },
835
+ {
836
+ "id": 120,
837
+ "titre": "‏متابعة ‏واختتام المناقشة العامة البرلمانات والزعماء الدينيون: تعزيز الحوار- 2",
838
+ "date": "2023-06-16",
839
+ "langue": "ar",
840
+ "lien": "https://www.youtube.com/watch?v=BH4VGJMPU1o"
841
+ },
842
+ {
843
+ "id": 121,
844
+ "titre": "Suite et fin du débat général : Parlements et chefs religieux : promouvoir le dialogue",
845
+ "date": "2023-06-15",
846
+ "langue": "ar",
847
+ "lien": "https://www.youtube.com/watch?v=n3N0WC-Y7to"
848
+ },
849
+ {
850
+ "id": 122,
851
+ "titre": "Continuation and closing of General Debate: Parliaments and religious leaders",
852
+ "date": "2023-06-15",
853
+ "langue": "ar",
854
+ "lien": "https://www.youtube.com/watch?v=9cHpMaWZcAU"
855
+ },
856
+ {
857
+ "id": 123,
858
+ "titre": "‏متابعة ‏واختتام المناقشة العامة البرلمانات والزعماء الدينيون: تعزيز الحوار",
859
+ "date": "2023-06-15",
860
+ "langue": "ar",
861
+ "lien": "https://www.youtube.com/watch?v=REKw7kC1kr0"
862
+ },
863
+ {
864
+ "id": 124,
865
+ "titre": "Continuation of the General Debate: Parliaments and religious leaders: Promoting dialogue",
866
+ "date": "2023-06-15",
867
+ "langue": "ar",
868
+ "lien": "https://www.youtube.com/watch?v=QVCZVHiBpWU"
869
+ },
870
+ {
871
+ "id": 125,
872
+ "titre": "Suite du débat général : Parlements et chefs religieux : promouvoir ledialogue",
873
+ "date": "2023-06-15",
874
+ "langue": "ar",
875
+ "lien": "https://www.youtube.com/watch?v=DI6Njuz_IDg"
876
+ },
877
+ {
878
+ "id": 126,
879
+ "titre": "‏متابعة المناقشة العامة البرلمانات والزعماء الدينيون: تعزيز الحوار",
880
+ "date": "2023-06-15",
881
+ "langue": "ar",
882
+ "lien": "https://www.youtube.com/watch?v=IcaPV3femuA"
883
+ },
884
+ {
885
+ "id": 127,
886
+ "titre": "General Debate: Parliaments and religious leaders: Promoting dialogue, Wednesday June 14 2023",
887
+ "date": "2023-06-14",
888
+ "langue": "ar",
889
+ "lien": "https://www.youtube.com/watch?v=XQk821llX8c"
890
+ },
891
+ {
892
+ "id": 128,
893
+ "titre": "Début du débat général : Parlements et chefs religieux :promouvoir le dialogue - mercredi 14/06/2023",
894
+ "date": "2023-06-14",
895
+ "langue": "ar",
896
+ "lien": "https://www.youtube.com/watch?v=4oIVvhXCb6c"
897
+ },
898
+ {
899
+ "id": 129,
900
+ "titre": "‏المناقشة العامة: البرلمانات وزعماء الدينيون: تعزيز الحوار - ‏الأربعاء 14 يونيو 2003",
901
+ "date": "2023-06-14",
902
+ "langue": "ar",
903
+ "lien": "https://www.youtube.com/watch?v=0X767JvkWEg"
904
+ },
905
+ {
906
+ "id": 130,
907
+ "titre": "المؤتمر حول الحوار بين الأديان - ‏ ‏مناقشة ‏رفيعة المستوى - ‏المحور 2:‏السلام ‏والاندماج ‏الاجتماعي",
908
+ "date": "2023-06-14",
909
+ "langue": "ar",
910
+ "lien": "https://www.youtube.com/watch?v=v7xqcSSDSSE"
911
+ },
912
+ {
913
+ "id": 131,
914
+ "titre": "Parliamentary Conference on Interfaith Dialogue - High-level panel – Track 2 (Peace and inclusion)",
915
+ "date": "2023-06-14",
916
+ "langue": "ar",
917
+ "lien": "https://www.youtube.com/watch?v=WN86GjumoW4"
918
+ },
919
+ {
920
+ "id": 132,
921
+ "titre": "Conférence sur le dialogue interconfessionnel - Débat de haut niveau – Volet 2 (Paix et inclusion)",
922
+ "date": "2023-06-14",
923
+ "langue": "ar",
924
+ "lien": "https://www.youtube.com/watch?v=5PPi_PIqExI"
925
+ },
926
+ {
927
+ "id": 133,
928
+ "titre": "Conférence sur le dialogue interconfessionnel - Débat de haut niveau – Volet 1 (État de droit)",
929
+ "date": "2023-06-14",
930
+ "langue": "ar",
931
+ "lien": "https://www.youtube.com/watch?v=iyVlcN7vIUE"
932
+ },
933
+ {
934
+ "id": 134,
935
+ "titre": "Parliamentary Conference on Interfaith Dialogue-High-level panel – Track 1 (The rule of law)",
936
+ "date": "2023-06-14",
937
+ "langue": "ar",
938
+ "lien": "https://www.youtube.com/watch?v=M8fXdS9eKe0"
939
+ },
940
+ {
941
+ "id": 135,
942
+ "titre": "المؤتمر البرلماني حول الحوار بين الأديان - ‏مناقشة رفيعة المستوى - الجزء الأول (سيادة القانون)",
943
+ "date": "2023-06-14",
944
+ "langue": "ar",
945
+ "lien": "https://www.youtube.com/watch?v=m9LiSTfWjSE"
946
+ },
947
+ {
948
+ "id": 136,
949
+ "titre": "Parliamentary Conference on Interfaith Dialogue - Opening session",
950
+ "date": "2023-06-13",
951
+ "langue": "ar",
952
+ "lien": "https://www.youtube.com/watch?v=llA73LyzQLc"
953
+ },
954
+ {
955
+ "id": 137,
956
+ "titre": "Conférence parlementaire sur le dialogue interconfessionnel - séance solennelle",
957
+ "date": "2023-06-13",
958
+ "langue": "ar",
959
+ "lien": "https://www.youtube.com/watch?v=4anoe_bQ_dg"
960
+ },
961
+ {
962
+ "id": 138,
963
+ "titre": "المؤتمر البرلماني حول الحوار بين الأديان - ‏الجلسة الافتتاحية",
964
+ "date": "2023-06-14",
965
+ "langue": "ar",
966
+ "lien": "https://www.youtube.com/watch?v=2v0XlCnrkL8"
967
+ },
968
+ {
969
+ "id": 139,
970
+ "titre": "جلسة للأسئلة الشفهية الشهرية الموجهة إلى رئيس الحكومة تليها جلسة تشريعية الاثنين 12 يونيو 2023",
971
+ "date": "2023-06-12",
972
+ "langue": "ar",
973
+ "lien": "https://www.youtube.com/watch?v=MMWdVq8oT-g"
974
+ },
975
+ {
976
+ "id": 140,
977
+ "titre": "جلسة عمومية للأسئلة الشفوية يوم الإثنين 5 يونيو 2023",
978
+ "date": "2023-06-06",
979
+ "langue": "ar",
980
+ "lien": "https://www.youtube.com/watch?v=yw0RxwrCadw"
981
+ },
982
+ {
983
+ "id": 141,
984
+ "titre": "جلسة عمومية للأسئلة الشفوية تليها جلسة تشريعية يوم الإثنين 29 مايو 2023",
985
+ "date": "2023-05-30",
986
+ "langue": "ar",
987
+ "lien": "https://www.youtube.com/watch?v=9CoLVOLukuI"
988
+ },
989
+ {
990
+ "id": 142,
991
+ "titre": "جلسة عمومية للأسئلة الشفوية الاثنين 22 ماي 2023",
992
+ "date": "2023-05-23",
993
+ "langue": "ar",
994
+ "lien": "https://www.youtube.com/watch?v=XFAPrQ8_jWM"
995
+ },
996
+ {
997
+ "id": 143,
998
+ "titre": "جلسة عمومية للأسئلة الشفوية تليها مباشرة جلسة عمومية لانتخاب رئيس لجنة العدل الاثنين 15 ماي 2023",
999
+ "date": "2023-05-15",
1000
+ "langue": "ar",
1001
+ "lien": "https://www.youtube.com/watch?v=3eqKW5-o7HQ"
1002
+ },
1003
+ {
1004
+ "id": 144,
1005
+ "titre": "جلسة للأسئلة الشهرية الموجهة لرئيس الحكومة تليها جلسة لانتخاب رئيس لجنة العدل الاثنين 8 ماي 2023",
1006
+ "date": "2023-05-08",
1007
+ "langue": "ar",
1008
+ "lien": "https://www.youtube.com/watch?v=T4PMFBP9gD0"
1009
+ },
1010
+ {
1011
+ "id": 145,
1012
+ "titre": "جلسة عمومية مشتركة يوم الثلاثاء 2 ماي 2023 لتقديم تقرير المجلس الأعلى للحسابات برسم سنة 2021",
1013
+ "date": "2023-05-03",
1014
+ "langue": "ar",
1015
+ "lien": "https://www.youtube.com/watch?v=Hu0XYy8gvHA"
1016
+ },
1017
+ {
1018
+ "id": 146,
1019
+ "titre": "جلسة عمومية تشريعية يوم الأربعاء 26 أبريل 2023",
1020
+ "date": "2023-04-26",
1021
+ "langue": "ar",
1022
+ "lien": "https://www.youtube.com/watch?v=ABInrwmjSh0"
1023
+ },
1024
+ {
1025
+ "id": 147,
1026
+ "titre": "جلسة الأسئلة الشفوية تليها مباشرة جلسة لانتخاب رئيس لجنة العدل الاثنين 17 أبريل 2023",
1027
+ "date": "2023-04-18",
1028
+ "langue": "ar",
1029
+ "lien": "https://www.youtube.com/watch?v=39WF9NGFMsY"
1030
+ },
1031
+ {
1032
+ "id": 148,
1033
+ "titre": "جلسة عمومية لافتتاح دورة أبريل 2023",
1034
+ "date": "2023-04-14",
1035
+ "langue": "ar",
1036
+ "lien": "https://www.youtube.com/watch?v=Zs9R1jVO2H8"
1037
+ },
1038
+ {
1039
+ "id": 149,
1040
+ "titre": "Conference in Moroccan Parliament on the hostile attacks against Morocco",
1041
+ "date": "2023-02-08",
1042
+ "langue": "ar",
1043
+ "lien": "https://www.youtube.com/watch?v=UBYeJVrdTXI"
1044
+ },
1045
+ {
1046
+ "id": 150,
1047
+ "titre": "Conferencia en el Parlamento marroquí dedicada a los ataques hostiles contra Marruecos",
1048
+ "date": "2023-02-08",
1049
+ "langue": "ar",
1050
+ "lien": "https://www.youtube.com/watch?v=mD1XBhqeBKg"
1051
+ },
1052
+ {
1053
+ "id": 151,
1054
+ "titre": "لقاء دراسي وإعلامي بالبرلمان حول الهجمات الصارخة والمتكررة للبرلمان الأوروبي ضد المغرب",
1055
+ "date": "2023-02-08",
1056
+ "langue": "ar",
1057
+ "lien": "https://www.youtube.com/watch?v=JcDMJ91ymW4"
1058
+ },
1059
+ {
1060
+ "id": 152,
1061
+ "titre": "Conférence-débat au Parlement sur les attaques flagrantes et répétées contre le Maroc au PE",
1062
+ "date": "2023-02-08",
1063
+ "langue": "ar",
1064
+ "lien": "https://www.youtube.com/watch?v=C8ZBgN3AgFU"
1065
+ },
1066
+ {
1067
+ "id": 153,
1068
+ "titre": "جلسة عمومية تشريعية تليها جلسة عمومية لاختتام الدورة يوم الثلاثاء 7 فبراير 2023",
1069
+ "date": "2023-02-07",
1070
+ "langue": "ar",
1071
+ "lien": "https://www.youtube.com/watch?v=emvNbCY1nLk"
1072
+ },
1073
+ {
1074
+ "id": 154,
1075
+ "titre": "جلسة عمومية للأسئلة الأسبوعية الشفوية يوم الاثنين 6 فبراير 2023",
1076
+ "date": "2023-02-06",
1077
+ "langue": "ar",
1078
+ "lien": "https://www.youtube.com/watch?v=BlLGvSXkLJs"
1079
+ },
1080
+ {
1081
+ "id": 155,
1082
+ "titre": "جلسة عمومية للأسئ��ة الشفهية الشهرية الموجهة لرئيس الحكومة تليها جلسة تشريعية الاثنين 30 يناير 2023",
1083
+ "date": "2023-01-30",
1084
+ "langue": "ar",
1085
+ "lien": "https://www.youtube.com/watch?v=Hh1MFRMChys"
1086
+ },
1087
+ {
1088
+ "id": 156,
1089
+ "titre": "جلسة عمومية للأسئلة الشفوية تليها جلسة تشريعية يوم الإثنين 23 يناير 2023",
1090
+ "date": "2023-01-23",
1091
+ "langue": "ar",
1092
+ "lien": "https://www.youtube.com/watch?v=wtIMbV04ebc"
1093
+ },
1094
+ {
1095
+ "id": 157,
1096
+ "titre": "Sesión plenaria conjunta sobre las recientes posiciones del Parlamento Europeo el lunes 23/01/2023",
1097
+ "date": "2023-01-23",
1098
+ "langue": "ar",
1099
+ "lien": "https://www.youtube.com/watch?v=4oKenNuDKZM"
1100
+ },
1101
+ {
1102
+ "id": 158,
1103
+ "titre": "Joint plenary sitting on the latest positions of the EUParl towards Morocco on Monday 01/23/2023",
1104
+ "date": "2023-01-23",
1105
+ "langue": "ar",
1106
+ "lien": "https://www.youtube.com/watch?v=rMMRPoyKR34"
1107
+ },
1108
+ {
1109
+ "id": 159,
1110
+ "titre": "جلسة عمومية مشتركة حول المواقف الأخيرة للبرلمان الأوروبي تجاه بلادنا الاثنين 23/01/2023",
1111
+ "date": "2023-01-23",
1112
+ "langue": "ar",
1113
+ "lien": "https://www.youtube.com/watch?v=iPhOENTEAYc"
1114
+ },
1115
+ {
1116
+ "id": 160,
1117
+ "titre": "‏جلسة عمومية لمناقشة تقرير يوم الثلاثاء 17 يناير 2023",
1118
+ "date": "2023-01-17",
1119
+ "langue": "ar",
1120
+ "lien": "https://www.youtube.com/watch?v=iMwjgzfkOHE"
1121
+ },
1122
+ {
1123
+ "id": 161,
1124
+ "titre": "جلسة عمومية للأسئلة الشفوية تليها جلسة تشريعية يوم الإثنين 16 يناير 2023",
1125
+ "date": "2023-01-16",
1126
+ "langue": "ar",
1127
+ "lien": "https://www.youtube.com/watch?v=ilXN_x6_2SM"
1128
+ },
1129
+ {
1130
+ "id": 162,
1131
+ "titre": "جلسة عمومية لمناقشة تقرير لجنة مراقبة المالية العامة الثلاثاء 10 يناير 2023",
1132
+ "date": "2023-01-10",
1133
+ "langue": "ar",
1134
+ "lien": "https://www.youtube.com/watch?v=ffclZJf8qKs"
1135
+ },
1136
+ {
1137
+ "id": 163,
1138
+ "titre": "جلسة عمومية للأسئلة الأسبوعية الشفوية يوم الاثنين 9 يناير 2023",
1139
+ "date": "2023-01-09",
1140
+ "langue": "ar",
1141
+ "lien": "https://www.youtube.com/watch?v=iZHLj-u-Z1w"
1142
+ },
1143
+ {
1144
+ "id": 164,
1145
+ "titre": "جلسة لمناقشة تقرير لجنة البنيات الأساسية حول الهيئة الوطنية لضبط الكهرباء الثلاثاء 3 يناير 2023",
1146
+ "date": "2023-01-03",
1147
+ "langue": "ar",
1148
+ "lien": "https://www.youtube.com/watch?v=OC9nbl4o45g"
1149
+ },
1150
+ {
1151
+ "id": 165,
1152
+ "titre": "جلسة عمومية للأسئلة الشفوية تليها جلسة تشريعية يوم الإثنين 2 يناير 2023",
1153
+ "date": "2023-01-02",
1154
+ "langue": "ar",
1155
+ "lien": "https://www.youtube.com/watch?v=2A7Jut2Kab0"
1156
+ },
1157
+ {
1158
+ "id": 166,
1159
+ "titre": "جلسة عمومية للأسئلة الأسبوعية الشفوية يوم الاثنين 26 دجنبر 2022",
1160
+ "date": "2022-12-26",
1161
+ "langue": "ar",
1162
+ "lien": "https://www.youtube.com/watch?v=l3OE1U6jW1E"
1163
+ },
1164
+ {
1165
+ "id": 167,
1166
+ "titre": "جلسة عمومية تشريعية يوم الثلاثاء 20 دجنبر 2022",
1167
+ "date": "2022-12-20",
1168
+ "langue": "ar",
1169
+ "lien": "https://www.youtube.com/watch?v=6SOQYue3o8A"
1170
+ },
1171
+ {
1172
+ "id": 168,
1173
+ "titre": "جلسة عمومية للأسئلة الأسبوعية الشفوية الاثنين 19 دجنبر 2022 تليها جلسة لانتخاب رئيس لجنة الداخلية",
1174
+ "date": "2022-12-19",
1175
+ "langue": "ar",
1176
+ "lien": "https://www.youtube.com/watch?v=5ZmChtpV4lg"
1177
+ },
1178
+ {
1179
+ "id": 169,
1180
+ "titre": "جلسة عمومية للأسئلة الشفهية الشهرية الموجهة لرئيس الحكومة حول السياسة العامة الاثنين 12 دجنبر 2022",
1181
+ "date": "2022-12-12",
1182
+ "langue": "ar",
1183
+ "lien": "https://www.youtube.com/watch?v=DBJFK9MsjlI"
1184
+ },
1185
+ {
1186
+ "id": 170,
1187
+ "titre": "جلسة عمومية للدراسة والتصويت على مشروع قانون المالية 2023 في قراءة ثانية الخميس 08 دجنبر 2022",
1188
+ "date": "2022-12-08",
1189
+ "langue": "ar",
1190
+ "lien": "https://www.youtube.com/watch?v=PIh3K0Haefc"
1191
+ },
1192
+ {
1193
+ "id": 171,
1194
+ "titre": "جلسة عمومية تشريعية يوم الأربعاء 7 دجنبر 2022",
1195
+ "date": "2022-12-07",
1196
+ "langue": "ar",
1197
+ "lien": "https://www.youtube.com/watch?v=28hbIow9vas"
1198
+ },
1199
+ {
1200
+ "id": 172,
1201
+ "titre": "جلسة عمومية للأسئلة الأسبوعية الشفوية يوم الاثنين 5 دجنبر 2022",
1202
+ "date": "2022-12-05",
1203
+ "langue": "ar",
1204
+ "lien": "https://www.youtube.com/watch?v=Upfu9pAHUyg"
1205
+ },
1206
+ {
1207
+ "id": 173,
1208
+ "titre": "جلسة عمومية للأسئلة الشفوية يوم الإثنين 28 نونبر 2022",
1209
+ "date": "2022-11-28",
1210
+ "langue": "ar",
1211
+ "lien": "https://www.youtube.com/watch?v=Go6Yfk_Jn7I"
1212
+ },
1213
+ {
1214
+ "id": 174,
1215
+ "titre": "جلسة عمومية للأسئلة الشفوية تليها جلسة تشريعية يوم الإثنين 21 نونبر 2022",
1216
+ "date": "2022-11-21",
1217
+ "langue": "ar",
1218
+ "lien": "https://www.youtube.com/watch?v=yXBdIjElSfM"
1219
+ },
1220
+ {
1221
+ "id": 175,
1222
+ "titre": "جلسة عمومية للأسئلة الأسبوعية الشفوية يوم الاثنين 14 نونبر 2022",
1223
+ "date": "2022-11-14",
1224
+ "langue": "ar",
1225
+ "lien": "https://www.youtube.com/watch?v=wVqSFZSu3zE"
1226
+ },
1227
+ {
1228
+ "id": 176,
1229
+ "titre": "جلسة عمومية لتقديم الميزانيات الفرعية والتصويت على الجزء 2 وعلى المشروع برمته الجمعة 11 نونبر 2022",
1230
+ "date": "2022-11-11",
1231
+ "langue": "ar",
1232
+ "lien": "https://www.youtube.com/watch?v=FNDizsGoYHc"
1233
+ },
1234
+ {
1235
+ "id": 177,
1236
+ "titre": "جلسة عمومية للتصويت على الجزء الأول من مشروع قانون المالية الخميس 10 نونبر 2022",
1237
+ "date": "2022-11-10",
1238
+ "langue": "ar",
1239
+ "lien": "https://www.youtube.com/watch?v=3IujmbovpeQ"
1240
+ },
1241
+ {
1242
+ "id": 178,
1243
+ "titre": "جلسة عمومية لتقديم التقرير والمناقشة العامة للجزء 1 من م ق م 2023 وجواب الحكومة الخميس 10 نونبر 2022",
1244
+ "date": "2022-11-10",
1245
+ "langue": "ar",
1246
+ "lien": "https://www.youtube.com/watch?v=wOlv2BPhP0A"
1247
+ },
1248
+ {
1249
+ "id": 179,
1250
+ "titre": "جلسة عمومية للأسئلة الشفوية تليها جلسة تشريعية يوم الإثنين 7 نونبر 2022",
1251
+ "date": "2022-11-07",
1252
+ "langue": "ar",
1253
+ "lien": "https://www.youtube.com/watch?v=98Fz6GmS1SE"
1254
+ }
1255
+ ]
output/title_cat_embeddings.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6dc7381ea48d8865435c1590c86cee6897a002cfa671cb765c15820dc09934da
3
+ size 11031680
output/title_cat_metadatas.json ADDED
The diff for this file is too large to render. See raw diff
 
output/youtube/chunks.csv ADDED
The diff for this file is too large to render. See raw diff
 
output/youtube/chunks_embedded.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e357316b4682a228ddd7f000a338540f0d2bf148eae8f5694d98603b5a1cbdfe
3
+ size 9256255
output/youtube/faiss_metadata.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e7bcb42f6fae8650be6a08c48f7f930867911ff20624deac6c7452df54840372
3
+ size 2844179
output/youtube/faiss_ytb.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:cf5ce15a3d85a3464d88d71ca19903f86a91ac46afcc67aab463b8f66dad28cf
3
+ size 2847789
output/youtube/parlement_transcript.csv ADDED
The diff for this file is too large to render. See raw diff
 
requirements.txt ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ beautifulsoup4==4.13.4
2
+ dotenv==0.9.9
3
+ faiss-cpu==1.11.0
4
+ google-api-python-client==2.174.0
5
+ gradio==5.38.2
6
+ langchain-google-genai==2.1.8
7
+ langdetect==1.0.9
8
+ langchain==0.3.26
9
+ langgraph==0.5.4
10
+ mcp==1.10.1
11
+ mcp-use==1.3.7
12
+ nest-asyncio==1.6.0
13
+ numpy==2.3.1
14
+ ollama==0.5.1
15
+ pandas==2.3.0
16
+ PyMuPDF==1.26.3
17
+ requests==2.32.4
18
+ sentence-transformers
19
+ sentencepiece==0.2.0
20
+ transformers==4.53.0
21
+ tqdm==4.67.1
22
+ yt-dlp==2025.6.30
23
+ youtube-transcript-api==1.1.0
24
+ fastapi==0.116.1
25
+ uvicorn==0.35.0
26
+
src/.DS_Store ADDED
Binary file (6.15 kB). View file
 
src/__init__.py ADDED
File without changes
src/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (173 Bytes). View file
 
src/agents/__pycache__/main_agent.cpython-311.pyc ADDED
Binary file (5.53 kB). View file
 
src/agents/__pycache__/rag_agent.cpython-311.pyc ADDED
Binary file (7.65 kB). View file
 
src/agents/main_agent.py ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langgraph.graph import StateGraph, END
2
+ from typing import TypedDict, List
3
+ from langchain_core.messages import BaseMessage, AIMessage
4
+ from langgraph.checkpoint.memory import MemorySaver
5
+ from src.mcp.client import summary_agent
6
+ from src.agents.rag_agent import rag_graph, invocation_state
7
+ from src.models.llm_wrapper import GeminiWrapper
8
+ import re
9
+ from src.utils.helpers import clean_agent_output, load_prompt_template
10
+ from src.configs.config import LOG_DIR
11
+ import logging
12
+ import os
13
+
14
+
15
+ # LOGGING SETUP
16
+ LOG_FILE = os.path.join(LOG_DIR, "Agents.log")
17
+ logging.basicConfig(
18
+ filename=LOG_FILE,
19
+ level=logging.INFO,
20
+ format='%(asctime)s - %(levelname)s - %(message)s',
21
+ datefmt='%Y-%m-%d %H:%M:%S'
22
+ )
23
+
24
+
25
+ llm = GeminiWrapper()
26
+ memory = MemorySaver()
27
+
28
+ # STATE
29
+ class MessagesState(TypedDict):
30
+ messages: List[BaseMessage]
31
+
32
+
33
+ # ROUTER
34
+ def route_query(state: dict) -> str:
35
+ query = state["messages"][-1].content.lower()
36
+
37
+ '''# Déterminer le type d'invocation
38
+ if "api" in query: # Juste un exemple, adapte selon tes besoins
39
+ invocation_state.invocation_type = "api"
40
+ else:
41
+ invocation_state.invocation_type = "chatbot"'''
42
+
43
+ # Inline classification prompt
44
+ prompt = f"""
45
+ You are a query router. Classify the following user query into one of two categories:
46
+ - "rag": if the query requires retrieving factual or external information.
47
+ - "summary": if the query asks to summarize document or youtube session from previous messages.
48
+
49
+ Respond with only one word: either "rag" or "summary".
50
+
51
+ User query: "{query}"
52
+ """
53
+
54
+ try:
55
+ response = llm.generate(prompt)
56
+ except Exception as e:
57
+ logging.error(f"Error generating routing response: {e}")
58
+ return "rag" # fallback routing
59
+
60
+ logging.info(f"Raw LLM response: {response!r}")
61
+ decision = response.strip().lower().split()[0]
62
+
63
+ logging.info(f"Routing decision for query '{query}': {decision}")
64
+ if decision not in ("summary", "rag"):
65
+ logging.warning(f"Unexpected routing result '{decision}', defaulting to 'rag'")
66
+ return "rag"
67
+
68
+ return decision
69
+
70
+ # MCP NODE
71
+ async def mcp_node(state: MessagesState) -> dict:
72
+ user_message = state["messages"][-1].content
73
+ logging.info(f"MCP agent input: {user_message}")
74
+ try:
75
+ raw_result = await summary_agent.run(user_message)
76
+ logging.info(f"MCP raw output: {raw_result}")
77
+ clean_result = clean_agent_output(raw_result)
78
+ logging.info(f"MCP cleaned output: {clean_result}")
79
+ return {"messages": [AIMessage(content=clean_result)]}
80
+ except Exception as e:
81
+ logging.error(f"Error in MCP agent: {e}")
82
+ return {"messages": [AIMessage(content="Une erreur est survenue avec l’agent MCP.")]}
83
+
84
+ # GRAPH DEFINITION
85
+ builder = StateGraph(MessagesState)
86
+
87
+ builder.add_node("router", lambda state: {"messages": state["messages"]}) # Dummy pass-through node
88
+ builder.add_node("rag", rag_graph) # RAG graph
89
+ builder.add_node("summary", mcp_node) # MCP node
90
+
91
+ builder.set_entry_point("router")
92
+ builder.add_conditional_edges("router", lambda state: route_query(state), {
93
+ "rag": "rag",
94
+ "summary": "summary"
95
+ })
96
+ builder.add_edge("rag", END)
97
+ builder.add_edge("summary", END)
98
+
99
+ multi_agent_graph = builder.compile(checkpointer=memory)
100
+
src/agents/rag_agent.py ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys
2
+ import os
3
+ sys.path.append(os.getcwd())
4
+
5
+ from langgraph.graph import START, StateGraph, MessagesState
6
+ from langgraph.prebuilt import ToolNode
7
+ from langchain_core.messages import SystemMessage
8
+ from langgraph.prebuilt import tools_condition
9
+ from langchain_core.tools import tool
10
+ from src.rag.documents_rag_pipeline import RAGPipeline
11
+ from src.rag.youtube_rag_pipeline import YouTubeRAGPipeline
12
+ from src.models.llm_wrapper import GeminiWrapper
13
+ from src.utils.search_docs_utils import search_relevant_documents
14
+ from src.configs.config import LOG_DIR
15
+ import logging
16
+ import os
17
+
18
+ # LOGGING SETUP
19
+ LOG_FILE = os.path.join(LOG_DIR, "Agents.log")
20
+ logging.basicConfig(
21
+ filename=LOG_FILE,
22
+ level=logging.INFO,
23
+ format='%(asctime)s - %(levelname)s - %(message)s',
24
+ datefmt='%Y-%m-%d %H:%M:%S'
25
+ )
26
+
27
+ # PIPELINE INIT
28
+ doc_rag_pipeline = RAGPipeline()
29
+ ytb_rag_pipeline = YouTubeRAGPipeline()
30
+
31
+ # TOOLS
32
+ @tool
33
+ def search_legal_documents(query: str) -> str:
34
+ """Search Moroccan **legal codes, decrees, and PDFs**. Use this tool when user asks about Moroccan **laws, articles, codes, legal references**, or related content."""
35
+ logging.info(f"Tool call: search_legal_documents with input: {query}")
36
+ try:
37
+ relevant_docs = search_relevant_documents(query, top_k=3)
38
+ results = doc_rag_pipeline.get_top_docs_chunks_for_query(query, relevant_docs['results'])
39
+ output = "\n".join([f"{r['text']}\n(Source: {r['pdf_link']})" for r in results])
40
+ logging.info(f"Tool result (search_legal_documents): {output}")
41
+ return output
42
+ except Exception as e:
43
+ logging.error(f"Error in search_legal_documents: {e}")
44
+ return "Une erreur est survenue lors de la recherche des documents légaux."
45
+
46
+ @tool
47
+ def search_youtube_transcripts(query: str) -> str:
48
+ """Search Moroccan **Parliament YouTube videos** (debates, speeches, questions, sessions). Use this tool when user asks about **video content** or **what someone said**."""
49
+ logging.info(f"Tool call: search_youtube_transcripts with input: {query}")
50
+ try:
51
+ results = ytb_rag_pipeline.search(query)
52
+ output = "\n".join([f"{r['texte']}\n(Source: {r['lien']})" for r in results])
53
+ logging.info(f"Tool result (search_youtube_transcripts): {output}")
54
+ return output
55
+ except Exception as e:
56
+ logging.error(f"Error in search_youtube_transcripts: {e}")
57
+ return "Une erreur est survenue lors de la recherche dans les transcriptions YouTube."
58
+
59
+ tools = [search_legal_documents, search_youtube_transcripts]
60
+
61
+ # LLM SETUP
62
+ llm = GeminiWrapper()
63
+ llm_with_tools = llm.bind_tools(tools)
64
+
65
+ # SYSTEM MESSAGE
66
+ #sys_msg = SystemMessage(content="""
67
+ #You are a helpful assistant specialized in answering user questions related to Moroccan Parliament YouTube videos and legal documents.
68
+ #Your response must be strictly in the same language as the user’s query.
69
+ #Provide accurate answers and include relevant sources (YouTube video links or PDF document links) in your response.
70
+ #""")
71
+
72
+ # LLM NODE
73
+ def assistant(state: MessagesState):
74
+ # Utiliser l'état d'invocation global
75
+ invocation_type = invocation_state.invocation_type
76
+
77
+ print(invocation_type)
78
+ # Créer le SystemMessage selon le type d'invocation
79
+ if invocation_type == "chatbot":
80
+ sys_msg = SystemMessage(content="""
81
+ You are a helpful assistant specialized in answering user questions related to Moroccan Parliament YouTube videos and legal documents.
82
+ Your response must be strictly in the same language as the user’s query.
83
+ Provide accurate answers and include relevant sources (YouTube video links or PDF document links) in your response.
84
+ """)
85
+ else :
86
+ sys_msg = SystemMessage(content="""
87
+ You are a helpful assistant for an API that answers user questions related to Moroccan Parliament YouTube videos and legal documents.
88
+ Ensure your responses are concise and formatted appropriately for API output. Your response should be maximum 100 words.
89
+ Your response shoud be in json format like that : {"text response" : "", "sources" : ""}
90
+ """)
91
+ user_msg = state["messages"][-1].content
92
+ logging.info(f"User input: {user_msg}")
93
+ try:
94
+ result = llm_with_tools.invoke([sys_msg] + state["messages"])
95
+ logging.info(f"🤖 Model Output: {result}")
96
+ return {"messages": [result]}
97
+ except Exception as e:
98
+ logging.error(f"LLM invocation failed: {e}")
99
+ return {"messages": [SystemMessage(content="Une erreur est survenue avec le modèle.")]}
100
+
101
+ class InvocationState:
102
+ def __init__(self):
103
+ self.invocation_type = None
104
+
105
+ # Créer une instance de l'état d'invocation
106
+ invocation_state = InvocationState()
107
+
108
+ # GRAPH SETUP
109
+ builder = StateGraph(MessagesState)
110
+
111
+ builder.add_node("llm_assistant", assistant)
112
+ builder.add_node("tools", ToolNode(tools))
113
+
114
+ builder.add_edge(START, "llm_assistant")
115
+ builder.add_conditional_edges("llm_assistant", tools_condition)
116
+ builder.add_edge("tools", "llm_assistant")
117
+
118
+ rag_graph = builder.compile()
src/api/__pycache__/chatbot_api.cpython-311.pyc ADDED
Binary file (2.14 kB). View file
 
src/api/chatbot_api.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException
2
+ from pydantic import BaseModel
3
+ from langchain_core.messages import HumanMessage
4
+ from src.agents.main_agent import multi_agent_graph
5
+ from src.agents.rag_agent import invocation_state
6
+
7
+ import time
8
+
9
+ invocation_state.invocation_type = 'api'
10
+
11
+ app = FastAPI()
12
+
13
+ # Modèle Pydantic pour valider l'entrée de l'utilisateur
14
+ class UserInput(BaseModel):
15
+ question: str
16
+
17
+ @app.post("/ask")
18
+ async def ask_question(user_input: UserInput):
19
+ messages = [HumanMessage(content=user_input.question)]
20
+ config = {"configurable": {"thread_id": "1"}}
21
+
22
+ # Mesurer le temps d'exécution
23
+ start_time = time.time()
24
+
25
+ try:
26
+ result = await multi_agent_graph.ainvoke({"messages": messages}, config=config)
27
+ except Exception as e:
28
+ raise HTTPException(status_code=500, detail=str(e))
29
+
30
+ end_time = time.time()
31
+ execution_time = end_time - start_time # Temps écoulé
32
+
33
+ # Retourner la réponse
34
+ response_message = result["messages"][-1].content
35
+ print(f"Temps d'exécution: {execution_time:.4f} secondes")
36
+ return {"response": response_message, "execution_time": execution_time}
src/configs/.env ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ GEMINI_API_KEY=AIzaSyBOdGCKrcmyrcz0DyR86fKRf3klT5a7kY8
2
+
src/configs/__pycache__/config.cpython-311.pyc ADDED
Binary file (1.65 kB). View file
 
src/configs/config.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pathlib import Path
2
+ import os
3
+
4
+ BASE_DIR = Path(__file__).resolve().parents[2]
5
+ OUTPUT_DIR = BASE_DIR / "output"
6
+
7
+ # Docs paths
8
+ METADATA_FILE = BASE_DIR / "dataset" / "docs_metadata.csv"
9
+
10
+ CHUNKS_FILE = OUTPUT_DIR / "documents" / "chunks.json"
11
+ EMBEDDINGS_FILE = OUTPUT_DIR / "documents" / "embeddings.npy"
12
+ FAISS_INDEX_FILE = OUTPUT_DIR / "documents" / "faiss_docs.bin"
13
+
14
+ # Ytb paths
15
+ RAW_CSV = OUTPUT_DIR / "youtube" / "parlement_transcript.csv"
16
+ PROCESSED_CHUNKS_CSV = OUTPUT_DIR / "youtube" / "chunks.csv"
17
+ FAISS_INDEX_FILE_YT = OUTPUT_DIR / "youtube" / "faiss_ytb.bin"
18
+ FAISS_METADATA_FILE_YT = OUTPUT_DIR / "youtube" / "faiss_metadata.pkl"
19
+
20
+
21
+ # Ensure parent directories exist
22
+ (OUTPUT_DIR / "documents").mkdir(parents=True, exist_ok=True)
23
+ (OUTPUT_DIR / "youtube").mkdir(parents=True, exist_ok=True)
24
+ (BASE_DIR / "dataset").mkdir(parents=True, exist_ok=True)
25
+
26
+
27
+ # Log directory
28
+ LOG_DIR = BASE_DIR / "logs"
29
+ os.makedirs(LOG_DIR, exist_ok=True)
30
+
31
+ # Processing settings
32
+ MAX_TOKENS = 512 # Chunk size
33
+ BATCH_SIZE = 32 # Embedding batch size
34
+ TOP_K=5
35
+
36
+ # Embedding model (multilingual for Arabic and French)
37
+ YT_EMBEDDING_MODEL = "paraphrase-multilingual-mpnet-base-v2"
38
+ EMBEDDING_MODEL = "paraphrase-multilingual-mpnet-base-v2"
39
+ LLM_MODEL = "gemini-2.5-flash" # Lightweight LLM for CPU
40
+
41
+ # Max docs and videos to process
42
+ MAX_DOCS = 540
43
+ MAX_VIDEOS = 5
44
+
45
+
src/configs/mcp_config.json ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "mcpServers": {
3
+ "summary-server": {
4
+ "command": "python",
5
+ "args": ["-m", "src.mcp.server"]
6
+ }
7
+ }
8
+ }
src/docs_embd/__pycache__/embed.cpython-311.pyc ADDED
Binary file (2.68 kB). View file
 
src/docs_embd/__pycache__/index.cpython-311.pyc ADDED
Binary file (1.9 kB). View file
 
src/docs_embd/__pycache__/preprocessing.cpython-311.pyc ADDED
Binary file (5.3 kB). View file
 
src/docs_embd/embed.py ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sentence_transformers import SentenceTransformer
2
+ from src.utils.helpers import load_chunks_from_disk, save_embeddings
3
+ from src.configs.config import CHUNKS_FILE, EMBEDDINGS_FILE, EMBEDDING_MODEL, BATCH_SIZE, LOG_DIR
4
+ import numpy as np
5
+ import logging
6
+ import os
7
+
8
+ LOG_FILE = os.path.join(LOG_DIR, "docs_preprocessing.log")
9
+ '''logging.basicConfig(
10
+ filename=LOG_FILE,
11
+ level=logging.INFO,
12
+ format="%(asctime)s - %(levelname)s - %(message)s",
13
+ datefmt="%Y-%m-%d %H:%M:%S",
14
+ )'''
15
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s %(message)s')
16
+
17
+ def generate_embeddings():
18
+ """Generate embeddings for all chunks."""
19
+ model = SentenceTransformer(EMBEDDING_MODEL)
20
+ chunks_data = load_chunks_from_disk(CHUNKS_FILE)
21
+
22
+ #all_chunks = [item["chunks"] for item in chunks_data]
23
+ all_chunks = [chunk for item in chunks_data for chunk in item["chunks"]]#used this instead to avoid having a list of list
24
+
25
+
26
+ if not all_chunks:
27
+ logging.warning("No chunks to embed")
28
+ return np.array([]), []
29
+
30
+ # Batch embedding
31
+ embeddings = []
32
+ for i in range(0, len(all_chunks), BATCH_SIZE):
33
+ batch = all_chunks[i:i + BATCH_SIZE]
34
+ batch_texts = [chunk["text"] for chunk in batch]
35
+ batch_embeddings = model.encode(batch_texts, convert_to_tensor=False, show_progress_bar=True)
36
+ embeddings.extend(batch_embeddings)
37
+ logging.info(f"Embedded batch {i // BATCH_SIZE + 1}")
38
+
39
+
40
+ embeddings = np.array(embeddings)
41
+ save_embeddings(embeddings, EMBEDDINGS_FILE)#the saved file is in .gitignore but gonna be used in indexing
42
+ return embeddings, all_chunks
src/docs_embd/index.py ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import faiss
2
+ import numpy as np
3
+ from src.utils.helpers import load_embeddings
4
+ from src.configs.config import EMBEDDINGS_FILE, FAISS_INDEX_FILE, LOG_DIR
5
+ import logging
6
+ import os
7
+
8
+ LOG_FILE = os.path.join(LOG_DIR, "docs_preprocessing.log")
9
+ logging.basicConfig(
10
+ filename=LOG_FILE,
11
+ level=logging.INFO,
12
+ format="%(asctime)s - %(levelname)s - %(message)s",
13
+ datefmt="%Y-%m-%d %H:%M:%S",
14
+ )
15
+
16
+ def create_faiss_index():
17
+ """Create and save a FAISS index from embeddings."""
18
+ embeddings = load_embeddings(EMBEDDINGS_FILE)
19
+ if embeddings.size == 0:
20
+ logging.warning("No embeddings to index")
21
+ return None
22
+
23
+ dimension = embeddings.shape[1]
24
+ num_vectors = len(embeddings)
25
+
26
+ logging.info(f"Using IndexFlatL2 for {num_vectors} vectors")
27
+ index = faiss.IndexFlatL2(dimension)
28
+ index.add(embeddings)
29
+
30
+ '''# Use simple flat index for small datasets (< 1000 vectors)
31
+ # Use IVF index for larger datasets
32
+ if num_vectors < 1000:
33
+ logging.info(f"Using IndexFlatL2 for {num_vectors} vectors")
34
+ index = faiss.IndexFlatL2(dimension)
35
+ index.add(embeddings)
36
+ else:
37
+ logging.info(f"Using IndexIVFFlat for {num_vectors} vectors")
38
+ # For IVF, we need at least 30x more vectors than clusters
39
+ nlist = min(100, max(1, num_vectors))
40
+ quantizer = faiss.IndexFlatL2(dimension)
41
+ index = faiss.IndexIVFFlat(quantizer, dimension, nlist, faiss.METRIC_L2)
42
+ index.train(embeddings)
43
+ index.add(embeddings)'''
44
+
45
+ faiss.write_index(index, str(FAISS_INDEX_FILE))
46
+ logging.info(f"FAISS index created and saved to {FAISS_INDEX_FILE} with {index.ntotal} vectors")
47
+ return index
src/docs_embd/preprocessing.py ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from src.utils.helpers import clean_text, chunk_text
2
+ from src.configs.config import MAX_TOKENS, LOG_DIR
3
+ from src.utils.helpers import clean_text, chunk_text
4
+ from src.configs.config import MAX_TOKENS, LOG_DIR
5
+ import requests
6
+ import fitz # PyMuPDF
7
+ from io import BytesIO
8
+ import pandas as pd
9
+ import logging
10
+ import os
11
+
12
+ LOG_FILE = os.path.join(LOG_DIR, "docs_preprocessing.log")
13
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s %(message)s')
14
+
15
+ def extract_and_clean_pdf_from_url(pdf_url, pdf_title, doc_id, faiss_index_start):
16
+ """Extract, clean, and chunk PDF text directly from URL (no local file)."""
17
+ try:
18
+ response = requests.get(pdf_url)
19
+ response.raise_for_status()
20
+
21
+ all_text = ""
22
+ with fitz.open(stream=BytesIO(response.content), filetype="pdf") as doc:
23
+ for page in doc:
24
+ text = page.get_text("text")
25
+ if text:
26
+ text = text.encode('utf-8', errors='ignore').decode('utf-8')
27
+ all_text += text + "\n"
28
+
29
+ # Table extraction
30
+ try:
31
+ table_finder = page.find_tables()
32
+ if table_finder.tables:
33
+ logging.info(f"Tables detected on page {page.number}: {len(table_finder.tables)}")
34
+ for table in table_finder.tables:
35
+ for row in table.cells:
36
+ row_text = []
37
+ for cell in row:
38
+ if cell and isinstance(cell, str):
39
+ cell = cell.encode('utf-8', errors='ignore').decode('utf-8')
40
+ row_text.append(cell)
41
+ else:
42
+ row_text.append("")
43
+ table_row = " | ".join(row_text)
44
+ all_text += table_row + "\n"
45
+ all_text += "\n"
46
+ except Exception as table_error:
47
+ logging.warning(f"Table extraction failed for page {page.number} in {pdf_title}: {table_error}")
48
+
49
+ cleaned_text = clean_text(all_text)
50
+ chunks = chunk_text(cleaned_text, max_tokens=MAX_TOKENS)
51
+
52
+ chunk_data = [
53
+ {
54
+ "faiss_index": faiss_index_start + i,
55
+ "text": chunk
56
+ }
57
+ for i, chunk in enumerate(chunks)
58
+ ]
59
+
60
+ logging.info(f"Processed {pdf_title} from URL: {len(chunks)} chunks")
61
+ return {
62
+ "Id": doc_id,
63
+ "download_link": pdf_url,
64
+ "pdf_title": pdf_title,
65
+ "chunks": chunk_data
66
+ }
67
+
68
+ except Exception as e:
69
+ logging.error(f"Error processing {pdf_title} from URL {pdf_url}: {e}")
70
+ return {
71
+ "Id": doc_id,
72
+ "download_link": pdf_url,
73
+ "pdf_title": pdf_title,
74
+ "chunks": []
75
+ }
76
+
77
+
78
+ def preprocess_pdfs_from_csv(csv_path, max_docs=None):
79
+ metadata = pd.read_csv(csv_path)
80
+ if max_docs:
81
+ metadata = metadata.head(max_docs)
82
+
83
+ chunks_data = []
84
+ faiss_index_start = 0
85
+
86
+ for _, row in metadata.iterrows():
87
+ doc_id = row["Id"]
88
+ pdf_title = row["Nom du document"]
89
+ pdf_url = row["Lien"]
90
+
91
+ chunk_data = extract_and_clean_pdf_from_url(pdf_url, pdf_title, doc_id, faiss_index_start)
92
+ chunks_data.append(chunk_data)
93
+ faiss_index_start += len(chunk_data["chunks"])
94
+
95
+ return chunks_data
src/main.py ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from langchain_core.messages import HumanMessage, AIMessage
3
+ from src.agents.main_agent import multi_agent_graph
4
+ from src.agents.rag_agent import invocation_state
5
+ from src.configs.config import LOG_DIR
6
+ import logging
7
+ import os
8
+
9
+ LOG_FILE = os.path.join(LOG_DIR, "Agents.log")
10
+ logging.basicConfig(
11
+ filename=LOG_FILE,
12
+ level=logging.INFO,
13
+ format='%(asctime)s - %(levelname)s - %(message)s',
14
+ datefmt='%Y-%m-%d %H:%M:%S'
15
+ )
16
+
17
+ import pandas as pd
18
+
19
+ invocation_state.invocation_type = 'chatbot'
20
+
21
+ class GradioChatbotApp:
22
+ def __init__(self):
23
+ graph_img = multi_agent_graph.get_graph(xray=True).draw_mermaid_png()
24
+ os.makedirs("docs", exist_ok=True)
25
+ with open("docs/full_graph.png", "wb") as f:
26
+ f.write(graph_img)
27
+
28
+ async def process_chat(self, history, user_input):
29
+ messages = []
30
+ for user, bot in history:
31
+ messages.append(HumanMessage(content=user))
32
+ messages.append(AIMessage(content=bot))
33
+ messages.append(HumanMessage(content=user_input))
34
+
35
+ logging.info(f"User query: {user_input}")
36
+ config = {"configurable": {"thread_id": "1"}}
37
+ result = await multi_agent_graph.ainvoke({"messages": messages}, config=config)
38
+ bot_msg = result["messages"][-1].content
39
+ history.append((user_input, bot_msg))
40
+ return history, ""
41
+
42
+ def create_interface(self):
43
+ # Load CSV and keep only needed columns
44
+ csv_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "../dataset/docs_metadata.csv"))
45
+ if os.path.exists(csv_path):
46
+ df_full = pd.read_csv(csv_path)
47
+ df = df_full[["Catégorie", "Nom du document", "Lien"]]
48
+ else:
49
+ df = pd.DataFrame(columns=["Catégorie", "Nom du document", "Lien"])
50
+
51
+ # Absolute path for logo
52
+ logo_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "docs", "logo.jpg"))
53
+
54
+ with gr.Blocks(title="HOLOKIA RAG/MCP", theme=gr.themes.Soft()) as demo:
55
+ with gr.Tab("Chatbot"):
56
+ # Centered logo
57
+ gr.HTML(f"""
58
+ <div style='display:flex; justify-content:center; align-items:center; margin-top:30px; margin-bottom:30px;'>
59
+ <img src="file://{logo_path}" style="width:110px; height:auto;" alt="Company Logo">
60
+ </div>
61
+ """)
62
+
63
+ gr.Markdown("""
64
+ ## HOLOKIA RAG/MCP Chatbot
65
+
66
+ Cette plateforme d’assistance juridique intelligente est dédiée à l’analyse et à l’interprétation du droit marocain ainsi qu’aux travaux parlementaires.
67
+
68
+ Elle s’appuie sur un système de génération augmentée par récupération (RAG), permettant de délivrer des réponses précises et documentées à partir des textes législatifs et des archives parlementaires.
69
+ """)
70
+
71
+ chatbot = gr.Chatbot(label="Assistant", type="tuples")
72
+ user_input = gr.Textbox(
73
+ label="Votre message",
74
+ placeholder="Posez une question sur la loi marocaine, le parlement, ou des documents légaux...",
75
+ scale=7
76
+ )
77
+
78
+ with gr.Row():
79
+ gr.Examples(
80
+ examples=[
81
+ ["ما هي العقوبات المقررة لبيع المشروبات الكحولية بدون رخصة؟"],
82
+ ["ما هو دور البرلمان حسب الدستور المغربي 2011 ؟"],
83
+ ["Quel est le role du parlement dans la Constitution marocaine 2011?"],
84
+ ["Comment est defini le droit de greve dans la Constitution ?"]
85
+ ],
86
+ inputs=user_input
87
+ )
88
+
89
+ with gr.Row():
90
+ send_btn = gr.Button("Envoyer", variant="primary")
91
+ clear_btn = gr.Button("Effacer la conversation")
92
+
93
+ state = gr.State([])
94
+
95
+ send_btn.click(self.process_chat, [chatbot, user_input], [chatbot, user_input])
96
+ user_input.submit(self.process_chat, [chatbot, user_input], [chatbot, user_input])
97
+ clear_btn.click(fn=lambda: [], inputs=None, outputs=chatbot)
98
+
99
+ with gr.Tab("Documents"):
100
+ gr.Markdown("## Liste des documents utilisés dans le RAG")
101
+ gr.DataFrame(df, label="Documents", interactive=False)
102
+
103
+ return demo
104
+
105
+ def launch(self):
106
+ logging.info("Launching Gradio app...")
107
+ demo = self.create_interface()
108
+ demo.launch(server_name="0.0.0.0", server_port=7860)
109
+
110
+ if __name__ == "__main__":
111
+ app = GradioChatbotApp()
112
+ app.launch()
src/mcp/__pycache__/client.cpython-311.pyc ADDED
Binary file (990 Bytes). View file
 
src/mcp/__pycache__/server.cpython-311.pyc ADDED
Binary file (8.8 kB). View file
 
src/mcp/client.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from mcp_use import MCPAgent, MCPClient
2
+ import os
3
+ from langchain_google_genai import ChatGoogleGenerativeAI
4
+ from dotenv import load_dotenv
5
+
6
+ load_dotenv(dotenv_path="src/configs/.env")
7
+
8
+ summary_client = MCPClient.from_config_file(os.path.join("src", "configs", "mcp_config.json"))
9
+
10
+ llm = ChatGoogleGenerativeAI(
11
+ model="gemini-2.5-flash",
12
+ temperature=0,
13
+ google_api_key=os.getenv("GEMINI_API_KEY")
14
+ )
15
+
16
+ summary_agent = MCPAgent(llm=llm, client=summary_client, max_steps=5, verbose=False)
17
+
src/mcp/server.py ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from mcp.server.fastmcp import FastMCP
2
+ from googleapiclient.discovery import build
3
+ from youtube_transcript_api import YouTubeTranscriptApi
4
+ from typing import List, Dict
5
+ from src.configs.config import RAW_CSV, CHUNKS_FILE, METADATA_FILE, LOG_DIR, PROCESSED_CHUNKS_CSV
6
+ from src.utils.helpers import load_metadata, load_chunks_from_disk, load_youtube_data, load_prompt_template
7
+ import logging
8
+ from dotenv import load_dotenv
9
+ import os
10
+
11
+
12
+ LOG_FILE = os.path.join(LOG_DIR, "Agents.log")
13
+ logging.basicConfig(
14
+ filename=LOG_FILE,
15
+ level=logging.INFO,
16
+ format='%(asctime)s - %(levelname)s - %(message)s',
17
+ datefmt='%Y-%m-%d %H:%M:%S'
18
+ )
19
+
20
+ load_dotenv()
21
+ api_key = os.getenv("YOUTUBE_API_KEY")
22
+ mcp = FastMCP("summary-server")
23
+
24
+ ytb_meta = load_youtube_data(RAW_CSV)
25
+ chunks_data = load_chunks_from_disk(CHUNKS_FILE)
26
+ metadata = load_metadata(METADATA_FILE)
27
+ chunked_transcript= load_youtube_data(PROCESSED_CHUNKS_CSV)
28
+
29
+
30
+ @mcp.tool()
31
+ async def fetch_new_youtube_transcripts(channel_id: str= "UCLmLW2hwH-kk9w8QrdX8uAA", max_videos: int = 2) -> List[Dict]:
32
+ """Fetch transcripts and metadata for the most recent YouTube videos from the specified channel."""
33
+ try:
34
+ youtube = build("youtube", "v3", developerKey=api_key)
35
+ request = youtube.search().list(part="id,snippet", channelId=channel_id, maxResults=max_videos, order="date")
36
+ response = request.execute()
37
+ except Exception as e:
38
+ logging.error(f"Error fetching YouTube data: {e}")
39
+ return []
40
+
41
+ results = []
42
+ for item in response.get("items", []):
43
+ try:
44
+ if isinstance(item.get("id"), dict) and "videoId" in item.get("id", {}):
45
+ vid = item["id"]["videoId"]
46
+ try:
47
+ transcript = YouTubeTranscriptApi.get_transcript(vid, languages=["ar", "fr", "en"])
48
+ text = " ".join([entry["text"] for entry in transcript])
49
+ results.append({
50
+ "id": vid,
51
+ "titre": item["snippet"]["title"],
52
+ "date": item["snippet"]["publishedAt"],
53
+ "sous-titre": text,
54
+ "lien": f"https://www.youtube.com/watch?v={vid}"
55
+ })
56
+ except Exception as e:
57
+ logging.warning(f"Could not fetch transcript for {vid}: {e}")
58
+ continue
59
+ else:
60
+ logging.warning(f"Skipping item with invalid id structure: {item.get('id')}")
61
+ except Exception as e:
62
+ logging.warning(f"Error processing item {item}: {e}")
63
+ continue
64
+
65
+ # Ensure we return up to max_videos results
66
+ return results[:max_videos]
67
+
68
+
69
+ @mcp.prompt(
70
+ name="summarize_doc_by_link",
71
+ description="Summarize a document using its download link"
72
+ )
73
+ async def summarize_doc_by_link(link: str):
74
+ """Summarize a document using its download link."""
75
+ # Find the document in chunks_data using the link
76
+ document = next((doc for doc in chunks_data if doc.get("download_link") == link), None)
77
+
78
+ if not document:
79
+ return f"Document with link '{link}' not found in chunks."
80
+
81
+ chunks = document.get("chunks", [])
82
+ full_text = "\n".join(chunk["text"] for chunk in chunks)
83
+ prompt_path = "src/prompts/summarize_doc.txt"
84
+ prompt = load_prompt_template(prompt_path, {
85
+ "full_text": full_text
86
+ })
87
+ return prompt
88
+
89
+ @mcp.prompt(
90
+ name="summarize_video_by_link",
91
+ description="Summarize a YouTube video from chunked CSV data using a sample of its transcript."
92
+ )
93
+ async def summarize_video_by_link(link: str):
94
+ """Summarize a YouTube video from chunked CSV data using a sample of its transcript."""
95
+
96
+ # Filter rows matching the given link
97
+ chunks = [row for row in chunked_transcript if row.get("lien") == link]
98
+
99
+ if not chunks:
100
+ return f"No chunks found for video with link '{link}'."
101
+
102
+ # Sort by chunk_id (assumes format like "1_0", "1_1", etc.)
103
+ try:
104
+ chunks.sort(key=lambda x: tuple(map(int, x["chunk_id"].split("_"))))
105
+ except Exception:
106
+ pass # fallback: leave order as-is
107
+
108
+ # smarter sampling
109
+ selected_chunks = sample_chunks(chunks, n=3)
110
+
111
+ # Extract metadata
112
+ title = selected_chunks[0]["titre"]
113
+ partial_transcript = "\n".join(chunk["texte"] for chunk in selected_chunks).strip()
114
+
115
+ if not partial_transcript:
116
+ return f"No transcript text found for the provided video link"
117
+
118
+ # Build prompt with disclaimer
119
+ prompt_path = "src/prompts/summarize_video.txt"
120
+ prompt = load_prompt_template(prompt_path, {
121
+ "title": title,
122
+ "transcript": partial_transcript
123
+ })
124
+ return prompt
125
+
126
+ def sample_chunks(chunks, n=3):
127
+ """Pick N evenly spaced chunks across the whole video."""
128
+
129
+ total = len(chunks)
130
+ if total <= n:
131
+ return chunks
132
+ step = total / n
133
+ return [chunks[int(i * step)] for i in range(n)]
134
+
135
+
136
+ if __name__ == "__main__":
137
+ # Initialize and run the server
138
+ mcp.run(transport='stdio')
src/models/__pycache__/llm_wrapper.cpython-311.pyc ADDED
Binary file (2.13 kB). View file
 
src/models/llm_wrapper.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from dotenv import load_dotenv
3
+ import logging
4
+ from langchain_google_genai import ChatGoogleGenerativeAI
5
+
6
+ load_dotenv(dotenv_path="src/configs/.env")
7
+
8
+ class GeminiWrapper:
9
+ def __init__(self, model_name="gemini-2.5-flash", temperature=0):
10
+ self.model_name = model_name
11
+ self.llm = ChatGoogleGenerativeAI(
12
+ model=model_name,
13
+ temperature=temperature,
14
+ google_api_key=os.getenv("GEMINI_API_KEY")
15
+ )
16
+
17
+ def generate(self, prompt, history=None):
18
+ if history:
19
+ # Prepend history to the prompt for context
20
+ #history_text = "\n".join([f"User: {h[0]}\nAssistant: {h[1]}" for h in history])
21
+ prompt = f"{history}\nUser: {prompt}"
22
+ return self._generate(prompt)
23
+
24
+ def _generate(self, prompt):
25
+ try:
26
+ return self.llm.invoke(prompt).content
27
+ except Exception as e:
28
+ logging.error(f"Gemini generation failed: {e}")
29
+ return "Error generating response."
30
+
31
+ def bind_tools(self, tools):
32
+ return self.llm.bind_tools(tools)
src/prompts/documents_rag_prompt.txt ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ You are a Moroccan legal assistant specialized in Moroccan law, parliament, and legal procedures. Based on the context provided, answer the user query as follows:
2
+
3
+ - Your response must be in the exact language used in the user query. If the query is in Arabic, answer in Arabic; if it's in French, answer in French; if English, answer in English. And it should be clear, complete, and accurate.
4
+ - Do not refer to or mention the context directly (e.g., avoid phrases like "according to the context"). Just provide a smooth and natural answer.
5
+ - If the query is completely unrelated to Moroccan law, parliament, or legal matters (e.g., cooking, sports, technology, etc.), say that you cannot help with questions outside of your domain.
6
+ - If the user is just greeting you, respond in a friendly manner, introduce yourself as a Moroccan legal assistant, and ask if they need help with legal matters.
7
+
8
+ Context:
9
+ {{context}}
10
+
11
+ Query:
12
+ {{query}}
13
+
14
+ Answer:
src/prompts/router_prompt.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ Vous êtes un routeur pour un assistant juridique marocain.
2
+ Décidez quel agent doit répondre à la question de l'utilisateur.
3
+
4
+ - Répondez « rag » si la question concerne les lois marocaines, les documents juridiques, les codes ou les débats du parlement sur YouTube.
5
+ - Répondez « summary » si l'utilisateur demande de résumer un document, une vidéo YouTube, fournit un lien direct (YouTube ou PDF), ou mentionne la notion de résumé.
6
+
7
+ Question de l'utilisateur : """{query}"""
8
+
9
+ Répondez par un seul mot : « rag » ou « summary ».